Skip to content
This repository has been archived by the owner on Dec 27, 2022. It is now read-only.

Re-use methods in WP_Customize_Nav_Menus in favor of duplication #56

Merged
304 changes: 67 additions & 237 deletions php/class-customize-snapshot-manager.php
Expand Up @@ -124,14 +124,6 @@ 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
Expand Down Expand Up @@ -163,8 +155,46 @@ public function __construct( Plugin $plugin ) {
}
}

/*
* Add WP_Customize_Nav_Menu component hooks which were short-circuited in 4.5 (r36611 for #35895).
* See https://core.trac.wordpress.org/ticket/35895
*/
if ( isset( $this->customize_manager->nav_menus ) && ! current_user_can( 'edit_theme_options' ) ) {
$hooks = array(
'customize_register' => array(
'callback' => array( $this->customize_manager->nav_menus, 'customize_register' ),
'priority' => 11,
),
'customize_dynamic_setting_args' => array(
'callback' => array( $this->customize_manager->nav_menus, 'filter_dynamic_setting_args' ),
'priority' => 10,
),
'customize_dynamic_setting_class' => array(
'callback' => array( $this->customize_manager->nav_menus, 'filter_dynamic_setting_class' ),
'priority' => 10,
),
'wp_nav_menu_args' => array(
'callback' => array( $this->customize_manager->nav_menus, 'filter_wp_nav_menu_args' ),
'priority' => 1000,
),
'wp_nav_menu' => array(
'callback' => array( $this->customize_manager->nav_menus, 'filter_wp_nav_menu' ),
'priority' => 10,
),
);
foreach ( $hooks as $hook_name => $hook_args ) {
// Note that add_action()/has_action() are just aliases for add_filter()/has_filter().
if ( ! has_filter( $hook_name, $hook_args['callback'] ) ) {
add_filter( $hook_name, $hook_args['callback'], $hook_args['priority'], PHP_INT_MAX );
}
}
}

// Preview a Snapshot.
add_action( 'after_setup_theme', array( $this, 'set_post_values' ), 1 );
if ( isset( $this->customize_manager->nav_menus ) ) {
add_action( 'customize_register', array( $this, 'preview_early_nav_menus_in_customizer' ), 9 );
}
add_action( 'wp_loaded', array( $this, 'preview' ) );

/*
Expand Down Expand Up @@ -388,235 +418,6 @@ 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 ) {
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 );
}
}
}

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.
*
Expand Down Expand Up @@ -1154,4 +955,33 @@ public function preview() {
}
}
}

/**
* Preview nav menu settings early so that the sections and controls for snapshot values will be added properly.
*
* This must happen at `customize_register` priority prior to 11 which is when `WP_Customize_Nav_Menus::customize_register()` runs.
* This is only relevant when accessing the Customizer app (customize.php), as this is where sections/controls matter.
*
* @see \WP_Customize_Nav_Menus::customize_register()
*/
public function preview_early_nav_menus_in_customizer() {
if ( ! is_admin() ) {
return;
}

$this->customize_manager->add_dynamic_settings( array_keys( $this->snapshot()->data() ) );
foreach ( $this->snapshot->settings() as $setting ) {
$is_nav_menu_setting = (
$setting instanceof \WP_Customize_Nav_Menu_Setting
||
$setting instanceof \WP_Customize_Nav_Menu_Item_Setting
||
preg_match( '/^nav_menu_locations\[/', $setting->id )
);
if ( $is_nav_menu_setting ) {
$setting->preview();
$setting->dirty = true;
}
}
}
}
39 changes: 0 additions & 39 deletions php/class-customize-snapshot-nav-menu-section.php

This file was deleted.

4 changes: 2 additions & 2 deletions readme.md
Expand Up @@ -6,12 +6,12 @@ Allow Customizer states to be drafted, and previewed with a private URL.

**Contributors:** [westonruter](https://profiles.wordpress.org/westonruter), [valendesigns](https://profiles.wordpress.org/valendesigns), [xwp](https://profiles.wordpress.org/xwp), [newscorpau](https://profiles.wordpress.org/newscorpau)
**Tags:** [customizer](https://wordpress.org/plugins/tags/customizer), [customize](https://wordpress.org/plugins/tags/customize), [snapshots](https://wordpress.org/plugins/tags/snapshots)
**Requires at least:** 4.5
**Requires at least:** 4.6-beta2
**Tested up to:** trunk
**Stable tag:** 0.4.0
**License:** [GPLv2 or later](http://www.gnu.org/licenses/gpl-2.0.html)

[![Build Status](https://travis-ci.org/xwp/wp-customize-snapshots.svg?branch=master)](https://travis-ci.org/xwp/wp-customize-snapshots) [![Coverage Status](https://coveralls.io/repos/xwp/wp-customize-snapshots/badge.svg?branch=master)](https://coveralls.io/github/xwp/wp-customize-snapshots) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.svg)](http://gruntjs.com) [![devDependency Status](https://david-dm.org/xwp/wp-customize-snapshots/dev-status.svg)](https://david-dm.org/xwp/wp-customize-snapshots#info=devDependencies)
[![Build Status](https://travis-ci.org/xwp/wp-customize-snapshots.svg?branch=master)](https://travis-ci.org/xwp/wp-customize-snapshots) [![Coverage Status](https://coveralls.io/repos/xwp/wp-customize-snapshots/badge.svg?branch=master)](https://coveralls.io/github/xwp/wp-customize-snapshots) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com) [![devDependency Status](https://david-dm.org/xwp/wp-customize-snapshots/dev-status.svg)](https://david-dm.org/xwp/wp-customize-snapshots#info=devDependencies)

## Description ##

Expand Down
2 changes: 1 addition & 1 deletion readme.txt
@@ -1,6 +1,6 @@
=== Customize Snapshots ===
Contributors: westonruter, valendesigns, xwp, newscorpau
Requires at least: 4.5
Requires at least: 4.6-beta2
Tested up to: trunk
Stable tag: 0.4.0
License: GPLv2 or later
Expand Down