<?php
/**
 * Class SEOPRESS_CSV_Setup_Wizard_Controller file.
 *
 * @version     3.7
 * @source 		WooCommerce/Admin/Importers/class-wc-product-csv-importer-controller.php
 */
defined('ABSPATH') or exit('Please don&rsquo;t call the plugin directly. Thanks :)');

if ( ! class_exists('WP_Importer')) {
    return;
}

/**
 * SEOPRESS_CSV_Setup_Wizard_Controller class.
 */
class SEOPRESS_CSV_Setup_Wizard_Controller
{
    /**
     * The path to the current file.
     *
     * @var string
     */
    protected $file = '';

    /**
     * Current step.
     *
     * @var string
     */
    private $step = '';

    /**
     * Steps for the setup wizard.
     *
     * @var array
     */
    private $steps = [];

    /**
     * Errors.
     *
     * @var array
     */
    protected $errors = [];

    /**
     * The current delimiter for the file being read.
     *
     * @var string
     */
    protected $delimiter = ';';

    /**
     * Ignore existing metadata.
     *
     * @var boolean
     */
    protected $import_ignore_metadata = false;

    /**
     * Get importer instance.
     *
     * @param string $file file to import
     * @param array  $args importer arguments
     *
     * @return SEOPRESS_CSV_Importer
     */
    public static function get_importer($file, $args = [])
    {
        $importer_class = apply_filters('seopress_csv_importer_class', 'SEOPRESS_CSV_Importer');
        $args = apply_filters('seopress_csv_importer_args', $args, $importer_class);

        return new $importer_class($file, $args);
    }

    /**
     * Check whether a file is a valid CSV file.
     *
     * @param string $file       file path
     * @param bool   $check_path whether to also check the file is located in a valid location (Default: true)
     *
     * @return bool
     */
    public static function is_file_valid_csv($file, $check_path = true)
    {
        if ($check_path && apply_filters('seopress_csv_importer_check_import_file_path', true) && false !== stripos($file, '://')) {
            return false;
        }

        $valid_filetypes = self::get_valid_csv_filetypes();
        $filetype = wp_check_filetype($file, $valid_filetypes);
        if (in_array($filetype['type'], $valid_filetypes, true)) {
            return true;
        }

        return false;
    }

    /**
     * Get all the valid filetypes for a CSV file.
     *
     * @return array
     */
    protected static function get_valid_csv_filetypes()
    {
        return apply_filters(
            'seopress_csv_import_valid_filetypes',
            [
                'csv' => 'text/csv',
            ]
        );
    }

    /**
     * Constructor.
     */
    public function __construct()
    {
        $default_steps = [
            'upload' => [
                'name' => esc_html__('Upload CSV file', 'wp-seopress-pro'),
                'view' => [$this, 'upload_form'],
                'handler' => [$this, 'upload_form_handler'],
            ],
            'mapping' => [
                'name' => esc_html__('Column mapping', 'wp-seopress-pro'),
                'view' => [$this, 'mapping_form'],
                'handler' => '',
            ],
            'import' => [
                'name' => esc_html__('Import', 'wp-seopress-pro'),
                'view' => [$this, 'import'],
                'handler' => '',
            ],
            'done' => [
                'name' => esc_html__('Done!', 'wp-seopress-pro'),
                'view' => [$this, 'done'],
                'handler' => '',
            ],
        ];

        $this->steps = apply_filters('seopress_setup_csv_wizard_steps', $default_steps);

        $this->step = isset($_REQUEST['step']) ? sanitize_key($_REQUEST['step']) : current(array_keys($this->steps));
        $this->file = isset($_REQUEST['file']) ? seopress_clean(wp_unslash($_REQUEST['file'])) : '';
        $this->delimiter = ! empty($_REQUEST['delimiter']) ? seopress_clean(wp_unslash($_REQUEST['delimiter'])) : ';';
        $this->import_ignore_metadata = ! empty($_REQUEST['import_ignore_metadata']) ? esc_attr($_REQUEST['import_ignore_metadata']) : false;

        // Import mappings for CSV data.
        include_once dirname(__FILE__) . '/mapping.php';
    }

