inpsyde / more-menu-fields
此包用于向 WordPress 菜单编辑页面添加更多字段。
Requires
- php: >=7
Requires (Dev)
- brain/monkey: ^2.1
- doctrine/instantiator: ~1.0.5
- phpunit/phpunit: 6.3.*
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_attr
、esc_html
或任何适合的方法进行转义。
关于自定义器
WordPress在自定义器中提供了菜单编辑UI。此包未集成到其中。
原因是,我们通过此包添加的许多字段都不是“视觉”上的东西(例如,请参阅此readme中的“nofollow”示例),因此提供实时预览来编辑它们并不是特别有帮助,所以我们(以及我们的客户)从未觉得需要在自定义器UI中包含这些字段。
对于任何对这类功能感兴趣的人,我们可以这样说:“可能以后吧”,但是PR总是开放的;)
需求
- PHP 7+
- 使用Composer进行安装
安装
通过Composer安装,包名为inpsyde/more-menu-fields
。
许可和版权
版权(c)2017 Inpsyde GmbH。
"更多菜单字段"代码遵循MIT许可。
Inpsyde团队的Web工程始于2006年。