inpsyde/more-menu-fields

此包已被废弃,不再维护。未建议替代包。

此包用于向 WordPress 菜单编辑页面添加更多字段。

0.2.0 2017-10-09 09:18 UTC

This package is auto-updated.

Last update: 2023-01-19 13:19:47 UTC


README

此包用于向 WordPress 菜单编辑页面添加更多字段。

什么是 / 为什么

WordPress 提供了编辑导航菜单的友好用户界面。

然而,它对每个菜单项的可用设置有很强的意见。它们是

  • "导航标签"
  • "标题属性"
  • "在新标签页中打开链接"
  • "CSS 类"
  • "链接关系 (XFN)"
  • "描述"

为了我们的客户,我们需要额外的字段,例如 "data" 属性或 "rel" 属性 ("noopener", "nofollow"...)。

问题在于 WordPress <5.4.0 提供了 没有 过滤器来编辑默认字段,也没有操作钩子允许回显自定义表单字段 HTML,就像在 WP 后端的其他许多部分发生的那样。

⚠️ 从 WordPress 5.4.0 开始,实现了一个新的钩子 wp_nav_menu_item_custom_fields,允许您过滤当前项并添加自定义字段。此包存在,因为我们需要在 WordPress <5.4.0 中找到一种方法来添加更多字段,这些字段可以在使用更多插件时工作。您仍然可以使用此库与较新的 WordPress 版本以面向对象的方式在自定义导航项属性上工作。

用法

第一步

由于 "More Menu Fields" 的使用目标是用于插件中,它本身不是一个插件,而是一个可以通过 Composer 请求的

当通过 Composer 请求此包并且 Composer 自动加载已经加载后,需要 引导 此包。

可以在插件内通过调用一个函数来完成

Inpsyde\MoreMenuFields\bootstrap();

不需要将调用包裹在任何钩子中,并且如果多次调用(由不同的插件调用)也不会发生任何坏的事情。

字段接口

要添加更多字段,需要为每个字段创建一个 PHP 类。该类必须实现 Inpsyde\MoreMenuFields\EditField 接口,如下所示

interface EditField {

	public function name(): string;

	public function field_markup(): string;
}

第一个方法 name() 必须返回字段名称,它可以是任何字符串,但必须是唯一的。这将在以后用于检索输入字段中输入的值。

第二个和最后一个方法 field_markup() 必须返回字段的 HTML 标记,就像它在 UI 上显示的那样。

在 HTML 标记中,很可能需要使用输入名称、其 ID 和其当前存储的值(如果有)。这些信息可以通过 Inpsyde\MoreMenuFields\EditFieldValue 类型的对象获得。很快就会详细介绍。

通常(如果不是总是)需要在将用户输入保存之前对生成的输入字段中的值进行清理。这就是为什么该包还提供另一个接口 Inpsyde\MoreMenuFields\SanitizedEditField,如下所示

interface SanitizedEditField extends EditField {

	public function sanitize_callback(): callable;
}

该接口扩展了 EditField,并且它的唯一方法 sanitize_callback() 可以用于返回用于清理用户输入的回调。建议实现此接口以创建字段,并且仅使用 EditField 为不实际接受输入的表单输入字段(如按钮)。

字段类示例

没有什么比例子更能说明事物是如何工作的了。

下面是一个现实世界的例子,展示了一个可以渲染复选框并在菜单项链接上添加“nofollow”属性的类。

namespace My\Plugin;

class NofollowField implements Inpsyde\MoreMenuFields\SanitizedEditField
{
	private $value;

	public function __construct( Inpsyde\MoreMenuFields\EditFieldValue $value )
	{
		$this->value = $value;
	}

	public function name(): string
	{
		return 'nofollow';
	}

	public function field_markup(): string
	{
		if ( ! $this->value->is_valid() ) {
			return '';
		}
		ob_start();
		?>
		<p class="<?= $this->value->form_field_class() ?>">
			<label>
				<?= esc_html__( 'Enable nofollow?', 'my-plugin' ) ?>
				<input
					type="checkbox"
					name="<?= $this->value->form_field_name() ?>"
					id="<?= $this->value->form_field_id() ?>"
					value="1"<?php checked( 1, $this->value->value() ) ?>/>
			</label>
		</p>
		<?php

		return ob_get_clean();
	}