    /**
     * Get the URL for the next step's screen.
     *
     * @param string $step slug (default: current step)
     *
     * @return string URL for next step if a next step exists.
     *                Admin URL if it's the last step.
     *                Empty string on failure.
     *
     * @since 3.7
     */
    public function get_next_step_link($step = '')
    {
        if ( ! $step) {
            $step = $this->step;
        }

        $keys = array_keys($this->steps);

        if (end($keys) === $step) {
            return admin_url();
        }

        $step_index = array_search($step, $keys, true);

        if (false === $step_index) {
            return '';
        }

        $params = [
            'step' => $keys[$step_index + 1],
            'file' => $this->file,
            'delimiter' => $this->delimiter,
            'import_ignore_metadata' => $this->import_ignore_metadata,
            '_wpnonce' => wp_create_nonce('seopress-csv-importer'),
        ];

        return add_query_arg($params);
    }

    /**
     * Output header view.
     */
    protected function output_header()
    { ?>
<div class="seopress-option seopress-wizard">
    <?php }

    /**
     * Output steps view.
     */
    protected function output_steps()
    {
        $output_steps = $this->steps; ?>
    <ol class="seopress-setup-steps">
        <?php
                $i = 1;
        foreach ($output_steps as $step_key => $step) {
            $is_completed = array_search($this->step, array_keys($this->steps), true) > array_search($step_key, array_keys($this->steps), true);

            if ($step_key === $this->step) {
                ?>
        <li class="active">
            <div class="icon" data-step="<?php echo $i; ?>"></div>
            <span><?php echo esc_html($step['name']); ?></span>
            <div class="divider"></div>
        </li>
        <?php
            } elseif ($is_completed) {
                ?>
        <li class="done">
            <div class="icon" data-step="<?php echo $i; ?>"></div>
            <a
                href="<?php echo esc_url(add_query_arg('step', $step_key, remove_query_arg('activate_error'))); ?>">
                <?php echo esc_html($step['name']); ?>
            </a>
            <div class="divider"></div>
        </li>
        <?php
            } else {
                ?>
        <li>
            <div class="icon" data-step="<?php echo $i; ?>"></div>
            <span><?php echo esc_html($step['name']); ?></span>
            <div class="divider"></div>
        </li>
        <?php
            }
            ++$i;
        } ?>
    </ol>
    <?php
    }

    /**
     * Output the content for the current step.
     */
    public function output_content()
    { ?>

    <?php if ( ! empty($this->steps[$this->step]['view'])) {
        call_user_func($this->steps[$this->step]['view'], $this);
    } ?>


    <?php
    }

    /**
     * Output footer view.
     */
    protected function output_footer()
    { ?>
</div>
<?php do_action('seopress_setup_footer');
    }

    /**
     * Add error message.
     *
     * @param string $message error message
     * @param array  $actions list of actions with 'url' and 'label'
     */
    protected function add_error($message, $actions = [])
    {
        $this->errors[] = [
            'message' => $message,
            'actions' => $actions,
        ];
    }

    /**
     * Add error message.
     */
    protected function output_errors()
    {
        if ( ! $this->errors) {
            return;
        }

        foreach ($this->errors as $error) { ?>
            <div class="seopress-notice is-error">
                <p><?php esc_html_e($error['message']); ?></p>

                <?php if ( ! empty($error['actions'])) { ?>
                    <p>
                        <?php foreach ($error['actions'] as $action) { ?>
                            <a class="btn btnPrimary"
                                href="<?php echo esc_url($action['url']); ?>">
                                <?php esc_html_e($action['label']); ?>
                            </a>
                        <?php } ?>
                    </p>
                <?php
                } ?>
            </div>
        <?php }
    }

    /**
     * Dispatch current step and show correct view.
     */
    public function dispatch()
    {
        if ( ! empty($_POST['save_step']) && ! empty($this->steps[$this->step]['handler'])) {
            call_user_func($this->steps[$this->step]['handler'], $this);
        }
        $this->output_steps();
        $this->output_header();
        $this->output_errors();
        $this->output_content();
        $this->output_footer();
    }

