/** * Test the customize_preview_enqueue_deps method. * * @see WP_Customize_Nav_Menus::customize_preview_enqueue_deps() */ function test_customize_preview_enqueue_deps() { do_action('customize_register', $this->wp_customize); $menus = new WP_Customize_Nav_Menus($this->wp_customize); $menus->customize_preview_enqueue_deps(); $this->assertTrue(wp_script_is('customize-preview-nav-menus')); }
/** * Test the export_preview_data method. * * @see WP_Customize_Nav_Menus::export_preview_data() */ function test_export_preview_data() { do_action('customize_register', $this->wp_customize); $menus = new WP_Customize_Nav_Menus($this->wp_customize); $request_uri = $_SERVER['REQUEST_URI']; ob_start(); $_SERVER['REQUEST_URI'] = '/wp-admin'; $menus->export_preview_data(); $data = ob_get_clean(); $_SERVER['REQUEST_URI'] = $request_uri; $this->assertContains('_wpCustomizePreviewNavMenusExports', $data); $this->assertContains('renderQueryVar', $data); $this->assertContains('renderNonceValue', $data); $this->assertContains('renderNoncePostKey', $data); $this->assertContains('requestUri', $data); $this->assertContains('theme', $data); $this->assertContains('previewCustomizeNonce', $data); $this->assertContains('navMenuInstanceArgs', $data); $this->assertContains('requestUri', $data); }
/** * Import theme starter content into the customized state. * * @since 4.7.0 * @access public * * @param array $starter_content Starter content. Defaults to `get_theme_starter_content()`. */ function import_theme_starter_content($starter_content = array()) { if (empty($starter_content)) { $starter_content = get_theme_starter_content(); } $changeset_data = array(); if ($this->changeset_post_id()) { $changeset_data = $this->get_changeset_post_data($this->changeset_post_id()); } $sidebars_widgets = isset($starter_content['widgets']) && !empty($this->widgets) ? $starter_content['widgets'] : array(); $attachments = isset($starter_content['attachments']) && !empty($this->nav_menus) ? $starter_content['attachments'] : array(); $posts = isset($starter_content['posts']) && !empty($this->nav_menus) ? $starter_content['posts'] : array(); $options = isset($starter_content['options']) ? $starter_content['options'] : array(); $nav_menus = isset($starter_content['nav_menus']) && !empty($this->nav_menus) ? $starter_content['nav_menus'] : array(); $theme_mods = isset($starter_content['theme_mods']) ? $starter_content['theme_mods'] : array(); // Widgets. $max_widget_numbers = array(); foreach ($sidebars_widgets as $sidebar_id => $widgets) { $sidebar_widget_ids = array(); foreach ($widgets as $widget) { list($id_base, $instance) = $widget; if (!isset($max_widget_numbers[$id_base])) { // When $settings is an array-like object, get an intrinsic array for use with array_keys(). $settings = get_option("widget_{$id_base}", array()); if ($settings instanceof ArrayObject || $settings instanceof ArrayIterator) { $settings = $settings->getArrayCopy(); } // Find the max widget number for this type. $widget_numbers = array_keys($settings); if (count($widget_numbers) > 0) { $widget_numbers[] = 1; $max_widget_numbers[$id_base] = call_user_func_array('max', $widget_numbers); } else { $max_widget_numbers[$id_base] = 1; } } $max_widget_numbers[$id_base] += 1; $widget_id = sprintf('%s-%d', $id_base, $max_widget_numbers[$id_base]); $setting_id = sprintf('widget_%s[%d]', $id_base, $max_widget_numbers[$id_base]); $setting_value = $this->widgets->sanitize_widget_js_instance($instance); if (empty($changeset_data[$setting_id]) || !empty($changeset_data[$setting_id]['starter_content'])) { $this->set_post_value($setting_id, $setting_value); $this->pending_starter_content_settings_ids[] = $setting_id; } $sidebar_widget_ids[] = $widget_id; } $setting_id = sprintf('sidebars_widgets[%s]', $sidebar_id); if (empty($changeset_data[$setting_id]) || !empty($changeset_data[$setting_id]['starter_content'])) { $this->set_post_value($setting_id, $sidebar_widget_ids); $this->pending_starter_content_settings_ids[] = $setting_id; } } $starter_content_auto_draft_post_ids = array(); if (!empty($changeset_data['nav_menus_created_posts']['value'])) { $starter_content_auto_draft_post_ids = array_merge($starter_content_auto_draft_post_ids, $changeset_data['nav_menus_created_posts']['value']); } // Make an index of all the posts needed and what their slugs are. $needed_posts = array(); $attachments = $this->prepare_starter_content_attachments($attachments); foreach ($attachments as $attachment) { $key = 'attachment:' . $attachment['post_name']; $needed_posts[$key] = true; } foreach (array_keys($posts) as $post_symbol) { if (empty($posts[$post_symbol]['post_name']) && empty($posts[$post_symbol]['post_title'])) { unset($posts[$post_symbol]); continue; } if (empty($posts[$post_symbol]['post_name'])) { $posts[$post_symbol]['post_name'] = sanitize_title($posts[$post_symbol]['post_title']); } if (empty($posts[$post_symbol]['post_type'])) { $posts[$post_symbol]['post_type'] = 'post'; } $needed_posts[$posts[$post_symbol]['post_type'] . ':' . $posts[$post_symbol]['post_name']] = true; } $all_post_slugs = array_merge(wp_list_pluck($attachments, 'post_name'), wp_list_pluck($posts, 'post_name')); // Re-use auto-draft starter content posts referenced in the current customized state. $existing_starter_content_posts = array(); if (!empty($starter_content_auto_draft_post_ids)) { $existing_posts_query = new WP_Query(array('post__in' => $starter_content_auto_draft_post_ids, 'post_status' => 'auto-draft', 'post_type' => 'any', 'posts_per_page' => -1)); foreach ($existing_posts_query->posts as $existing_post) { $post_name = $existing_post->post_name; if (empty($post_name)) { $post_name = get_post_meta($existing_post->ID, '_customize_draft_post_name', true); } $existing_starter_content_posts[$existing_post->post_type . ':' . $post_name] = $existing_post; } } // Re-use non-auto-draft posts. if (!empty($all_post_slugs)) { $existing_posts_query = new WP_Query(array('post_name__in' => $all_post_slugs, 'post_status' => array_diff(get_post_stati(), array('auto-draft')), 'post_type' => 'any', 'posts_per_page' => -1)); foreach ($existing_posts_query->posts as $existing_post) { $key = $existing_post->post_type . ':' . $existing_post->post_name; if (isset($needed_posts[$key]) && !isset($existing_starter_content_posts[$key])) { $existing_starter_content_posts[$key] = $existing_post; } } } // Attachments are technically posts but handled differently. if (!empty($attachments)) { $attachment_ids = array(); foreach ($attachments as $symbol => $attachment) { $file_array = array('name' => $attachment['file_name']); $file_path = $attachment['file_path']; $attachment_id = null; $attached_file = null; if (isset($existing_starter_content_posts['attachment:' . $attachment['post_name']])) { $attachment_post = $existing_starter_content_posts['attachment:' . $attachment['post_name']]; $attachment_id = $attachment_post->ID; $attached_file = get_attached_file($attachment_id); if (empty($attached_file) || !file_exists($attached_file)) { $attachment_id = null; $attached_file = null; } elseif ($this->get_stylesheet() !== get_post_meta($attachment_post->ID, '_starter_content_theme', true)) { // Re-generate attachment metadata since it was previously generated for a different theme. $metadata = wp_generate_attachment_metadata($attachment_post->ID, $attached_file); wp_update_attachment_metadata($attachment_id, $metadata); update_post_meta($attachment_id, '_starter_content_theme', $this->get_stylesheet()); } } // Insert the attachment auto-draft because it doesn't yet exist or the attached file is gone. if (!$attachment_id) { // Copy file to temp location so that original file won't get deleted from theme after sideloading. $temp_file_name = wp_tempnam(basename($file_path)); if ($temp_file_name && copy($file_path, $temp_file_name)) { $file_array['tmp_name'] = $temp_file_name; } if (empty($file_array['tmp_name'])) { continue; } $attachment_post_data = array_merge(wp_array_slice_assoc($attachment, array('post_title', 'post_content', 'post_excerpt')), array('post_status' => 'auto-draft')); // In PHP < 5.6 filesize() returns 0 for the temp files unless we clear the file status cache. // Technically, PHP < 5.6.0 || < 5.5.13 || < 5.4.29 but no need to be so targeted. // See https://bugs.php.net/bug.php?id=65701 if (version_compare(PHP_VERSION, '5.6', '<')) { clearstatcache(); } $attachment_id = media_handle_sideload($file_array, 0, null, $attachment_post_data); if (is_wp_error($attachment_id)) { continue; } update_post_meta($attachment_id, '_starter_content_theme', $this->get_stylesheet()); update_post_meta($attachment_id, '_customize_draft_post_name', $attachment['post_name']); } $attachment_ids[$symbol] = $attachment_id; } $starter_content_auto_draft_post_ids = array_merge($starter_content_auto_draft_post_ids, array_values($attachment_ids)); } // Posts & pages. if (!empty($posts)) { foreach (array_keys($posts) as $post_symbol) { if (empty($posts[$post_symbol]['post_type']) || empty($posts[$post_symbol]['post_name'])) { continue; } $post_type = $posts[$post_symbol]['post_type']; if (!empty($posts[$post_symbol]['post_name'])) { $post_name = $posts[$post_symbol]['post_name']; } elseif (!empty($posts[$post_symbol]['post_title'])) { $post_name = sanitize_title($posts[$post_symbol]['post_title']); } else { continue; } // Use existing auto-draft post if one already exists with the same type and name. if (isset($existing_starter_content_posts[$post_type . ':' . $post_name])) { $posts[$post_symbol]['ID'] = $existing_starter_content_posts[$post_type . ':' . $post_name]->ID; continue; } // Translate the featured image symbol. if (!empty($posts[$post_symbol]['thumbnail']) && preg_match('/^{{(?P<symbol>.+)}}$/', $posts[$post_symbol]['thumbnail'], $matches) && isset($attachment_ids[$matches['symbol']])) { $posts[$post_symbol]['meta_input']['_thumbnail_id'] = $attachment_ids[$matches['symbol']]; } if (!empty($posts[$post_symbol]['template'])) { $posts[$post_symbol]['meta_input']['_wp_page_template'] = $posts[$post_symbol]['template']; } $r = $this->nav_menus->insert_auto_draft_post($posts[$post_symbol]); if ($r instanceof WP_Post) { $posts[$post_symbol]['ID'] = $r->ID; } } $starter_content_auto_draft_post_ids = array_merge($starter_content_auto_draft_post_ids, wp_list_pluck($posts, 'ID')); } // The nav_menus_created_posts setting is why nav_menus component is dependency for adding posts. if (!empty($this->nav_menus) && !empty($starter_content_auto_draft_post_ids)) { $setting_id = 'nav_menus_created_posts'; $this->set_post_value($setting_id, array_unique(array_values($starter_content_auto_draft_post_ids))); $this->pending_starter_content_settings_ids[] = $setting_id; } // Nav menus. $placeholder_id = -1; $reused_nav_menu_setting_ids = array(); foreach ($nav_menus as $nav_menu_location => $nav_menu) { $nav_menu_term_id = null; $nav_menu_setting_id = null; $matches = array(); // Look for an existing placeholder menu with starter content to re-use. foreach ($changeset_data as $setting_id => $setting_params) { $can_reuse = !empty($setting_params['starter_content']) && !in_array($setting_id, $reused_nav_menu_setting_ids, true) && preg_match('#^nav_menu\\[(?P<nav_menu_id>-?\\d+)\\]$#', $setting_id, $matches); if ($can_reuse) { $nav_menu_term_id = intval($matches['nav_menu_id']); $nav_menu_setting_id = $setting_id; $reused_nav_menu_setting_ids[] = $setting_id; break; } } if (!$nav_menu_term_id) { while (isset($changeset_data[sprintf('nav_menu[%d]', $placeholder_id)])) { $placeholder_id--; } $nav_menu_term_id = $placeholder_id; $nav_menu_setting_id = sprintf('nav_menu[%d]', $placeholder_id); } $this->set_post_value($nav_menu_setting_id, array('name' => isset($nav_menu['name']) ? $nav_menu['name'] : $nav_menu_location)); $this->pending_starter_content_settings_ids[] = $nav_menu_setting_id; // @todo Add support for menu_item_parent. $position = 0; foreach ($nav_menu['items'] as $nav_menu_item) { $nav_menu_item_setting_id = sprintf('nav_menu_item[%d]', $placeholder_id--); if (!isset($nav_menu_item['position'])) { $nav_menu_item['position'] = $position++; } $nav_menu_item['nav_menu_term_id'] = $nav_menu_term_id; if (isset($nav_menu_item['object_id'])) { if ('post_type' === $nav_menu_item['type'] && preg_match('/^{{(?P<symbol>.+)}}$/', $nav_menu_item['object_id'], $matches) && isset($posts[$matches['symbol']])) { $nav_menu_item['object_id'] = $posts[$matches['symbol']]['ID']; if (empty($nav_menu_item['title'])) { $original_object = get_post($nav_menu_item['object_id']); $nav_menu_item['title'] = $original_object->post_title; } } else { continue; } } else { $nav_menu_item['object_id'] = 0; } if (empty($changeset_data[$nav_menu_item_setting_id]) || !empty($changeset_data[$nav_menu_item_setting_id]['starter_content'])) { $this->set_post_value($nav_menu_item_setting_id, $nav_menu_item); $this->pending_starter_content_settings_ids[] = $nav_menu_item_setting_id; } } $setting_id = sprintf('nav_menu_locations[%s]', $nav_menu_location); if (empty($changeset_data[$setting_id]) || !empty($changeset_data[$setting_id]['starter_content'])) { $this->set_post_value($setting_id, $nav_menu_term_id); $this->pending_starter_content_settings_ids[] = $setting_id; } } // Options. foreach ($options as $name => $value) { if (preg_match('/^{{(?P<symbol>.+)}}$/', $value, $matches)) { if (isset($posts[$matches['symbol']])) { $value = $posts[$matches['symbol']]['ID']; } elseif (isset($attachment_ids[$matches['symbol']])) { $value = $attachment_ids[$matches['symbol']]; } else { continue; } } if (empty($changeset_data[$name]) || !empty($changeset_data[$name]['starter_content'])) { $this->set_post_value($name, $value); $this->pending_starter_content_settings_ids[] = $name; } } // Theme mods. foreach ($theme_mods as $name => $value) { if (preg_match('/^{{(?P<symbol>.+)}}$/', $value, $matches)) { if (isset($posts[$matches['symbol']])) { $value = $posts[$matches['symbol']]['ID']; } elseif (isset($attachment_ids[$matches['symbol']])) { $value = $attachment_ids[$matches['symbol']]; } else { continue; } } // Handle header image as special case since setting has a legacy format. if ('header_image' === $name) { $name = 'header_image_data'; $metadata = wp_get_attachment_metadata($value); if (empty($metadata)) { continue; } $value = array('attachment_id' => $value, 'url' => wp_get_attachment_url($value), 'height' => $metadata['height'], 'width' => $metadata['width']); } elseif ('background_image' === $name) { $value = wp_get_attachment_url($value); } if (empty($changeset_data[$name]) || !empty($changeset_data[$name]['starter_content'])) { $this->set_post_value($name, $value); $this->pending_starter_content_settings_ids[] = $name; } } if (!empty($this->pending_starter_content_settings_ids)) { if (did_action('customize_register')) { $this->_save_starter_content_changeset(); } else { add_action('customize_register', array($this, '_save_starter_content_changeset'), 1000); } } }
/** * Import theme starter content into post values. * * @since 4.7.0 * @access public * * @param array $starter_content Starter content. Defaults to `get_theme_starter_content()`. */ function import_theme_starter_content($starter_content = array()) { if (empty($starter_content)) { $starter_content = get_theme_starter_content(); } $sidebars_widgets = isset($starter_content['widgets']) && !empty($this->widgets) ? $starter_content['widgets'] : array(); $posts = isset($starter_content['posts']) && !empty($this->nav_menus) ? $starter_content['posts'] : array(); $options = isset($starter_content['options']) ? $starter_content['options'] : array(); $nav_menus = isset($starter_content['nav_menus']) && !empty($this->nav_menus) ? $starter_content['nav_menus'] : array(); $theme_mods = isset($starter_content['theme_mods']) ? $starter_content['theme_mods'] : array(); // Widgets. $max_widget_numbers = array(); foreach ($sidebars_widgets as $sidebar_id => $widgets) { $sidebar_widget_ids = array(); foreach ($widgets as $widget) { list($id_base, $instance) = $widget; if (!isset($max_widget_numbers[$id_base])) { // When $settings is an array-like object, get an intrinsic array for use with array_keys(). $settings = get_option("widget_{$id_base}", array()); if ($settings instanceof ArrayObject || $settings instanceof ArrayIterator) { $settings = $settings->getArrayCopy(); } // Find the max widget number for this type. $widget_numbers = array_keys($settings); if (count($widget_numbers) > 0) { $widget_numbers[] = 1; $max_widget_numbers[$id_base] = call_user_func_array('max', $widget_numbers); } else { $max_widget_numbers[$id_base] = 1; } } $max_widget_numbers[$id_base] += 1; $widget_id = sprintf('%s-%d', $id_base, $max_widget_numbers[$id_base]); $setting_id = sprintf('widget_%s[%d]', $id_base, $max_widget_numbers[$id_base]); $class = 'WP_Customize_Setting'; /** This filter is documented in wp-includes/class-wp-customize-manager.php */ $args = apply_filters('customize_dynamic_setting_args', false, $setting_id); if (false !== $args) { /** This filter is documented in wp-includes/class-wp-customize-manager.php */ $class = apply_filters('customize_dynamic_setting_class', $class, $setting_id, $args); $setting = new $class($this, $setting_id, $args); $setting_value = call_user_func($setting->sanitize_js_callback, $instance, $setting); $this->set_post_value($setting_id, $setting_value); $sidebar_widget_ids[] = $widget_id; } } $this->set_post_value(sprintf('sidebars_widgets[%s]', $sidebar_id), $sidebar_widget_ids); } // Posts & pages. if (!empty($posts)) { foreach (array_keys($posts) as $post_symbol) { $r = $this->nav_menus->insert_auto_draft_post($posts[$post_symbol]); if ($r instanceof WP_Post) { $posts[$post_symbol]['ID'] = $r->ID; } } $this->set_post_value('nav_menus_created_posts', wp_list_pluck($posts, 'ID')); // This is why nav_menus component is dependency for adding posts. } // Nav menus. $placeholder_id = -1; foreach ($nav_menus as $nav_menu_location => $nav_menu) { $nav_menu_term_id = $placeholder_id--; $nav_menu_setting_id = sprintf('nav_menu[%d]', $nav_menu_term_id); $this->set_post_value($nav_menu_setting_id, array('name' => isset($nav_menu['name']) ? $nav_menu['name'] : $nav_menu_location)); // @todo Add support for menu_item_parent. $position = 0; foreach ($nav_menu['items'] as $nav_menu_item) { $nav_menu_item_setting_id = sprintf('nav_menu_item[%d]', $placeholder_id--); if (!isset($nav_menu_item['position'])) { $nav_menu_item['position'] = $position++; } $nav_menu_item['nav_menu_term_id'] = $nav_menu_term_id; if (isset($nav_menu_item['object_id'])) { if ('post_type' === $nav_menu_item['type'] && preg_match('/^{{(?P<symbol>.+)}}$/', $nav_menu_item['object_id'], $matches) && isset($posts[$matches['symbol']])) { $nav_menu_item['object_id'] = $posts[$matches['symbol']]['ID']; if (empty($nav_menu_item['title'])) { $original_object = get_post($nav_menu_item['object_id']); $nav_menu_item['title'] = $original_object->post_title; } } else { continue; } } else { $nav_menu_item['object_id'] = 0; } $this->set_post_value($nav_menu_item_setting_id, $nav_menu_item); } $this->set_post_value(sprintf('nav_menu_locations[%s]', $nav_menu_location), $nav_menu_term_id); } // Options. foreach ($options as $name => $value) { if (preg_match('/^{{(?P<symbol>.+)}}$/', $value, $matches) && isset($posts[$matches['symbol']])) { $value = $posts[$matches['symbol']]['ID']; } $this->set_post_value($name, $value); } // Theme mods. foreach ($theme_mods as $name => $value) { if (preg_match('/^{{(?P<symbol>.+)}}$/', $value, $matches) && isset($posts[$matches['symbol']])) { $value = $posts[$matches['symbol']]['ID']; } $this->set_post_value($name, $value); } }