livy / climber
WordPress导航菜单系统的替代方案。
Requires
- php: >=7.1
- zenodorus/arrays: ^1.1
- zenodorus/strings: ^1.0
Requires (Dev)
- phpunit/phpunit: ^6.4
- squizlabs/php_codesniffer: ^3.2
- zenodorus/core: dev-master
README
为什么非得“walk”而不能“climb”?
WordPress内置Nav_Walker的替代方案,🧗 Climber创建了一个更合理的数据结构,可以直接与之交互或用于生成导航菜单的HTML。
☠️ 目前处于开发中 ☠️
⚡ 可能还没有准备好投入生产 ⚡
用法
🧗 Climber最简单的实现如下
use Livy\Climber; echo new Climber( new Tree( new Spotter\WordPress(wp_get_nav_menu_items($menuID)) ) ); // <nav class="simpleMenu" > // <ul class="simpleMenu__menu level-0"> // ...etc
...也许并不那么简单。最终会有便利函数的!
本文档并未详细说明与🧗 Climber交互的所有方法和方式——只有你最可能使用的方法。方法本身有大量文档,所以如果你对某个功能的工作原理感兴趣,可以自由地深入研究代码。
它是如何工作的?
🧗 Climber需要三个基本组件才能工作
- Spotter
- Tree
- Climber
Spotter 允许🧗 Climber成为平台无关:虽然它随WordPress Spotter一起发货,但你也可以添加你喜欢的任何Spotter来收集和处理数据。Spotter的职责是以Tree期望的格式返回数据。
Tree 处理从Spotter接收到的数据并实现几个可以用于快速轻松地与包含的数据交互的方法。其组织结构允许Climber快速找到生成导航菜单所需的内容。
Climber 收集一个Tree并返回一个正确构建的HTML导航菜单。
通常,你只会直接与Climber交互,但你可以轻松扩展或修改其他组件以满足你的需求——或者使用它们来修改你的数据。
展示给我看
顶部的用法部分展示了最简单的版本,它将返回一个简单的菜单。然而,在大多数情况下,你可能想让菜单知道你当前所在的页面(以便它能够突出显示该部分)。或者你可能想挂钩到流程的某个部分以添加或修改元素、CSS类或HTML属性。
/** * Instantiate our Climber, and tell it where we are. */ $Climber = new Climber( new Tree(new Spotter\WordPress(wp_get_nav_menu_items($menuID))), get_permalink(get_the_ID())) // This returns the URL for the current page. ); /** * Open all links in a new window. */ $Climber->hook( 'link', function ($data) { $data['attrs'][] = ['target', '_blank']; return $data; } ); /** * Put the link after the submenu, instead of before. */ $Climber->hook( 'itemOutput', function($data) { $data['format'] = '%2$s%1$s'; return $data; } ); /** * Print out our menu */ echo $Climber;
如果将Climber
对象作为字符串处理,它将返回一个HTML菜单。很方便!
挂钩
为了允许你在不扩展类的情况下修改菜单的内容和行为,Climber公开了几个挂钩。每个挂钩提供一个单一的变量—$data
—给任何挂钩到它们的函数。该变量的内容取决于你将其附加到的挂钩。通常,它是一个带有键值的数组。
传递给挂钩的任何函数必须返回类似于它接收的$data
。否则,事情会出错。请参阅本文档的展示给我看部分,或查看Climber::__construct()
的内容,以了解如何正确构建挂钩的示例。
top
这是导航菜单的“顶级”:<nav>元素。它提供的数组包括
class
- 字符串 该元素的CSS类。attrs
- 数组 该元素的HTML属性数组。tree
- Tree 用于此菜单的Tree实例。element
- 字符串 用于元素生成的sprintf
格式。echo
- 布尔值 是否应将菜单echo到Tree::element()
。很少需要更改此值。
menu
此钩子会为每个子菜单运行。如果您想针对特定的子菜单,您需要在传递的函数中运行某种测试以定位它。它提供的数组包括
class
- 字符串 该元素的CSS类。attrs
- 数组 该元素的HTML属性数组。level
- 整数 当前菜单的深度。可能不需要修改。element
- 字符串 用于元素生成的sprintf
格式。bud
- 数组 一个完整的叶子,包含所有叶子数据。
项目
一个位于 <ul>
中的单个 <li>
。最终将包含指向您网站一部分的链接,以及可能的子菜单。它提供的数组包括
class
- 字符串 该元素的CSS类。attrs
- 数组 该元素的HTML属性数组。element
- 字符串 用于元素生成的sprintf
格式。bud
- 数组 一个完整的叶子,包含所有叶子数据。
项目输出
这描述了 item
的实际 内容。它可以用来向 item
添加新事物(例如,用于打开子菜单的 <button>
)或修改 item
中出现的事物的顺序。它提供的数组包括
format
- 字符串 用于vsprintf()
的格式化字符串。args
- 数组 将传递给vsprintf()
的值数组。它们的顺序很重要,因为它们对应于format
。
链接
这是 item
中的链接元素。它提供的数组包括
链接
- 字符串 该链接指向的 URL。class
- 字符串 该元素的CSS类。attrs
- 数组 该元素的HTML属性数组。element
- 字符串 用于元素生成的sprintf
格式。内容
- 字符串 链接元素的内容。通常是所链接内容的名称,例如 "关于"。
设置
这些设置将应用于其类型的所有元素,因此它们可以用于设置菜单中的样式或行为。内置的类格式化为字符串。您可以通过修改 baseClass
在一行中更改它们所有。您也可以根据需要完全覆盖它们。
您可以覆盖或设置 Climber 全局属性,用于元素类和属性。这样做非常简单
// For string-type properties... $Climber->topClass = 'newMenuClass'; // For array-type properties... $Climber->topAttrs = ['target', '_blank'];
请注意
- 字符串类型属性会被 覆盖。
- 数组类型属性会被 追加。
这意味着,如果您想补充现有的类,您将执行以下操作
$Climber->topClass .= ' newMenuClass'; // <ul class="simpleMenu newMenuClass"> ...
您也可以覆盖和删除数组类型属性条目
// override $Climber->topAttr = ['data-star', 'wars']; $Climber->topAttr = ['data-star', 'trek']; // <nav data-star="trek"> ... // remove $Climber->topAttr = ['data-star', 'wars']; $Climber->topAttr = ['data-star', false]; //<nav> ...
太复杂了
我同意!幸运的是,有一些好用的、干净的便利函数可以帮助您做到这一点,而无需在代码中填充所有这些类和其他内容。
(此列表将根据需要扩展。如果您认为这里应该有一个功能而目前没有,请打开一个问题或提交一个 PR 来添加它!)
所有便利函数都以 pulley__
开头。它们遵循一个约定(从 WordPress 借鉴):名为 get_something
的函数将返回一个值,而仅以 something
命名的函数将输出该值。因此,这些函数通常成对出现。如果它们不这样做,那么可能是因为 get_
版本返回的内容不能被输出。
一般
这些函数可以在任何上下文中工作,但您需要传递一个有效的 Spotter。
pulley__get_menu()
pulley__get_menu( Spotter $Spotter, string $currentUrl = null )
参数
- $Spotter - Spotter 适用于您调用此操作的上下文的
Spotter
实例。 - $currentUrl - 字符串 您当前正在操作的活动 URL,用于激活正确的树分支。默认:
null
。
返回
Climber | false 如果成功,返回 Climber 对象,否则返回布尔值 false
。
_
pulley__menu()
pulley__menu( Spotter $Spotter, string $currentUrl = null )
与 pulley__get_menu()
相同,但此函数将自动输出菜单。
参数
- $Spotter - Spotter 适用于您调用此操作的上下文的
Spotter
实例。 - $currentUrl - 字符串 您当前正在操作的活动 URL,用于激活正确的树分支。默认:
null
。
返回
string | false 如果成功,返回菜单的 HTML 字符串,否则返回布尔值 false
。
WordPress
这些函数只能在 WordPress 中使用(实际上,如果 Climber 认为它处于 WordPress 上下文中,则只会加载它们)。因为 Climber 包含一个 WordPress Spotter,所以不需要手动传递 Spotter!
pulley__wp_get_menu()
pulley__wp_get_menu( int|string|WP_Term $menu, string $currentUrl = null )
返回传递给它的 $menu
的 Climber
。
参数
- $menu - int|string|WP_Term
$menu
的值可以是菜单 ID、slug、名称或对象。更具体地说,它可以是被wp_get_nav_menu_items()
接受作为菜单标识符的任何值。 - $currentUrl - 字符串 您当前正在操作的活动 URL,用于激活正确的树分支。默认:
null
。
返回
Climber | false 如果成功,返回 Climber 对象,否则返回布尔值 false
。
pulley__wp_menu()
pulley__wp_menu( int|string|WP_Term $menu, string $currentUrl = null )
pully__wp_get_menu()
的输出版本。
参数
- $menu - int|string|WP_Term
$menu
的值可以是菜单 ID、slug、名称或对象。更具体地说,它可以是被wp_get_nav_menu_items()
接受作为菜单标识符的任何值。 - $currentUrl - 字符串 您当前正在操作的活动 URL,用于激活正确的树分支。默认:
null
。
返回
string | false 如果成功,返回菜单的 HTML 字符串,否则返回布尔值 false
。
pulley__wp_get_menu_by_location()
function pulley__wp_get_menu_by_location( string $location, string $currentUrl = null )
根据位置获取菜单。
参数
- $location - string $location 的名称,如
register_nav_menus()
中定义。 - $currentUrl - 字符串 您当前正在操作的活动 URL,用于激活正确的树分支。默认:
null
。
返回
Climber | false 如果成功,返回 Climber 对象,否则返回布尔值 false
。
pulley__wp_menu_by_location()
function pulley__wp_menu_by_location( string $location, string $currentUrl = null )
与 pulley__wp_get_menu_by_location()
相同,只是输出。
参数
- $location - string $location 的名称,如
register_nav_menus()
中定义。 - $currentUrl - 字符串 您当前正在操作的活动 URL,用于激活正确的树分支。默认:
null
。
返回
string | false 如果成功,返回菜单的 HTML 字符串,否则返回布尔值 false
。
这还不够复杂
好吧,公平。也许你需要这里没有覆盖到的功能:也许你传递给 Climber 的菜单只包括你网站的最高级别,但当你访问子项时,你仍然想高亮显示父项。由于 Climber(按设计)对你的网站内部组织一无所知,它不支持这一点:Climber 只知道它知道的事情。
然而,你可以使用一些逻辑告诉 Climber 应该考虑什么为“活动状态”。
设置当前 URL
Climber 的最常见用法是在实例化时传递一个 URL给它——无论是直接通过类,还是通过某个辅助函数。在两种情况下,Climber 内部都使用相同的方法来激活当前 URL,这也是你可以使用的方法!
可以使用 Climber::setCurrentUrl()
直接将 URL 传递给 Climber。Climber 会查找指向该 URL 的叶子(或叶子),并将它们标记为“活动状态”(如果你有一个多级菜单,它也会将它们的祖先标记为活动状态)。使用它非常简单
$Climber = new Climber( new Tree(new Spotter\WordPress(wp_get_nav_menu_items($menuID))) ); $Climber->setCurrentURL(get_permalink(get_the_ID())); // Now this is the current URL!
如果你正在使用的 Climber 没有那个 URL,它将不会做任何事情。
值得注意的是,Climber 不假设只有一个活动叶子:运行 setCurrentUrl()
不会删除之前活动的叶子。
对 setCurrentUrl()
的访问意味着,通过一些努力,你可以让 Climber 认为你在任何你喜欢的页面上!不幸的是,如果你需要用大量 URL 执行此操作,setCurrentUrl()
就开始变得不那么有用。
这就是为什么还有另一种方法!
测量员
Surveyor 类为你提供了一种简单的方法来编写查找特定 URL 模式的查找,你希望在 Climber 中匹配这些 URL。它使用正则表达式数组来确定哪些 URL 匹配哪些。
要使用 Surveyor,用正则表达式和 URL 的数组实例化它,然后调用 Surveyor::evaluateUrl()
$Surveyor = new Surveyord([ ['/(?:stories\/bedtime\/[\w_-]*)/', 'https://example.com/stories/bedtime/'], ['/(?:stories(?:|\/[\w_-]*))/', 'https://example.com/stories/'], ]); echo $Surveyor->evaluateUrl('https://example.com/stories/bedtime/goodnight-moon'); // Yields `https://example.com/stories/bedtime/`
可能的 URL 将按顺序评估,并在找到匹配项时返回。如果没有找到匹配项,则返回最初传递给 evaluateUrl()
的 URL。这意味着你可以在 Climber 调用中使用 Surveyor,如果没有找到匹配项,它将回退到 Climber 想要对该 URL 做的事情。如下所示
$Surveyor = new Surveyord([ ['/(?:stories\/bedtime\/[\w_-]*)/', 'https://example.com/stories/bedtime/'], ['/(?:stories(?:|\/[\w_-]*))/', 'https://example.com/stories/'], ]); $Climber = new Climber( new Tree(new Spotter\WordPress(wp_get_nav_menu_items($menuID))), $Surveyor->evaluateUrl(get_permalink(get_the_ID())) );