    /**
     * Output information about the uploading process.
     */
    protected function upload_form()
    {
        $bytes = apply_filters('import_upload_size_limit', wp_max_upload_size());
        $size = size_format($bytes);
        $upload_dir = wp_upload_dir(); ?>

<h1>
    <?php esc_html_e('Import metadata from a CSV file', 'wp-seopress-pro'); ?>
</h1>
<form method="post" enctype="multipart/form-data">
    <div class="seopress-notice">
        <p>
            <?php esc_html_e('This tool allows you to import SEO metadata to your site from a CSV file.', 'wp-seopress-pro'); ?>
        </p>
        <p>
            <?php esc_html_e('Existing posts / terms that match by ID will be updated.', 'wp-seopress-pro'); ?>
        </p>
        <p>
            <?php esc_html_e('Posts, pages, custom post types or term taxonomies that do not exist will be skipped.', 'wp-seopress-pro'); ?>
        </p>
    </div>

    <?php
        if ( ! empty($upload_dir['error'])) {
            ?>
    <div class="inline error">
        <p>
            <?php esc_html_e('Before you can upload your import file, you will need to fix the following error:', 'wp-seopress-pro'); ?>
        </p>
        <p>
            <strong><?php echo esc_html($upload_dir['error']); ?></strong>
        </p>
    </div>
    <?php
        } else { ?>
    <p>
        <strong>
            <?php esc_html_e('Select your separator:', 'wp-seopress-pro'); ?>
        </strong>
    </p>
    <p>
        <label for="import_sep_comma">
            <input id="import_sep_comma" name="delimiter" type="radio" value="comma" />
            <?php echo wp_kses_post(__('Comma separator: <code>,</code>', 'wp-seopress-pro')); ?>
        </label>
    </p>
    <p>
        <label for="import_sep_semicolon">
            <input id="import_sep_semicolon" name="delimiter" type="radio" value="semicolon" />
            <?php echo wp_kses_post(__('Semicolon separator: <code>;</code>', 'wp-seopress-pro')); ?>
        </label>
    </p>
    <p>
        <strong>
            <label
                for="import_file"><?php esc_html_e('Choose a CSV file from your computer:', 'wp-seopress-pro'); ?></label>
        </strong>
    </p>
    <p>
        <input type="file" id="upload" name="import" size="25" />
        <input type="hidden" name="action" value="save" />
        <input type="hidden" name="max_file_size"
            value="<?php echo esc_attr($bytes); ?>" />

        <small>
            <?php
                $bytes = apply_filters('import_upload_size_limit', wp_max_upload_size());
            $size = size_format($bytes);
            $upload_dir = wp_upload_dir();
            printf(
                /* translators: %s: maximum upload size */
                esc_html__('Maximum size: %s', 'wp-seopress-pro'),
                esc_html($size)
            );
            ?>
        </small>
    </p>
    <p>
        <strong>
            <?php esc_html_e('Ignore existing values?', 'wp-seopress-pro'); ?>
        </strong>
    </p>
    <p>
        <label for="import_ignore_metadata">
            <input id="import_ignore_metadata" name="import_ignore_metadata" type="checkbox" value="1" />
            <?php esc_html_e('Existing post and term metas will not be updated. Only empty values will be filled.', 'wp-seopress-pro'); ?>
        </label>
    </p>
    <?php
        } ?>
    <p class="seopress-setup-actions step">
        <button type="submit" class="btn btnPrimary"
            value="<?php esc_attr_e('Next step', 'wp-seopress-pro'); ?>"
            name="save_step">
            <?php esc_html_e('Next step', 'wp-seopress-pro'); ?>
        </button>
        <?php wp_nonce_field('seopress-csv-importer'); ?>
    </p>
</form>

<?php
    }

    /**
     * Handle the upload form and store options.
     */
    public function upload_form_handler()
    {
        check_admin_referer('seopress-csv-importer');

        $file = $this->handle_upload();

        if (is_wp_error($file)) {
            $this->add_error($file->get_error_message());

            return;
        } else {
            $this->file = $file;
        }

        wp_redirect(esc_url_raw($this->get_next_step_link()));
        exit;
    }

