Skip to content

Instantly share code, notes, and snippets.

@hissy
Last active August 13, 2023 17:06
Show Gist options
  • Star 58 You must be signed in to star a gist
  • Fork 21 You must be signed in to fork a gist
  • Save hissy/6739352 to your computer and use it in GitHub Desktop.
Save hissy/6739352 to your computer and use it in GitHub Desktop.
[WordPress Plugin] Nav Menu Exporter and Importer / Export and Import nav menus. Requires WordPress Importer plugin.
<?php
/*
Plugin Name: Nav Menu Exporter and Importer
Description: Export and Import nav menus. Requires WordPress Importer plugin
Author: hissy, megumi themes
Version: 0.1
Text Domain: nav-menu-exporter-importer
License: GPL version 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/
/**
* Exporter
*/
function add_mav_menu_to_export() {
$post_type = get_post_type_object('nav_menu_item');
?>
<p><label><input type="radio" name="content" value="<?php echo esc_attr( $post_type->name ); ?>" /> <?php echo esc_html( $post_type->label ); ?></label></p>
<?php
}
add_action('export_filters','add_mav_menu_to_export');
/**
* Importer
*/
if ( ! defined( 'WP_LOAD_IMPORTERS' ) )
return;
// Load Importer API
require_once ABSPATH . 'wp-admin/includes/import.php';
if ( ! class_exists( 'WP_Importer' ) ) {
$class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
if ( file_exists( $class_wp_importer ) )
require $class_wp_importer;
}
// include WXR file parsers
$wordpress_importer = ABSPATH . 'wp-content/plugins/wordpress-importer/wordpress-importer.php';
if ( file_exists( $wordpress_importer ) )
require_once $wordpress_importer;
/**
* Nav Menu Importer class
*/
if ( class_exists( 'WP_Import' ) ) {
class Nav_Menu_Importer extends WP_Import {
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();
}
function greet() {
wp_import_upload_form( add_query_arg('step', 1) );
}
function import_end() {
wp_import_cleanup( $this->id );
wp_cache_flush();
echo '<p>' . __( 'All done.', 'wordpress-importer' ) . ' <a href="' . admin_url() . '">' . __( 'Have fun!', 'wordpress-importer' ) . '</a>' . '</p>';
}
function import( $file ) {
$this->import_start( $file );
wp_suspend_cache_invalidation( true );
// only processing nav menus
$this->process_menus();
wp_suspend_cache_invalidation( false );
$this->import_end();
}
function process_menus() {
$count = 0;
foreach ( $this->posts as $item ) {
$count++;
// check the item is public nav item
if ( 'nav_menu_item' == $item['post_type'] && 'draft' != $item['status'] ) {
$menu_slug = false;
if ( isset($item['terms']) ) {
// loop through terms, assume first nav_menu term is correct menu
foreach ( $item['terms'] as $term ) {
if ( 'nav_menu' == $term['domain'] ) {
$menu_slug = $term['slug'];
break;
}
}
}
// no nav_menu term associated with this menu item
if ( ! $menu_slug ) {
_e( 'Menu item skipped due to missing menu slug', 'wordpress-importer' );
echo '<br>';
continue;
}
$menu_id = term_exists( $menu_slug, 'nav_menu' );
if ( ! $menu_id ) {
printf( __( 'Menu item skipped due to invalid menu slug: %s', 'wordpress-importer' ), esc_html( $menu_slug ) );
echo '<br>';
continue;
} else {
$menu_id = is_array( $menu_id ) ? $menu_id['term_id'] : $menu_id;
}
// set postmeta
foreach ( $item['postmeta'] as $meta )
$$meta['key'] = $meta['value'];
// skip nav item when menu item object is not exists
switch ($_menu_item_type) {
case 'taxonomy':
$_menu_item_object_id = get_term($_menu_item_object_id,$_menu_item_object);
if ($_menu_item_object_id == null || is_wp_error($_menu_item_object_id)) {
printf( __( 'Menu item skipped due to %s is not exists', 'nav-menu-exporter-importer' ), esc_html( $_menu_item_object ) );
echo '<br>';
}
break;
case 'post_type':
$_menu_item_object_id = get_post($_menu_item_object_id);
if ($_menu_item_object_id instanceof WP_Post) {
$_menu_item_object_id = $_menu_item_object_id->ID;
unset($_post);
} else {
printf( __( 'Menu item skipped due to %s is not exists', 'nav-menu-exporter-importer' ), esc_html( $_menu_item_object ) );
echo '<br>';
}
break;
}
if ($_menu_item_object_id == null || is_wp_error($_menu_item_object_id))
continue;
// wp_update_nav_menu_item expects CSS classes as a space separated string
$_menu_item_classes = maybe_unserialize( $_menu_item_classes );
if ( is_array( $_menu_item_classes ) )
$_menu_item_classes = implode( ' ', $_menu_item_classes );
$args = array(
'menu-item-object-id' => $_menu_item_object_id,
'menu-item-object' => $_menu_item_object,
'menu-item-parent-id' => $_menu_item_menu_item_parent,
'menu-item-position' => intval( $item['menu_order'] ),
'menu-item-type' => $_menu_item_type,
'menu-item-title' => $item['post_title'],
'menu-item-url' => $_menu_item_url,
'menu-item-description' => $item['post_content'],
'menu-item-attr-title' => $item['post_excerpt'],
'menu-item-target' => $_menu_item_target,
'menu-item-classes' => $_menu_item_classes,
'menu-item-xfn' => $_menu_item_xfn,
'menu-item-status' => $item['status']
);
$r = wp_update_nav_menu_item( $menu_id, 0, $args );
if ( $r && is_wp_error( $r ) ) {
echo $r->get_error_message();
echo '<br>';
} else {
echo '.';
}
}
}
echo '<br>';
printf( __( '%s items processed.', 'nav-menu-exporter-importer' ), esc_html( $count ) );
}
}
// setup importer
$nav_menu_importer = new Nav_Menu_Importer();
register_importer('nav_menu', __('Nav Menu', 'nav-menu-exporter-importer'), __('Export and Import nav menus. Requires WordPress Importer plugin', 'nav-menu-exporter-importer'), array ($nav_menu_importer, 'dispatch'));
} // class_exists( 'WP_Import' )
@thednp
Copy link

