web-dev-qa-db-fra.com

Echec de l'importation de la méta du menu de navigation

Je suis l'auteur du plug-in Rôles de menus de navigation qui vous permet d'afficher/masquer des éléments de menu en fonction du rôle de l'utilisateur. Il a été porté à mon attention que la méta de l'élément de menu n'est pas importée lors de l'utilisation du plugin/outil WordPress standard pour l'importation.

Chaque élément de menu est essentiellement une publication dans la base de données, et j’enregistre les données au format méta. Il apparaît dans le XML exporté. Voici un exemple d'un test d'exportation que je viens de faire localement.

<item>
    <title>Art &amp; Design</title>
    <link>http://localhost/blog/2013/01/13/263/</link>
    <pubDate>Mon, 14 Jan 2013 03:36:16 +0000</pubDate>
    <dc:creator>helga</dc:creator>
    <guid isPermaLink="false">http://localhost/blog/2013/01/13/263/</guid>
    <description></description>
    <content:encoded><![CDATA[]]></content:encoded>
    <excerpt:encoded><![CDATA[]]></excerpt:encoded>
    <wp:post_id>263</wp:post_id>
    <wp:post_date>2013-01-13 22:36:16</wp:post_date>
    <wp:post_date_gmt>2013-01-14 03:36:16</wp:post_date_gmt>
    <wp:comment_status>open</wp:comment_status>
    <wp:ping_status>open</wp:ping_status>
    <wp:post_name>263</wp:post_name>
    <wp:status>publish</wp:status>
    <wp:post_parent>0</wp:post_parent>
    <wp:menu_order>1</wp:menu_order>
    <wp:post_type>nav_menu_item</wp:post_type>
    <wp:post_password></wp:post_password>
    <wp:is_sticky>0</wp:is_sticky>
    <category domain="nav_menu" nicename="main-menu"><![CDATA[Main Menu]]></category>
    <wp:postmeta>
        <wp:meta_key>_menu_item_type</wp:meta_key>
        <wp:meta_value><![CDATA[taxonomy]]></wp:meta_value>
    </wp:postmeta>
    <wp:postmeta>
        <wp:meta_key>_menu_item_menu_item_parent</wp:meta_key>
        <wp:meta_value><![CDATA[0]]></wp:meta_value>
    </wp:postmeta>
    <wp:postmeta>
        <wp:meta_key>_menu_item_object_id</wp:meta_key>
        <wp:meta_value><![CDATA[6]]></wp:meta_value>
    </wp:postmeta>
    <wp:postmeta>
        <wp:meta_key>_menu_item_object</wp:meta_key>
        <wp:meta_value><![CDATA[category]]></wp:meta_value>
    </wp:postmeta>
    <wp:postmeta>
        <wp:meta_key>_menu_item_target</wp:meta_key>
        <wp:meta_value><![CDATA[]]></wp:meta_value>
    </wp:postmeta>
    <wp:postmeta>
        <wp:meta_key>_menu_item_classes</wp:meta_key>
        <wp:meta_value><![CDATA[a:1:{i:0;s:6:"design";}]]></wp:meta_value>
    </wp:postmeta>
    <wp:postmeta>
        <wp:meta_key>_menu_item_xfn</wp:meta_key>
        <wp:meta_value><![CDATA[]]></wp:meta_value>
    </wp:postmeta>
    <wp:postmeta>
        <wp:meta_key>_menu_item_url</wp:meta_key>
        <wp:meta_value><![CDATA[]]></wp:meta_value>
    </wp:postmeta>
    <wp:postmeta>
        <wp:meta_key>_nav_menu_role</wp:meta_key>
        <wp:meta_value><![CDATA[a:2:{i:0;s:13:"administrator";i:1;s:12:"shop_manager";}]]></wp:meta_value>
    </wp:postmeta>
</item>

Mais lors de l'importation, la clé méta _nav_menu_role n'apparaît même pas dans la base de données. Je gère un site multisite localement, mais l'utilisateur qui a signalé ce problème à mon attention ne le fait pas. J'aimerais résoudre ce problème pour tous ceux qui utilisent ce plugin, mais je ne sais pas trop par où commencer à chercher. Je pensais que cela pourrait être un problème de sérialisation/non-sérialisation, mais la clé n'est pas corrompue, elle n'y est même pas après l'importation.

UPDATE: J'ai étudié le plug-in importateur et, pour les éléments de menu, le plug-in importe uniquement les métadonnées prédéfinies traditionnelles, telles que 'class'.

5
helgatheviking

Le problème était finalement avec le plugin WordPress Importer. Je pourrais le pirater (et j'ai suggéré une amélioration aux développeurs) mais je vais contourner ce problème en écrivant un propre importateur personnalisé. Ce n'est pas le plus pratique (télécharger à nouveau le fichier .XML), mais dans les cas où les utilisateurs ont des menus complexes, il vaut mieux que de perdre les méta-valeurs.

Il a besoin de plus de tests, mais je devrais l'ajouter à mon plugin dans la prochaine version.

Importateur personnalisé pour élément de menu Meta

Le problème était finalement avec le plugin WordPress Importer. Je pourrais le pirater (et j'ai suggéré une amélioration aux développeurs) mais je vais contourner ce problème en écrivant un propre importateur personnalisé. Ce n'est pas le plus pratique (télécharger à nouveau le fichier .XML), mais dans les cas où les utilisateurs ont des menus complexes, il vaut mieux que de perdre les méta-valeurs.

Cela nécessite plus de tests, mais je devrais l'ajouter à mon plugin dans la prochaine version.

Importateur personnalisé pour élément de menu Meta

<?php
/**
 * Nav Menu Roles Importer - import menu item meta
 *
 */

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

if ( class_exists( 'WP_Importer' ) ) {
    class Nav_Menu_Roles_Import extends WP_Importer {

    var $max_wxr_version = 1.2; // max. supported WXR version

    var $id; // WXR attachment ID

    // information to import from WXR file
    var $version;
    var $posts = array();
    var $base_url = '';


        /**
         * __construct function.
         *
         * @access public
         * @return void
         */
        public function __construct() {
            $this->import_page = 'nav_menu_roles';
        }

    /**
     * Registered callback function for the WordPress Importer
     *
     * Manages the three separate stages of the WXR import process
     */
    function dispatch() {
        $this->header();

        $step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step'];
        switch ( $step ) {
            case 0:
                $this->greet();
                break;
            case 1:
                check_admin_referer( 'import-upload' );
                if ( $this->handle_upload() ) {
                    $file = get_attached_file( $this->id );
                    set_time_limit(0);
                    $this->import( $file );
                }
                break;
        }

        $this->footer();
    }

    /**
     * The main controller for the actual import stage.
     *
     * @param string $file Path to the WXR file for importing
     */
    function import( $file ) {
        add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
        add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );

        $this->import_start( $file );

        wp_suspend_cache_invalidation( true );
        $this->process_nav_menu_meta();
        wp_suspend_cache_invalidation( false );

        $this->import_end();
    }

    /**
     * Parses the WXR file and prepares us for the task of processing parsed data
     *
     * @param string $file Path to the WXR file for importing
     */
    function import_start( $file ) {
        if ( ! is_file($file) ) {
            echo '<p><strong>' . __( 'Sorry, there has been an error.', 'nav-menu-roles' ) . '</strong><br />';
            echo __( 'The file does not exist, please try again.', 'nav-menu-roles' ) . '</p>';
            $this->footer();
            die();
        }

        $import_data = $this->parse( $file );

        if ( is_wp_error( $import_data ) ) {
            echo '<p><strong>' . __( 'Sorry, there has been an error.', 'nav-menu-roles' ) . '</strong><br />';
            echo esc_html( $import_data->get_error_message() ) . '</p>';
            $this->footer();
            die();
        }

        $this->version = $import_data['version'];
        $this->posts = $import_data['posts'];
        $this->base_url = esc_url( $import_data['base_url'] );

        wp_defer_term_counting( true );
        wp_defer_comment_counting( true );

        do_action( 'import_start' );
    }

    /**
     * Performs post-import cleanup of files and the cache
     */
    function import_end() {
        wp_import_cleanup( $this->id );

        wp_cache_flush();
        foreach ( get_taxonomies() as $tax ) {
            delete_option( "{$tax}_children" );
            _get_term_hierarchy( $tax );
        }

        wp_defer_term_counting( false );
        wp_defer_comment_counting( false );

        echo '<p>' . __( 'All done.', 'nav-menu-roles' ) . ' <a href="' . admin_url() . '">' . __( 'Have fun!', 'nav-menu-roles' ) . '</a>' . '</p>';

        do_action( 'import_end' );
    }

    /**
     * Handles the WXR upload and initial parsing of the file to prepare for
     * displaying author import options
     *
     * @return bool False if error uploading or invalid file, true otherwise
     */
    function handle_upload() {
        $file = wp_import_handle_upload();

        if ( isset( $file['error'] ) ) {
            echo '<p><strong>' . __( 'Sorry, there has been an error.', 'nav-menu-roles' ) . '</strong><br />';
            echo esc_html( $file['error'] ) . '</p>';
            return false;
        } else if ( ! file_exists( $file['file'] ) ) {
            echo '<p><strong>' . __( 'Sorry, there has been an error.', 'nav-menu-roles' ) . '</strong><br />';
            printf( __( 'The export file could not be found at <code>%s</code>. It is likely that this was caused by a permissions problem.', 'nav-menu-roles' ), esc_html( $file['file'] ) );
            echo '</p>';
            return false;
        }

        $this->id = (int) $file['id'];
        $import_data = $this->parse( $file['file'] );
        if ( is_wp_error( $import_data ) ) {
            echo '<p><strong>' . __( 'Sorry, there has been an error.', 'nav-menu-roles' ) . '</strong><br />';
            echo esc_html( $import_data->get_error_message() ) . '</p>';
            return false;
        }

        $this->version = $import_data['version'];
        if ( $this->version > $this->max_wxr_version ) {
            echo '<div class="error"><p><strong>';
            printf( __( 'This WXR file (version %s) may not be supported by this version of the importer. Please consider updating.', 'nav-menu-roles' ), esc_html($import_data['version']) );
            echo '</strong></p></div>';
        }

        return true;
    }



    /**
     * Create new posts based on import information
     *
     * Posts marked as having a parent which doesn't exist will become top level items.
     * Doesn't create a new post if: the post type doesn't exist, the given post ID
     * is already noted as imported or a post with the same title and date already exists.
     * Note that new/updated terms, comments and meta are imported for the last of the above.
     */
    function process_nav_menu_meta() {
        foreach ( $this->posts as $post ) {

            // we only want to deal with the nav_menu_item posts
            if ( 'nav_menu_item' != $post['post_type'] || ! empty( $post['post_id'] ) )
                continue;

            // ok we've got a nav_menu_item
            $post_id = (int) $post['post_id'];

            // add/update post meta
            if ( isset( $post['postmeta'] ) ) {
                foreach ( $post['postmeta'] as $meta ) {
                    $key = apply_filters( 'import_post_meta_key', $meta['key'] );
                    $value = false;


                    if ( $key ) {
                        // export gets meta straight from the DB so could have a serialized string
                        if ( ! $value )
                            $value = maybe_unserialize( $meta['value'] );

                        update_post_meta( $post_id, $key, $value );
                        do_action( 'import_post_meta', $post_id, $key, $value );

                    }
                }
            }
        }

        unset( $this->posts );
    }




    /**
     * Parse a WXR file
     *
     * @param string $file Path to WXR file for parsing
     * @return array Information gathered from the WXR file
     */
    function parse( $file ) {
        $parser = new WXR_Parser();
        return $parser->parse( $file );
    }

    // Display import page title
    function header() {
        echo '<div class="wrap">';
        screen_icon();
        echo '<h2>' . __( 'Import Nav Menu Roles', 'nav-menu-roles' ) . '</h2>';

        $updates = get_plugin_updates();
        $basename = plugin_basename(__FILE__);
        if ( isset( $updates[$basename] ) ) {
            $update = $updates[$basename];
            echo '<div class="error"><p><strong>';
            printf( __( 'A new version of this importer is available. Please update to version %s to ensure compatibility with newer export files.', 'nav-menu-roles' ), $update->update->new_version );
            echo '</strong></p></div>';
        }
    }

    // Close div.wrap
    function footer() {
        echo '</div>';
    }

    /**
     * Display introductory text and file upload form
     */
    function greet() {
        echo '<div class="narrow">';
        echo '<p>'.__( 'Re-Upload your normal WordPress eXtended RSS (WXR) file and we&#8217;ll import the Nav Menu Roles and any other missing post meta for the Nav Menu items.', 'nav-menu-roles' ).'</p>';
        echo '<p>'.__( 'Choose a WXR (.xml) file to upload, then click Upload file and import.', 'nav-menu-roles' ).'</p>';
        wp_import_upload_form( 'admin.php?import=nav_menu_roles&amp;step=1' );
        echo '</div>';
    }

    /**
     * Decide if the given meta key maps to information we will want to import
     *
     * @param string $key The meta key to check
     * @return string|bool The key if we do want to import, false if not
     */
    function is_valid_meta_key( $key ) {
        // skip attachment metadata since we'll regenerate it from scratch
        // skip _edit_lock as not relevant for import
        if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) )
            return false;
        return $key;
    }


    /**
     * Added to http_request_timeout filter to force timeout at 60 seconds during import
     * @return int 60
     */
    function bump_request_timeout() {
        return 60;
    }

    // return the difference in length between two strings
    function cmpr_strlen( $a, $b ) {
        return strlen($b) - strlen($a);
    }


    } // end class
} // end if
0
helgatheviking