近期公司內部服務都朝向 Laravel framework 來維護,其中常見需求是製作具有 CMS 管理的機制,提供不同部門的同事編輯資料及發佈出去。就來試試看 Twill 這個 CMS Toolkit 套件。從他的文件得知,引入他可以快速擁有後台登入機制,以及省去自己規劃資料庫的資料表,而相較 wordpress 則是有更大的彈性做事。
目前在 Macbook M1 和 MacPorts 環境下,操作一下,先弄個 Laravel project 出來:
```% sudo port install php83 php83-iconv php83-intl php83-mbstring php83-openssl php83-curl php83-sqlite php83-zip php83-gd php83-exif% alias php=php83% wget https://getcomposer.org/download/latest-stable/composer.phar -O /tmp/composer.phar% php /tmp/composer.phar self-update% alias composer="php /tmp/composer.phar"% composer create-project --prefer-dist laravel/laravel /tmp/laravel-workspaceCreating a "laravel/laravel" project at "/tmp/laravel-workspace"Installing laravel/laravel (v11.1.4)- Installing laravel/laravel (v11.1.4): Extracting archiveCreated project in /tmp/laravel-workspace> @php -r "file_exists('.env') || copy('.env.example', '.env');"Loading composer repositories with package informationUpdating dependencies...```
這邊偷懶用 alias composer="php /tmp/composer.phar" ,後面會碰到類似的的錯誤訊息時,其實就是找不到 composer 指令:
```Symfony\Component\Process\Exception\ProcessStartFailedExceptionThe command "'composer' 'dump-autoload'" failed.Working directory: /private/tmp/laravel-workspaceError: proc_open(): posix_spawn() failed: No such file or directory```
因此可以把 /tmp/composer.phar 擺到 PATH 內會尋找指令的地方,或是人工再補個 composer dump-autoload 等等
```% cp /tmp/composer.phar ~/.bin/composer% chmod 755 ~/.bin/composer```
接下來安裝 Twill Toolkit,整個流程其實參考 Twill 官網教學文即可:Building a simple page builder with Laravel Blade,在此僅記錄一下操作流程:
```% cd /tmp/laravel-workspacelaravel-workspace % composer require area17/twill:"^3.0"laravel-workspace % php artisan twill:install...Let's create a superadmin account!Enter an email:> user@example.comEnter a password:>Confirm the password:>Your account has been createdAll good!```
接著安裝後台模組 Pages:
```laravel-workspace % php artisan twill:make:module pagesDo you need to use the block editor on this module? [yes]:[0] no[1] yes>Do you need to translate content on this module? [yes]:[0] no[1] yes>Do you need to generate slugs on this module? [yes]:[0] no[1] yes>Do you need to attach images on this module? [yes]:[0] no[1] yes>Do you need to attach files on this module? [yes]:[0] no[1] yes>Do you need to manage the position of records on this module? [yes]:[0] no[1] yes>Do you need to enable revisions on this module? [yes]:[0] no[1] yes>Do you need to enable nesting on this module? [no]:[0] no[1] yes>Do you also want to generate a model factory? [yes]:[0] no[1] yes>Do you also want to generate a model seeder? [yes]:[0] no[1] yes>Migration created successfully! Add some fields!INFO Factory [database/factories/PageFactory.php] created successfully.Models created successfully! Fill your fillables!Repository created successfully! Control all the things!Controller created successfully! Define your index/browser/form endpoints options!Form request created successfully! Add some validation rules!Do you also want to generate the preview file? [yes]:[0] no[1] yes>INFO Seeder [database/seeders/PageSeeder.php] created successfully.The following snippet has been added to routes/twill.php:-----TwillRoutes::module('pages');-----To add a navigation entry add the following to your AppServiceProvider BOOT method.-----use A17\Twill\Facades\TwillNavigation;use A17\Twill\View\Components\Navigation\NavigationLink;public function boot(){...TwillNavigation::addLink(NavigationLink::make()->forModule('pages'));}-----Do not forget to migrate your database after modifying the migrations.Enjoy.```
上述的意思是 routes/twill.php 已經增加好後台管理介面的 routing 規則:
```% cat routes/twill.php<?phpuse A17\Twill\Facades\TwillRoutes;// Register Twill routes here eg.// TwillRoutes::module('posts');TwillRoutes::module('pages');```
但是 app/Providers/AppServiceProvider.php 必須自己處理,調整成下方:
```laravel-workspace % cat app/Providers/AppServiceProvider.php<?phpnamespace App\Providers;use Illuminate\Support\ServiceProvider;use A17\Twill\Facades\TwillNavigation;use A17\Twill\View\Components\Navigation\NavigationLink;class AppServiceProvider extends ServiceProvider{/*** Register any application services.*/public function register(): void{//}/*** Bootstrap any application services.*/public function boot(): void{TwillNavigation::addLink(NavigationLink::make()->forModule('pages'));}}```
這些更動是讓後台 /admin 時,上方導覽可以多一項 Pages 的功能,後續透過下方來使用:
laravel-workspace % php artisan migratelaravel-workspace % php artisan serve --host 0.0.0.0 --port 8000
如此,就可以用 http://localhost:8000/admin 登入後台,點擊 Pages 切換到 http://localhost:8000/admin/pages 可以新增 Pages ,可點擊 Add new 按鈕一則,這時可以看到前台網址規則是 localhost/en/pages/hello-world ,但實際上在 PHP Laravel routing 規則中,前台網址規則都還沒實作處理,所以是看不到資料的。
上述僅做了簡易的後台搭建,後續要處理的有:
- 讓後來編輯界面更加豐富,例如有更多的元件(image, text)等,主要是擴增編輯使用的表單元素
- 處理後台編輯時,preview 缺少的 css 資源 (運行 npm install && npm run build)
- 建立新元素的樣板資料
- 建立前台網頁的網址規則跟處理的 Controller (PageDisplayController)
如此,在後台把頁面發布出去後,就可以在前台被瀏覽到。但光上述四點的操作項目是不少的。
接著來進行,也就是 Twill 官網導覽流程,並且把其他碰到的問題也解一解:Configuring the page module
由於預設的前台網頁網址規則是跟語言相關的,例如建立個 Hello World Page 後,可以看到他的前台網址是 localhost/en/pages/hello-world ,若要去掉語言,就是調整 app/Http/Controllers/Twill/PageController.php :
```18 protected function setUpController(): void19 {20 $this->setPermalinkBase(''); // 去掉 /pages/ 那層網址21 $this->withoutLanguageInPermalink(); // 去掉 /en/ 那層網址22 }```
接著來調整撰文時的表單功能,例如目前每一個 Page 都可以填寫 title 跟 description 可增加 SEO 的效果,而增加文章分享後的美觀,則是要增加圖片,這時直接修改 app/Http/Controllers/Twill/PageController.php ,添加發文時可以上傳圖片功能:
```6 use A17\Twill\Services\Forms\Fields\Medias;...29 public function getForm(TwillModelContract $model): Form30 {31 $form = parent::getForm($model);3233 $form->add(34 Input::make()->name('description')->label('Description')->translatable()35 );3637 $form->add(38 Medias::make()->name('cover')->label('Cover image')39 );4041 return $form;42 }...```
主要是新增引入 `use A17\Twill\Services\Forms\Fields\Medias;` 跟 `$form->add( Medias::make()->name('cover')->label('Cover image') );`
這時我們的 laravel 是透過 artisan 跑在 8000 port,拖拉上傳圖片時,其實會顯示不出來
因為他的圖片網址規則並沒有帶 port ,且只要把網址複製出來加上 port number 就可以正常顯示,代表只需處理 Laravel framework 的 .env 中 APP_URL 規則:
```% cat .env | grep APP_URLAPP_URL=http://localhost```
這時建議測試時可以有兩套環境設置,運行時指定設定檔案:
```% cp .env .env.local% cat .env.local | grep APP_URLAPP_URL=http://localhost:8000% php artisan serve --host 0.0.0.0 --port 8000 --env localINFO Server running on [http://0.0.0.0:8000].Press Ctrl+C to stop the server```
如此也解掉後台圖片顯示失敗的問題。
下一刻則是擴充文章編輯環境,引入 Block Editor 架構,也就是在編輯文章時,可以拖拉區塊到文章內,還可以自行開發,把常用的項目元件化。從 Twill 官網的範例資訊,預設有兩個 Block 了,一個是 image block ,另一個是 wysiwyg block,官網範例會試著新增一個小的區塊,例如名為 Text 的區塊。
首先,先啟用 Block Editor,啟用方式是在 app/Http/Controllers/Twill/PageController.php 裡引入 `use A17\Twill\Services\Forms\Fields\BlockEditor;` 和增加 `$form->add( BlockEditor::make() );`
接著則是試著建立一個 text block:
```laravel-workspace % php artisan twill:make:block textShould we also generate a view file for rendering the block? (yes/no) [no]:> yesCreating block...File: /private/tmp/laravel-workspace/resources/views/twill/blocks/text.blade.phpBlock text was created.Block text blank render view was created.Block is ready to use with the name 'text'laravel-workspace % cat resources/views/twill/blocks/text.blade.php@twillBlockTitle('Text')@twillBlockIcon('text')@twillBlockGroup('app')<x-twill::inputname="title"label="Title":translated="true"/><x-twill::wysiwygname="text"label="Text"placeholder="Text":toolbar-options="['bold','italic',['list' => 'bullet'],['list' => 'ordered'],[ 'script' => 'super' ],[ 'script' => 'sub' ],'link','clean']":translated="true"/>```
可以看到其樣板也長出來了
但是在後台 preview 時,仍會有待處理的訊息:
This is a basic preview. You can use dd($block) to view the data you have access to. <br />This preview file is located at: /private/tmp/laravel-workspace/resources/views/site/blocks/text.blade.php
將他修改一下:
```% cat resources/views/site/blocks/text.blade.php<div class="prose"><h2>{{$block->translatedInput('title')}}</h2>{!! $block->translatedInput('text') !!}</div>```
接著再產生另一個 image block 並更新他的 block view 跟 preview:
```laravel-workspace % php artisan twill:make:block imageShould we also generate a view file for rendering the block? (yes/no) [no]:> yesCreating block...File: /private/tmp/laravel-workspace/resources/views/twill/blocks/image.blade.phpBlock image was created.Block image blank render view was created.Block is ready to use with the name 'image'laravel-workspace % cat resources/views/twill/blocks/image.blade.php@twillBlockTitle('Image')@twillBlockIcon('text')@twillBlockGroup('app')<x-twill::mediasname="highlight"label="Highlight"/>laravel-workspace % cat resources/views/site/blocks/image.blade.php<div class="py-8 mx-auto max-w-2xl flex items-center"><img src="{{$block->image('highlight', 'desktop')}}"/></div>```
此外,image block 要生效還需要調整 config/twill.php
```% cat config/twill.php<?phpreturn ['block_editor' => ['crops' => ['highlight' => ['desktop' => [['name' => 'desktop','ratio' => 16 / 9,],],'mobile' => [['name' => 'mobile','ratio' => 1,],],],],],];```
接著,還要幫前後台產的文章添加 CSS 效果 `@vite('resources/css/app.css')` ,添加方式是修改 `resources/views/site/layouts/block.blade.php` 跟 `resources/views/site/page.blade.php`
```laravel-workspace % cat resources/views/site/layouts/block.blade.php<!doctype html><html lang="en"><head><title>#madewithtwill website</title>@vite('resources/css/app.css')</head><body><div>@yield('content')</div></body></html>laravel-workspace % cat resources/views/site/page.blade.php<!doctype html><html lang="en"><head><title>{{ $item->title }}</title>@vite('resources/css/app.css')</head><body><div class="mx-auto max-w-2xl">{!! $item->renderBlocks() !!}</div></body></html>```
此外,還要用 npm 工具編譯出 resources/css/app.css:
```% nvm use v20Now using node v20.9.0 (npm v10.3.0)% npm installadded 23 packages, and audited 24 packages in 577ms5 packages are looking for fundingrun `npm fund` for detailsfound 0 vulnerabilitieslaravel-workspace % tree resources/css/resources/css/└── app.css1 directory, 1 file```
如此,在 Twill 後台編輯文章時,就可以在 Block editor 操作下增加文字區塊、圖片等等的功能。
不過,直到現在前台機制還沒打通,尚未提供前台 routing rule 等顯示前台網頁,先建立個 PageDisplayController 來處理:
```% php artisan make:controller PageDisplayControllerINFO Controller [app/Http/Controllers/PageDisplayController.php] created successfully.```
把 PageDisplayController 更新為可以接一個參數,並且立刻把它印出 debug 訊息:
```% cat app/Http/Controllers/PageDisplayController.php<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;use Illuminate\Contracts\View\View;class PageDisplayController extends Controller{public function show(string $slug): View{dd($slug);}}```
接著,再把 routing 設置好:
```% cat routes/web.php<?phpuse Illuminate\Support\Facades\Route;//Route::get('/', function () {// return view('welcome');//});Route::get('{slug}', [\App\Http\Controllers\PageDisplayController::class, 'show'])->name('frontend.page');```
如此在前台瀏覽網頁就會看到:
最後,再把 PageDisplayController 調整成顯示正確的資料:
```laravel-workspace % cat app/Http/Controllers/PageDisplayController.php<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;use Illuminate\Contracts\View\View;use App\Repositories\PageRepository;class PageDisplayController extends Controller{//public function show(string $slug): View//{// dd($slug);//}public function show(string $slug, PageRepository $pageRepository): View{$page = $pageRepository->forSlug($slug);if (!$page) {abort(404);}return view('site.page', ['item' => $page]);}}```
如此瀏覽前台時,例如 http://localhost:8000/hello-world 就可以顯示網頁內容了。
最後,如果碰到前台圖片沒有顯示出來的部分,則是留意拖拉建立圖片時,需要依照不同裝置版型做設定,例如 PC 瀏覽時看不到圖片,那應當是少設定的 desktop 的設置:
```laravel-workspace % cat resources/views/site/blocks/image.blade.php<div class="py-8 mx-auto max-w-2xl flex items-center"><img src="{{$block->image('highlight', 'desktop')}}"/></div>```
需留意在 block editor 時,其 Image 拖拉進去時,有沒有 `desktop crop` 的描述
沒有留言:
張貼留言