monstrex /
Voyager 网站包
Requires
- ext-json: *
- liquid/liquid: ^1.4
- monstrex/voyager-extension: *
- webwizo/laravel-shortcodes: ^1.0.20
Requires (Dev)
- laravel/framework: ~8.0|~9.0|~10.0
- phpunit/phpunit: ~8.0|~9.0|~10.0
- dev-master
- v0.95.82
- v0.95.7
- v0.95.4
- v0.95.3
- v0.95.2
- v0.95
- v0.93
- v0.92.4
- v0.92.3
- v0.92.2
- v0.92
- 0.91
- 0.90
- v0.88
- v0.87
- v0.86
- v0.85
- v0.84
- v0.8
- 0.7.x-dev
- dev-dependabot/npm_and_yarn/express-4.19.2
- dev-dependabot/npm_and_yarn/webpack-dev-middleware-5.3.4
- dev-dependabot/npm_and_yarn/follow-redirects-1.15.6
- dev-dev
This package is auto-updated.
Last update: 2024-09-28 19:04:21 UTC
README
该包是Voyager 管理面板包的基本内容组织的一个简单但有用的子系统实现。使用此包,您可以快速轻松地构建小型和中型网站。
功能
- 基本页面管理模块,包括系统页面。
- 基本 SEO 实现 - SEO 标题、Meta 描述和 Meta 关键字参数。
- 面包屑实现。
- 灵活的区块/小部件管理模块,用于构建网站页面的一部分。
- 表单管理系统,包括 AJAX 发送。
- Liquid 模板子系统用于区块/小部件和表单。
- 使用灵活的区块/小部件构建页面布局。
- 短代码集成。
- 从数据库表进行本地化,您可以在其中轻松保存和管理您的翻译。
- 高级网站设置模块,包括 SMTP 邮件设置和开箱即用的邮件发送测试。
安装
要求
在之前,您应该完全安装Voyager 扩展包。
通过 Composer
$ composer require monstrex/voyager-site
然后运行安装命令
$ php artisan voyager-site:install
如果需要,发布配置
$ php artisan vendor:publish --provider="MonstreX\VoyagerSite\VoyagerSiteServiceProvider" --tag="config"
用法
配置文件
- route_home_page - 主页的路由名称(默认为 'home')。
- default_model_table - 查找记录的默认模型表名称(默认为 'pages')。
- default_slug_field - 默认 slug 字段名称(默认为 'slug')。
- use_legacy_error_handler - 如果为 false,将使用 voyager-site 404 错误处理器。
- template - 存储视图模板文件的根文件夹名称(默认为 'template')。
- template_master - 主模板名称(默认为 'layouts.master')。
- template_layout - 主要布局模板名称(默认为 'layouts.main')。
- template_page - 页面模板名称(默认为 'pages.page')。
- template_filters - 添加自定义 Liquid 过滤器或 Null 的类。
网站设置
网站设置是一个灵活可扩展且易于使用的设置子系统,集成在包中。
您可以使用和修改现有设置,以及添加您自己的组和设置。要检索特定设置,您可以使用辅助函数
$mail = site_setting('mail.to_address');
内部包函数使用的某些网站设置将覆盖 Laravel .env 设置。
您可以通过点击编辑操作,使用类似 JSON 的设置字段配置来轻松修改设置或添加新的设置。
{ "fields": { "to_address": { "label": "Default address for site emails", "type": "text", "value": "destination@example.com", "class": "col-md-12" }, "section_smtp": { "type": "section", "icon": "voyager-mail", "label": "E-Mail transport" }, "driver": { "label": "Mail driver", "type": "dropdown", "value": "smtp", "options": { "smtp": "SMTP", "mailgun": "MAILGUN", "log": "LOG" }, "class": "col-md-12" } } }
内置的字段类型有
- 文本
- 数字
- 多行文本框
- 富文本框(tinyMCE 编辑器)
- 代码编辑器(ACE 代码编辑器)
- 复选框
- 单选按钮
- 图像(voyager 类型图像)
- 媒体(图像文件,使用 laravel medialibrary 包)
- 路由(使用路由名称返回 URL)
- 部分(没有值,仅用于视觉上分隔字段组)
本地化
本包为所有需要本地化的字符串提供类似数据库的本地化存储。只需将语言列添加到存储中,它将代替文件中的本地化使用。
页面
VPage模块允许您管理网站上的基本页面。您可以轻松找到并准备任何页面及其相关属性,例如SEO数据、面包屑和数据源,然后将这些数据集发送到视图。它可以以两种方式使用:将PageTrait
类实现到您的控制器中或使用外观VPage
。查看示例
示例 #1
namespace App\Http\Controllers; use MonstreX\VoyagerSite\Traits\PageTrait; class PagesController extends Controller { use PageTrait; public function home() { $this->create('home'); return $this->view(); } public function show($alias) { $this->create($alias); return $this->view(); } public function showArticle($alias) { $this->create($alias,'articles'); return $this->view('layout.article', ['vars' => $some_vars]); } }
示例 #2
namespace App\Http\Controllers; use MonstreX\VoyagerSite\Traits\PageTrait; use VSite, VPage, VData; class PagesController extends Controller { public function home() { VPage::create(VData::find('home'), VSite::getSettings()); return VPage::view(); } }
示例执行的操作
- 在默认(或指定)模型中查找特定记录(默认使用'slug'字段)。如果您使用(int)值,则将通过ID字段查找。如果未找到记录或记录有空的(null)状态字段,则将抛出异常404。
- 创建一个VPage实例,并用页面数据初始化该实例。
- 找到的模型对象。
- 网站设置。
- 初始化了面包屑。
- 初始化SEO参数(SEO标题、元描述、元关键词)。
- 附加数据源,如果
details
字段有数据源描述。
- 使用默认(或指定)视图渲染页面。
视图中可用的变量
$template // Root template folder $template_master // Master template name (to extend View) $template_page // Internal page template name $breadcrumbs // Breadcrumbs array $title // Page title $banner // Page banner image (if present) $page // Page instance $parents // Chain of parents of current page $children // Children pages if present for current page $data_sources // Extra Data sources attached to the Page $seo['title'] // Seo Title $seo['description'] // Meta Description $seo['keywords'] // Meta Keywords $data // Additional given data
页面数据集
这是一个子系统,用于检索在特定页面上使用所需的附加数据。数据是从不同模型的记录集合中不同的记录。
要使用它,您需要在您的模型中具有details
字段,该记录填充了某种JSON数据结构
注意:在调用
create
方法时,将在JSON结构中定义的附加数据自动加载。
{ "data_sources": { "articles": { "model": "Article", "where": { "status": 1 } }, "services": { "model": "Service", "where": { "status": 1, "featured": 0, "type": "main" }, "with": [ "category", "country" ], "order" : { "field" : "order", "direction" : "asc" } } } }
在您的视图模板中,您可以轻松地像这样使用它
@foreach($data_sources['articles'] as $article) <h2>{{ $article['title'] }}</h2> @endforeach
注意:此类JSON数据结构也用于块/小部件子系统。
覆盖页面上的默认模板
您可能想覆盖特定页面上的默认模板名称。为此,请在details
字段中定义新的模板名称
{ "template": "my-theme", "template_master": "layout.master", "template_layout": "layout.main", "template_page": "pages.contacts" }
在控制器中覆盖(使用页面特性)
public function service($alias) { $pageContent = $this->create($alias,'services')->getContent(); $this->setPageTemplate('pages.service'); $this->buildBreadcrumbs(); $this->setChildren('parent_id'); return $this->view(); }
页面SEO参数
SEO参数是在create
页面方法内部生成的。默认情况下
SEO标题 - 从页面SEO字段组,如果适当的字段不为空,否则检查标题
字段,如果该字段不存在,则检查网站设置seo.seo_title
,如果该设置为空,则从网站设置general.site_title
中获取值。最后,给定值通过SEO标题模板网站设置seo.seo_title_template
传递。
您可以使用方法
VPage::setSeoTitle('new title')
覆盖SEO标题
值。
元描述 - 从页面SEO字段组,如果适当的字段不为空,否则检查网站设置seo.meta_description
,如果该设置为空,则从网站设置general.site_description
中获取值。
您可以使用方法
VPage::setMetaDescription('new description')
覆盖元描述
值。
元关键词 - 从页面SEO字段组,如果适当的字段不为空,否则检查网站设置seo.meta_keywords
。
您可以使用方法
VPage::setMetaKeywords('new keywords')
覆盖元关键词
值。
页面面包屑
当您调用页面create
方法时,它将第一个元素添加到Breadcrumbs
数组中。
如何设置第一个面包屑元素
addBreadcrumbs(__('site.breadcrumb_home'), route(config('voyager-site.route_home_page')));
要向Breadcrumbs
数组添加其他元素,只需使用方法VPage::addBreadcrumbs($title, $path)
您还可以使用方法buildBreadcrumbs()
来构建一个包含在Parents属性中的嵌套页面链。当您使用方法setParents($page, $parent_field_name)
加载和创建页面实例时,该属性会自动设置,其中$页是当前页面实例,$parent_field_name是包含当前页面父ID的字段名称。
注意:为模型进行的额外设置 - 构建父链、面包屑和获取横幅
// Example (Additional Model properties) public $masterPageRouteName = 'page'; public $masterPageSlug = 'pages'; public $masterPageId = 2; public $pageRouteName = 'service'; public $bannerField = 'banner_image';
块 / 小部件
块 / 小部件是一个灵活的子系统,它为您提供了实现和整理额外的内容部分,并将它们包含到页面中的方法。
每个块都具有以下结构
状态 - 如果禁用,则块将被忽略。
标题 - 仅在管理员面板中可见。
块键 - 用于查找和渲染此块的关键字(短名)。
区域位置 - 用于分组块,然后按特定顺序将它们作为组渲染。可用的位置可以在“区域”菜单中编辑。
块内容 - 主要块内容。您可以使用纯HTML代码或Liquid模板。
可用变量
- this.images - 包含以下列出的图像项。
- this.field_name - 包含额外的字段值,其中field_name是块表中额外的字段名称。
- data - 如果在“选项”字段中定义了数据源。
示例 #1(使用图像列表)
<!-- Block liquid template --> <h3>My images</h3> <div class="images-list"> {% for image in this.images %} <img src="{{ image.url | crop: 300,200 | url }}" alt=""/> {% endfor %} </div>
其中 image.url 表示图像的相对URL。 裁剪 过滤器 - 裁剪并存储(如果尚未存储)具有给定尺寸的图像。 -url 过滤器 - 从相对URL创建完整URL。 image.full_url - 图像的完整URL。 image.props.* - 自定义图像属性。
示例 #2(使用数据源)
<!-- Block liquid template --> <h3>Articles Block</h3> <ul> {% for article in data.articles %} <li>{{ article.title }}</li> {% endfor %} </ul>
对于此类模板,您需要在“选项”字段中定义类似于JSON的 数据源 结构
{ "data_sources": { "articles": { "model": "Article", "where": { "status": 1, "news": 1 }, "order" : { "field" : "order", "direction" : "asc" } } } }
其中 "model" 是等于在Voyager面包系统注册的模型名称的模型名称。
示例 #3(使用内部块的字段)
<!-- Block liquid template --> {{ this.title }} <!-- Get TITLE block field --> {{ this.images[0].url }} <!-- Get Image URL with index 0 --> {{ this.images[0].props.title }} <!-- Get Image custom property --> {{ this.additional_field }} <!-- Get any additional block field value --> {{ options.data_section }} <!-- Get JSON parameter stored in the parameters field -->
您还可以使用辅助程序获取特定块的任何字段
<h1>{{ get_block_field('top-line', 'title') }}</h1>
块渲染
只需使用helper render_block('key')。您可以使用块标题或ID(数字)代替键。
{!! render_block('top-line') !!} {!! render_block('Our services') !!} {!! render_block(3) !!}
区域(组)渲染和URL路径规则。
它可以用于在需要时在模板中组织并渲染具有相同区域(组)名称的一组块。例如
{!! render_region('content-before') !!}
将渲染所有设置了此区域(组)'content-before'的块。并且该包将检查所有块是否可以渲染 - 这取决于设置“URL路径规则”
这是一个类似Drupal的块系统渲染。这可以依赖于当前URL,也可以不依赖。
表单
类似于块。但您只能使用有限的内部变量集。'send.form'是在表单子系统内部通过sendForm($request)方法实现的。它发送任何表单数据,包括附件。您还可以使用Google ReCaptcha 2表单保护。只需在您需要的表单内添加一行
<div class="g-recaptcha" data-sitekey="{{ 'general.site_captcha_site_key' | site_setting }}"></div>
并将recaptcha验证规则添加到表单选项中
{ "validator": { "g-recaptcha-response": "required|recaptcha" } }
模板部分
<form class="form{{ form_alias }}" action="{{ 'send.form' | route }}" method="post" enctype="multipart/form-data"> <input type="hidden" name="_token" value="{{ csrf_token }}"> <input type="hidden" name="_form_alias" value="{{ form_alias }}"> <input type="hidden" name="subject" value="Send us a message!"> <input class="form-control" type="text" name="name" value="" required> <input class="form-control" type="email" name="email" value="" required> <input class="form-control phone" type="text" name="phone" value="" required> <textarea class="form-control" name="message" required=""></textarea> <div class="g-recaptcha" data-sitekey="{{ 'site_setting' | func: 'general.site_captcha_site_key' }}"></div> <button type="submit" class="btn-send-form ">Send</button> </form>
参数部分
{ "to_address": "info@site.com,support@site.com", "validator": { "name":"required", "email":"required", "phone":"required", "g-recaptcha-response": "required|recaptcha" }, "messages": { "name.required": "The field NAME shouldn't be empty.", "email.required": "The field EMAIL shouldn't be empty.", "phone.required": "The field PHONE shouldn't be empty." } }
如果不存在参数'to_address',将使用配置设置:mail.to_address。
在表单模板内部,您可以使用内部变量
{{ old }} <!-- Previous values saved in session = session()->getOldInput() --> {{ errors_messages}} <!-- = $errors->all() --> {{ errors }} <!-- = $errors->toArray() --> {{ form_alias }} <!-- Form Key --> {{ form_suffix }} <!-- Additional form suffix if you need --> {{ form_subject }}} <!-- Form Subject --> {{ csrf_token }} <!-- = csrf_token() -->
要从视图中渲染表单,请使用辅助程序renderForm($key, $subject = null, $suffix = null)
{!! render_form('callback-form', 'Send us a message!', '-second-form') !!}
要在块内部渲染
{{ 'callback-form' | form: 'Send us a message!','-second-form' }}
更多示例
<div id="{{ form_alias }}-{{ form_suffix }}" class="default-form contact-form"> <form data-holder-id="{{ form_alias }}-{{ form_suffix }}" class="{{ form_alias }}" action="{{ "send.form" | route }}" method="post" enctype="multipart/form-data"> <input type="hidden" name="_token" value="{{ csrf_token }}"> <input type="hidden" name="_form_alias" value="{{ form_alias }}"> <input type="hidden" name="subject" value="Callback form"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" name="name" placeholder="Your name" value="{{ old.name }}"> {% if errors.name %} <span class="help-block"> {% for error in errors.name %} <div>{{ error }}</div> {% endfor %} </span> {% endif %} </div> <div class="form-group"> <label for="phone">Phone</label> <input type="text" class="form-control" id="phone" name="phone" placeholder="Your phone number" value="{{ old.phone }}"> {% if errors.phone %} <span class="help-block"> {% for error in errors.phone %} <div>{{ error }}</div> {% endfor %} </span> {% endif %} </div> <div class="form-group"> <label for="email">E-Mail address</label> <input type="email" class="form-control" id="email" name="email" placeholder="Your E-Mail address" value="{{ old.email }}"> {% if errors.email %} <span class="help-block"> {% for error in errors.email %} <div>{{ error }}</div> {% endfor %} </span> {% endif %} </div> <div class="form-group"> <label for="message">Message</label> <textarea class="form-control" id="message" name="message" placeholder="Your message">{{ old.message }}</textarea> {% if errors.message %} <span class="help-block"> {% for error in errors.message %} <div>{{ error }}</div> {% endfor %} </span> {% endif %} </div> <div class="form-group form-group-default"> <label>Attachment #1</label> <input type="file" name="images[]" accept="file_extension|image/*|media_type" multiple> </div> <div class="g-recaptcha" data-sitekey="{{ 'site_setting' | func: 'general.site_captcha_site_key' }}"></div> <button type="submit" class="btn btn-default">Submit</button> </form> </div> <h2>Form Messages</h2> {% for message in errors_messages %} <div>{{ message }}</div> {% endfor %}
您还可以使用AJAX表单发送。该包实现了AJAX发送的JS部分,只需包含jQuery库并在此视图中添加此行(或者您可以使用自己的JS函数)
@include('voyager-site::mail.send_form_ajax_js')
AJAX示例
<div id="{{ form_alias }}-{{ form_suffix }}" class="default-form contact-form"> <form data-holder-id="{{ form_alias }}-{{ form_suffix }}" class="{{ form_alias }}" action="{{ "send.form" | route }}" method="post" enctype="multipart/form-data" onsubmit="formSendAJAX(event, this)"> <input type="hidden" name="_token" value="{{ csrf_token }}"> <input type="hidden" name="_form_alias" value="{{ form_alias }}"> <input type="hidden" name="subject" value="Callback form AJAX"> <div class="row clearfix"> <div class="form-group"> <input type="text" name="name" placeholder="Ваше имя" value=""> </div> <div class="form-group"> <input type="email" name="email" placeholder="Ваш Email адрес" value=""> </div> <div class="form-group"> <input class="phone" type="text" name="phone" placeholder="Ваш телефон" value=""> </div> <div class="form-group"> <textarea rows="7" name="message" placeholder="Ваше сообщение"></textarea> </div> <div class="form-group form-group-default"> <label>Attachment</label> <input type="file" name="images[]" accept="file_extension|image/*|media_type" multiple> </div> <div class="col-sm-12"> <div class="g-recaptcha" data-sitekey="{{ 'general.site_captcha_site_key' | site_setting }}"></div> </div> <div class="form-button"> <button type="submit" class="btn btn-primary btn-send-form"> <span class="btn-loader hidden">...loading icon...</span> <span class="btn-title-normal">Send Form</span> <span class="btn-title-sending hidden">Sending...</span> </button> </div> </div> </form> <div class="form-message"></div> </div>
页面布局渲染
该特殊系统允许您管理特定页面上的块或表单以及字段。您可以在编辑页面模式下轻松添加/删除块、表单和字段(并对其进行排序),然后使用辅助程序进行渲染
{{ render_layout($page->layout, $page) }}
其中 $page 是页面实例。
或手动
@if ($layoutFields = json_decode($page->layout)) @if ($layoutFields) @foreach($layoutFields as $field) @if($field->type === 'Block') {!! render_block($field->key) !!} @elseif ($field->type === 'Form') {!! render_form($field->key) !!} @elseif ($field->type === 'Field') <div class="page-content"> {!! $page->{$field->key} !!} </div> @endif @endforeach @endif @endif
内置短码
block - 渲染一个块。例如:[block name="top-line"]
form - 渲染一个表单。例如:[form name="top-line" subject="表单主题" suffix="-callback-form"]
div - 渲染div包装器。不允许嵌套元素。例如:[div class="wrapper"] 内容 [/div]
image - 使用当前内容实例附加的媒体文件渲染HTML代码中的图片(并裁剪、转换图片)。
可用选项
field - 与附加媒体文件相关的媒体文件字段
index - 文件在集合中的索引,从1开始。
url - 图片路径(如果未使用field和index)
class - 图片标签的类。例如:class="lazy responsive"
lightbox - 创建灯箱包装器。例如:lightbox="true"
lightbox_class - 灯箱包装器的类
width - 图片标签的宽度属性。
height - 图片标签的高度属性。
picture - 添加图片包装器。
crop - 裁剪图片。
format - 将图片转换为webp、jpg、png。
示例
[image field="image" index="1"]
[image url="/images/banners/banner-1.jpg"]
[image field="images" index="3" picture="true" format="webp" width="100" height="200" crop="400,400" class="lazy-class" lazy="true" lightbox_class="image-gallery"]
内置的Liquid过滤器
url - 返回给定路径的完整URL。例如:{{ '/images/file.jpg' | url }}
route - 返回laravel路由路径。例如:{{ 'page' | route: 'slug' }}
crop - 裁剪(和/或转换)图片。例如:{{ this.images[0].url | crop: 300,300,'webp',75 }}
webp - 将图片转换为webp格式。例如:{{ this.images[0].url | webp }}
site_setting - 获取网站设置参数。例如:{{ 'mail' | site_setting: 'to_address' }} menu - 渲染菜单。例如:{{ 'main-menu' | menu: 'template.menus.main' }}
block - 渲染块。例如:{{ 'top-line' | block }}
form - 渲染表单。例如:{{ 'callback-form' | form: 'Form subject','-callback' }}
trans - 使用当前区域翻译字符串。例如:{{ '[[en]]English string[[ru]]Русская строка' | trans }}
lang -- 使用语言文件翻译字符串。例如:{{ 'auth.password' | lang }}
view -- 使用数据变量渲染blade视图。例如:{{ data | view: 'template.partials.portfolio-list' }}
service -- 使用服务方法获取数据(并将其传递到视图)。例如:{{ 'getPortfolio' | service: '\App\Services\DataService' | view: 'template.partials.portfolio-list' }}
自定义Liquid过滤器
您可以使用自定义类添加自己的liquid过滤器。您应该将此类添加到配置中
'template_filters' => 'App\Template\TemplateFilters'
<?php namespace App\Template; class TemplateFilters { public function handle($instance, $content) { $instance->registerFilter('div', function ($arg) { return '<div>' . $arg . '</div'; }); } }
辅助函数
translit_cyrillic($string) - 将给定的西里尔字符串转换为拉丁符号字符串。
get_file($file_path) - 返回给定file_path的URL,可以解包JSON voyager文件编码格式。
store_post_files(Request $request, $slug, $field, $public = 'public') - 存储请求中的文件给定的$request $field,并返回包含文件链接及其原始名称的Voyager数组。
generate_filename($file, $path) - 如果文件在给定的路径上存在,则返回新的文件名。
site_setting($key, $default = null) - 返回网站设置(或默认值)。
site_settings_group($group_key) - 返回一组网站设置。
get_image_or_create($image_path, $width, $height, $format, $quality) - 返回请求的图片的链接,具有给定的宽度和/或高度、格式和品质。如果不存在,则将其创建。
位置
$image_path - 域名或相对(到域名)的完整URL。
$width - 新图片宽度或空值,
$height - 新图片高度或空值(如果同时使用宽度和高度,则图片将被裁剪),
$format - 'webp', 'png', 'jpg':图片将转换为webp、png、jpg,
$quality - 新图片的品质水平。
get_first_not_empty(array $values) - 返回给定数组中的第一个非空元素。
render_block($key) - 渲染块。
render_region($key, $path = null) - 渲染区域(具有相同区域/组键的块组)。
render_form($key, $subject = null, $suffix = null) - 渲染具有给定键的表单。也接受主题字段和后缀,用于表单中。
render_layout($layout, $page) - 渲染页面布局(页面的块组、表单和页面字段)。
get_block_field($block_key, $field_name) - 返回给定块键的字段值。
安全性
如果您发现任何安全相关的问题,请通过作者邮箱联系,而不是使用问题跟踪器。
鸣谢
许可证
许可证。请参阅许可证文件以获取更多信息。