<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class ACUI_Batch_Exporter{
	protected $path = '';
	protected $filename;
	protected $limit = 50;
	protected $exported_row_count = 0;
	protected $row_data = array();
	protected $total_rows = 0;
	protected $columns_to_export = array();
	
    protected $page = 1;
    protected $delimiter = ',';
    protected $role = '';
    protected $from = '';
    protected $to = '';
    protected $convert_timestamp = false;
    protected $datetime_format;
    protected $order_fields_alphabetically = false;
    protected $double_encapsulate_serialized_values = false;
	protected $display_arrays_as_comma_separated_list_of_values = false;
    protected $filtered_columns = array();
    protected $orderby = '';
    protected $order = '';

    protected $user_data;
    protected $accepted_order_by;
    protected $woocommerce_default_user_meta_keys;
    protected $other_non_date_keys;
    
    function __construct() {
        add_filter( 'acui_export_columns', array( $this, 'maybe_order_columns_alphabetacally' ), 10, 2 );
		add_filter( 'acui_export_data', array( $this, 'maybe_double_encapsulate_serialized_values' ), 8, 3 );
        add_filter( 'acui_export_data', array( $this, 'maybe_order_row_alphabetically' ), 10, 3 );
		add_filter( 'acui_export_data', array( $this, 'maybe_order_row_filtered_columns_parameter' ), 11, 5 );
        
		$this->filename = uniqid( 'user-export-' . get_current_user_id() . '-' ) . ".csv";
		$this->user_data = array( "user_login", "user_email", "source_user_id", "user_pass", "user_nicename", "user_url", "user_registered", "display_name" );
        $this->accepted_order_by = array( 'ID', 'display_name', 'name', 'user_name', 'login', 'user_login', 'nicename', 'user_nicename', 'email', 'user_email', 'url', 'user_url', 'registered', 'user_registered', 'post_count' );
		$this->woocommerce_default_user_meta_keys = array( 'billing_first_name', 'billing_last_name', 'billing_email', 'billing_phone', 'billing_country', 'billing_address_1', 'billing_city', 'billing_state', 'billing_postcode', 'shipping_first_name', 'shipping_last_name', 'shipping_country', 'shipping_address_1', 'shipping_address_2', 'shipping_city', 'shipping_state', 'shipping_postcode' );
		$this->other_non_date_keys = array( 'shipping_phone', '_vat_number', '_billing_vat_number' );
	}

	function fill_total_rows( $recalculate_total_rows = false ){
		$this->total_rows = $this->get_total_rows( $recalculate_total_rows );
	}

    function get_non_date_keys(){
		return apply_filters( 'acui_export_non_date_keys', array_merge( $this->user_data, $this->woocommerce_default_user_meta_keys, $this->other_non_date_keys ) );
	}

    function maybe_order_columns_alphabetacally( $row, $args ){
        if( !$args['order_fields_alphabetically'] )
			return $row;
		
		sort( $row, SORT_LOCALE_STRING );
		return $row;
	}

	function maybe_order_row_alphabetically( $row, $user, $args ){
        if( !$args['order_fields_alphabetically'] )
			return $row;

        $row_sorted = array();
        foreach( $args['columns'] as $field ){
            $row_sorted[ $field ] = $row[ $field ];
        }

        return $row_sorted;
	}

    function maybe_order_row_filtered_columns_parameter( $row, $user, $args ){
        if( !is_array( $args['filtered_columns'] ) || count( $args['filtered_columns'] ) == 0 )
			return $row;

        $row_sorted = array();
        foreach( $args['filtered_columns'] as $field ){
            $row_sorted[ $field ] = isset( $row[ $field ] ) ? $row[ $field ] : '';
        }

        return $row_sorted;
	}

    function maybe_double_encapsulate_serialized_values( $row, $user, $args ){
        if( !$args['double_encapsulate_serialized_values'] )
			return $row;

        foreach( $args['columns'] as $field ){
            if( is_serialized( $row[ $field ] ) )
                $row[ $field ] = '"' . $row[ $field ] . '"';
        }

        return $row;
	}

    function load_columns(){
        $row = array();
		
		foreach ( $this->get_user_data() as $key ) {
            $row[ $key ] = $key;
		}

        if( count( $this->get_filtered_columns() ) == 0 || in_array( 'role', $this->get_filtered_columns() ) )
		    $row[ "role" ] = "role";

		foreach ( $this->get_user_meta_keys() as $key ) {
			$row[ $key ] = $key;
		}

		$columns = apply_filters( 'acui_export_columns', $row, array( 
			'order_fields_alphabetically' => $this->get_order_fields_alphabetically(), 
			'double_encapsulate_serialized_values' => $this->get_double_encapsulate_serialized_values(), 
			'filtered_columns' => $this->get_filtered_columns() ) );
		
		$this->set_columns_to_export( $columns );
    }

	function set_path( $path ){
		$this->path = $path;
	}

	function get_path(){
		return $this->path;
	}

    function set_columns_to_export( $columns ) {
		$this->columns_to_export = $columns;
	}

	function extract_keys_names_from_columns( $columns ){
		$elements = array_values( $columns );
		$columns_array = array();

		foreach( $elements as $element ){
			if( strpos( $element, '=>' ) !== false ){
				list( $key, $value ) = explode( '=>', $element );
				$columns_array[ trim( $key ) ] = trim( $value );
			} else {
				$columns_array[ $element ] = trim( $element );
			}
		}

		return $columns_array;
	}

	function get_columns_to_export() {
		return $this->columns_to_export;
	}

	function get_columns_keys_to_export(){
		return array_keys( $this->columns_to_export );
	}

	function get_columns_names_to_export(){
		return ( count( $this->get_filtered_columns( 'names' ) ) > 0 ) ? array_values( $this->get_filtered_columns( 'names' ) ) : $this->columns_to_export;
	}

    function set_delimiter( $delimiter ){
        switch ( $delimiter ) {
			case 'COMMA':
				$this->delimiter = ",";
				break;
			
			case 'COLON':
				$this->delimiter = ":";
				break;

			case 'SEMICOLON':
				$this->delimiter = ";";
				break;

			case 'TAB':
				$this->delimiter = "\t";
				break;

            default:
                $this->delimiter = ",";
                break;
		}
    }

    function get_delimiter() {
		return $this->delimiter;
	}

    function set_role( $role ){
        $this->role = $role;
    }

    function get_role(){
		if( empty( $this->role ) )
			return '';
		
		return is_array( $this->role ) ? $this->role : explode( ',', $this->role );
    }

    function set_from( $from ){
        $this->from = $from;
    }

    function get_from(){
        return $this->from;
    }

    function set_to( $to ){
        $this->to = $to;
    }

    function get_to(){
        return $this->to;
    }

    function set_convert_timestamp( $convert_timestamp ){
        $this->convert_timestamp = filter_var( $convert_timestamp, FILTER_VALIDATE_BOOLEAN );
    }

    function get_convert_timestamp(){
        return $this->convert_timestamp;
    }

    function set_datetime_format( $datetime_format ){
        $this->datetime_format = $datetime_format;
    }

    function get_datetime_format(){
        return $this->datetime_format;
    }

    function set_order_fields_alphabetically( $order_fields_alphabetically ){
        $this->order_fields_alphabetically = filter_var( $order_fields_alphabetically, FILTER_VALIDATE_BOOLEAN );
    }

    function get_order_fields_alphabetically(){
        return $this->order_fields_alphabetically;
    }

    function set_double_encapsulate_serialized_values( $double_encapsulate_serialized_values ){
        $this->double_encapsulate_serialized_values = filter_var( $double_encapsulate_serialized_values, FILTER_VALIDATE_BOOLEAN );
    }

    function get_double_encapsulate_serialized_values(){
        return $this->double_encapsulate_serialized_values;
    }

	function set_display_arrays_as_comma_separated_list_of_values( $display_arrays_as_comma_separated_list_of_values ){
        $this->display_arrays_as_comma_separated_list_of_values = filter_var( $display_arrays_as_comma_separated_list_of_values, FILTER_VALIDATE_BOOLEAN );
    }

    function get_display_arrays_as_comma_separated_list_of_values(){
        return $this->display_arrays_as_comma_separated_list_of_values;
    }

    function set_filtered_columns( $filtered_columns ){
        if ( ! is_array( $filtered_columns ) ) {
            $filtered_columns = preg_replace( '/\s*,\s*/', ',', $filtered_columns );
        }
        $filtered_columns = ( is_array( $filtered_columns ) ) ? array_map( 'sanitize_text_field', $filtered_columns ) : explode( ',', sanitize_text_field( $filtered_columns ) );

        if( empty( $filtered_columns[0] ) )
            $filtered_columns = array();

        $this->filtered_columns = array_map( 'trim', $this->extract_keys_names_from_columns( $filtered_columns ) );
		
		if( $this->get_order_fields_alphabetically() )
			ksort( $this->filtered_columns );
    }

    function get_filtered_columns( $return = 'keys' ){
        return ( $return == 'keys' ) ? array_keys( $this->filtered_columns ) : array_values( $this->filtered_columns );
    }

    function set_orderby( $orderby ){
        $this->orderby = $orderby;
    }

    function get_orderby(){
        return $this->orderby;
    }

    function set_order( $order ){
        $this->order = $order;
    }

    function get_order(){
        return $this->order;
    }

    function get_total_rows( $recalculate_total_rows = false ){
        $total_rows = ( $recalculate_total_rows ) ? 0 : get_transient( 'acui_export_total_rows' );
		
        if( empty( $total_rows ) ){
            $this->total_rows = $this->calculate_total();
        }
        else{
            $this->total_rows = $total_rows;
        }

        return $this->total_rows;
    }

    function get_total_steps(){
        return floor( $this->get_total_rows() / $this->get_limit() ) + 1;
    }

    function set_time_limit( $limit = 0 ) {
        if ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
            @set_time_limit( $limit );
        }
    }

    function maybe_define_constant( $name, $value ) {
        if ( ! defined( $name ) ) {
            define( $name, $value );
        }
    }

    function set_nocache_constants() {
		$this->maybe_define_constant( 'DONOTCACHEPAGE', true );
		$this->maybe_define_constant( 'DONOTCACHEOBJECT', true );
		$this->maybe_define_constant( 'DONOTCACHEDB', true );
	}

    function send_nocache_headers() {
        $this->set_nocache_constants();
        nocache_headers();
    }

	function send_headers() {
		if ( function_exists( 'gc_enable' ) ) {
			gc_enable();
		}
		if ( function_exists( 'apache_setenv' ) ) {
			@apache_setenv( 'no-gzip', 1 );
		}
		@ini_set( 'zlib.output_compression', 'Off' );
		@ini_set( 'output_buffering', 'Off' );
		@ini_set( 'output_handler', '' );
		ignore_user_abort( true );
		$this->set_time_limit( 0 );
		$this->send_nocache_headers();
		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename=' . $this->get_filename() );
		header( 'Pragma: no-cache' );
		header( 'Expires: 0' );
	}

	function set_filename( $filename ) {
		$this->filename = sanitize_file_name( str_replace( '.csv', '', $filename ) . '.csv' );
	}

	function get_filename() {
		return sanitize_file_name( $this->filename );
	}

	function send_content( $csv_data ) {
		echo $csv_data;
	}

	protected function get_csv_data() {
		return $this->export_rows();
	}

	protected function export_column_headers() {
		$columns = $this->get_columns_names_to_export();
		$export_row = array();
		$buffer = fopen( 'php://output', 'w' );
		ob_start();

		foreach ( $columns as $key => $value ) {
			$export_row[] = $this->format_data( $value );
		}

		$this->fputcsv( $buffer, $export_row );

		return ob_get_clean();
	}

	protected function get_data_to_export() {
		return $this->row_data;
	}

	protected function export_rows() {
		$data   = $this->get_data_to_export();
		$buffer = fopen( 'php://output', 'w' );
		ob_start();

		array_walk( $data, array( $this, 'export_row' ), $buffer );

		return ob_get_clean();
	}

	protected function export_row( $row_data, $key, $buffer ) {
		$this->fputcsv( $buffer, $row_data );
		++ $this->exported_row_count;
	}

	function get_limit() {
		return $this->limit;
	}

	function set_limit( $limit ) {
		$this->limit = ( $limit == -1 ) ? $limit : absint( $limit );
	}

	function escape_data( $data ) {
		$active_content_triggers = array( '=', '+', '-', '@' );

		if ( in_array( mb_substr( $data, 0, 1 ), $active_content_triggers, true ) ) {
			$data = "'" . $data;
		}

		return $data;
	}

	function format_data( $data ) {
		if ( is_bool( $data ) ) {
			$data = $data ? 1 : 0;
		}

		$use_mb = function_exists( 'mb_convert_encoding' );
		if ( $use_mb ) {
			$encoding = mb_detect_encoding( $data, mb_detect_order(), true );
			if ( $encoding ) {
				$data = mb_convert_encoding( $data, 'UTF-8', $encoding );
			} else {
				$data = mb_convert_encoding( $data, 'UTF-8', 'UTF-8' );
			}
		} else {
			$data = wp_check_invalid_utf8( $data, true );
		}

		return $this->escape_data( $data );
	}
    
	protected function implode_values( $values ) {
		$values_to_implode = array();

		foreach ( $values as $value ) {
			$value               = (string) is_scalar( $value ) ? $value : '';
			$values_to_implode[] = str_replace( ',', '\\,', $value );
		}

		return implode( ', ', $values_to_implode );
	}

	protected function fputcsv( $buffer, $export_row ) {
		if ( version_compare( PHP_VERSION, '5.5.4', '<' ) ) {
			ob_start();
			$temp = fopen( 'php://output', 'w' );
    		fputcsv( $temp, $export_row, $this->get_delimiter(), '"' );
			fclose( $temp );
			$row = ob_get_clean();
			$row = str_replace( '\\"', '\\""', $row );
			fwrite( $buffer, $row );
		} else {
			fputcsv( $buffer, $export_row, $this->get_delimiter(), '"', "\0" );
		}
	}

    protected function get_file_path() {
		if( !empty( $this->get_path() ) )
			return $this->get_path();
		
		$upload_dir = wp_upload_dir();
		return trailingslashit( $upload_dir['basedir'] ) . $this->get_filename();
	}

    protected function get_headers_row_file_path() {
		return $this->get_file_path() . '.headers';
	}

	function get_headers_row_file() {
		$file = chr( 239 ) . chr( 187 ) . chr( 191 ) . $this->export_column_headers();

		if ( @file_exists( $this->get_headers_row_file_path() ) ){
			$file = @file_get_contents( $this->get_headers_row_file_path() );
		}

		return $file;
	}

	function get_file() {
		$file = '';
		if ( @file_exists( $this->get_file_path() ) ){
			$file = @file_get_contents( $this->get_file_path() );
		} else {
			@file_put_contents( $this->get_file_path(), '' );
			@chmod( $this->get_file_path(), 0664 );
		}
		return $file;
	}

	function export() {
		$this->send_headers();
		$this->send_content( $this->get_headers_row_file() . $this->get_file() );

		do_action( 'acui_export_before_delete_file', $this->get_file_path() );

		@unlink( $this->get_file_path() );
		@unlink( $this->get_headers_row_file_path() );
		die();
	}
    
    function generate_file() {
        if( 1 === $this->get_page() ){
			@unlink( $this->get_file_path() );

			$this->get_file();
		}
		$this->prepare_data_to_export();
		$this->write_csv_data( $this->get_csv_data() );
	}

    function calculate_total(){
        $total_rows = count( $this->get_user_id_list( true ) );
        set_transient( 'acui_export_total_rows', $total_rows, HOUR_IN_SECONDS );

        return $total_rows;
    }

	protected function write_csv_data( $data ) {
		if ( ! file_exists( $this->get_file_path() ) || ! is_writeable( $this->get_file_path() ) ) {
			return false;
		}

		$fp = fopen( $this->get_file_path(), 'a+' );

		if ( $fp ) {
			fwrite( $fp, $data );
			fclose( $fp );
		}

		if ( 100 <= $this->get_percent_complete() ) {
			$header = chr( 239 ) . chr( 187 ) . chr( 191 ) . $this->export_column_headers();

			@file_put_contents( $this->get_headers_row_file_path(), $header );
		}

	}

	function get_page() {
		return $this->page;
	}

    function set_page( $page ) {
		$this->page = absint( $page );
	}

	function get_total_exported() {
		return ( ( $this->get_page() - 1 ) * $this->get_limit() ) + $this->exported_row_count;
	}

	function get_percent_complete() {
        return $this->get_total_rows() ? floor( ( $this->get_total_exported() / $this->get_total_rows() ) * 100 ) : 100;
	}
    
    function get_user_data(){
        if( count( $this->get_filtered_columns() ) == 0 )
            return $this->user_data;
        
        $result = array();
        foreach( $this->user_data as $column ){
            if( in_array( $column, $this->get_filtered_columns() ) )
                $result[] = $column;
        }
        
        return $result;
    }

    function get_user_id_list( $calculate_total = false ){
        $args = array( 'fields' => array( 'ID' ), 'order' => $this->get_order() );

        if( !$calculate_total && $this->get_limit() != -1 ){
            $args['number'] = $this->get_limit();
            $args['offset'] = ($this->get_page() - 1) * $this->get_limit();
        }

		if( !empty( $this->get_role() ) )
			$args['role__in'] = $this->get_role();

		$date_query = array();

		if( !empty( $this->get_from() ) )
			$date_query[] = array( 'after' => $this->get_from(), 'inclusive' => true );
		
		if( !empty( $this->get_to() ) )
			$date_query[] = array( 'before' => $this->get_to(), 'inclusive' => true );

		if( !empty( $date_query ) ){
			$date_query['inclusive'] = true;
			$args['date_query'] = $date_query;
		}

        if( !empty( $this->get_orderby() ) ){
			if( in_array( $this->get_orderby(), $this->accepted_order_by ) )
			    $args['orderby'] = $this->get_orderby();
            else{
                $args['orderby'] = "meta_value";
                $args['meta_key'] = $this->get_orderby();
            }
		}

		$args['meta_query'] = array(
			'relation' => 'OR',
			array( 'key' => '_acui_exclude_from_export', 'compare' => 'NOT EXISTS' ),
			array( 'key' => '_acui_exclude_from_export', 'value' => '1', 'compare' => '!=' ),
		);

		$users = get_users( $args );

        if( $calculate_total )
            return $users;

		$list = array();

	    foreach ( $users as $user ) {
	    	$list[] = $user->ID;
	    }

	    return $list;
	}
    
	function prepare_data_to_export() {
		$users = $this->get_user_id_list();
        $this->row_data = array();

		foreach ( $users as $user ) {
            $row = array();
			$userdata = get_userdata( $user );

            foreach ( $this->get_user_data() as $key ) {
				if( $key == 'source_user_id' )
					$row[ $key ] = $this->prepare( $key, $userdata->ID, $this->get_datetime_format(), $user );
				else
					$row[ $key ] = $this->prepare( $key, $userdata->data->{$key}, $this->get_datetime_format(), $user );
			}

            if( count( $this->get_filtered_columns() ) == 0 || in_array( 'role', $this->get_filtered_columns() ) )
			    $row['role'] = implode( ',', ACUIHelper()->get_roles_by_user_id( $user ) );

			foreach ( $this->get_user_meta_keys() as $key ) {
				$row[ $key ] = $this->prepare( $key, get_user_meta( $user, $key, true ), $this->get_datetime_format(), $user );
			}

            if( count( $this->get_filtered_columns() ) == 0 || in_array( 'user_email', $this->get_filtered_columns() ) || in_array( 'user_login', $this->get_filtered_columns() ) )
			    $row = $this->maybe_fill_empty_data( $row, $user, $this->get_filtered_columns() );
			
			$row = apply_filters( 'acui_export_data', $row, $user, array( 
				'columns' => $this->get_columns_to_export(), 
				'datetime_format' => $this->get_datetime_format(), 
				'order_fields_alphabetically' => $this->get_order_fields_alphabetically(), 
				'double_encapsulate_serialized_values' => $this->get_double_encapsulate_serialized_values(),
				'filtered_columns' => $this->get_filtered_columns() 
			) );

			foreach( $row as $key => $value )
				$row[ $key ] = apply_filters( 'acui_export_data_' . $key, $value );

            $this->row_data[] = array_values( $row );
		}
	}

    function prepare( $key, $value, $datetime_format = '', $user = 0 ){
		$original_value = $value;

		$value = $this->clean_bad_characters_formulas( $value, $key, $user );

        if( has_filter( 'acui_export_prepare' ) ){
            return apply_filters( 'acui_export_prepare', $value, $original_value );
        }

		if( $key == 'role' ){
			return implode( ',', ACUIHelper()->get_roles_by_user_id( $user ) );
		}

		if( 
			( is_array( $value ) || ( is_string( $value ) && is_array( @unserialize( $value, array( 'allowed_classes' => false ) ) ) ) ) 
			&& 
			$this->get_display_arrays_as_comma_separated_list_of_values() 
		){
			$value_array = is_serialized( $value ) ? unserialize( $value, array( 'allowed_classes' => false ) ) : $value;

			if( ACUIHelper()->array_one_dimension( $value_array ) && ACUIHelper()->array_correlative_index( $value_array ) && !ACUIHelper()->array_contains_wp_error( $value_array ) ){
				return implode( ',', $value_array );
			}
		}

		if( is_array( $value ) || is_object( $value ) ){
			return serialize( $value );
		}

		if( in_array( $key, $this->get_non_date_keys() ) || empty( $datetime_format ) ){
			return $value;
		}

		if( $this->get_convert_timestamp() && (string)(int)$value == $value && ( ( $this->is_valid_timestamp( $value ) && strlen( $value ) > 4 ) || in_array( $key, apply_filters( 'acui_export_timestamp_keys', array( 'wc_last_active' ) ) ) ) ){ // dates in timestamp format
			return date( $datetime_format, $value );
		}

        return $value;
	}

    function clean_bad_characters_formulas( $value, $key, $user ){
        if( !is_string( $value ) )
            return $value;

		if( strlen( $value ) == 0 )
			return $value;

		$bad_characters = array( "\t", "\r", "+", "-", "=", "@" );
		$first_character = substr( $value, 0, 1 );
		if( in_array( $first_character, $bad_characters ) ){
			$value = "'" . $first_character . substr( $value, 1 );
			$this->add_bad_character_formulas_values_cleaned( $key, $value, $user );
		}

		return $value;
	}

	function add_bad_character_formulas_values_cleaned( $key, $value, $user ){
		$current = get_transient( 'acui_export_bad_character_formulas_values_cleaned' );
		if( !is_array( $current ) )
			$current = array();

		$current[] = array( 'key' => $key, 'value' => $value, 'user_id' => $user );
		set_transient( 'acui_export_bad_character_formulas_values_cleaned', $current );
	}

    function is_valid_timestamp( $timestamp ){
		return ( (string) (int) $timestamp === $timestamp ) && ( $timestamp <= PHP_INT_MAX ) && ( $timestamp >= ~PHP_INT_MAX );
	}

    function maybe_fill_empty_data( $row, $user_id, $filtered_columns ){
		if( empty( $row['user_login'] ) || empty( $row['user_email'] ) ){
			$user = new WP_User( $user_id );

			if( $user->ID == 0 )
				return $row;

            if( count( $filtered_columns ) == 0 || in_array( 'user_login', $filtered_columns ) )
			    $row['user_login'] = $user->user_login;

            if( count( $filtered_columns ) == 0 || in_array( 'user_email', $filtered_columns ) )
			    $row['user_email'] = $user->user_email;
		}
		
		return $row;
	}

    function get_user_meta_keys() {
	    global $wpdb;
	    $meta_keys = array();

        $usermeta = get_transient( 'acui_export_user_meta_keys' );
		
        if( empty( $usermeta ) ){
            $usermeta = $wpdb->get_results( "SELECT distinct BINARY($wpdb->usermeta.meta_key) as meta_key FROM $wpdb->usermeta", ARRAY_A );
            set_transient( 'acui_export_user_meta_keys', $usermeta, HOUR_IN_SECONDS );
        }

	  	foreach( $usermeta as $key => $value) {
			if( $value["meta_key"] == 'role' || $value["meta_key"] == 'source_user_id' )
				continue;

            if( count( $this->get_filtered_columns() ) == 0 || in_array( $value["meta_key"], $this->get_filtered_columns() ) )
			    $meta_keys[] = $value["meta_key"];
		}

	    return apply_filters( 'acui_export_get_user_meta_keys', $meta_keys );
	}
}
