首先,关于导航菜单,您应该了解一些事情:
菜单只是一种分类法中的术语,称为nav_menu
.菜单项是一种特殊的帖子类型,简而言之:菜单就像WordPress中几乎所有其他内容一样,只是有一个自定义UI。
这样一来,任务就相当简单了:在编辑屏幕上放置一个自定义元框,显示选择导航菜单的选项。在前端,将导航菜单切换到您在管理区域中设置的任何菜单。唯一需要担心的是theme_location
价值在于主题对wp_nav_menu
. 您想在哪里切换菜单?
这是一个示例,它将使用主题位置primary
.
一个将所有内容总结为以下内容的电话:
<?php
class PerPostNavMenu
{
const NONCE = \'wpse85243_nav_nonce\';
const FIELD = \'_wpse85243_per_post_menu\';
const LOC = \'primary\'; // the location for twenty twelve
private static $ins = null;
public static function instance()
{
if (is_null(self::$ins)) {
self::$ins = new self;
}
return self::$ins;
}
public static function init()
{
add_action(\'plugins_loaded\', array(self::instance(), \'_setup\'));
}
public function _setup()
{
// we\'ll add actions/filters here later
}
}
现在,让我们添加元框。由于这篇文章在很多地方都有详细的介绍,我将给出悬崖笔记的解释:钩住
add_meta_boxes
, 呼叫
add_meta_box
. 在元框回调函数中,输出一个nonce和字段。
要保存这些值,请挂接到save_post
, 检查以确保我们处于想要的位置(无自动保存,nonce验证),并且当前用户可以使用(update|delete)_post_meta
.
<?php
class PerPostNavMenu
{
const NONCE = \'wpse85243_nav_nonce\';
const FIELD = \'_wpse85243_per_post_menu\';
const LOC = \'primary\'; // the location for twenty twelve
// snip snip
public function _setup()
{
add_action(\'add_meta_boxes\', array($this, \'addBox\'));
add_action(\'save_post\', array($this, \'save\'), 10, 2);
}
public function addBox($post_type)
{
if (!post_type_exists($post_type)) {
return;
}
add_meta_box(
\'wpse85243_nav_menu\',
__(\'Nav Menu\', \'wpse\'),
array($this, \'boxCallback\'),
$post_type,
\'side\',
\'low\'
);
}
public function boxCallback($post)
{
$menu = get_post_meta($post->ID, static::FIELD, true);
wp_nonce_field(static::NONCE . $post->ID, static::NONCE, false);
printf(
\'<label for="%s">%s</label>\',
esc_attr(static::FIELD),
esc_html__(\'Nav Menu\', \'wpse\')
);
echo \'<br />\';
printf(\'<select name="%1$s" id="%1$s">\', esc_attr(static::FIELD));
foreach ($this->getNavMenus() as $id => $name) {
printf(
\'<option value="%s" %s>%s</option>\',
esc_attr($id),
selected($menu, $id, false),
esc_html($name)
);
}
echo \'</select>\';
}
public function save($post_id, $post)
{
if (defined(\'DOING_AUTOSAVE\') && DOING_AUTOSAVE) {
return;
}
if (
!isset($_POST[static::NONCE]) ||
!wp_verify_nonce($_POST[static::NONCE], static::NONCE . $post_id)
) {
return;
}
$type = get_post_type_object($post->post_type);
if (!current_user_can($type->cap->edit_post, $post_id)) {
return;
}
$menu = isset($_POST[static::FIELD]) ? $_POST[static::FIELD] : false;
if ($menu && \'-\' !== $menu) {
update_post_meta($post_id, static::FIELD, absint($menu));
} else {
delete_post_meta($post_id, static::FIELD);
}
}
private function getNavMenus()
{
$terms = get_terms(\'nav_menu\');
$menus = array(\'-\' => __(\'Default\', \'wpse\'));
if ($terms && !is_wp_error($terms)) {
foreach($terms as $t) {
$menus[$t->term_id] = $t->name;
}
}
return apply_filters(\'per_post_nav_menus_list\', $menus);
}
}
请注意用于检索导航菜单的助手方法。不多,只是一个方便的助手,可以通过过滤器运行结果。
最后,我们只需要关掉菜单。要做到这一点,请wp_nav_menu_args
而且,如果我们在一个单独的页面上,并且有正确的主题位置,请根据需要切换菜单。还包括一些额外的过滤器,使其更具可扩展性。
<?php
class PerPostNavMenu
{
const NONCE = \'wpse85243_nav_nonce\';
const FIELD = \'_wpse85243_per_post_menu\';
const LOC = \'primary\'; // the location for twenty twelve
// snip snip
public function _setup()
{
add_action(\'add_meta_boxes\', array($this, \'addBox\'));
add_action(\'save_post\', array($this, \'save\'), 10, 2);
add_filter(\'wp_nav_menu_args\', array($this, \'switchMenu\'));
}
// snip snip
public function switchMenu($args)
{
// we can only deal with singular pages
if (!is_singular()) {
return;
}
$switch = apply_filters(
\'per_post_nav_menus_switch\',
isset($args[\'theme_location\']) && static::LOC === $args[\'theme_location\'],
$args
);
// if we\'re allowed to switch, the the `menu` argument to
// the correct menu ID.
if ($switch) {
$menu = get_post_meta(get_queried_object_id(), static::FIELD, true);
if (\'-\' !== $menu) {
$args[\'menu\'] = absint($menu);
}
}
return $args;
}
// snip snip
}
以上所有内容
as a plugin.