ralphjsmit / laravel-filament-seo

一个结合Laravel SEO和Filament Admin强大功能的包。

1.4.0 2024-08-30 10:38 UTC

README

laravel-filament-seo

结合Laravel SEO和Filament PHP的功能。

本包是使用laravel-seo包的便捷助手,与Filament Admin和表单一起使用。

它提供了一个简单的组件,返回一个Filament字段组,用于修改SEO模型的、<author>和<description>字段。它自动处理获取和保存所有数据到<code>seo()</code>关系,因此可以在任何地方使用,无需额外配置!</p> <pre><span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Resources</span>\<span class="pl-v">Form</span>; <span class="pl-k">use</span> <span class="pl-v">RalphJSmit</span>\<span class="pl-v">Filament</span>\<span class="pl-c1">SEO</span>\<span class="pl-c1">SEO</span>; <span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-k">function</span> <span class="pl-en">form</span>(<span class="pl-smi"><span class="pl-smi">Form</span></span> <span class="pl-s1"><span class="pl-c1">$</span>form</span>): <span class="pl-smi"><span class="pl-smi">Form</span></span> { <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span>form</span>-><span class="pl-en">schema</span>([ <span class="pl-c1">SEO</span>::<span class="pl-en">make</span>(), <span class="pl-c">// .. Your other fields</span> ]); }</pre> <p>以下是一个<code>SEO</code>组件的示例</p> <p><a target="_blank" href="https://raw.githubusercontent.com/ralphjsmit/laravel-filament-seo/main/docs/images/card.png" rel="nofollow noindex noopener external ugc"><img src="https://rawcdn.githack.com/ralphjsmit/laravel-filament-seo/main/docs/images/card.png" alt="Using the Laravel Filament SEO component"></a></p> <h2 class="heading-element">安装</h2><a id="user-content-installation" class="anchor" href="#user-content-installation" rel="nofollow noindex noopener external ugc"></a> <p>首先,安装包</p> <pre>composer require ralphjsmit/laravel-filament-seo</pre> <p>这将需要安装<code>ralphjsmit/laravel-seo</code>,如果您尚未安装。请确保<a href="https://github.com/ralphjsmit/laravel-seo" rel="nofollow noindex noopener external ugc">查看主包的文档</a>并配置特殊<code>seo.php</code>配置文件中的值!</p> <p>接下来,确保您正在编辑的<strong>Eloquent模型</strong>使用了<code>HasSEO</code>特质</p> <pre><span class="pl-k">class</span> <span class="pl-v">Post</span> <span class="pl-k">extends</span> <span class="pl-v">Model</span> { <span class="pl-k">use</span> <span class="pl-v">HasSEO</span>; }</pre> <p>现在,<strong><code>SEO::make()</code>助手在任何地方都可以使用</strong>。以下是一些如何使用它的示例</p> <h3 class="heading-element">在Filament Admin中</h3><a id="user-content-in-filament-admin" class="anchor" href="#user-content-in-filament-admin" rel="nofollow noindex noopener external ugc"></a> <p>这是在经典<a href="https://filamentphp.com/docs/2.x/admin/installation" rel="nofollow noindex noopener external ugc">Filament Admin</a>中使用本包的示例。</p> <p>它适用于创建和编辑帖子</p> <pre><span class="pl-ent"><?php</span> <span class="pl-k">namespace</span> <span class="pl-v">App</span>\<span class="pl-v">Filament</span>\<span class="pl-v">Resources</span>; <span class="pl-k">use</span> <span class="pl-v">App</span>\<span class="pl-v">Filament</span>\<span class="pl-v">Resources</span>; <span class="pl-k">use</span> <span class="pl-v">App</span>\<span class="pl-v">Models</span>\<span class="pl-v">Post</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Forms</span>\<span class="pl-v">Components</span>\<span class="pl-v">TextInput</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Resources</span>\<span class="pl-v">Form</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Resources</span>\<span class="pl-v">Resource</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Resources</span>\<span class="pl-v">Table</span>; <span class="pl-k">use</span> <span class="pl-v">RalphJSmit</span>\<span class="pl-v">Filament</span>\<span class="pl-c1">SEO</span>\<span class="pl-c1">SEO</span>; <span class="pl-k">class</span> <span class="pl-v">PostResource</span> <span class="pl-k">extends</span> <span class="pl-v">Resource</span> { <span class="pl-k">protected</span> <span class="pl-k">static</span> ?<span class="pl-smi">string</span> <span class="pl-c1"><span class="pl-c1">$</span>model</span> = <span class="pl-v">Post</span>::class; <span class="pl-k">protected</span> <span class="pl-k">static</span> ?<span class="pl-smi">string</span> <span class="pl-c1"><span class="pl-c1">$</span>slug</span> = <span class="pl-s">'<span class="pl-s">posts</span>'</span>; <span class="pl-k">protected</span> <span class="pl-k">static</span> ?<span class="pl-smi">string</span> <span class="pl-c1"><span class="pl-c1">$</span>recordTitleAttribute</span> = <span class="pl-s">'<span class="pl-s">title</span>'</span>; <span class="pl-k">protected</span> <span class="pl-k">static</span> ?<span class="pl-smi">string</span> <span class="pl-c1"><span class="pl-c1">$</span>navigationGroup</span> = <span class="pl-s">'<span class="pl-s">Blog</span>'</span>; <span class="pl-k">protected</span> <span class="pl-k">static</span> ?<span class="pl-smi">string</span> <span class="pl-c1"><span class="pl-c1">$</span>navigationIcon</span> = <span class="pl-s">'<span class="pl-s">heroicon-o-document-text</span>'</span>; <span class="pl-k">protected</span> <span class="pl-k">static</span> ?<span class="pl-smi">int</span> <span class="pl-c1"><span class="pl-c1">$</span>navigationSort</span> = <span class="pl-c1">0</span>; <span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-k">function</span> <span class="pl-en">form</span>(<span class="pl-smi"><span class="pl-smi">Form</span></span> <span class="pl-s1"><span class="pl-c1">$</span>form</span>): <span class="pl-smi"><span class="pl-smi">Form</span></span> { <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span>form</span>-><span class="pl-en">schema</span>([ <span class="pl-v">TextInput</span>::<span class="pl-en">make</span>(<span class="pl-s">'<span class="pl-s">title</span>'</span>), <span class="pl-c1">SEO</span>::<span class="pl-en">make</span>(), ]); } <span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-k">function</span> <span class="pl-en">table</span>(<span class="pl-smi"><span class="pl-smi">Table</span></span> <span class="pl-s1"><span class="pl-c1">$</span>table</span>): <span class="pl-smi"><span class="pl-smi">Table</span></span> { <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span>table</span>-><span class="pl-en">columns</span>([ <span class="pl-c">/* */</span> ]); } <span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-k">function</span> <span class="pl-en">getPages</span>(): <span class="pl-smi">array</span> { <span class="pl-k">return</span> [ <span class="pl-s">'<span class="pl-s">index</span>'</span> => <span class="pl-v">Resources</span>\<span class="pl-v">PostResource</span>\<span class="pl-v">Pages</span>\<span class="pl-v">ListPosts</span>::<span class="pl-en">route</span>(<span class="pl-s">'<span class="pl-s">/</span>'</span>), <span class="pl-s">'<span class="pl-s">create</span>'</span> => <span class="pl-v">Resources</span>\<span class="pl-v">PostResource</span>\<span class="pl-v">Pages</span>\<span class="pl-v">CreatePost</span>::<span class="pl-en">route</span>(<span class="pl-s">'<span class="pl-s">/create</span>'</span>), <span class="pl-s">'<span class="pl-s">edit</span>'</span> => <span class="pl-v">Resources</span>\<span class="pl-v">PostResource</span>\<span class="pl-v">Pages</span>\<span class="pl-v">EditPost</span>::<span class="pl-en">route</span>(<span class="pl-s">'<span class="pl-s">{record}/edit</span>'</span>), ]; } }</pre> <h3 class="heading-element">与Filament Forms一起使用</h3><a id="user-content-with-filament-forms" class="anchor" href="#user-content-with-filament-forms" rel="nofollow noindex noopener external ugc"></a> <p>您还可以使用本包与独立的<a href="https://filamentphp.com/docs/2.x/forms/installation" rel="nofollow noindex noopener external ugc">Filament Forms</a>包一起使用。</p> <p>以下是一个简单的示例,说明如何设置一个创建新帖子的Livewire组件。在这个例子中,我将<code>SEO</code>组件包裹在一个Card中。</p> <pre><span class="pl-ent"><?php</span> <span class="pl-k">namespace</span> <span class="pl-v">App</span>\<span class="pl-v">Http</span>\<span class="pl-v">Livewire</span>; <span class="pl-k">use</span> <span class="pl-v">App</span>\<span class="pl-v">Models</span>\<span class="pl-v">Post</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Forms</span>\<span class="pl-v">Components</span>\<span class="pl-v">Card</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Forms</span>\<span class="pl-v">Components</span>\<span class="pl-v">TextInput</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Forms</span>\<span class="pl-v">Concerns</span>\<span class="pl-v">InteractsWithForms</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Forms</span>\<span class="pl-v">Contracts</span>\<span class="pl-v">HasForms</span>; <span class="pl-k">use</span> <span class="pl-v">Illuminate</span>\<span class="pl-v">Contracts</span>\<span class="pl-v">View</span>\<span class="pl-v">View</span>; <span class="pl-k">use</span> <span class="pl-v">Illuminate</span>\<span class="pl-v">Database</span>\<span class="pl-v">Eloquent</span>\<span class="pl-v">Model</span>; <span class="pl-k">use</span> <span class="pl-v">Livewire</span>\<span class="pl-v">Component</span>; <span class="pl-k">use</span> <span class="pl-v">RalphJSmit</span>\<span class="pl-v">Filament</span>\<span class="pl-c1">SEO</span>\<span class="pl-c1">SEO</span>; <span class="pl-k">class</span> <span class="pl-v">CreatePost</span> <span class="pl-k">extends</span> <span class="pl-v">Component</span> <span class="pl-k">implements</span> <span class="pl-v">HasForms</span> { <span class="pl-k">use</span> <span class="pl-v">InteractsWithForms</span>; <span class="pl-k">public</span> <span class="pl-smi">array</span> <span class="pl-c1"><span class="pl-c1">$</span>data</span> = []; <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">mount</span>(): <span class="pl-smi">void</span> { <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-><span class="pl-c1">form</span>-><span class="pl-en">fill</span>(); } <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">render</span>(): <span class="pl-smi"><span class="pl-smi">View</span></span> { <span class="pl-k">return</span> <span class="pl-en">view</span>(<span class="pl-s">'<span class="pl-s">livewire.create-post</span>'</span>); } <span class="pl-k">protected</span> <span class="pl-k">function</span> <span class="pl-en">getFormSchema</span>(): <span class="pl-smi">array</span> { <span class="pl-k">return</span> [ <span class="pl-v">TextInput</span>::<span class="pl-en">make</span>(<span class="pl-s">'<span class="pl-s">title</span>'</span>), <span class="pl-v">Card</span>::<span class="pl-en">make</span>([ <span class="pl-c1">SEO</span>::<span class="pl-en">make</span>() ]), ]; } <span class="pl-k">protected</span> <span class="pl-k">function</span> <span class="pl-en">getFormStatePath</span>(): ?<span class="pl-smi">string</span> { <span class="pl-k">return</span> <span class="pl-s">'<span class="pl-s">data</span>'</span>; } <span class="pl-k">protected</span> <span class="pl-k">function</span> <span class="pl-en">getFormModel</span>(): <span class="pl-smi"><span class="pl-smi">Model</span></span>|<span class="pl-smi">string</span>|<span class="pl-smi">null</span> { <span class="pl-k">return</span> <span class="pl-v">Post</span>::class; } <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">submitForm</span>() { <span class="pl-s1"><span class="pl-c1">$</span>post</span> = <span class="pl-v">Post</span>::<span class="pl-en">create</span>(<span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-><span class="pl-c1">form</span>-><span class="pl-en">getState</span>()); <span class="pl-c">/** Do not forget this step. */</span> <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-><span class="pl-c1">form</span>-><span class="pl-en">model</span>(<span class="pl-s1"><span class="pl-c1">$</span>post</span>)-><span class="pl-en">saveRelationships</span>(); } }</pre> <p>以下是一个编辑帖子的Livewire组件的示例</p> <pre><span class="pl-ent"><?php</span> <span class="pl-k">namespace</span> <span class="pl-v">App</span>\<span class="pl-v">Http</span>\<span class="pl-v">Livewire</span>; <span class="pl-k">use</span> <span class="pl-v">App</span>\<span class="pl-v">Models</span>\<span class="pl-v">Post</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Forms</span>\<span class="pl-v">Components</span>\<span class="pl-v">TextInput</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Forms</span>\<span class="pl-v">Concerns</span>\<span class="pl-v">InteractsWithForms</span>; <span class="pl-k">use</span> <span class="pl-v">Filament</span>\<span class="pl-v">Forms</span>\<span class="pl-v">Contracts</span>\<span class="pl-v">HasForms</span>; <span class="pl-k">use</span> <span class="pl-v">Illuminate</span>\<span class="pl-v">Contracts</span>\<span class="pl-v">View</span>\<span class="pl-v">View</span>; <span class="pl-k">use</span> <span class="pl-v">Illuminate</span>\<span class="pl-v">Database</span>\<span class="pl-v">Eloquent</span>\<span class="pl-v">Model</span>; <span class="pl-k">use</span> <span class="pl-v">Livewire</span>\<span class="pl-v">Component</span>; <span class="pl-k">use</span> <span class="pl-v">RalphJSmit</span>\<span class="pl-v">Filament</span>\<span class="pl-c1">SEO</span>\<span class="pl-c1">SEO</span>; <span class="pl-k">use</span> <span class="pl-v">RalphJSmit</span>\<span class="pl-v">Filament</span>\<span class="pl-c1">SEO</span>\<span class="pl-v">Tests</span>\<span class="pl-v">Fixtures</span>\<span class="pl-v">Models</span>\<span class="pl-v">Post</span>; <span class="pl-k">class</span> <span class="pl-v">EditPost</span> <span class="pl-k">extends</span> <span class="pl-v">Component</span> <span class="pl-k">implements</span> <span class="pl-v">HasForms</span> { <span class="pl-k">use</span> <span class="pl-v">InteractsWithForms</span>; <span class="pl-k">public</span> <span class="pl-smi"><span class="pl-smi">Post</span></span> <span class="pl-c1"><span class="pl-c1">$</span>post</span>; <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">mount</span>(): <span class="pl-smi">void</span> { <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-><span class="pl-c1">form</span>-><span class="pl-en">fill</span>([ <span class="pl-s">'<span class="pl-s">title</span>'</span> => <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-><span class="pl-c1">post</span>-><span class="pl-c1">title</span>, ]); } <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">render</span>(): <span class="pl-smi"><span class="pl-smi">View</span></span> { <span class="pl-k">return</span> <span class="pl-en">view</span>(<span class="pl-s">'<span class="pl-s">livewire.edit-post</span>'</span>); } <span class="pl-k">protected</span> <span class="pl-k">function</span> <span class="pl-en">getFormSchema</span>(): <span class="pl-smi">array</span> { <span class="pl-k">return</span> [ <span class="pl-v">TextInput</span>::<span class="pl-en">make</span>(<span class="pl-s">'<span class="pl-s">title</span>'</span>), <span class="pl-c1">SEO</span>::<span class="pl-en">make</span>(), ]; } <span class="pl-k">protected</span> <span class="pl-k">function</span> <span class="pl-en">getFormModel</span>(): <span class="pl-smi"><span class="pl-smi">Model</span></span>|<span class="pl-smi">string</span>|<span class="pl-smi">null</span> { <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-><span class="pl-c1">post</span>; } <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">submitForm</span>() { <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-><span class="pl-c1">post</span>-><span class="pl-en">update</span>( <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-><span class="pl-c1">form</span>-><span class="pl-en">getState</span>(), ); } }</pre> <h2 class="heading-element">通用</h2><a id="user-content-general" class="anchor" href="#user-content-general" rel="nofollow noindex noopener external ugc"></a> <p>🐞 如果您发现一个错误,请提交详细的问题,我会尽快修复。</p> <p>🔐 如果您发现一个漏洞,请查看<a href="https://github.com/ralphjsmit/laravel-filament-seo/blob/HEAD/../../security/policy" rel="nofollow noindex noopener external ugc">我们的安全策略</a>。</p> <p>🙌 如果您想做出贡献,请提交拉取请求。所有PR都将得到充分认可。如果您不确定我会不会接受您的想法,请随时联系我!</p> <p>🙋‍♂️ <a href="https://ralphjsmit.com" rel="nofollow noindex noopener external ugc">Ralph J. Smit</a></p> </div> </div> </div> </section> </section> </section> <footer class="wrapper-footer"> <nav class="container"> <div class="row"> <ul class="social col-xs-7 col-sm-4 col-md-2 pull-right"> <li><a href="http://github.com/composer/packagist" title="GitHub"><span class="icon-github"></span></a></li> <li><a href="https://twitter.com/packagist" title="Follow @packagist"><span class="icon-twitter"></span></a></li> <li><a href="mailto:contact@packagist.org" title="Contact"><span class="icon-mail"></span></a></li> </ul> <ul class="col-xs-4 col-sm-4 col-md-2"> <li><a href="/about">About Packagist</a></li> <li><a href="/feeds/" rel="nofollow">Atom/RSS Feeds</a></li> </ul> <div class="clearfix visible-xs-block"></div> <ul class="col-xs-3 col-sm-4 col-md-2"> <li><a href="/statistics" rel="nofollow">Statistics</a></li> <li><a href="/explore/">Browse Packages</a></li> </ul> <div class="clearfix visible-xs-block visible-sm-block"></div> <ul class="col-xs-3 col-sm-4 col-md-2"> <li><a href="/apidoc">API</a></li> <li><a href="/mirrors">Mirrors</a></li> </ul> <div class="clearfix visible-xs-block"></div> <ul class="col-xs-3 col-sm-4 col-md-2"> <li><a href="https://status.packagist.org/">Status</a></li> <li><a href="https://p.datadoghq.com/sb/x98w56x71erzshui-4a54c45f82bacc991e83302548934b6a">Dashboard</a></li> </ul> </div> <div class="row sponsor"> <p class="col-xs-12">Packagist maintenance and hosting provided by <a href="https://packagist.com/"><img alt="Private Packagist" src="/img/private-packagist.svg?v=1726064759"></a></p> </div> <div class="row sponsor"> <p class="col-xs-12">Monitoring provided by <a href="https://datadog.com/"><img alt="Datadog" src="/img/datadog-light.png?v=1726064759"></a></p> </div> </nav> </footer> <script nonce="dWETXCo9xvyyT6OanryLmA=="> var algoliaConfig = {"app_id":"M58222SH95","search_key":"5ae4d03c98685bd7364c2e0fd819af05","index_name":"packagist"}; window.process = { env: { DEBUG: undefined }, }; </script> <script nonce="dWETXCo9xvyyT6OanryLmA==" src="/build/app.js?v=1726064759"></script> </body></html>