    /**
     * Handles the CSV upload and initial parsing of the file.
     *
     * @return string|WP_Error
     */
    public function handle_upload()
    {
        $file_url = isset($_POST['file_url']) ? sanitize_text_field(wp_unslash($_POST['file_url'])) : '';

        if (empty($file_url)) {
            if ( ! isset($_FILES['import'])) {
                return new WP_Error('seopress_metadata_csv_importer_upload_file_empty', esc_html__('File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.', 'wp-seopress-pro'));
            }

            if ( ! self::is_file_valid_csv(sanitize_text_field(wp_unslash($_FILES['import']['name'])), false)) {
                return new WP_Error('seopress_metadata_csv_importer_upload_file_invalid', esc_html__('Invalid file type. The importer supports CSV and TXT file formats.', 'wp-seopress-pro'));
            }

            $overrides = [
                'test_form' => false,
                'mimes' => self::get_valid_csv_filetypes(),
            ];
            $import = $_FILES['import'];
            $upload = wp_handle_upload($import, $overrides);

            if (isset($upload['error'])) {
                return new WP_Error('seopress_metadata_csv_importer_upload_error', $upload['error']);
            }

            // Construct the object array.
            $object = [
                'post_title' => basename($upload['file']),
                'post_content' => $upload['url'],
                'post_mime_type' => $upload['type'],
                'guid' => $upload['url'],
                'context' => 'import',
                'post_status' => 'private',
            ];

            // Save the data.
            $id = wp_insert_attachment($object, $upload['file']);

            /*
             * Schedule a cleanup for one day from now in case of failed
             * import or missing wp_import_cleanup() call.
             */
            wp_schedule_single_event(time() + DAY_IN_SECONDS, 'importer_scheduled_cleanup', [$id]);

            return $upload['file'];
        } elseif (file_exists(ABSPATH . $file_url)) {
            if ( ! self::is_file_valid_csv(ABSPATH . $file_url)) {
                return new WP_Error('seopress_metadata_csv_importer_upload_file_invalid', esc_html__('Invalid file type. The importer supports CSV and TXT file formats.', 'wp-seopress-pro'));
            }

            return ABSPATH . $file_url;
        }

        return new WP_Error('seopress_metadata_csv_importer_upload_invalid_file', esc_html__('Please upload or provide the link to a valid CSV file.', 'wp-seopress-pro'));
    }

    /**
     * Column mapping.
     */
    public function mapping_form()
    {
        check_admin_referer('seopress-csv-importer');
        $args = [
            'lines' => 1,
            'delimiter' => $this->delimiter,
        ];

        $importer = self::get_importer($this->file, $args);
        $headers = $importer->get_raw_keys();
        $mapped_items = $this->auto_map_columns($headers);
        $sample = current($importer->get_raw_data());

        if (empty($sample)) {
            $this->add_error(
                esc_html__('The file is empty or using a different encoding than UTF-8, please try again with a new file.', 'wp-seopress-pro'),
                [
                    [
                        'url' => admin_url('admin.php?page=seopress_csv_importer'),
                        'label' => esc_html__('Upload a new file', 'wp-seopress-pro'),
                    ],
                ]
            );

            // Force output the errors in the same page.
            $this->output_errors();

            return;
        } ?>
<h1>
    <?php esc_html_e('Map CSV fields to post metas', 'wp-seopress-pro'); ?>
</h1>
<form method="post"
    action="<?php echo esc_url($this->get_next_step_link()); ?>">
    <p>
        <?php esc_html_e('Select fields from your CSV file to map against posts / terms fields, or to ignore during import.', 'wp-seopress-pro'); ?>
    </p>

    <section class="seopress-importer-mapping-table-wrapper">
        <table class="widefat seopress-importer-mapping-table">
            <thead>
                <tr>
                    <th>
                        <?php esc_html_e('Column name', 'wp-seopress-pro'); ?>
                    </th>
                    <th>
                        <?php esc_html_e('Map to field', 'wp-seopress-pro'); ?>
                    </th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ($headers as $index => $name) { ?>
                <?php $mapped_value = $mapped_items[$index];
                $hidden = in_array($name, ['post_type', 'taxonomy']) ? ' style="display:none"' : '';
                ?>
                <tr<?php echo $hidden; ?>>
                    <td class="seopress-importer-mapping-table-name">
                        <?php echo esc_html($name); ?>
                        <?php if ( ! empty($sample[$index])) { ?>
                        <span
                            class="description"><?php esc_html_e('Sample:', 'wp-seopress-pro'); ?>
                            <code><?php echo esc_html($sample[$index]); ?></code></span>
                        <?php } ?>
                    </td>
                    <td class="seopress-importer-mapping-table-field">
                        <input type="hidden"
                            name="map_from[<?php echo esc_attr($index); ?>]"
                            value="<?php echo esc_attr($name); ?>" />
                        <select
                            name="map_to[<?php echo esc_attr($index); ?>]">
                            <option value="">
                                <?php esc_html_e('Do not import', 'wp-seopress-pro'); ?>
                            </option>
                            <option value="">--------------</option>
                            <?php foreach ($this->get_mapping_options($mapped_value) as $key => $value) { ?>
                            <option
                                value="<?php echo esc_attr($key); ?>"
                                <?php selected($mapped_value, $key); ?>><?php echo esc_html($value); ?>
                            </option>
                            <?php } ?>
                        </select>
                    </td>
                </tr>
                <?php } ?>
            </tbody>
        </table>
    </section>

    <p class="seopress-setup-actions step">
        <button type="submit" class="btn btnPrimary"
            value="<?php esc_attr_e('Run the importer', 'wp-seopress-pro'); ?>"
            name="save_step">
            <?php esc_html_e('Run the importer', 'wp-seopress-pro'); ?>
        </button>
        <input type="hidden" name="file"
            value="<?php echo esc_attr($this->file); ?>" />
        <input type="hidden" name="delimiter"
            value="<?php echo esc_attr($this->delimiter); ?>" />
        <input type="hidden" name="import_ignore_metadata"
            value="<?php echo esc_attr($this->import_ignore_metadata); ?>" />
        <?php wp_nonce_field('seopress-csv-importer'); ?>
    </p>
</form>
<?php
    }

