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;
});由于解析过程在每次前端页面渲染时都会发生,因此,如果可能的话,最好缓存解析项目所需的所有信息。