	public function sanitize_callback(): callable {
		return 'intval';
	}
}

相当简单。因为许多用于生成字段HTML的“艰苦工作”都是由在构造函数中接收到的EditFieldValue实例完成的。但它从哪里来呢?

添加字段

如果包不了解这个字段类,仅仅拥有这个类并不会做什么,为了使包了解这个类,我们需要将其实例添加到存储在常量Inpsyde\MoreMenuFields\FILTER_FIELDS中由filter钩子存储的数组中。

这个过滤器将当前添加的过滤器的数组传递给钩子回调,并将EditFieldValueFactory的实例作为第二个参数:一个可以用来获取用于字段类的EditFieldValue实例的对象。

让我们看一个使用示例

add_filter(
	Inpsyde\MoreMenuFields\FILTER_FIELDS,
	function ( array $items, EditMenuFieldValueFactory $value_factory )
	{
		$fields[] = new My\Plugin\NofollowField( $value_factory->create( 'nofollow' ) );

		return $fields;
	},
	10,
	2
);

当挂钩Inpsyde\MoreMenuFields\FILTER_FIELDS时,传递的EditMenuFieldValueFactory被用来获取一个EditFieldValue实例,该实例被注入到字段对象中(正如上面所示,没有更多)。

要获取EditFieldValue实例,在工厂上调用create()方法,并传递字段的名称,该名称必须是字段对象name()方法返回的确切名称。

就是这样。上面的过滤器,加上前一个部分中的类,就是打印字段并保存它的全部内容。

当添加了多个字段时,可以清楚地看到这种方法的优点。此外,Inpsyde\MoreMenuFields\FILTER_FIELDS过滤器可以被许多不知道彼此的插件使用,而且所有插件都将正常工作。

检索已保存的值

在某个时候,将需要使用添加的字段存储的值。

该包将它们存储在相关菜单项文章的post meta中。因此,要检索它们,只需使用get_post_meta()即可。

为此所需的一切只是知道元数据键,该键是由包通过将一个存储在EditFieldValue::KEY_PREFIX类常量中的固定前缀添加到字段对象name()方法的返回值而生成的。

$no_follow = get_post_meta( $menu_item_id, Inpsyde\MoreMenuFields\EditFieldValue::KEY_PREFIX . 'nofollow', TRUE );

考虑到这一点相当冗长,该包提供了一个更简短的方法来完成完全相同的事情

$no_follow = Inpsyde\MoreMenuFields\field_value( $menu_item, 'nofollow' );

例如,为了实际使用上面的“nofollow”字段,可以这样做

add_filter( 'nav_menu_link_attributes', function ( array $attributes, $item )
{
	$current_rel = $attributes[ 'rel' ] ?? '';

	if ( Inpsyde\MoreMenuFields\field_value( $item, 'nofollow' ) ) {
		$attributes[ 'rel' ] = trim( $current_rel .= ' nofollow' );
	}
	
    return $attributes;
}

其中'nav_menu_link_attributes'过滤器用于在后台之前添加的复选框被选中时,向菜单项添加rel="nofollow"属性。

关于检索到的值转义

当通过Inpsyde\MoreMenuFields\field_value()或通过(get_post_meta())检索值时,该值不会通过字段对象sanitize_callback()方法返回的回调进行清理,该方法仅在将值保存到数据库之前进行清理。

因此,在使用值之前需要对其进行转义。在上面的使用示例中,获取的值仅用于布尔检查,因此不需要转义,但如果将值打印到页面,则需要通过esc_attresc_html或任何适合的方法进行转义。

关于自定义器

WordPress在自定义器中提供了菜单编辑UI。此包未集成到其中。

原因是,我们通过此包添加的许多字段都不是“视觉”上的东西(例如,请参阅此readme中的“nofollow”示例),因此提供实时预览来编辑它们并不是特别有帮助,所以我们(以及我们的客户)从未觉得需要在自定义器UI中包含这些字段。

对于任何对这类功能感兴趣的人,我们可以这样说:“可能以后吧”,但是PR总是开放的;)

需求

  • PHP 7+
  • 使用Composer进行安装

安装

通过Composer安装,包名为inpsyde/more-menu-fields

许可和版权

版权(c)2017 Inpsyde GmbH。

"更多菜单字段"代码遵循MIT许可

Inpsyde团队的Web工程始于2006年。