-
Notifications
You must be signed in to change notification settings - Fork 16
Support Customize Menus #55
Changes from 15 commits
bef6bc6
bfe83dc
3b033d2
78affd1
bf9938b
9f0b918
4c73e3d
390083c
7d619f1
726e194
8ae0764
44d8d4a
b7176d3
3488780
6393ddd
924c872
19bbcfa
e42ac1a
2617a10
310b365
22504bd
bce3453
adca567
d5e0bbc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -124,6 +124,14 @@ public function __construct( Plugin $plugin ) { | |
add_action( 'admin_bar_menu', array( $this, 'customize_menu' ), 41 ); | ||
add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_templates' ) ); | ||
|
||
add_filter( 'theme_mod_nav_menu_locations', array( $this, 'filter_theme_mod_nav_menu_locations' ) ); | ||
add_filter( 'wp_get_nav_menus', array( $this, 'filter_wp_get_nav_menus' ) ); | ||
add_filter( 'wp_get_nav_menu_items', array( $this, 'filter_wp_get_nav_menu_items' ), 10, 3 ); | ||
add_filter( 'wp_get_nav_menu_object', array( $this, 'filter_wp_get_nav_menu_object' ), 10, 2 ); | ||
|
||
// Needs priority 12 since it has to happen after the default nav menus are registered. | ||
add_action( 'customize_register', array( $this, 'customize_register_nav_menus' ), 12 ); | ||
|
||
/* | ||
* Add WP_Customize_Widget component hooks which were short-circuited in 4.5 (r36611 for #35895). | ||
* See https://core.trac.wordpress.org/ticket/35895 | ||
|
@@ -380,6 +388,235 @@ function suspend_kses_for_snapshot_revision_restore() { | |
} ); | ||
} | ||
|
||
/** | ||
* Filter for displaying the Snapshot menu location values. | ||
* | ||
* @param array $menu_locations Default menu locations. | ||
* @return array Modified menu locations. | ||
*/ | ||
public function filter_theme_mod_nav_menu_locations( $menu_locations ) { | ||
if ( false === $this->snapshot->is_preview() ) { | ||
return $menu_locations; | ||
} | ||
|
||
$values = $this->snapshot->values(); | ||
$locations = get_registered_nav_menus(); | ||
|
||
foreach ( $locations as $location => $name ) { | ||
if ( isset( $values[ 'nav_menu_locations[' . $location . ']' ] ) ) { | ||
$menu_locations[ $location ] = $values[ 'nav_menu_locations[' . $location . ']' ]; | ||
} | ||
} | ||
|
||
return $menu_locations; | ||
} | ||
|
||
/** | ||
* Filter wp_get_nav_menus() to load Snapshot values. | ||
* | ||
* @see wp_get_nav_menus() | ||
* | ||
* @param array $menus Array of menus. | ||
* @return array Modified array of menus. | ||
*/ | ||
public function filter_wp_get_nav_menus( $menus ) { | ||
if ( false === $this->snapshot->is_preview() ) { | ||
return $menus; | ||
} | ||
|
||
$values = $this->snapshot->values(); | ||
$removed = array(); | ||
|
||
foreach ( $values as $setting_id => $value ) { | ||
if ( preg_match( '/^nav_menu\[(?P<id>-?\d+)\]$/', $setting_id, $matches ) ) { | ||
if ( false !== $value ) { | ||
$menus[] = $this->get_nav_menu_object( $matches['id'], $value ); | ||
} else { | ||
$removed[] = intval( $matches['id'] ); | ||
} | ||
} | ||
} | ||
|
||
if ( ! empty( $removed ) && ! empty( $menus ) ) { | ||
foreach ( $menus as $key => $term ) { | ||
if ( in_array( $term->term_id, $removed, true ) ) { | ||
unset( $menus[ $key ] ); | ||
} | ||
} | ||
} | ||
|
||
return array_values( $menus ); | ||
} | ||
|
||
/** | ||
* Filter wp_get_nav_menu_items() to load Snapshot values. | ||
* | ||
* @see wp_get_nav_menu_items() | ||
* | ||
* @param array $items An array of menu item post objects. | ||
* @param object $menu The menu object. | ||
* @param array $args An array of arguments used to retrieve menu item objects. | ||
* @return array Array of menu items. | ||
*/ | ||
function filter_wp_get_nav_menu_items( $items, $menu, $args ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder why this is needed as opposed to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue is that these filters are used only settings-specifically but the menus are initially loaded at this moment in Loading the |
||
if ( false === $this->snapshot->is_preview() ) { | ||
return $items; | ||
} | ||
|
||
$values = $this->snapshot->values(); | ||
$removed = array(); | ||
|
||
foreach ( $values as $setting_id => $value ) { | ||
if ( preg_match( '/^nav_menu_item\[(?P<id>-?\d+)\]$/', $setting_id, $matches ) && false === $value ) { | ||
$removed[] = intval( $matches['id'] ); | ||
} | ||
} | ||
|
||
if ( ! empty( $removed ) && ! empty( $items ) ) { | ||
foreach ( $items as $key => $post ) { | ||
if ( in_array( $post->ID, $removed, true ) ) { | ||
unset( $items[ $key ] ); | ||
} | ||
} | ||
} | ||
|
||
foreach ( $values as $setting_id => $item ) { | ||
if ( preg_match( \WP_Customize_Nav_Menu_Item_Setting::ID_PATTERN, $setting_id, $matches ) ) { | ||
if ( (int) $menu->term_id === (int) $item['nav_menu_term_id'] ) { | ||
$item['post_id'] = intval( $matches['id'] ); | ||
$items[] = $this->value_as_wp_post_nav_menu_item( (object) $item ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe we can re-use if ( preg_match( \WP_Customize_Nav_Menu_Item_Setting::ID_PATTERN, $setting_id, $matches ) ) {
$wp_customize->register_dynamic_settings( array( $setting_id ) );
$nav_menu_item_setting = $wp_customize->get_setting( $setting_id );
if ( $nav_menu_item_setting && (int) $menu->term_id === (int) $item['nav_menu_term_id'] ) {
$item['post_id'] = intval( $matches['id'] );
$items[] = $nav_menu_item_setting->value_as_wp_post_nav_menu_item(); // <========
}
} |
||
} | ||
} | ||
} | ||
|
||
return array_values( $items ); | ||
} | ||
|
||
/** | ||
* Filter wp_get_nav_menu_object() to load Snapshot values. | ||
* | ||
* @see wp_get_nav_menu_object() | ||
* | ||
* @param object|null $menu_obj Object returned by wp_get_nav_menu_object(). | ||
* @param string $menu_id ID of the nav_menu term. Requests by slug or name will be ignored. | ||
* @return object|null New menu object or null. | ||
*/ | ||
function filter_wp_get_nav_menu_object( $menu_obj, $menu_id ) { | ||
if ( false === $this->snapshot->is_preview() ) { | ||
return $menu_obj; | ||
} | ||
|
||
if ( false === $menu_obj && $menu_id < 0 ) { | ||
$values = $this->snapshot->values(); | ||
if ( isset( $values[ 'nav_menu[' . $menu_id . ']' ] ) ) { | ||
$menu_obj = $this->get_nav_menu_object( $menu_id, $values[ 'nav_menu[' . $menu_id . ']' ] ); | ||
} | ||
} | ||
|
||
return $menu_obj; | ||
} | ||
|
||
/** | ||
* Build a nav menu object from a Snapshot value. | ||
* | ||
* @param int $menu_id Menu ID. | ||
* @param array $value Menu value. | ||
* @return \WP_Term | ||
*/ | ||
public function get_nav_menu_object( $menu_id, $value ) { | ||
$menu_obj = new \WP_Term( (object) $value ); | ||
$menu_obj->term_id = $menu_obj->term_taxonomy_id = $menu_id; | ||
$menu_obj->taxonomy = 'nav_menu'; | ||
$menu_obj->slug = sanitize_title( $menu_obj->name ); | ||
|
||
return $menu_obj; | ||
} | ||
|
||
/** | ||
* Get the value emulated into a WP_Post and set up as a nav_menu_item. | ||
* | ||
* @param object $item Snapshot nav menu item. | ||
* @return WP_Post With wp_setup_nav_menu_item() applied. | ||
*/ | ||
public function value_as_wp_post_nav_menu_item( $item ) { | ||
unset( $item->nav_menu_term_id ); | ||
|
||
$item->post_status = $item->status; | ||
unset( $item->status ); | ||
|
||
$item->post_type = 'nav_menu_item'; | ||
$item->menu_order = $item->position; | ||
unset( $item->position ); | ||
|
||
if ( $item->title ) { | ||
$item->post_title = $item->title; | ||
} | ||
|
||
$item->ID = $item->post_id; | ||
$item->db_id = $item->post_id; | ||
$post = new \WP_Post( (object) $item ); | ||
|
||
if ( empty( $post->post_author ) ) { | ||
$post->post_author = get_current_user_id(); | ||
} | ||
|
||
if ( ! isset( $post->type_label ) ) { | ||
if ( 'post_type' === $post->type ) { | ||
$object = get_post_type_object( $post->object ); | ||
if ( $object ) { | ||
$post->type_label = $object->labels->singular_name; | ||
} else { | ||
$post->type_label = $post->object; | ||
} | ||
} elseif ( 'taxonomy' == $post->type ) { | ||
$object = get_taxonomy( $post->object ); | ||
if ( $object ) { | ||
$post->type_label = $object->labels->singular_name; | ||
} else { | ||
$post->type_label = $post->object; | ||
} | ||
} else { | ||
$post->type_label = __( 'Custom Link', 'customize-snapshots' ); | ||
} | ||
} | ||
|
||
/** This filter is documented in wp-includes/nav-menu.php */ | ||
$post->attr_title = apply_filters( 'nav_menu_attr_title', $post->attr_title ); | ||
|
||
/** This filter is documented in wp-includes/nav-menu.php */ | ||
$post->description = apply_filters( 'nav_menu_description', wp_trim_words( $post->description, 200 ) ); | ||
|
||
/** This filter is documented in wp-includes/nav-menu.php */ | ||
$post = apply_filters( 'wp_setup_nav_menu_item', $post ); | ||
|
||
return $post; | ||
} | ||
|
||
/** | ||
* Register nav menus found in a Snapshot. | ||
*/ | ||
public function customize_register_nav_menus() { | ||
if ( false === $this->snapshot->is_preview() ) { | ||
return; | ||
} | ||
|
||
$menus = wp_get_nav_menus(); | ||
|
||
foreach ( $menus as $menu ) { | ||
if ( $menu->term_id < 0 ) { | ||
|
||
// Create a section for each menu. | ||
$section_id = 'nav_menu[' . $menu->term_id . ']'; | ||
$this->customize_manager->remove_section( $section_id ); | ||
$this->customize_manager->add_section( new Customize_Snapshot_Nav_Menu_Section( $this->customize_manager, $section_id, array( | ||
'title' => html_entity_decode( $menu->name, ENT_QUOTES, get_bloginfo( 'charset' ) ), | ||
'priority' => 10, | ||
'panel' => 'nav_menus', | ||
) ) ); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Remove edit bulk action for snapshots. | ||
* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
/** | ||
* Customize Snapshot Nav Menu Section Class | ||
* | ||
* @package CustomizeSnapshots | ||
*/ | ||
|
||
namespace CustomizeSnapshots; | ||
|
||
/** | ||
* Customize Snapshot Menu Section Class | ||
* | ||
* Custom section only needed in JS. | ||
* | ||
* @see \WP_Customize_Section | ||
*/ | ||
class Customize_Snapshot_Nav_Menu_Section extends \WP_Customize_Section { | ||
|
||
/** | ||
* Control type. | ||
* | ||
* @access public | ||
* @var string | ||
*/ | ||
public $type = 'nav_menu'; | ||
|
||
/** | ||
* Get section parameters for JS. | ||
* | ||
* @access public | ||
* @return array Exported parameters. | ||
*/ | ||
public function json() { | ||
$exported = parent::json(); | ||
$exported['menu_id'] = intval( preg_replace( '/^nav_menu\[(-?\d+)\]/', '$1', $this->id ) ); | ||
|
||
return $exported; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why this is needed as opposed to what
WP_Customize_Nav_Menu_Setting::preview()
adds? https://github.com/xwp/wordpress-develop/blob/master/src/wp-includes/customize/class-wp-customize-nav-menu-setting.php#L204-L296