    /**
     * Import the file if it exists and is valid.
     */
    public function import()
    {
        // Displaying this page triggers Ajax action to run the import with a valid nonce,
        // therefore this page needs to be nonce protected as well.
        check_admin_referer('seopress-csv-importer');

        if ( ! self::is_file_valid_csv($this->file)) {
            $this->add_error(esc_html__('Invalid file type. The importer supports CSV and TXT file formats.', 'wp-seopress-pro'));
            $this->output_errors();

            return;
        }

        if ( ! is_file($this->file)) {
            $this->add_error(esc_html__('The file does not exist, please try again.', 'wp-seopress-pro'));
            $this->output_errors();

            return;
        }

        if ( ! empty($_POST['map_from']) && ! empty($_POST['map_to'])) {
            $mapping_from = seopress_clean(wp_unslash($_POST['map_from']));
            $mapping_to = seopress_clean(wp_unslash($_POST['map_to']));
        } else {
            wp_redirect(esc_url_raw($this->get_next_step_link('upload')));
            exit;
        }
        wp_localize_script(
            'seopress-csv-import',
            'seopress_csv_import_params',
            [
                'import_nonce' => wp_create_nonce('seopress-csv-importer'),
                'mapping' => [
                    'from' => $mapping_from,
                    'to' => $mapping_to,
                ],
                'file' => $this->file,
                'delimiter' => $this->delimiter,
                'import_ignore_metadata' => $this->import_ignore_metadata,
            ]
        );
        //wp_print_scripts( 'seopress-csv-import' );
        wp_enqueue_script('seopress-csv-import'); ?>
<h1>
    <?php esc_html_e('Importing', 'wp-seopress-pro'); ?>
</h1>
<p>
    <?php esc_html_e('Your metadata are now being imported...', 'wp-seopress-pro'); ?>
</p>
<div class="seopress-progress-form-content seopress-importer seopress-importer__importing">
    <section>
        <span class="spinner is-active"></span>
        <progress class="seopress-importer-progress" max="100" value="0"></progress>
    </section>
</div>
<?php
    }

    /**
     * Final step.
     */
    public function done()
    {
        check_admin_referer('seopress-csv-importer');
        $imported = isset($_GET['metadatas-imported']) ? absint($_GET['metadatas-imported']) : 0;
        $updated = isset($_GET['metadatas-updated']) ? absint($_GET['metadatas-updated']) : 0;
        $failed = isset($_GET['metadatas-failed']) ? absint($_GET['metadatas-failed']) : 0;
        $skipped = isset($_GET['metadatas-skipped']) ? absint($_GET['metadatas-skipped']) : 0;
        $errors = array_filter((array) get_user_option('seopress_import_error_log')); ?>
<h2>
    <?php esc_html_e('Import complete!', 'wp-seopress-pro'); ?>
</h2>

<div class="seopress-progress-form-content seopress-importer">
    <section class="seopress-importer-done">
        <?php
                    $results = [];

        if (0 < $imported) {
            $results[] = sprintf(
                /* translators: %s: posts count */
                _n('%s post or term imported.', '%s posts / terms imported.', $imported, 'wp-seopress-pro'),
                '<strong>' . number_format_i18n($imported) . '</strong>'
            );
        }

        if (0 < $updated) {
            $results[] = sprintf(
                /* translators: %s: posts count */
                _n('%s post or term updated.', '%s posts / terms updated.', $updated, 'wp-seopress-pro'),
                '<strong>' . number_format_i18n($updated) . '</strong>'
            );
        }

        if (0 < $skipped) {
            $results[] = sprintf(
                /* translators: %s: posts count */
                _n('%s post or term was skipped.', '%s posts / terms were skipped.', $skipped, 'wp-seopress-pro'),
                '<strong>' . number_format_i18n($skipped) . '</strong>'
            );
        }

        if (0 < $failed) {
            $results[] = sprintf(
                /* translators: %s: posts count */
                _n('Failed to import %s post or term.', 'Failed to import %s posts / terms.', $failed, 'wp-seopress-pro'),
                '<strong>' . number_format_i18n($failed) . '</strong>'
            );
        }

        if (0 < $failed || 0 < $skipped) {
            $results['log'] = '<a href="#" class="seopress-importer-done-view-errors">' . esc_html__('View import log', 'wp-seopress-pro') . '</a>';
        }

        if ( ! empty($results)) {
            echo '<ul>';
            foreach ($results as $key => $result) {
                if ($key === 'log') {
                    echo '<li><br>' . $result . '</li>';
                } else {
                    echo '<li><span class="dashicons dashicons-minus"></span>' . $result . '</li>';
                }
            }
            echo '<ul>';
        }
        ?>
    </section>
    <section class="seopress-importer-error-log" style="display:none">
        <table class="widefat seopress-importer-error-log-table">
            <thead>
                <tr>
                    <th><?php esc_html_e('Post', 'wp-seopress-pro'); ?>
                    </th>
                    <th><?php esc_html_e('Reason for failure', 'wp-seopress-pro'); ?>
                    </th>
                </tr>
            </thead>
            <tbody>
                <?php
                    if (count($errors)) {
                        foreach ($errors as $error) {
                            if ( ! is_wp_error($error)) {
                                continue;
                            }
                            $error_data = $error->get_error_data(); ?>
                <tr>
                    <th><code><?php echo esc_html($error_data['row']); ?></code>
                    </th>
                    <td><?php echo esc_html($error->get_error_message()); ?>
                    </td>
                </tr>
                <?php
                        }
                    } ?>
            </tbody>
        </table>
    </section>
    <script type="text/javascript">
        jQuery(function() {
            jQuery('.seopress-importer-done-view-errors').on('click', function() {
                jQuery('.seopress-importer-error-log').slideToggle();
                return false;
            });
        });
    </script>
    <div class="seopress-actions">
        <p>
            <a class="btn btnPrimary"
                href="<?php echo esc_url(admin_url('edit.php')); ?>"><?php esc_html_e('View posts', 'wp-seopress-pro'); ?></a>
            <a class="btn btnSecondary"
                href="<?php echo esc_url(admin_url('admin.php?page=seopress_csv_importer&step=upload')); ?>">
                <?php esc_html_e('Make another import', 'wp-seopress-pro'); ?>
            </a>
        </p>
    </div>
</div>
<?php
    }

    /**
     * Columns to normalize.
     *
     * @param array $columns list of columns names and keys
     *
     * @return array
     */
    protected function normalize_columns_names($columns)
    {
        $normalized = [];

        foreach ($columns as $key => $value) {
            $normalized[strtolower($key)] = $value;
        }

        return $normalized;
    }

