Instantly share code, notes, and snippets.
-
Star
7
(7)
You must be signed in to star a gist -
Fork
1
(1)
You must be signed in to fork a gist
-
Save overclokk/bad83a7cb3db4263192aa52db0a60fc0 to your computer and use it in GitHub Desktop.
<?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 | |
*/ | |
/** | |
* Original code https://gist.github.com/hissy/6739352 | |
* Forked from https://gist.github.com/raynov/5171cfb2083f35fb4e051183b47808ce | |
*/ | |
/** | |
* 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() { | |
$this->wp_import_upload_form( add_query_arg( 'step', 1 ) ); | |
} | |
function import_end() { | |
wp_import_cleanup( $this->id ); | |
wp_cache_flush(); | |
printf( | |
'<p>%s <a href="%s">%s</a></p>', | |
__( 'All done.', 'wordpress-importer' ), | |
admin_url( 'nav-menus.php' ), | |
__( 'Have fun!', 'wordpress-importer' ) | |
); | |
} | |
public 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(); | |
} | |
/** | |
* Upload the nav menu item | |
* | |
* @todo This works only with 2 levels of hierarchy | |
* Needs a method to work with more than 2 levels. | |
* | |
* @todo Theme menu position, when loaded it is not appended to no | |
* theme menu positions. Maybe depends to the export functionality. | |
* | |
* @todo More test for multiple menu | |
*/ | |
public function process_menus() { | |
$count = 0; | |
$parents = array(); | |
foreach ( $this->posts as $item ) { | |
$count++; | |
// check the item is public nav item | |
if ( 'nav_menu_item' !== $item['post_type'] ) { | |
continue; | |
} | |
if ( 'draft' === $item['status'] ) { | |
continue; | |
} | |
$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 ) { | |
printf( | |
__( 'Menu item <code>%s</code>" skipped due to missing menu slug. <br>', 'wordpress-importer' ), | |
esc_attr( $item['post_title'] ) | |
); | |
continue; | |
} | |
$menu_exists = wp_get_nav_menu_object( $menu_slug ); | |
if ( ! $menu_exists ) { | |
$menu_id = wp_create_nav_menu( $menu_slug ); | |
} | |
// $menu_id = term_exists( $menu_slug, 'nav_menu' ); | |
if ( ! $menu_id ) { | |
printf( | |
__( 'Menu item skipped due to invalid menu slug: %s %s', 'wordpress-importer' ), | |
esc_html( $menu_slug ), | |
'<br>' | |
); | |
continue; | |
} | |
// else { | |
// $menu_id = is_array( $menu_id ) ? $menu_id['term_id'] : $menu_id; | |
// } | |
// set postmeta | |
foreach ( (array) $item['postmeta'] as $meta ) { | |
/** | |
* This resolved PHP Notice: Array to string conversion | |
* I don't know way | |
*/ | |
$_key = $meta['key']; | |
$_value = $meta['value']; | |
$$_key = $_value; | |
} | |
if ( ! isset( $_menu_item_type ) ) { | |
continue; | |
} | |
// 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; | |
case 'custom': | |
if ( isset( $_POST['new_url'] ) && '#' !== $_menu_item_url ) { | |
$_menu_item_url = preg_replace( '/https?:\/\/([\w]+\.{1}[\w]+\.?[\w]+)+/', esc_url( $_POST['new_url'] ), $_menu_item_url ); | |
} | |
break; | |
} | |
if ( is_null( $_menu_item_object_id ) || 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 ); | |
} | |
$menu_item_parent_id = isset( $parents[ $_menu_item_menu_item_parent ] ) ? $parents[ $_menu_item_menu_item_parent ] : null; | |
/** | |
* This fix "Object of class WP_Term could not be converted to int" | |
* in "wp-includes/nav-menu.php:494" | |
*/ | |
if ( $_menu_item_object_id instanceof WP_Term ) { | |
$item['post_title'] = $_menu_item_object_id->name; | |
/** | |
* This prevents 'Trying to get property of non-object' | |
*/ | |
$_menu_item_object_id = $_menu_item_object_id->term_id; | |
} | |
$menu_item_data = array( | |
'menu-item-object-id' => $_menu_item_object_id, | |
'menu-item-object' => $_menu_item_object, | |
'menu-item-parent-id' => $menu_item_parent_id, | |
'menu-item-position' => absint( $item['menu_order'] ), | |
'menu-item-type' => $_menu_item_type, | |
'menu-item-title' => wp_slash( $item['post_title'] ), | |
// This is set maybe only for custom menu item. | |
'menu-item-url' => $_menu_item_url, | |
'menu-item-description' => wp_slash( $item['post_content'] ), | |
'menu-item-attr-title' => wp_slash( $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( (int) $menu_id, 0, (array) $menu_item_data ); | |
if ( $r && is_wp_error( $r ) ) { | |
echo $r->get_error_message(); | |
echo '<br>'; | |
} else { | |
$parents[ absint( $item['post_id'] ) ] = $r; | |
printf( | |
'<p>ID: <strong>%s</strong> - Title: <strong>%s</strong> - URL: <strong>%s</strong> - Type: <strong>%s</strong></p>', | |
$r, | |
$item['post_title'], | |
$_menu_item_url, | |
$_menu_item_type | |
); | |
} | |
} | |
echo '<br>'; | |
printf( __( '%s items processed.', 'nav-menu-exporter-importer' ), esc_html( $count ) ); | |
} | |
/** | |
* Outputs the form used by the importers to accept the data to be imported | |
* | |
* @see wp_import_upload_form( $action ) in 'https://core.trac.wordpress.org/browser/tags/4.7/src/wp-admin/includes/template.php#L846' | |
* | |
* @since 2.0.0 | |
* | |
* @param string $action The action attribute for the form. | |
*/ | |
public function wp_import_upload_form( $action ) { | |
/** | |
* Filters the maximum allowed upload size for import files. | |
* | |
* @since 2.3.0 | |
* | |
* @see wp_max_upload_size() | |
* | |
* @param int $max_upload_size Allowed upload size. Default 1 MB. | |
*/ | |
$bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() ); | |
$size = size_format( $bytes ); | |
$upload_dir = wp_upload_dir(); | |
if ( ! empty( $upload_dir['error'] ) ) : | |
?><div class="error"><p><?php _e( 'Before you can upload your import file, you will need to fix the following error:' ); ?></p> | |
<p><strong><?php echo $upload_dir['error']; ?></strong></p></div><?php | |
else : | |
?> | |
<form enctype="multipart/form-data" id="import-upload-form" method="post" class="wp-upload-form" action="<?php echo esc_url( wp_nonce_url( $action, 'import-upload' ) ); ?>"> | |
<p> | |
<label for="upload"><?php _e( 'Choose a file from your computer:' ); ?></label> (<?php printf( __( 'Maximum size: %s' ), $size ); ?>) | |
<input type="file" id="upload" name="import" size="25" /> | |
<br> | |
<label for="new_url"> | |
<?php | |
printf( | |
esc_html__( 'Use this field in case you are doing a migration from a domain to another, this works only for custom item menu url and not for custom menu with <code>#</code>.<br> <code>%s</code>' ), | |
esc_url( get_option( 'siteurl' ) ) | |
); | |
?> | |
</label> | |
<input type="text" id="new_url" name="new_url" /> | |
<input type="hidden" name="action" value="save" /> | |
<input type="hidden" name="max_file_size" value="<?php echo $bytes; // XSS ok. ?>" /> | |
</p> | |
<?php submit_button( __('Upload file and import' ), 'primary' ); ?> | |
</form> | |
<?php | |
endif; | |
} | |
} | |
// 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' ) |
Do not work with sub-menus items! Please fix it!
Hi Rene, what I did was to copy the php file above into Notepad++ and saved it as "Nav_Menu_Exporter_and_Importer_Plugin.php" Then I zipped or compressed the file so that its now: "Nav_Menu_Exporter_and_Importer_Plugin.zip". Then I logged into my WordPress site and installed it like you would any WordPress plugin
This is not working at all for me on WordPress 4.8. Export and Import seem to run fine but nothing shows up on the menus.
Attempting to export from a local build to import to a live server and just does not work. Is this not something that can be done? Only from a live site to a live site?
I'm getting the following error when trying to import the the export file generated by this plugin in WP 4.8
( ! ) Notice: Array to string conversion in /srv/www/eka.dev/current/web/app/plugins/wordpress-importer/wordpress-importer.php on line 884
--
Hi,
this looks like a very useful tool, but where do I have to insert the code / file nav-menu-exporter-importer.php?
Shall I copy the nav-menu-exporter-importer.php into the folder /httpdocs/wp-content/plugins/wordpress-importer?
Best regards,
Rene