如何為 Gutenberg 創建動態塊
已發表: 2022-08-03你還在為古騰堡感到困惑嗎? 或者您是那些堅信塊編輯器的潛力並想知道使用塊編輯器可以將他們的創造力推到多遠的人中的一員?
無論您屬於哪種類型的用戶,Gutenberg 都會留下來,這篇文章將讓您深入了解 WordPress 塊編輯器幕後發生的事情。 但這還不是全部!
在我們之前的教程中我們提供了對 Gutenberg 塊開發的一般介紹之後,本文超越了基礎知識,介紹了更高級的塊類型。 這些塊被稱為動態塊。
今天,您將了解什麼是動態塊、它們是如何工作的,以及從頭開始創建動態塊所需了解的一切。
那麼,什麼是 Gutenberg 動態塊,靜態塊和動態塊之間的主要區別是什麼?
什麼是動態塊? 一個例子
使用靜態塊時,用戶在編輯帖子或頁面時手動添加內容,而使用動態塊時,內容會在頁面加載時動態加載和處理。 使用動態塊,塊內容從數據庫中提取並按原樣顯示或由任何類型的數據操作產生。
讓我們用一個例子來解釋一下。 假設您要創建一組嵌套塊,顯示帖子作者詳細信息以及來自同一作者的最新帖子的選擇。
作為 Gutenberg 用戶,您可以使用以下塊:
- 標題核心塊
- 帖子作者核心塊
- 最新帖子核心塊
您還可以創建一個包含這些塊的組,並將該組添加到可重複使用的塊中以供將來使用。
這很簡單,不是嗎? 您可以創建一個動態塊並將其添加到您的帖子和頁面中。
從 WordPress 5.9 開始,塊編輯器提供了 90 多個不同的塊,您很可能會立即找到適合您的塊。 而且,如果您需要更多,請在 WordPress 插件目錄中快速搜索,您會發現很多免費插件提供了額外的塊。
但是,如果您是 WordPress 開發人員,或者您正計劃從事 WordPress 開發人員的職業,該怎麼辦? 也許您有非常特定的需求,找不到您正在尋找的區塊,或者您只是想獲得新的專業技能。 在這種情況下,您可能想學習如何創建動態塊。
從開發人員的角度來看 Gutenberg 動態塊
動態塊有兩個主要用例。
第一個用例是當包含塊的頁面尚未更新時,您需要更新塊的內容。 例如,當塊包含最新帖子或評論的列表時會發生這種情況,並且通常只要塊的內容是使用從數據庫檢索的數據動態生成的。
第二個用例是需要立即在前端顯示對塊代碼的更新。 使用動態塊而不是靜態塊會導致更改立即應用於所有出現的塊。
另一方面,如果您要更改靜態塊生成的 HTML,用戶將看到一個無效對話框,直到該塊的先前版本的每個實例都被刪除並替換為新版本,或者您將舊版本標記為不推薦使用的版本(另請參閱棄用和塊驗證、棄用和遷移經驗)。
話雖如此,在開始構建動態塊之前,您需要了解一些概念。
應用程序狀態和數據存儲
Gutenberg 是一個 React SPA 應用程序,Gutenberg 中的所有內容都是一個 React 組件。 編輯器中的帖子標題、標題、段落、圖像和任何 HTML 內容塊都是 React 組件,以及側邊欄和塊工具欄控件。
在我們之前的文章中,我們只使用屬性來存儲數據。 在本文中,我們將通過引入state的概念更進一步。
簡而言之, state
對像是一個普通的 JavaScript 對象,用於包含有關組件的信息。 組件的state
會隨著時間而改變,並且任何時候改變,組件都會重新渲染。
與state
對像類似,屬性是普通的 JavaScript 對象,用於保存有關組件的信息。 但是 props 和state
之間有一個關鍵區別:
props
被傳遞給組件(類似於函數參數),而state
是在組件內管理的(類似於在函數中聲明的變量)。
您可以將狀態視為在給定時間點獲取的數據快照,應用程序存儲這些數據以控制組件的行為。 例如,如果塊編輯器設置側邊欄打開,一條信息將存儲在state
對象的某處。
當信息在單個組件內共享時,我們稱之為本地狀態。 當信息在應用程序內的組件之間共享時,我們稱之為應用程序狀態。
Application State 與 store 的概念密切相關。 根據 Redux 文檔:
一個 store 保存著應用程序的整個狀態樹。 更改其內部狀態的唯一方法是在其上分派一個操作。
因此,Redux 將應用程序狀態存儲在單個不可變對象樹(即存儲)中。 對象樹只能通過使用 action 和 reducer 創建新對象來更改。
在 WordPress 中,商店由WordPress 數據模塊管理。
Gutenberg 中的模塊化、包和數據存儲
Gutenberg 存儲庫從頭開始構建在幾個可重用且獨立的模塊上,這些模塊組合在一起構建了編輯界面。 這些模塊也稱為包。
官方文檔列出了兩種不同類型的包:
- 生產包組成了在瀏覽器中運行的生產代碼。 WordPress 中有兩種類型的生產包:
- 帶有樣式表的包提供了正確運行的樣式表。
- 帶有數據存儲的包定義了數據存儲來處理它們的狀態。 第三方插件和主題可以使用帶有數據存儲的包來檢索和操作數據。
- 開發包用於開發模式。 這些包包括用於 linting、測試、構建等的工具。
在這裡,我們最感興趣的是帶有數據存儲的包,用於檢索和操作數據。
WordPress 數據存儲
WordPress 數據模塊建立在 Redux 之上,並共享三個 Redux 核心原則,儘管有一些關鍵區別。
官方文檔提供瞭如下定義:
WordPress 的數據模塊用作管理插件和 WordPress 本身的應用程序狀態的中心,提供工具來管理不同模塊內和模塊之間的數據。 它被設計為一種用於組織和共享數據的模塊化模式:簡單到足以滿足小型插件的需求,同時可擴展以服務於復雜的單頁應用程序的需求。
默認情況下,Gutenberg 在應用程序狀態中註冊多個數據存儲。 這些商店中的每一個都有特定的名稱和用途:
-
core
:WordPress 核心數據 core/annotations
:註釋core/blocks
:塊類型數據core/block-editor
: 塊編輯器的數據core/editor
:帖子編輯的數據core/edit-post
: 編輯器的 UI 數據core/notices
:通知數據core/nux
:NUX(新用戶體驗)數據core/viewport
:視口數據
通過這些商店,您將能夠訪問一大堆數據:
- 與當前帖子相關的數據,例如帖子標題、摘錄、類別和標籤、塊等。
- 與用戶界面相關的數據,即開關是打開還是關閉。
- 與整個 WordPress 安裝相關的數據,例如註冊分類法、帖子類型、博客標題、作者等。
這些存儲存在於全局wp
對像中。 要訪問商店的狀態,您將使用select
函數。
要查看它是如何工作的,請創建一個新帖子或頁面並啟動瀏覽器的檢查器。 找到控制台並輸入以下代碼行:
wp.data.select("core")
結果將是一個對象,其中包含可用於從core
數據存儲中獲取數據的函數列表。 這些函數稱為選擇器並充當訪問狀態值的接口。
WordPress 數據存儲通常包含有關 WordPress 的信息,選擇器是您獲取該信息的方式。 例如, getCurrentUser()
返回當前用戶的詳細信息:
wp.data.select("core").getCurrentUser()
另一個可用於從數據存儲中檢索用戶詳細信息的選擇器是getUsers()
:
wp.data.select("core").getUsers()
下圖顯示了響應對象:
要獲取單個用戶的詳細信息,您只需鍵入以下行:
wp.data.select("core").getUsers()[0]
使用相同的選擇器,您還可以檢索分配了author
角色的站點用戶:
wp.data.select( 'core' ).getUsers({ who: 'authors' })
您還可以檢索已註冊的分類法:
wp.data.select("core").getTaxonomies()
已註冊的帖子類型列表:
wp.data.select("core").getPostTypes()
或插件列表:
wp.data.select("core").getPlugins()
現在讓我們嘗試訪問不同的數據存儲。 為此,您仍將使用select
函數,但提供不同的命名空間。 讓我們嘗試以下方法:
wp.data.select("core/edit-post")
現在您將獲得以下響應對象。
如果您想知道設置側邊欄是否打開,您可以使用isEditorSidebarOpened
選擇器:
wp.data.select("core/edit-post").isEditorSidebarOpened()
如果側邊欄打開,此函數返回true
:
如何訪問帖子數據
您現在應該對如何訪問數據有了基本的了解。 現在我們將仔細研究一個特定的選擇器, getEntityRecords
函數,它是提供對發布數據的訪問權限的選擇器。
在塊編輯器中,右鍵單擊並選擇Inspect 。 在控制台選項卡中,複製並粘貼以下行:
wp.data.select("core").getEntityRecords('postType', 'post')
這會向 Rest API 發送請求,並返回與上次發布的博客文章相對應的記錄數組。
getEntityRecords
接受三個參數:
-
kind
string :實體種類(即postType
)。 -
name
字符串:實體名稱(即post
)。 -
query
?Object : 可選術語查詢(即{author: 0}
)。
您可以使用參數對象構建更具體的請求。
例如,您可以決定響應應該只包含指定類別的帖子:
wp.data.select("core").getEntityRecords('postType', 'post', {categories: 3})
您還可以僅請求給定作者的文章:
wp.data.select("core").getEntityRecords('postType', 'post', {author: 2})
如果單擊getEntityRecords
返回的任何記錄,您將獲得所選記錄的屬性列表:
如果您希望響應包含特色圖片,則需要在之前的請求中添加一個附加參數:
wp.data.select("core").getEntityRecords('postType', 'post', {author: 2, _embed: true})
現在您應該對如何訪問 WordPress 數據存儲和檢索帖子詳細信息有了更好的了解。 有關getEntityRecords
選擇器的詳細視圖,另請參閱在 Gutenberg 中使用 getEntityRecords 請求數據。
如何創建動態塊:示例項目
在我們長期的理論前提之後,我們可以繼續練習並使用我們在之前的塊開發教程中介紹的工具創建一個動態塊。
在那篇文章中,我們討論了:
- 如何設置 WordPress 開發環境
- 什麼是塊式腳手架
- 如何構建靜態古騰堡塊
這就是為什麼我們不會在本文中深入討論這些主題,但請隨時參考我們之前的指南以獲取任何其他信息,或者只是為了複習。
設置 JavaScript 開發環境
讓我們從設置 JavaScript 開發環境開始。
安裝或更新 Node.js
首先,安裝或更新 Node.js。 完成後,啟動命令行工具並運行以下命令:
node -v
您應該看到您的節點版本。
設置您的開發環境
接下來,您需要一個 WordPress 開發環境。 對於我們的示例,我們使用了 DevKinsta,這是我們的免費 WordPress 開發工具,可讓您立即啟動本地 WordPress 網站。
但是您仍然可以自由選擇任何您喜歡的 WordPress 本地開發環境,例如 MAMP 或 XAMPP,甚至是官方的 wp-env 解決方案。
如果您使用的是 DevKinsta,請單擊New WordPress Site或Custom Site ,填寫表單字段並按下Create site 。
安裝過程需要一兩分鐘。 完成後,啟動您當地的 WordPress 開發網站。
設置你的塊插件
您現在需要的是一個入門塊插件。 為了避免手動配置的所有麻煩,WordPress 核心開發團隊發布了 @wordpress/create-block 工具,這是用於創建 Gutenberg 塊的官方零配置工具。
我們在上一篇文章中深入介紹了@wordpress/create-block
,所以在這裡我們可以立即開始設置。
在命令行工具中,導航到/wp-content/plugins文件夾:
在那裡,運行以下命令:
npx @wordpress/create-block
您現在已準備好安裝@wordpress/create-block
包:
要確認,請輸入y
並按 Enter。
這會以交互模式生成插件的 PHP、SCSS 和 JS 文件。
以下是我們將在示例中使用的詳細信息。 隨意根據您的喜好更改這些詳細信息:
點擊回車後,它會下載並配置插件。
該過程可能需要幾分鐘。 完成後,您應該會看到以下屏幕:
您將看到可以從插件目錄中運行的命令列表:
-
$ npm start
– 開始構建以進行開發。 -
$ npm run build
– 構建生產代碼。 -
$ npm run format
– 格式化文件。 -
$ npm run lint:css
– Lint CSS 文件。 -
$ npm run lint:js
– Lint JavaScript 文件。 -
$ npm run packages-update
– 將 WordPress 包更新到最新版本。
好的,現在使用以下命令移動到插件目錄:
cd author-plugin
並開始您的開發構建:
npm start
接下來,導航到 WordPress 儀表板中的插件屏幕並激活作者框插件:
現在您可以檢查插件是否正常工作。 創建一個新帖子並開始輸入/
以啟動快速插入器:
您還可以在小部件類別下的塊插入器中找到作者框塊。 選擇塊以將其添加到編輯器畫布:
你完成了。 現在保存帖子並預覽頁面以檢查塊是否正確顯示。
塊腳手架
我們在上一篇文章中介紹了塊腳手架。 因此,在這裡我們將只提供我們將為我們的示例修改的文件的快速概述。
根文件夾
根文件夾是您可以找到主要 PHP 文件和幾個子文件夾的地方。
作者-plugin.php
默認情況下, @wordpress/create-block
包提供以下 PHP 文件:
/** * Plugin Name: Author box * Description: An example block for Kinsta readers * Requires at least: 5.8 * Requires PHP: 7.0 * Version: 0.1.0 * Author: Carlo * License: GPL-2.0-or-later * License URI: https://www.gnu.org/licenses/gpl-2.0.html * Text Domain: author-plugin * * @package author-box */ /** * Registers the block using the metadata loaded from the `block.json` file. * Behind the scenes, it registers also all assets so they can be enqueued * through the block editor in the corresponding context. * * @see https://developer.wordpress.org/reference/functions/register_block_type/ */ function author_box_author_plugin_block_init() { register_block_type( __DIR__ . '/build' ); } add_action( 'init', 'author_box_author_plugin_block_init' );
在標題中,您會注意到我們在設置時輸入的詳細信息。
使用靜態塊,大部分時間您將處理位於src文件夾中的 JavaScript 文件。 使用動態塊,您將編寫 PHP 代碼以在前端顯示塊內容。
src文件夾
src文件夾是您的開發文件夾。 在這裡,您將找到以下文件:
- 塊.json
- index.js
- 編輯.js
- 保存.js
- 編輯器.scss
- 樣式.scss
塊.json
block.json是您的元數據文件。 @wordpress/create-block
生成以下block.json文件:
{ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 2, "name": "author-box/author-plugin", "version": "0.1.0", "title": "Author box", "category": "widgets", "icon": "businessperson", "description": "An example block for Kinsta readers", "supports": { "html": false }, "textdomain": "author-plugin", "editorScript": "file:./index.js", "editorStyle": "file:./index.css", "style": "file:./style-index.css" }
要更詳細地了解block.json文件,請參閱我們之前的博客文章。
index.js
index.js文件是您在客戶端註冊塊類型的地方:
import { registerBlockType } from '@wordpress/blocks'; import './style.scss'; import Edit from './edit'; import save from './save'; registerBlockType('author-box/author-plugin', { edit: Edit, save, });
編輯.js
edit.js文件是您構建在編輯器中呈現的塊界面的位置:
import { __ } from '@wordpress/i18n'; import { useBlockProps } from '@wordpress/block-editor'; import './editor.scss'; export default function Edit() { return ( <p {...useBlockProps()}> {__('Author box – hello from the editor!', 'author-plugin')} </p> ); }
保存.js
save.js文件包含構建要保存到數據庫中的塊內容的腳本。 我們不會在本教程中使用此文件:
import { __ } from '@wordpress/i18n'; import { useBlockProps } from '@wordpress/block-editor'; export default function save() { return ( <p {...useBlockProps.save()}> {__('Author box – hello from the saved content!', 'author-plugin')} </p> ); }
在編輯器中構建要渲染的塊
在 Visual Studio Code 或您喜歡的任何代碼編輯器中打開您的項目。
如果您使用的是 Visual Studio Code,請轉到Terminal -> New Terminal 。 這將在項目的根文件夾上啟動一個終端窗口。
在終端(或您最喜歡的命令行工具)中,輸入以下命令:
npm start
您現在正在開發模式下運行節點環境。
從這裡開始,您將遵循兩條不同的路線。 要在編輯器中呈現塊,您將在edit.js文件中工作。 要在前端渲染塊,您需要在主插件文件中編寫 PHP 代碼。
現在捲起袖子,因為編碼開始了:
在服務器上註冊塊
首先,您必須在服務器上註冊塊並編寫 PHP 代碼以從數據庫中檢索數據。
在author-plugin.php文件中,您需要將第二個參數傳遞給register_block_type
函數:
function author_box_author_plugin_block_init() { register_block_type( __DIR__ . '/build', array( 'render_callback' => 'author_box_author_plugin_render_author_content' ) ); } add_action( 'init', 'author_box_author_plugin_block_init' );
第二個參數是用於註冊塊類型的參數數組(請參閱此處的可用參數的完整列表)。 在上面的代碼中,我們只提供了render_callback
,它決定了在屏幕上渲染塊的回調函數。
接下來,您將聲明該函數:
function author_box_author_plugin_render_author_content() { return 'Hello World!'; }
保存文件,創建新帖子或頁面,並將作者框塊添加到編輯器畫布。
塊編輯器仍然顯示起始塊,因為我們還沒有更改edit.js文件。
但是如果你在前端預覽帖子,你會看到原來的塊內容現在已經被“Hello World”字符串替換了。
現在,由於前端呈現的 HTML 是由 PHP 文件生成的,因此save
函數不需要返回任何內容。 所以我們直接進入save.js文件,修改代碼如下:
export default function save() { return null; }
定義塊屬性
現在您需要一個地方來存儲用戶設置。 例如,要從數據庫中檢索的帖子數量、是否顯示指定字段等。為此,您將在block.json文件中定義許多attributes
。
例如,您可以讓用戶確定要包含在塊中的帖子數量、顯示特色圖片、日期、摘錄和/或隱藏/顯示作者個人資料圖片的選項。
以下是我們將用於構建示例塊的完整屬性列表:
{ ... "attributes": { "numberOfItems": { "type": "number", "default": 3 }, "columns": { "type": "number", "default": 1 }, "displayDate": { "type": "boolean", "default": true }, "displayExcerpt": { "type": "boolean", "default": true }, "displayThumbnail": { "type": "boolean", "default": true }, "displayAuthorInfo": { "type": "boolean", "default": true }, "showAvatar": { "type": "boolean", "default": true }, "avatarSize": { "type": "number", "default": 48 }, "showBio": { "type": "boolean", "default": true } } }
構建要在編輯器中渲染的塊
getEntityRecords
選擇器包含在@wordpress/data
包中。 要使用它,你需要從你的edit.js
文件中的那個包中導入useSelect
鉤子:
import { useSelect } from '@wordpress/data';
接下來,將以下代碼添加到Edit()
函數中:
const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': 3 }); });
在上面的代碼中,我們硬編碼了帖子的數量。 但是您可能希望讓用戶能夠設置不同數量的帖子。 您可以為此使用屬性。
在您的block.json 中,您應該已經定義了numberOfItems
屬性。 您可以在Edit
功能中使用它,如下所示:
export default function Edit( { attributes } ) { const { numberOfItems } = attributes; const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': numberOfItems }); }); console.log( posts ); return ( ... ); }
您還不會在屏幕上看到這些帖子,但運行一個console.log
並查看瀏覽器檢查器的控制台中會發生什麼:
useSelect
可能有兩個參數:一個內聯回調和一個依賴數組。 兩者都返回回調的記憶版本,僅當其中一個依賴項發生更改時才會更改。
因此,為了在每個numberOfItems
屬性更改時重新獲取帖子,您必須更改Edit
函數,如下所示:
export default function Edit( { attributes } ) { const { numberOfItems } = attributes; const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': numberOfItems }); }, [ numberOfItems ] ); console.log(posts); return ( ... ); }
接下來,您必須呈現您的帖子列表。 為此,您可以使用內置的 JavaScript map
方法:
export default function Edit( { attributes } ) { const { numberOfItems } = attributes; const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': numberOfItems }); }, [ numberOfItems ] ); console.log(posts); return ( <div { ...useBlockProps() }> <ul> { posts && posts.map( ( post ) => { return ( <li key={ post.id }> <h5> <a href={ post.link }> { post.title.rendered ? post.title.rendered : __( 'Default title', 'author-plugin' ) } </a> </h5> </li> ) })} </ul> </div> ); }
首先,它檢查數組中是否至少有一個帖子,然後運行循環。
請注意,當我們使用帶有 React 組件的map
方法時,我們還使用key
屬性將帖子 ID 分配給當前列表項。
post.link
和post.title.rendered
分別呈現帖子 URL 和標題。
下圖顯示了post
對象屬性的完整列表。
上面的代碼只是getEntityRecords
用法的一個基本示例。 現在是時候將我們的知識付諸實踐了。
假設您希望阻止您的塊呈現用戶可能已添加到帖子標題中的 HTML 標記。 WordPress 為此提供了一個RawHTML
組件。
首先,您將從 @wordpress/element 包中導入組件:
import { RawHTML } from '@wordpress/element';
接下來,您將在RawHTML
元素中包裝文章標題:
<div { ...useBlockProps() }> <ul> { posts && posts.map((post) => { return ( <li key={ post.id }> <h5> <a href={ post.link }> { post.title.rendered ? ( <RawHTML> { post.title.rendered } </RawHTML> ) : ( __( 'Default title', 'author-plugin' ) )} </a> </h5> </li> ) })} </ul> </div>
就是這樣。 現在將 HTML 標籤添加到您的帖子標題並保存帖子。 然後在使用和不RawHTML
的情況下測試您的代碼,並查看您的塊的內容在屏幕上的變化情況。
添加日期
WordPress 提供了許多 JavaScript 函數來管理和格式化日期。 要使用這些函數,您首先需要從edit.js文件中的@wordpress/date
包中導入它們:
import { dateI18n, format, __experimentalGetSettings } from '@wordpress/date';
-
dateI18n
:格式化日期,將其轉換為站點的語言環境。 -
format
:格式化日期。 -
__experimentalGetSettings
:以 WordPress 常規設置中設置的格式顯示日期。
這些函數沒有記錄,但您會在幾個塊的源代碼中找到有用的示例。 例如,請參閱 latest-posts 和 post-date edit.js文件。
現在添加displayDate
屬性:
const { numberOfItems, displayDate } = attributes;
然後在<li>
元素中添加以下代碼:
{ displayDate && ( <time className='wp-block-author-box-author-plugin__post-date' dateTime={ format( 'c', post.date_gmt ) } > { dateI18n( __experimentalGetSettings().formats.date, post.date_gmt )} </time> ) }
這裡會發生什麼?
- 如果
displayDate
為true
,則使用time
元素顯示日期。 -
dateTime
屬性以一種允許的格式提供元素的時間和/或日期。 -
dateI18n
以本地化格式檢索日期。 此函數的工作方式類似於 PHPPHPdate_i18n
WordPress 函數。
添加摘錄
現在應該很容易添加帖子摘錄。 首先,看一下瀏覽器檢查器中的excerpt
屬性。 您會看到實際內容存儲在excerpt.rendered
中。
接下來,將displayExcerpt
屬性添加到attributes
對象:
const { numberOfItems, displayDate, displayExcerpt } = attributes;
然後在Edit
函數中的</li>
結束標記之前添加以下代碼:
{ displayExcerpt && post.excerpt.rendered && ( <p> <RawHTML> { post.excerpt.rendered } </RawHTML> </p> ) }
如果您不熟悉 JavaScript,這里和上面我們使用了短路評估,如果所有條件都為真,則返回最後一個操作數的值(在 Inline If with Logical && Operator and Logical AND (&& ))。
最後,您可以再次測試您的代碼。 更改block.json文件中的屬性值,看看在編輯器中會發生什麼。
添加特色圖片
現在您需要添加呈現特色圖像的代碼。 開始將displayThumbnail
屬性添加到attributes
:
const { numberOfItems, displayDate, displayExcerpt, displayThumbnail } = attributes;
現在您需要弄清楚特色圖像的存儲位置。 正如我們上面提到的,要獲得特色圖像,您需要在查詢中添加一個新的_embed
參數。 回到您的代碼,更改查詢參數,如下所示:
const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': numberOfItems, '_embed': true }); }, [ numberOfItems ] );
在這裡,我們簡單地將'_embed': true
添加到參數數組中。 這提供了一個包含_embedded
屬性的post
對象,該屬性提供了顯示特色圖像所需的圖像詳細信息。
現在您應該知道在哪裡可以找到圖像詳細信息。
您只需要添加在屏幕上呈現圖像的代碼:
{ displayThumbnail && post._embedded && post._embedded['wp:featuredmedia'] && post._embedded['wp:featuredmedia'][0] && <img className='wp-block-author-box-author-plugin__post-thumbnail' src={ post._embedded['wp:featuredmedia'][0].media_details.sizes.medium.source_url } alt={ post._embedded['wp:featuredmedia'][0].alt_text } /> }
保存文件,切換到塊編輯器,檢查displayThumbnail
屬性設置為true
時圖像是否正確顯示。
添加側邊欄控件
到目前為止,我們一直在使用block.json中設置的屬性默認值。 但是從我們之前的文章中我們知道,我們可以定義事件處理程序,讓用戶能夠為每個屬性分配自定義值。
為此,您將向塊設置側邊欄添加一組控件。 在edit.js中,從相應的包中導入以下組件:
import { useBlockProps, InspectorControls } from '@wordpress/block-editor'; import { PanelBody, PanelRow, QueryControls, ToggleControl, RangeControl } from '@wordpress/components';
-
InspectorControls
:包含影響整個塊的側邊欄設置(參見 GitHub) -
PanelBody
:將可折疊容器添加到設置側邊欄(參見 GitHub) -
PanelRow
:為側邊欄控件生成一個通用容器(參見 GitHub) -
QueryControls
:提供設置控件來構建查詢(參見 GitHub) -
ToggleControl
:為用戶提供一個切換按鈕來啟用/禁用特定選項(參見 GitHub) -
RangeControl
:用於從一系列增量值中進行選擇(參見 GitHub)
接下來,您需要更新Edit
功能以使用現在可用的控件。 首先,修改Edit
函數如下:
export default function Edit( { attributes, setAttributes } ) { const { numberOfItems, columns, displayExcerpt, displayDate, displayThumbnail } = attributes; const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': numberOfItems, '_embed': true }); }, [ numberOfItems ] ); ... }
請注意傳遞給Edit
函數的setAttributes
屬性。
現在您可以將相應的元素添加到您的 JSX 代碼中:
return ( <> <InspectorControls> <PanelBody title={ __( 'Content Settings', 'author-plugin' ) }> <PanelRow> <QueryControls numberOfItems={ numberOfItems } onNumberOfItemsChange={ ( value ) => setAttributes( { numberOfItems: value } ) } minItems={ 1 } maxItems={ 10 } /> </PanelRow> <PanelRow> <RangeControl label={ __( 'Number of Columns', 'author-plugin' ) } value={ columns } onChange={ ( value ) => setAttributes( { columns: value } ) } min={ 1 } max={ 4 } required /> </PanelRow> <PanelRow> <ToggleControl label={ __( 'Show Featured Image', 'author-plugin' ) } checked={ displayThumbnail } onChange={ () => setAttributes( { displayThumbnail: ! displayThumbnail } ) } /> </PanelRow> <PanelRow> <ToggleControl label={ __( 'Show Date', 'author-plugin' ) } checked={ displayDate } onChange={ () => setAttributes( { displayDate: ! displayDate } ) } /> </PanelRow> <PanelRow> <ToggleControl label={ __( 'Display Excerpt', 'author-plugin' ) } checked={ displayExcerpt } onChange={ () => setAttributes( { displayExcerpt: ! displayExcerpt } ) } /> </PanelRow> </PanelBody> </InspectorControls> <div { ...useBlockProps() }> ... </div> </> );
哇,這麼多代碼,不是嗎? 但這很容易理解。
這裡最值得關注的元素屬性是QueryControls
中的onNumberOfItemsChange
和RangeControl
和ToggleControl
中的onChange
。 這些屬性設置了使用戶能夠自定義塊的外觀和/或行為所需的事件處理程序。
你還會注意到我們使用了<>
和</>
標籤,它們是聲明 React 片段的簡短語法。
現在,保存您的文件,跳到編輯器中,然後刷新頁面:
裡面都有嗎? 然後讓我們繼續添加帖子作者的詳細信息。
查找帖子作者
正如我們上面提到的,我們的塊將顯示由與當前帖子相同的作者撰寫的文章列表。
要獲取帖子作者的 ID,您將從core/editor
數據存儲區導入getCurrentPostAttribute
選擇器:
wp.data.select( 'core/editor' ).getCurrentPostAttribute( 'author' )
getCurrentPostAttribute
返回已保存帖子的屬性值。
獲得作者 ID 後,您可以更改查詢,如下所示:
const posts = useSelect( ( select ) => { const _authorId = select( 'core/editor' ).getCurrentPostAttribute( 'author' ); return select( 'core' ).getEntityRecords( 'postType', 'post', { 'author': _authorId, 'per_page': numberOfItems, '_embed': true }); }, [ numberOfItems ] );
使用此代碼,您將獲得與當前帖子相同作者的n
篇文章的列表。
現在您有了作者 ID,您還可以使用它從數據庫中獲取其他數據。
顯示作者詳細信息
由於我們沒有任何可用的文檔,我們使用核心 Post Author 塊中的代碼作為參考。
要顯示作者詳細信息,您首先需要導入一個新的依賴項:
import { forEach } from 'lodash';
然後,在Edit
函數中,按如下方式更新attributes
對象:
const { numberOfItems, columns, displayExcerpt, displayDate, displayThumbnail, displayAuthorInfo, showAvatar, avatarSize, showBio } = attributes;
完成後,您將編輯上一節中看到的代碼以檢索作者詳細信息:
const { authorDetails, posts } = useSelect( ( select ) => { const _authorId = select( 'core/editor' ).getCurrentPostAttribute( 'author' ); const authorDetails = _authorId ? select( 'core' ).getUser( _authorId ) : null; const posts = select( 'core' ).getEntityRecords( 'postType', 'post', { 'author': _authorId, 'per_page': numberOfItems, '_embed': true }); return { authorDetails: authorDetails, posts: posts }; }, [ numberOfItems ] );
請注意,我們使用getUser
選擇器來獲取作者詳細信息。
接下來,您可能想要獲取作者的頭像。 下面的代碼構建了一個存儲頭像 URL 和大小的項目數組:
const avatarSizes = []; if ( authorDetails ) { forEach( authorDetails.avatar_urls, ( url, size ) => { avatarSizes.push( { value: size, label: `${ size } x ${ size }`, } ); } ); }
然後,您將添加側邊欄面板和控件,以使用戶能夠自定義塊中的作者區域:
return ( <> <InspectorControls> <PanelBody title={ __( 'Author Info', 'author-plugin' ) }> <PanelRow> <ToggleControl label={ __( 'Display Author Info', 'author-plugin' ) } checked={ displayAuthorInfo } onChange={ () => setAttributes( { displayAuthorInfo: ! displayAuthorInfo } ) } /> </PanelRow> { displayAuthorInfo && ( <> <PanelRow> <ToggleControl label={ __( 'Show avatar' ) } checked={ showAvatar } onChange={ () => setAttributes( { showAvatar: ! showAvatar } ) } /> { showAvatar && ( <SelectControl label={ __( 'Avatar size' ) } value={ avatarSize } options={ avatarSizes } onChange={ ( size ) => { setAttributes( { avatarSize: Number( size ), } ); } } /> ) } </PanelRow> <PanelRow> <ToggleControl label={ __( 'Show Bio', 'author-plugin' ) } checked={ showBio } onChange={ () => setAttributes( { showBio: ! showBio } ) } /> </PanelRow> </> ) } </PanelBody> ... </InspectorControls> ... </> );
下圖顯示了更新的設置側邊欄:
最後,您可以將作者部分添加到您的塊中:
return ( <> <InspectorControls> ... </InspectorControls> <div { ...useBlockProps() }> { displayAuthorInfo && authorDetails && ( <div className="wp-block-author-box-author-plugin__author"> { showAvatar && ( <div className="wp-block-author-box-author-plugin__avatar"> <img width={ avatarSize } src={ authorDetails.avatar_urls[ avatarSize ] } alt={ authorDetails.name } /> </div> ) } <div className='wp-block-author-box-author-plugin__author-content'> <p className='wp-block-author-box-author-plugin__name'> { authorDetails.name } </p> { showBio && // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining authorDetails?.description && authorDetails.description.length > 0 && ( <p className='wp-block-author-box-author-plugin__description'>{ authorDetails.description }</p> ) } </div> </div> )} <ul> ... </ul> </div> </> );
下圖顯示了它在屏幕上的呈現方式。
現在保存您的edit.js文件並運行您的測試。 您的塊應包含不同的元素,具體取決於塊設置。
最後一件事仍然缺失:顯示文章的列數。
更改列數
為了讓用戶能夠在列中顯示文章預覽,我們在block.json文件中定義了columns
屬性。 我們還在腳本中包含了一個columns
屬性,並創建了一個設置控件以允許用戶更改列數,儘管此更改目前無效。
在上面的 JSX 代碼中,您應該已經註意到我們為幾個元素添加了 CSS 類:
分配給作者部分中元素的類:
-
wp-block-author-box-author-plugin__author
-
wp-block-author-box-author-plugin__avatar
-
wp-block-author-box-author-plugin__author-content
-
wp-block-author-box-author-plugin__name
-
wp-block-author-box-author-plugin__description
分配給內容部分元素的類:
-
wp-block-author-box-author-plugin__post-items
-
wp-block-author-box-author-plugin__post-thumbnail
-
wp-block-author-box-author-plugin__post-title
-
wp-block-author-box-author-plugin__post-date
-
wp-block-author-box-author-plugin__post-excerpt
還缺一節課。 該類的名稱將動態生成,以反映用戶設置的列數。
回到Edit.js
文件,修改ul
元素如下:
<ul className={ `wp-block-author-box-author-plugin__post-items columns-${ columns }` }> ... </ul>
我們根據模板文字語法添加了一個新的columns-${ columns }
類,以在字符串中插入表達式。 這樣,附加到ul
元素的屬性將取決於用戶設置(例如columns-1
、 columns-2
等)。
現在打開style.scss
文件並將現有代碼替換為以下內容:
.wp-block-author-box-author-plugin { background-color: #21759b; color: #fff; padding: .6em; ul.wp-block-author-box-author-plugin__post-items { padding: 0; list-style-type: none; display: grid; gap: .5em; @for $i from 2 through 4 { &.columns-#{ $i } { grid-template-columns: repeat(#{ $i }, 1fr); } } li { list-style: none; img.wp-block-author-box-author-plugin__post-thumbnail { height: auto; max-width: 100%; } } } } .wp-block-author-box-author-plugin__author { display: flex; flex-wrap: wrap; } .wp-block-author-box-author-plugin__avatar { margin-right: 1em; } .wp-block-author-box-author-plugin__author-content { flex-basis: 0; flex-grow: 1; }
我們不會深入研究該代碼,超出了本文的範圍。 但是,如果您想深入了解,可以參考以下資源:
- CSS 網格佈局
- 學習 CSS 網格
- Sass 中的@for 規則
- 嵌套在 Sass 中
這就是在編輯器中渲染塊的過程。
構建要在頁面上呈現的塊
現在在編輯器中渲染塊的代碼已經完成,我們可以繼續構建塊以在前端渲染。
正如我們前面提到的,當涉及到動態塊時,插件文件負責生成要在前端呈現的 HTML。
因此,打開插件的主文件(在我們的示例中為author-plugin.php )。
首先要做的是使塊屬性可用於 WordPress PHP 函數。 在您的 PHP 文件中,按如下方式更改函數定義:
function author_box_author_plugin_render_author_content( $attr ) { ... }
現在您可以使用 WordPress 函數來檢索和操作數據。 例如,您可以使用get_posts
檢索最新的博客文章(在我們涵蓋get_posts
函數的深入文章中閱讀更多內容):
function author_box_author_plugin_render_author_content( $attr ) { $args = array( 'numberposts' => $attr['numberOfItems'], ); $my_posts = get_posts( $args ); if( ! empty( $my_posts ) ){ $output = '<ul>'; foreach ( $my_posts as $p ){ $output .= '<li><a href="' . esc_url( get_permalink( $p->ID ) ) . '">' . $p->post_title . '</a></li>'; } $output .= '</ul>'; } return $output ?? '<strong>Sorry. No posts matching your criteria!</strong>'; }
上面的函數從您的 WordPress 數據庫中檢索最新的numberOfItems
個博客文章(默認情況下post_type
設置為post
)並返回一個$post
對像數組。 然後它遍歷數組以構建列表項。
如果您檢查 HTML 輸出,您會注意到它是一個簡單的帖子列表,如下圖所示:
在我們之前的文章中,我們提到您將使用useBlockProps
React 鉤子在 JSX 代碼中標記塊的包裝器元素。 您需要在 PHP 函數中執行相同的操作。
WordPress 為此提供了get_block_wrapper_attributes
函數。
因此,更改您的 PHP 代碼如下:
function author_box_author_plugin_render_author_content( $attr ) { $args = array( 'numberposts' => $attr['numberOfItems'] ); $my_posts = get_posts( $args ); if( ! empty( $my_posts ) ){ $output = '<div ' . get_block_wrapper_attributes() . '>'; $output .= '<ul>'; foreach ( $my_posts as $p ){ $title = $p->post_title ? $p->post_title : 'Default title'; $url = esc_url( get_permalink( $p->ID ) ); $output .= '<li>'; $output .= '<a href="' . $url . '">' . $title . '</a>'; $output .= '</li>'; } $output .= '</ul>'; $output .= '</div>'; } return $output ?? '<strong>Sorry. No posts matching your criteria!</strong>'; }
現在已經為容器元素分配了一個wp-block-author-box-author-plugin
類,並且該塊具有不同的背景顏色。
然後get_posts
函數獲取WP_Posts
數據, foreach
循環構建列表項(另請參見如何顯示 get_posts 返回的數據)。
添加特色圖片、日期和摘錄
接下來,您需要添加帖子縮略圖、日期和摘錄。 在同一個文件中,更改您的 PHP 代碼,如下所示:
function author_box_author_plugin_render_author_content( $attr ) { $args = array( 'numberposts' => $attr['numberOfItems'] ); $my_posts = get_posts( $args ); if( ! empty( $my_posts ) ){ $output = '<div ' . get_block_wrapper_attributes() . '>'; $output .= '<ul class="wp-block-author-box-author-plugin__post-items columns-">'; foreach ( $my_posts as $p ){ $title = $p->post_title ? $p->post_title : 'Default title'; $url = esc_url( get_permalink( $p->ID ) ); $thumbnail = has_post_thumbnail( $p->ID ) ? get_the_post_thumbnail( $p->ID, 'medium' ) : ''; $output .= '<li>'; if( ! empty( $thumbnail ) && $attr['displayThumbnail'] ){ $output .= $thumbnail; } $output .= '<h5><a href="' . $url . '">' . $title . '</a></h5>'; if( $attr['displayDate'] ){ $output .= '<time datetime="' . esc_attr( get_the_date( 'c', $p ) ) . '">' . esc_html( get_the_date( '', $p ) ) . '</time>'; } if( get_the_excerpt( $p ) && $attr['displayExcerpt'] ){ $output .= '<p>' . get_the_excerpt( $p ) . '</p>'; } $output .= '</li>'; } $output .= '</ul>'; $output .= '</div>'; } return $output ?? '<strong>Sorry. No posts matching your criteria!</strong>'; }
foreach
循環遍歷$my_posts
數組。 在每次迭代中,有幾個條件檢查屬性值並相應地構建輸出。
現在看看屏幕上的輸出:
現在你可以運行你的測試了。 更改日期、摘錄和縮略圖設置,並在前端檢查塊內容的變化情況。
在列中顯示帖子
在我們的 JavaScript 代碼中,我們使用了columns-${ columns }
類在列中顯示帖子預覽。 現在我們需要在 PHP 中做同樣的事情。
為此,您只需添加這兩行代碼:
$num_cols = $attr['columns'] > 1 ? strval( $attr['columns'] ) : '1'; $output .= '<ul class="wp-block-author-box-author-plugin__post-items columns-' . $num_cols . '">';
這會將columns-n
類附加到包含帖子預覽的ul
元素。 現在頁面上顯示的列數應該與塊設置中設置的列數匹配。
建立作者框
最後,您需要構建包含作者詳細信息的框,包括頭像、姓名和描述。
在回調函數中,您需要添加一組條件來檢查每個屬性的當前值:
if( $attr['displayAuthorInfo'] ){ $output .= '<div class="wp-block-author-box-author-plugin__author">'; if( $attr['showAvatar'] ){ $output .= '<div class="wp-block-author-box-author-plugin__avatar">' . get_avatar( get_the_author_meta( 'ID' ), $attr['avatarSize'] ) . '</div>'; } $output .= '<div class="wp-block-author-box-author-plugin__author-content">'; $output .= '<div class="wp-block-author-box-author-plugin__name">' . get_the_author_meta( 'display_name' ) . '</div>'; if( $attr['showBio'] ){ $output .= '<div class="wp-block-author-box-author-plugin__description">' . get_the_author_meta( 'description' ) . '</div>'; } $output .= '</div>'; $output .= '</div>'; }
代碼非常簡單。 它檢查每個屬性的當前值,如果為true
,則生成必要的 HTML。
現在保存您的 PHP 文件並將編輯器中的塊與前端的相同塊進行比較。
您可以在這個公共 Gist 中找到示例塊的完整代碼。
動態塊開發的推薦資源
如果您在閱讀本文時豎起耳朵並開始認識到學習如何創建古騰堡區塊所帶來的專業發展機會,那麼我們的建議是繼續探索和獲得區塊開發背後技術的新技能。
儘管仍然缺少可靠的官方文檔,但仍然有很好的資源,包括免費和付費的,我們在撰寫本文時進行了諮詢。 在眾多可用資源中,我們推薦以下資源:
官方資源
- 數據
- 核心數據
- 創建動態塊
- 古騰堡區塊開發簡介
- MeetUp 上的 WordPress 社交學習
來自 WordPress 核心貢獻者的推薦教程
- Ryan Welcher (@ryanwelcher) 使用 getEntityRecords 在 Gutenberg 請求數據
- Darren Ethier (@nerrad) 的 @wordpress/data API 實用概述
JavaScript、React 和 Redux 資源
- MDN 的 JavaScript 教程
- React 入門(官方)
- Redux 教程(官方)
Kinsta的相關資源
- 什麼是 JavaScript? 看看網絡上最流行的腳本語言
- 處理 JavaScript 錯誤的權威指南
- 什麼是 Node.js 以及為什麼要使用它
- 如何在 Windows、macOS 和 Linux 上安裝 Node.js 和 npm
- 如何使用多種工具調試 Node.js 代碼
- Node.js 與 PHP:正面對比
- 2022 年 10 種最受歡迎的 Node.js 應用程序類型
- Angular vs React:詳細的並排比較
概括
通過古騰堡區塊開發,我們已經到達了這個(第二次)漫長旅程的終點。
在本文中,我們介紹了一些高級主題,例如應用程序狀態和 Redux 存儲。 但希望您現在應該對塊開發有更好的了解。
是的,在構建高級 Gutenberg 塊時,Node.js、Webpack、Babel、React 和 Redux 技能是必不可少的,但您無需成為 React 忍者即可開始。 學習如何開發古騰堡積木並不一定很複雜。 只需以正確的動機並遵循適當的學習路徑即可。
我們希望這篇文章 - 以及上一篇文章 - 為您提供正確的地圖,以找到您的道路並立即開始 Gutenberg 開發。
現在由你決定! 你創建動態塊了嗎? 你有什麼例子可以和我們分享嗎? 在你的經歷中,最大的障礙是什麼? 隨意在下面發表評論。