    /**
     * Auto map column names.
     *
     * @param array $raw_headers raw header columns
     * @param bool  $num_indexes if should use numbers or raw header columns as indexes
     *
     * @return array
     */
    protected function auto_map_columns($raw_headers, $num_indexes = true)
    {
        $default_columns = $this->normalize_columns_names(
            apply_filters(
                'seopress_csv_metadata_import_mapping_default_columns',
                [
                    esc_html__('ID', 'wp-seopress-pro') => 'id',
                    esc_html__('Post / term title', 'wp-seopress-pro') => 'post_title',
                    esc_html__('Slug', 'wp-seopress-pro') => 'slug',
                    esc_html__('Taxonomy', 'wp-seopress-pro') => 'taxonomy',
                    esc_html__('Post Type', 'wp-seopress-pro') => 'post_type',
                    esc_html__('Meta Title', 'wp-seopress-pro') => 'meta_title',
                    esc_html__('Meta description', 'wp-seopress-pro') => 'meta_desc',
                    esc_html__('Facebook title', 'wp-seopress-pro') => 'fb_title',
                    esc_html__('Facebook description', 'wp-seopress-pro') => 'fb_desc',
                    esc_html__('Facebook thumbnail', 'wp-seopress-pro') => 'fb_img',
                    esc_html__('X title', 'wp-seopress-pro') => 'tw_title',
                    esc_html__('X description', 'wp-seopress-pro') => 'tw_desc',
                    esc_html__('X thumbnail', 'wp-seopress-pro') => 'tw_img',
                    esc_html__('noindex', 'wp-seopress-pro') => 'noindex',
                    esc_html__('nofollow', 'wp-seopress-pro') => 'nofollow',
                    esc_html__('noimageindex', 'wp-seopress-pro') => 'noimageindex',
                    esc_html__('noarchive', 'wp-seopress-pro') => 'noarchive',
                    esc_html__('nosnippet', 'wp-seopress-pro') => 'nosnippet',
                    esc_html__('Canonical URL', 'wp-seopress-pro') => 'canonical_url',
                    esc_html__('Primary category', 'wp-seopress-pro') => 'primary_cat',
                    esc_html__('Active redirect', 'wp-seopress-pro') => 'redirect_active',
                    esc_html__('Redirect status', 'wp-seopress-pro') => 'redirect_status',
                    esc_html__('Redirection type', 'wp-seopress-pro') => 'redirect_type',
                    esc_html__('URL redirect', 'wp-seopress-pro') => 'redirect_url',
                    esc_html__('Target Keyword', 'wp-seopress-pro') => 'target_kw',
                ],
                $raw_headers
            )
        );

        $headers = [];
        foreach ($raw_headers as $key => $field) {
            $field = strtolower($field);
            $index = $num_indexes ? $key : $field;
            $headers[$index] = $field;

            if (isset($default_columns[$field])) {
                $headers[$index] = $default_columns[$field];
            }
        }

        return apply_filters('seopress_csv_metadata_import_mapping_default_columns', $headers, $raw_headers);
    }

    /**
     * Get mapping options.
     *
     * @param string $item item name
     *
     * @return array
     */
    protected function get_mapping_options($item = '')
    {
        // Available options.
        $options = [
            'id' => esc_html__('ID', 'wp-seopress-pro'),
            'post_title' => esc_html__('Post / term title', 'wp-seopress-pro'),
            'slug' => esc_html__('Slug', 'wp-seopress-pro'),
            'taxonomy' => esc_html__('Taxonomy', 'wp-seopress-pro'),
            'post_type' => esc_html__('Post Type', 'wp-seopress-pro'),
            'meta_title' => esc_html__('Meta Title', 'wp-seopress-pro'),
            'meta_desc' => esc_html__('Meta description', 'wp-seopress-pro'),
            'fb_title' => esc_html__('Facebook title', 'wp-seopress-pro'),
            'fb_desc' => esc_html__('Facebook description', 'wp-seopress-pro'),
            'fb_img' => esc_html__('Facebook thumbnail', 'wp-seopress-pro'),
            'tw_title' => esc_html__('X title', 'wp-seopress-pro'),
            'tw_desc' => esc_html__('X description', 'wp-seopress-pro'),
            'tw_img' => esc_html__('X thumbnail', 'wp-seopress-pro'),
            'noindex' => esc_html__('noindex? (yes)', 'wp-seopress-pro'),
            'nofollow' => esc_html__('nofollow? (yes)', 'wp-seopress-pro'),
            'noimageindex' => esc_html__('noimageindex? (yes)', 'wp-seopress-pro'),
            'noarchive' => esc_html__('noarchive? (yes)', 'wp-seopress-pro'),
            'nosnippet' => esc_html__('nosnippet? (yes)', 'wp-seopress-pro'),
            'canonical_url' => esc_html__('Canonical URL', 'wp-seopress-pro'),
            'primary_cat' => esc_html__('Primary category', 'wp-seopress-pro'),
            'redirect_active' => esc_html__('Active redirect', 'wp-seopress-pro'),
            'redirect_status' => esc_html__('Redirect status', 'wp-seopress-pro'),
            'redirect_type' => esc_html__('Redirection type', 'wp-seopress-pro'),
            'redirect_url' => esc_html__('URL redirect', 'wp-seopress-pro'),
            'target_kw' => esc_html__('Target Keyword', 'wp-seopress-pro'),
        ];

        return apply_filters('seopress_csv_metadata_import_mapping_options', $options, $item);
    }
}