thednp commented Apr 20, 2014

Hi. Thanks for your code. I was wondering if we can implement your code and merge with this one here
http://wordpress.org/support/topic/failure-to-import-post-meta-for-nav-menu-item?replies=6#post-3926917

This one should include the menu items meta data, something that's missing as well from WP Importer.

Thanks for any reply.

@thatryan
Copy link

Super helpful, thank you for sharing! Just saved me a few hours :)

@cubalibre
Copy link

Hi, can I export only a specific menu name and not all definited menus?

Thanks for any reply.

@robinpecha
Copy link

Hi,
plugin like this is really important. It last (probalby) working one in the world.
But it didnt work in my case.
After importing wp shows error:
Menu item skipped due to invalid menu slug: default
Menu item skipped due to invalid menu slug: default
Menu item skipped due to invalid menu slug: default
....

@chrslcy
Copy link

chrslcy commented Jul 30, 2016

I am getting the same error as reported by robinpecha.

@chrslcy
Copy link

chrslcy commented Jul 30, 2016

The above error reported by robinpecha is overcome by creating empty menus with the same name as the source website menus before importing. However, once imported, the menus are flat, having lost all submenu structure.

@bobettekyle
Copy link

Great job. This just saved me from setting up over 100 menu items. FYI, the one quirk: menu hierarchy is lost on the imported menu. The new menu has all top-level items. They looked to be ordered by original menu level. i.e. all the top-level items first, followed by their children, etc.

As chrslcy suggested, I first made empty menus in the site I was importing to, identical in name to the originals.

I got two import errors. These make sense because I had two pages on the old site that were not on the new site. Can't find what is not there.

@yelnyafacee
Copy link

how to use this 'plugin'?

there is no guide or instructions about how to 'install' this

@raynov
Copy link

raynov commented Oct 20, 2016

@elzix
Copy link

elzix commented Nov 16, 2016

I have tried this plugin and raynov's patched plugin. I cannot seem to get a plugin that works for custom menus. I have a single page solution with anchor links (#something) for the menu. Having no menu gives errors described above. Creating an empty menu solves the error problem. However the menu items are not created at all.

@overclokk
Copy link

I made some fix and modification, with WordPress 4.7 in my dev enviroments it works fine with tax, post_type and custom nav menu items and now if the menu doesn't exist it will be created during the import.
Here the link https://gist.github.com/overclokk/bad83a7cb3db4263192aa52db0a60fc0

@renegithub
Copy link

renegithub commented Jan 30, 2017

Hello,

can I use this Tool to migrate from one Domain www.123.com to another Domain www.abc.de
How can I do this?

The pages are the same on both Domains.

I´ve renamed in domains inside the export file to the new domain, but I got this error:

Menu item skipped due to invalid menu slug: primary

Best regards,

Rene

@TELUS-Alexander
Copy link

It is unfortunate but this tool does not work in multisite.

@duchuy
Copy link

duchuy commented Jun 20, 2019

how to use this 'plugin'?

there is no guide or instructions about how to 'install' this

save the file as nav-menu-exporter-importer.php and put into wp-content/plugins/wordpress-importer directory. then go into Plugins in Admin Dashboard to activate

@css31
Copy link

css31 commented Mar 22, 2020

Hi,
Almost working.
Export is OK (do not update Nav Menu Exporter and Importer).
Import run well (create a menu with same name before) : 87 items processed. But menu is empty.
Anyway thank you,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment