pagefinder - 渲染一个用于选择页面链接的字段。展开该字段会显示选择器以定位页面。最终的选择结果是一个包含类型和引用的字符串。
featured_page:
label: Featured Page
type: pagefinder选定值使用以下格式存储。
october://<TYPE>@link/<REFERENCE>?<PARAM>=<VALUE>
以下 字段属性 受支持且常用。
| Property | Description |
|---|---|
| label | a name when displaying the form field to the user. |
| default | specifies a default string value, optional. |
| comment | places a descriptive comment below the field. |
| singleMode | only allows items to be selected that resolve to a single URL. Default: false |
使用 关联列类型 解决列表中
pagefinder的值.
使用 |link Twig 过滤器 将页面查找器值转换为 URL。
{{ featured_page|link }}使用 |content Twig 过滤器 来处理 HTML 标记并替换内容中的所有链接。
{{ blog_html|content }}插件可以通过各种事件扩展页面查找器,增加新的页面类型. 订阅事件最常见的位置是插件注册文件中的boot方法.
public function boot()
{
Event::listen('cms.pageLookup.listTypes', function() {
// ...
});
Event::listen('cms.pageLookup.getTypeInfo', function($type) {
// ...
});
Event::listen('cms.pageLookup.resolveItem', function($type, $item, $url, $theme) {
// ...
});
}cms.pageLookup.listTypes 事件处理器返回插件支持的页面类型列表。该处理器应返回一个关联数组,其中索引为类型代码,值为类型名称。强烈建议在类型代码中使用插件名称,以避免与其他页面类型提供者发生冲突。例如:
Event::listen('cms.pageLookup.listTypes', function() {
return [
'blog-post' => 'Blog Post'
];
});对于支持嵌套子项的页面类型,例如链接到所有博客文章,类型名称值应该是一个数组,其中最后一项设置为 true。这将把它排除在只能选择一个链接的场景之外。以下将 blog-posts 类型标记为支持嵌套。
Event::listen('cms.pageLookup.listTypes', function() {
return [
'blog-posts' => ['All Blog Posts', true]
];
});这个 cms.pageLookup.getTypeInfo 事件处理程序返回关于支持的页面类型的详细信息。该处理程序接收一个参数 - 页面类型代码 (您通过 cms.pageLookup.listTypes 处理程序注册的代码之一)。处理程序代码必须检查所请求的项类型代码是否属于该插件。该处理程序应该返回一个采用以下格式的关联数组。
Event::listen('cms.pageLookup.getTypeInfo', function($type) {
if ($type == 'blog-post') {
return [
'references' => [
11 => 'News',
12 => 'Tutorials',
13 => 'Philosophy',
],
'cmsPages' => Page::withComponent('blogPosts')->all()
];
}
});references 元素是页面可以引用的对象列表。例如,博客分类页面类型返回博客分类列表。某些对象支持嵌套,例如,完整的页面列表。其他对象不支持嵌套,例如,博客分类。references 值的格式取决于引用是否有子项。没有子项的引用格式如下。
'references' => [
'item-key' => 'Item title'
]带子项的参考文献格式如下。
'references' => [
'item-key' => [
'title' => 'Item title',
'items' => [...]
]
]以下迭代器可用于在模型具有子项时生成引用。
$iterator = function($records) use (&$iterator) {
$result = [];
foreach ($records as $record) {
if (!$record->children) {
$result[$record->id] = $record->title;
}
else {
$result[$record->id] = [
'title' => $record->title,
'items' => $iterator($record->children)
];
}
}
return $result;
};
return ['references' => $iterator($records)];cmsPages 是一个 CMS 页面列表,可以显示该页面类型支持的对象。例如,对于 博客分类 项类型,页面列表包含托管 blogPosts 组件的页面。该组件可以显示博客分类内容。该 cmsPages 元素应该是一个 Cms\Classes\Page 对象的数组。
以下 withComponent 方法将查找所有使用 blogPosts 组件的页面,针对当前活动主题。
'cmsPages' => Page::withComponent('blogPosts')->all();使用 whereComponent 来查找所有使用 section 组件的页面,其中属性 handle 设置为 Your\Handle。
'cmsPages' => Page::whereComponent('section', 'handle', 'Your\Handle')->all();使用 inTheme 通过传递主题代码来查找另一个主题中的页面。
'cmsPages' => Page::inTheme('demo')->withComponent('blogPosts')->all();当页面查找器生成链接时,每个项目都应该由提供项目类型的插件解析。解析过程涉及生成实际项目 URL、确定项目是否处于活动状态,以及生成子项目(如果需要)。
cms.pageLookup.resolveItem 事件处理程序解析页面信息,并返回实际的项目 URL、标题、指示项目当前是否处于活动状态的标志,以及(如果存在)子项目。该事件处理程序接受四个参数:
$type - 项目类型名称. 插件必须只处理它们提供的项目类型并忽略其他类型.$item - 项对象 (Cms\Models\PageLookupItem)。该项对象表示用户提供的项配置。该对象具有以下属性:title, type, reference, cmsPage。$url - 指定当前绝对 URL,小写形式。始终使用 Url::to() 助手来生成项目链接并与当前 URL 进行比较。$theme - 当前主题对象 (Cms\Classes\Theme).事件处理程序应该检查匹配的 type 并返回一个数组。
Event::listen('cms.pageLookup.resolveItem', function($type, $item, $url, $theme) {
if ($type === 'blog-post') {
return [...];
}
if ($item->type == 'all-blog-posts') {
return [...];
}
});url 和 isActive 元素对于指向特定页面的条目是必需的。
return [
'title' => 'Some Category',
'url' => 'https://example.tld/blog/category/some-category',
'isActive' => true
];已解析的页面链接也可能返回多个项目。例如,一个 所有页面 项目类型不会有一个特定的页面指向,因为它可能有多个链接。
在这些情况下,当 $item 参数的 nesting 属性设置为 true 时,解析器将请求子项。
Event::listen('cms.pageLookup.resolveItem', function($type, $item, $url, $theme) {
// Resolve item
$result = [...];
// Subitems requested
if ($item->nesting) {
$result['items'] = [...];
}
return $result;
});项目应在 items 元素中列出。items 元素应仅为标记为嵌套的项目提供。
return [
'url' => 'https://example.tld/blog/category/another-category',
'isActive' => true,
'items' => [
[
'title' => 'Another category',
'url' => 'https://example.tld/blog/category/another-category',
'isActive' => true
],
[
'title' => 'News',
'url' => 'https://example.tld/blog/category/news',
'isActive' => false
]
]
];一个已解析的页面链接有可能返回包含此页面链接的其他站点。在这种情况下,$item 参数可能包含一个设置为 true 的 sites 属性。Site 和 Cms 门面在此很有帮助,请参见下面的示例。
Event::listen('cms.pageLookup.resolveItem', function($type, $item, $url, $theme) {
// Resolve item
$result = [...];
$page = \Cms\Classes\Page::loadCached($theme, $item->reference);
// Sites requested
if ($item->sites) {
$sites = [];
if (Site::hasMultiSite()) {
foreach (Site::listEnabled() as $site) {
$url = Cms::siteUrl($page, $site, [
'id' => $record->id,
'slug' => $record->slug,
'fullslug' => $record->fullslug
]);
$sites[] = [
'url' => $url,
'id' => $site->id,
'code' => $site->code,
'locale' => $site->hard_locale,
];
}
}
$result['sites'] = $sites;
}
return $result;
});结果项应包含一个sites数组,其中包含站点定义对象,每个对象都带有一个已设置的url。
下面是一个基本的示例,展示如何使用 Cms\Classes\Controller 类和 pageUrl 方法,通过查找模型和页面 URL 来解析页面 URL。当通过 $item->nesting 请求时,它还会使用模型上的 children 关系递归处理子项。
Event::listen('cms.pageLookup.resolveItem', function($type, $item, $url, $theme) {
if ($type !== 'my-model') {
return;
}
$model = MyModel::find($item->reference);
if (!$model) {
return;
}
$controller = new Controller($theme);
$pageUrl = $controller->pageUrl($item->cmsPage, [
'id' => $model->id,
'slug' => $model->slug
]);
$result = [
'url' => $pageUrl,
'isActive' => $pageUrl == $url,
'title' => $model->title,
'mtime' => $model->updated_at,
];
if (!$item->nesting) {
return $result;
}
$iterator = function($children) use (&$iterator, &$item, &$theme, $url, $controller, $model) {
$branch = [];
foreach ($children as $child) {
$childUrl = $controller->pageUrl($item->cmsPage, [
'id' => $model->id,
'slug' => $model->slug
]);
$childItem = [
'url' => $childUrl,
'isActive' => $childUrl == $url,
'title' => $child->title,
'mtime' => $child->updated_at,
];
if ($child->children) {
$childItem['items'] = $iterator($child->children);
}
$branch[] = $childItem;
}
return $branch;
};
$result['items'] = $iterator($model->children);
return $result;
});由于解析过程在每次前端页面渲染时都会发生,如果可能的话,最好缓存所有解析项目所需的所有信息。