【 書摘 】Building Web Apps with WordPress

能夠看到這麼多實務技巧以及如此全面的 WordPress 開發書籍,就覺得買這台電子書閱讀器值回票價了!

Building Web Apps with WordPress 是由 Jason Coleman&Brian Messenlehner 合力撰寫的一本關於如何使用 WordPress 開發 Web App 的程式書籍,雖然標題是寫 Web Apps,但對於想要致力於開發 Theme 或是 Plugin 的朋友都非常適合,因為它涵蓋了所有在開發 WordPress 時會涉及的議題。

像是從檔案結構、資料庫結構,到怎麼開發外掛、佈景主題,CPT、Taxonomy、OOP 開發技巧、User Role、WordPress API、安全性、ES6、WordPress REST API、Gutenberg Block editor、Multisite、本地化、效能優化、規模化、WooCommerce、整合 PHP Libraries 等等,

最後一章還預測了未來 WordPress 會走到哪個方向,對於想要掌握開發趨勢、學習基礎、進階技巧,個人超級大推這一本,看完之後一整個對於 WordPress 有了全新的認識。

全書的範例檔在這邊 –> https://github.com/bwawwp/bwawwp,裡面用了一個 SchoolPress Open Source 當教學範例—>https://github.com/bwawwp/schoolpress,Jason Coleman 是  Stranger Studios 的創辦人,這公司開發了 Paid Membership Pro 這隻外掛。

本書共有 18 個章節、1546 頁,每一章我會努力的用中文做摘要,再加入我自己的經驗做腦補,希望有辦法能在一個月之內整理完這個大工程,好長的一條路啊,開始走囉~

目錄

一、Building Web Apps with WordPress / 使用 WordPress 打造 Web Apps

二、WordPress Basic / WordPress 基本介紹

三、Using WordPress Plugin / 使用 WordPress 外掛

四、Themes / 佈景主題

五、Custom Post Types, Post Metadata, and Taxonomy / 自訂文章、文章欄位、文章分類

六、Users, Roles, and Capabilities / 使用者、角色、權限

七、Working with WordPress API, Objects, and Helper Functions / 使用 WordPress API、物件、與實用函式

八、Secure WordPress / 加強安全性

九、JavaScript Frameworks and Workflow / JavaScript 框架與工作流程

十、WordPress REST API

十一、Project Gutenberg, Blocks, and Custom Block Types / 關於古騰堡編輯器

十二、WordPress Multisite Networks / 多站網路管理

十三、Localizing WordPress Apps / 多語系

十四、WordPress Optimization and Scaling / WordPress 效能優化與規模化

十五、Ecommerce / 電子商務

十六、Mobile Apps Power by WordPress / 用 WordPress 運作手機應用程式

十七、PHP Libraries, Web Service Integrations, and Platform Migrations / PHP 函式庫、網頁服務與平台整合

十八、The Future / 未來

一、Building Web Apps with WordPress / 使用 WordPress 打造 Web Apps

在開始之前,作者先來定義什麼叫做網頁應用程式 Web App 。

Web / 網站

由許多頁面所構成,使用網頁瀏覽器進行瀏覽與操作

App(Application) / 應用程式

由很多可以互動的功能所組成的軟體

Web App / 網頁應用程式

可以運作在瀏覽器上面的軟體,或是泛指帶有更多互動的網站,Web App 的特徵如下:

(一)有互動元素可以進行互動

(二)任務優先於內容,可以解決某些問題或是產出某些東西的網站

(三)有登入註冊會員系統,可以儲存會員資料

(四)完整的裝置相容性,可以取得裝置的硬體使用權限,像是相機、地理位置定位

(五)沒有網路在離線狀態時也能使用

(六)與其他平台串接整合,使用各種服務的 API

因為觀察到 Web App 的趨勢,Google 推出了 Progressive Web App ( PWA ) 的技術來讓網站方便整合 Web App 的特性,使用 WordPress 架站的話可以利用 PWA plugin 讓現行網站具備 Web App 的功能,關於 PWA 的特性如下:

(一)有獨立的 URL:Web App 在現今的開發框架上多半採用 Single Page 單頁式的方式來呈現操作介面,然後透過 Ajax 去呼叫資料來載入並顯示內容,所以整個 Web App 就只有一頁,在某些情況下對使用者體驗不佳,所以 PWA 可以把不同的內容用 Rewrite 的方式拆分成不同的網址,然每個頁面可以獨立被連到。

(二)頁面切換沒有延遲或是必須等待載入的感覺,因為如同第一點所提,整個網站只有一頁,所以切換頁面完全不用讀取,需要等待的只有透過 Ajax 載入資料的時間。

(三)連線為 HTTPS

(四)使用 Responsive Web Design ( RWD ) 技術來頁面相容於各種裝置

(五)載入快速,因為只有一頁

(六)使用本地儲存技術讓網站在沒有連線的狀況下也可以使用儲存在客戶端的資料來呈現內容,待裝置與網路連線後再把本地資料傳送給伺服器進行儲存

(七)加入桌面捷徑 Add to Home Screen 功能:因為 Web App 必須透過瀏覽器執行,為了讓使用者可以方便再次進入,開發者通常都會希望使用者把這個網址加入桌面的圖示變成像手機原生的 App 一樣,不用再開啟瀏覽器即可再次造訪

Google 提供了 Lighthouse Tool 來測試你的網站是否支援 PWA 功能。

如果還是有朋友不了解什麼叫做 Web App,可以打開一下 Google Map、Google 文件、Gmail,這些使用瀏覽器就可以造訪的服務或軟體,就是很標準的 Web App。

也因為這樣的技術已經成熟到一個階段了,有非常多的軟體公司在靠著這樣的服務在創造營收,Netflix、Office 365、Dropbox,這樣的商業模式叫做軟體及服務 Software as a Service ( SAAS ),這類服務最典型的收費模式就是訂閱制,而本書常提及的外掛 Paid Membership Pro 就是一套可以設計 SAAS 服務的工具。

為什麼要用 WordPress 做 Web Apps

網頁技術百百種,為什麼要選擇 WordPress?首要原因當然就是因為你已經用它做過很多網站了,而你非常熟悉它,閉著眼睛都可以數得出來後台左側選單依序有哪些,如果今天要開發一套工具,當然是非他莫屬!

除了個人因素外,其他客觀原因還有:

(ㄧ)內容管理超級好用,常有的欄位都已內建,不夠用還可以自行新增,或是創造新的文章類型

(二)會員管理簡單易用又安全,密碼自動 Md5 加密,角色權限分層直接內建完整,不夠用一樣可以自行新增

(三)第三方的外掛數量爆炸多,而且大部分都是免費,付費的功能超多價格又能負擔得起

(四)彈性很高,WordPress 可以做各種類型的網站,通常一間新創公司對於網站的需求大致如下:使用者一頁式網頁宣傳服務 -> 加入表單搜集名單 –> 加入部落格 —> 做 SEO —> 社群分享 —> 增加論壇 –> 加入付費機制 —> 加入付費會員專屬內容或功能 —> UI 改版 —> 優化網站並擴大硬體規格 —> 多語系 —> 加入 PWA –> 上架 APP 等等,以上這些步驟 WordPress 全部都有相對應的外掛或服務可以利用

(五)WordPress 核心維護團隊對於安全性漏洞的修補速度快

(六)建置成本低,WordPress 程式碼是免費的,PHP / MySQL 免費、大部分的外掛也都是免費,初期要負擔的成本就是主機租賃的費用

Open Source 軟體我覺得最重要的就是社群,因為 WordPress 本身是免費的,能否有辦法得到社群的技術資源是關鍵。我自己最早用的開源 CMS 是 Xoops,當年的資源少得可憐,一遇到問題只能去國外論壇爬文,就算提問也很少得到解答。

Xoops 相關的外掛更是少到不行,台灣只有吳弘凱老師有固定持續在開發新的模組,很謝謝他當年的分享!所以之後嘗試了 Joomla,Joomla 在台灣有固定的小聚,而且還剛好在上班的地方附近,但我一次也沒去過,因為 Joomla 的後台操作邏輯太奇妙了…

至於現在 WordPress 的社群就不用講了,在多位大大的努力之下,早已遍地開花,偶爾想上去正體中文社團幫忙回答一些問題,只要問題ㄧ PO 出來一分鐘內立馬就會有人主動回覆,根本搶不到XD

更不用說還有國際級的 WordPress 活動 WordCamp 也在台灣成功舉辦兩次了,只能說當年改用 WordPress 一整個是壓對寶!也因為用的人超多,一堆能想得到的各種應用都有人做出來,國外的 WordPress 商業模式也已非常成熟,從主機到各種進階的外掛應有盡有!

作者對於一些關於 WordPress 的批評也作出了回應:

(ㄧ)WordPress 只是拿來寫部落格用的工具:早在 WordPress 3.0 加入 Custom Post Type 的機制後,WordPress 就能用來製作各種類型的內容網站,形象官網、新聞媒體、購物商城,只要網站需要資訊呈現的內容,WordPress 都能輕鬆應付!

(二)WordPress 無法適應大型網站:WordPress.com 就是一個最好的範例,相同的原始碼,可以承載世界頂尖的媒體網站,像是 BBC AmericaTechCrunchFacebook Newsroom,就跟其他框架一樣,分散式架構、快取、CDN 都可以應用在 WordPress 上面,看人會不會用而已。

(三)WordPress 不安全:WordPress 的核心程式碼有全世界專門的團隊在維護,有嚴重的漏洞發生時很快就會釋出更新,跟請一位工程師自行開發的網站比起來,完全不用擔心哪天工程師離職了就沒人維護,歷年來的 WordPress 更新紀錄可以參考 Release Note

(四)WordPress 的外掛爛透了:有些真的很爛,而且出問題了根本找不到開發者,但這幾年來因為市場的規模擴大,越來越多公司投入外掛開發,商業模式的成熟讓外掛品質有顯著的提升,也讓公司賺進大把的鈔票,又因此吸引更多公司投入,形成良性的競爭循環。

個人覺得最功不可沒的就是 Envato,他們把整個 WordPress 的商業生態給建立了起來,早期投入的廠商獲得豐厚的果實,讓後期投入的開發者無不絞盡腦汁設計出各種類型的高品質商品,值接促進更多企業願意選擇 WordPress 作為架站系統,這樣的循環持續下去,如果哪天 WordPress 的全球市占率超過 50% 我也一點都不意外。

何時不要用 WordPress 做 Web Apps

(一)如果你的商業模式是要把網站連 Source Code 都要一起售出的時候:WordPress 採用的的是 GPL 授權,它的主要授權方式是任何人都可以自由的修改、散播程式碼,而用在 WordPress 裡面的所有程式也必須言用 GPL 授權。

如果今天你的 App 是架在自己的主機上,販售的是會員使用權限,像是付費會員有更多進階功能或內容,那麼這跟 GPL 授權沒有關係。

但如果這套系統是要裝在對方的主機上,那麼就不得根據「程式碼」來進行收費,因為所有 WordPress 的 source code 都是開源的,而你客製過的程式也必須遵守開源的規範,必須以相同的授權進行免費散播,同時讓人有自由修改的權利。

簡單來說,當你使用 WordPress 進行創作的時候,如果要給其他人使用,都是必須照著 GPL 的規範,所以如果你是計畫要賣掉網站來賺錢,WordPress 就不是一個合適的選項。

因為 GPL 的授權方式,現在可以找到一堆 GPL Download 的服務,這些服務從各種管道取得付費程式的原始碼,然後用低於市價或是訂閱制的方式銷售這些程式,然後聲稱他們收的是「維護費」,並強調他們提供的程式 100% 正版,絕對沒有後門,而且還會定期更新。

之前看過一篇訪談,被訪者是幾間知名外掛大廠的負責人,談對於 GPL 授權以及 GPL Download 的想法,多數老闆對於 GPL Download 斥之以鼻,但也有老闆不在意,因為他們賣的不是程式碼,而是「服務」,協助使用者解決問題或是開發更多新功能才是他們的核心價值。

身為開發者的我當然很度爛 GPL Download,但與其要去防堵這些堵不完的網站似乎不太可能,因為 GPL 的授權條款就是這樣運作的,WordPress 看來也沒打算改變,只能專注在提供更好的服務。

對於使用者而言,如果你不擔心程式碼是否為正版、不在意是否有售後服務、不關心開發者的心血,那就還是去乖乖買正版,因為不買正版你就沒有這麼多價格實惠又功能強大的外掛可以用,只能花大錢、花時間、花精力請一個世界級的團隊幫你開發了。

(二)如果你的技術人員有其他更熟悉的技術,像是 Asp.net、Ruby、JAVA,那就不要用 WordPress,可以快速把商業需求實作出來的技術才是重點,用什麼技術取決於執行人員的掌握度。

(三)如果你的網站很單純,未來不需要持續更新或加入更多的新功能,甚至是連內容的更新都不需要,這種可以用幾個 HTML 頁面就搞定的網站,就不要用 WordPress。

(四)如果你需要高度即時互動的網站,像是可以即時聊天的線上遊戲、或是需要每秒更新內容的網站,這種就不要用 WordPress 來架。但這並非是 WordPress 的問題,而是傳統網站系統架構的問題,因為所有使用者請求都要經過伺服器,再透過後端語言來處理請求結果必顯示在畫面上。

WordPress 這兩年已開始透過 Gutenberg 這個編輯器來設計不需要透過後端伺服器來進行資料的處理,大量使用 JavaScript 、REST API 與非同步技術來改善傳統網站的流程,也許在未來即時互動網站也適合使用 WordPress 來處理。

WordPress vs. MVC Framework

從早年的 Blog 成長為 CMS 內容管理系統,到現在有非常成熟的 API 以及豐富的 Hook 機制, WordPress 已成為網站開發框架 ( Platform )。

相較於強調其他 MVC 框架,WordPress 沒有採取非常正規的MVC 設計模式,但還是有可以互相對應的地方。Plugin 可以看作是 Model,控制資料的部分,Theme 是 View,負責視覺呈現的介面,而 Template Loader 則可以看作 Controller。

當造訪 WordPress 網站時一律會達到 index.php,再透過 Theme 的模版系統來決定資料要呈現在哪一個模板上,也就是 Controller 負責的工作。

MVC 模式(Model–view–controller)是軟體工程中的一種軟體架構模式,把軟體系統分為三個基本部分:模型(Model)、視圖(View)和控制器(Controller),

MVC模式的目的是實現一種動態的程式設計,使後續對程式的修改和擴充簡化,並且使程式某一部分的重複利用成為可能。

WikiPedia

SchoolPress 專案介紹

SchoolPress 是一個開源的專案,它是運作在多站網路上面的一套系統,主要功能為讓學校的老師可以透過這套系統來管理班級、課程內容、出作業以及管理學生提交的作業,主要的架構簡要如下:

  • 商業模式為學校付錢給老師使用,老師使用來管理班級學生
  • 每一個學校是多站網路下面的一個子站,網址使用子網域
  • 班級管理是用 BuddyPress 的 Groups
  • 老師出的作業是 CPT
  • 學生交的作業是 CPT
  • 學年度是班級 CPT 的 Taxonomy
  • 系所示班級 CPT 的 Taxonomy
  • Theme 使用 MemberLite

了解這個專案的內容結構對於接下來的範例會比較有概念。

二、WordPress Basic / WordPress 基本介紹

第二章的部分先從介紹 WordPress 主程式的資料夾結構以及資料庫結構與相對應的 API 開始。

WordPress 資料夾結構

要開發 WordPress 之前,必須知道的第一條鐵律就是「永遠不要修改 WordPress」。這意思是說千萬不要去修改 WordPress 的核心程式,因為只要一更新所有的修改就會被覆蓋,而更新通常都會有修補漏洞的項目,所以為了要能讓網站維持在安全的狀態,更新到最新版本是必要的。

也因此不要修改核心程式碼,要修改之前先找看看有沒有相關的 Hook 可以使用,如果沒找到適合的可以回報給核心維護團隊,請他們把你需要的 Hook 加入,這樣最好的作法。

至於哪些是核心程式碼?除了 wp-content 資料夾以及 wp-config.php 以外,其他都是核心程式碼,你永遠、絕對、不要修改它!

Hook 的機制可以想像成是蓋房子的時候預留的管線,當今天房客要牽新的電話線或是水管時,不用把牆壁全部打掉,只要用之前準備好的管線來接就可以。

Hook 分為兩種,Action 是可以把一些特定的 Function 交由 Hook 來執行,Filter 是可以修改參數、顯示文字與設定值,Hook 可以放在你的佈景主題或是外掛來執行,這樣就不用修改到核心程式碼。

現在還不了解 Hook 是什麼也沒關係,更多關於 Hook 的部分之後會一直反覆出現,反覆到你都嫌煩了它還是會一直出現XD,因為他是 WordPress 程式運作的核心要素之一。

(ㄧ)wp-admin – 所有 WordPress 後台的程式碼都放在這個資料夾裡面,每個檔案都對應一個後台的頁面或是功能。

如果想要客製 WordPress 後台,會需要知道一堆 Hook,有時候與其去爬 Google 查文件,個人覺得直接看檔案還比較快,有看到 do_action 就是可以掛 Action 的地方,有看到 apply_filter 就是可以掛 Filter 的地方,等找到 Hook 名稱再去 Google 看要怎麼用,不然官方列出來的 Hook 爆炸多,而且很多又長得超像,常常都是要不停用除錯法才能試到我想要的 Hook,非常花時間…

(二)wp-include – WordPress 所有的 API 、類別都是放在這個資料夾裡面,深入理解他們可以了解 WordPress 的工作方式。

裡面非常精彩,我最喜歡看他們的類別是怎麼設計的,或是常用的 function 是怎麼寫的,每次隨便逛逛都會有意想不到的收穫~

(三)wp-content – 我們可以修改的地方,也是放外掛、佈景主題與上傳檔案的地方。

(四)wp-content/themes – 放所有佈景主題的資料夾,要手動上傳佈景主題把東西放在這邊就對了。

(五)wp-content/plugins – 放所有外掛的資料夾,要手動上傳外掛把東西放在這邊就對了。

(六)wp-content/mu-plugins – MU 是 Must Use 必須使用的意思,當把外掛放在這邊的時候,WordPress 會直接自動啟用該外掛,並且不會出現在後台 > 外掛的清單之中,所以當今天如果你要停用所有外掛來進行網站除錯的時候,記得檢查一下有沒有 mu-plugins 這個資料夾,否則萬一問題是出在 mu-pluings 裡面的外掛時,會讓你以為自己在鬼打牆。

專門定義資料結構的外掛,也就是註冊 CPT、Taxonomy、Nav 的外掛,非常適合放在這個資料夾,因為這些資料是網站的基本元素,不會因為換了佈景主題而消失,也不應該被停用,所以有預設應該被啟用的外掛就放在這邊。

wp-content 裡面還有其他資料夾,有 WordPress 內建的,也有會因為你使用的外掛而自動產生的,當要搬移網站的時候,最簡單的方式就是把整個 wp-content 打包然後丟到新家去,就能移轉你的網站。當然,資料庫也要記得搬,接下來說明資料庫結構:

WordPress 資料庫結構

這邊介紹了 WordPress 的資料表,以及存取寫入這些資料表相關的 Function,這些 Function 都可以寫在佈景主題裡面的 function.php 來使用它,或是放在你自己寫的外掛裡面。

資料表名稱的前綴使用預設的 wp_,這可以在 wp-config.php 裡面透過以下參數來修改:

$table_prefix = 'wp_'; // 把 wp 換成其他前綴

如果你的 WordPress 是使用主機面板安裝的,像是 cPanel、Plesk,因為安全性考量他們會自動幫你修改資料表前綴,所以你打開 PhpMyAdmin 要找的是 abc_options、abc_posts 這些資料表就好,前綴 abc 不用管他。


(ㄧ)wp_option – 該表存放全站設定相關的資料,也就是在後台左側選單 > 設定裡面的設定都會存在這張表裡面,如果你有自己開發外掛的話,也可以把相關的變數存在這個表中。為了節省效能,在寫入時會先把設定的值組成一個陣列再進行 INSERT。

wp_options 資料表結構

wp_options 相關的 Function 定義在 wp-include/option.php,常用的如下:

add_option( $option_name, $option_value, autoload=yes) 新增設定

它會先自動檢查 $option_name 是否存在,不存在的話新增一筆資料,已存在的話會把 $option_value 進行覆寫。autoload 預設為 yes,作用是設定該 $option 是否加入到快取之中。如果你確定每個頁面都會用到這個設定的話,就保持預設值 yes,反之為 no。範例如下:

// add option
$twitters = array( '@bwawwp', '@bmess', '@jason_coleman' );	// 用陣列來整理 option_value
add_option( 'bwawwp_twitter_accounts', $twitters );

update_option( $option_name, $option_value ) 更新設定

更新已存在的 $optioni_value,如果該 $option_name 不存在的會自動新增一筆,範例如下:

// update option
$twitters = array_merge(
         $twitters,
         array(
                 '@alphaweb',
                 '@pmproplugin'
         )
);
update_option( 'bwawwp_twitter_accounts', $twitters );

get_option( $option_name ) 取得設定欄位的值

範例如下:

// get option
$bwawwp_twitter_accounts = get_option( 'bwawwp_twitter_accounts' );
foreach( $bwawwp_twitter_accounts as $account ){
	echo $account.', '; // 輸出 @bwawwp, @bmewss, @jason_coleman
}

delete_option( $option_name ) 刪除設定欄位

範例如下:

// delete option
delete_option( 'bwawwp_twitter_accounts' );

每次要修改網站管理員電子郵件的時候,WordPress 會發確認信到新的信箱來做確認,但我懶,所以都直接進 wp_options 這個表來修改管理員的 E-mail,找到 option_name 為 admin_email 的欄位,然後修改 option_value 為新的電子郵件即可。


(二)wp_users – 存放使用者帳密與基本資料,如果要從資料庫修改使用者相關資訊,像是客戶忘記密碼或是要新增一個管理員帳號,就可以在這個表進行處理。

wp_users 資料表結構

wp_users 相關的 Function 定義在 wp-include/pluggable.php、wp-include/user.php,常用的如下:

wp_insert_user( $userdata ) 新增使用者

$userdata 為一個陣列,使用陣列來定義使用者的資料欄位,範例如下:

// insert user
$userdata = array(
    'user_login'    => 'brian',
	'user_pass'     => 'KO03gT7@n*',
	'user_nicename' => 'Brian',
	'user_url'      => 'https://alphaweb.com/',
	'user_email'    => 'brian@alphaweb.com',
	'display_name'  => 'Brian',
	'nickname'      => 'Brian',
	'first_name'    => 'Brian',
	'last_name'     => 'Messenlehner',
	'description'   => 'This is a WordPress Administrator account.',
	'role'          => 'administrator'
);
wp_insert_user( $userdata );

wp_create_user( $username, $password, $email ) 新增使用者簡易版

相較於 wp_insert_user(),它只要提供帳戶名、密碼、電子郵件三個參數就可以新增使用者,範例如下:

// create users
wp_create_user( 'jason', 'YR529G%*v@', 'jason@schoolpress.me' );

wp_update_user( $userdata ) 修改 wp_users 與 wp_usermeta 裡面的欄位

如果修改了使用者密碼,所有的 cookie 會被清除,該使用者會強制登出,$userdata 的欄位與 wp_insert_user() 相同,範例如下:

// update user-change username fields and change role to admin
$userdata = array(
	'ID'         => $user->ID,
	'first_name' => 'Jason',
	'last_name'  => 'Coleman',
	'user_url'   => 'http://strangerstudios.com/',
	'role'       => 'administrator'
);
wp_update_user( $userdata );

get_user_by( $field, $value ) 根據使用者資料來取得使用者

取得的使用者會以 WP_User 物件進行回傳,這支的作用等同於 Sql 語句下:SELECT * FROM wp_users WHERE $field = $value,$field 是使用者資料欄位,$value 是使用者資料值,範例如下:

// get user by email
$user = get_user_by( 'email', 'jason@schoolpress.me' );
echo 'username: ' . $user->user_login . ' / ID: ' . $user->ID . '<br>';

wp_delete_user( $user_id, $reassign ) 刪除使用者並把該使用者文章移轉給其他人

第一個參數為要被刪除的使用者 ID,第二個參數為要繼承文章的使用者 ID,要注意的是如果第二個參數沒有指定,則該使用者的文章都會被移除,範例如下:

// delete user-delete the original admin and set their posts to our new admin
wp_delete_user( 1, $user->ID );

忘記使用者密碼的話進入 wp_users 找到要修改密碼的使用者,然後找到 user_pass 欄位,在修改前記得先把你的新密碼用這個工具來加密成 MD5,加密後才把 MD5 的字串填進 user_pass。因為安全性考量,WordPress 會把所有的使用者密碼都用 MD5 進行加密,如果直接填未加密的密碼進去是無效的。

至於如何從資料庫新增一個管理員帳號可以參考這篇文章 —> https://wpengine.com/support/add-admin-user-phpmyadmin/


(三)wp_usermeta – 使用者自訂欄位

記錄使用者更多更詳細的資料,也就是除了 wp_user 已經寫死欄位以外的使用者資料,可自行新增使用者欄位

wp_usermeta 資料表結構

wp_usermeta 相關 Function 常用的如下:

get_user_meta( $user_id, $meta_key, $single=false ) 取得特定使用者的資料

$user_id 為使用者 id,$meta_key 要取得的欄位,如果留空值,會回傳所有相同 $meta_key 的 $meta_value,$single 為 true 的話會以字串回傳符合第一個 $meta_key 的 $meta_value,false 的話則會使用陣列回傳所有符合的 $meta_value,範例如下:

// get brian's id
$brian_id = get_user_by( 'login', 'brian' )->ID;
$brians_wife = get_user_meta( $brian_id, 'bwawwp_wife', true); // Wife 可能有多個(?),true 的話回傳第一個	
echo "Brian's wife: " . $brians_wife . "<br>";

update_user_meta( $user_id, $meta_key, $meta_value, $prev_value=”” ) 更新使用者的資料

需要注意的是第四個參數,如果 $meta_key 有多筆符合,在 $prev_value 為空的情況下,$meta_value 只會修改第一筆 $meta_key,如果 $prev_value 有符合多筆 $meta_key 的 $meta_value 其中一筆,則這一筆的 value 會被第三個 $meta_value 給取代掉。範例如下:

// update user meta - this will update brian to brian jr.
update_user_meta( $brian_id, 'bwawwp_kid', 'Brian Jr', 'Briand' ); // Brian 有多個小孩(多筆相同的 meta_key),名字叫做 Braind 的會被修改為 Brain Jr

add_user_meta( $user_id, $meta_key, $meta_value, $unique=false) 新增使用者資料欄位

習慣上新增使用者資料會使用 update_user_meta(),因為它有判斷 $meta_key 是否存在的功能,會用 add_user_meta 的情境在於要新增多筆 $meat_value 到相同的 $meta_key。第四個參數 $unique 為 true 時代表不允許有多筆相同的 $meta_key,範例如下:

// add user meta - 3rd parameter is a unique value
add_user_meta( $brian_id, 'bwawwp_kid', 'Dalya' );
add_user_meta( $brian_id, 'bwawwp_kid', 'Brian' );
add_user_meta( $brian_id, 'bwawwp_kid', 'Nina' );
add_user_meta( $brian_id, 'bwawwp_kid', 'Cam' );
add_user_meta( $brian_id, 'bwawwp_kid', 'Aksel' );

delete_user_meta( $user_id, $meta_key, $meta_value=””) 刪除使用者資料

第三個參數當有指定 $meta_value 只會刪除符合該 value 的 $meta_key,範例如下:

// delete brian's user meta
delete_user_meta( $brian_id, 'bwawwp_wife' );
delete_user_meta( $brian_id, 'bwawwp_kid', 'Dalya' ); // 沒指定 Dalya 的話則所有小孩都會被刪除

(四)wp_posts – 存放文章、頁面、選單、文章版本、以及自定義文章的資料表,而自定義文章就是用這個表裡面的 post_type 欄位來紀錄不同的文章類型

wp_posts 資料表結構

wp_options 相關的 Function 定義在 wp-include/post.php,常用的如下:

wp_inset_post( $postarr, $wp_error=false) 插入新文章

$postarr 是一個定義新文章內容的陣列,裡面有許多參數可以定義,$wp_error 為 true 時會在文章插入失敗時回傳一個 WP_Error 物件,範例如下:

// insert post - set post status to draft
$args = array(
	'post_title'   => '文章標題',
	'post_excerpt' => '文章摘要',
	'post_content' => '內文',
	'post_status'  => 'draft',  // 文章狀態,有 draft、publish
	'post_type'    => 'post', // 文章類型,預設為 post,可以是 page 或其他 CPT
	'post_author'  => 1, // 作者 ID
	'menu_order'   => 0 // 文章順序
);
$post_id = wp_insert_post( $args );  // 新文章插入完成後會回傳該文章的 post ID
echo 'post ID: ' . $post_id . '<br>';

wp_update_post( $postarr, $wp_error = false) 更新文章資料

同樣使用 $postarr 陣列來更新資料,記得要提供需要被更新的文章 ID,範例如下:

// update post - change post status to publish
$args = array(
	'ID'  => $post_id,
	'post_status' => 'publish'
);
wp_update_post( $args );

get_post( $post=null, $output=OBJECT, $filter=’raw’) 取得文章資料

第一個參數指定要取得的文章的 ID,如果是在 post loop 中的話留空會自動取得當前文章。$output 資料格式可以設定為 OBJECT 或是 ARRAY_A (關聯式陣列) 與 ARRAY_N(索引式陣列)。$filter 參數為設定要 sanitize 的模式,可選值有 raw、edit、db、display、attribute 與 js,這是與安全性有關的議題,會在第八章的時候提到。範例如下:

// get post - return post data as an object
$post = get_post( $post_id );
echo 'Object Title: ' . $post->post_title . '<br>';

// get post - return post data as an array
$post = get_post( $post_id, ARRAY_A );
echo 'Array Title: ' . $post['post_title'] . '<br>';

get_posts( $args = null ) 取得文章列表

當要取得文章清單時,像是最新文章列表、特定分類列表就可以使用這支 Function。它是根據 WP_Query 類別所設計的。$args 參數可以用陣列的方式來提供文章取得條件,範例如下:

// get posts - return 100 posts
$posts = get_posts( array(
  		'numberposts' => '100', // 顯示文章數量
  		'category'         => 0,  // 文章分類 ID	
        'orderby'          => 'date',  // 排序條件
        'order'            => 'DESC',  // 排序方式,DESC 為降冪,ASC 為升冪
        'include'          => array(1,2,3),  // 只顯示特定的文章	
        'exclude'          => array(4,5,6),  // 排除指定文章
        'meta_key'         => '',  // 顯示帶有指定欄位的文章
        'meta_value'       => '',  // 顯示帶有指定欄位值的文章
        'post_type'        => 'post',  // 文章類型
        'suppress_filters' => true,  // 如果需要使用 filter 來修改 get_posts 的結果,這個參數要設為 false
	)
);
// loop all posts and display the ID & title
foreach ( $posts as $post ) {
	echo $post->ID . ': ' .$post->post_title . '<br>';
}

wp_delete_post( $postid=0, $force_delete =false ) 刪除指定文章

第一個參數為要刪除的文章 ID,第二個參數如果為 true 的話,文章就不會進垃圾桶而直接被刪除,代表連救回來的機會都沒有,預設值為 false,範例如下:

// delete post - skip the trash and permanently delete it
wp_delete_post( $post_id, true );

(五)wp_postmeta – 文章自訂欄位

如果內建的文章欄位不夠用,想要新增其他欄位的話就會寫在這張表中。WordPress 提供很方便的作法讓你不用再自行增加資料表,每個欄位使用 post_id 來對應到文章。

如果你需要新增欄位但又不想讓使用者在文章編輯畫面看到該欄位,可以用下底線開頭的欄位名稱,這樣 WordPress 會自動在後台隱藏這個欄位而不被使用者看見。

寫到這張表的時候就想到一件事,每次使用 ACF 開了一堆欄位,當網站開始上大量的資料之後,這張表就會以飛快的速度開始爆肥,因為所有的自訂欄位全部都會塞在裡面,這對於在 DB Query 上會是不小的負擔。

好奇的查了一下有沒有可以把 ACF 欄位獨立成一張表的外掛,想不到還真的有!一間澳洲的公司叫做 Hookturn,他們開發了一隻外掛叫做 ACF Custom Database Tables,看影片介紹非常猛,完全就是我想像的功能,售價 139 鎂,對於有規模的網站來說,絕對比再多開兩台 DB 來得划算的多!

Hookturn 還有另外兩隻外掛商品,一隻很實用,直接幫你把欄位的 PHP 產好,另外一隻我覺得根本就是 ACF 應該要內建的功能:前台表單。它可以把 ACF 的欄位完整呈現在前台,這個拿來做 Web App 超級方便,就不用自己在那邊刻表單刻個老半天了,下一個 Web App 我一定會用它!

wp_postmeta 資料表結構

get_post_meta( $post_id, $meta_key, $single=false ) 取得文章欄位值

第一個參數為文章 ID,第二個為欄位名稱,如果留空值,會回傳所有相同 $meta_key 的 $meta_value,$single 為 true 的話會以字串回傳符合第一個 $meta_key 的 $meta_value,false 的話則會使用陣列回傳所有符合的 $meta_value,範例如下:

// get post meta - get 1st instance of key
	$student = get_post_meta( $post_id, 'bwawwp_student', true );
	echo 'oldest student: ' . $student;

update_post_meta( $post_id, $meta_key, $meta_value, $prev_value=”) 更新文章欄位

需要注意的是第四個參數,如果 $meta_key 有多筆符合,在 $prev_value 為空的情況下,$meta_value 只會修改第一筆 $meta_key,如果 $prev_value 有符合多筆 $meta_key 的 $meta_value 其中一筆,則這一筆的 value 會被第三個 $meta_value 給取代掉。範例如下:

// update post meta - public metadata
$content = 'You SHOULD see this custom field when editing your latest post.';
update_post_meta( $post_id, 'bwawwp_displayed_field', $content );

// update post meta - hidden metadata
$content = str_replace( 'SHOULD', 'SHOULD NOT', $content );
update_post_meta( $post_id, '_bwawwp_hidden_field', $content );

add_post_meta( $post_id, $meta_key, $meta_value, $unique=false)

習慣上新增文章欄位會使用 update_post_meta(),因為它有判斷 $meta_key 是否存在的功能,會用 add_post_meta 的情境在於要新增多筆 $meat_value 到相同的 $meta_key。第四個參數 $unique 為 true 時代表不允許有多筆相同的 $meta_key,範例如下:

add_post_meta( $post_id, 'bwawwp_students', $students, true );

delete_post_meta( $post_id, $meta_key, $meta_value=” ) 刪除文章欄位

第三個參數當有指定 $meta_value 只會刪除符合該 value 的 $meta_key,範例如下

// delete post meta
delete_post_meta( $post_id, 'bwawwp_student' );

(六)wp_comments – 紀錄文章留言的資料表

wp_comments 資料表結構

wp_comments 相關的 Function 定義在 wp-include/comment.php,常用的如下:

get_comment( $comment, $output=OBJECT ) 根據留言 ID 取得留言內容

第一個參數可以為留言 ID 或是 OBJECT,第二個為返回格式,可以為 OBJECT、ARRAY_A 與 ARRAY_n。範例如下:

// make comments array
$comments[] = 'ICE CREAM!!!!';
$comments[] = 'Taco Bell';
$comments[] = 'Get a good night sleep';

//loop comments array
foreach ( $comments as $key => $comment ) {
	// insert comments
	$commentdata = array(
		'comment_post_ID' => $post_id,
		'comment_content' => $comments[$key],
	);
	$comment_ids[] = wp_insert_comment( $commentdata );  // 插入留言
}

// get comment - get best comment
$comment = get_comment( $comment_ids[0] );
echo 'best comment: ' . $comment->comment_content;

get_comments( $args=” ) 取得特定文章的留言列表

該 Funciton 使用 WP_Coomen_Query 類別來取得留言,$args 為選填的陣列或是用 & 符號連結的字串來取留言,常用參數有:

  • author_email 留言者的電子郵件
  • ID 留言 ID
  • karma 留言評價
  • number 顯示留言筆數
  • offset 跳過顯示留言比數
  • orderby 排序條件,可選的值有 ‘comment_agent’,’comment_approved’,’comment_author’,’comment_author_email’,’comment_author_IP’,’comment_author_url’,’comment_content’,’comment_date’,’comment_date_gmt’,’comment_ID’,’comment_karma’,’comment_parent’,’comment_post_ID’,’comment_type’,’user_id’,’comment__in’,’meta_value’,’meta_value_num’
  • order 排序方式,可選值為 DESC 與 ASC
  • parent 父留言的 id (comment 有階層)
  • post_id 特定文章的留言
  • post_author 文章作者
  • post_name 文章名稱
  • post_parent 父文章
  • post_status 文章狀態
  • post_type 文章類型
  • status 留言狀態,可選值有 hode, approve, spam, trash
  • type 留言類型,可選值有 pingback, trackback
  • user_id 留言者的 id
  • search 可針對留言的欄位進行關鍵字搜尋,搜尋範圍有:comment_author, comment_author_email, comment_author_url, comment_author_IP, comment_content
  • count 當為 true 時返回符合 query 條件的留言筆數,false 時返為留言 Object,預設為 false
  • meta_key 留言 meta 的 key
  • meta_value 留言 meta 的 value

範例如下:

$comment_count = get_comments( 'post_id= ' . $post_id . '&count=true' );
echo 'comment count: ' . $comment_count . '<br>';

一直對 Karma 那個參數很在意,因為從來沒看過 WP 留言內建有什麼評價機制,查了很多都沒有具體的使用範例,最後查到這一篇是說資料表裡面有一個叫 comment_karma 的欄位,是用來做防止垃圾留言機制的,但現在都沒人會用這個欄位來做留言評價的功能,所以我想應該是早期 WordPress 留下來的產物,而為了要相容舊版所以就擺在那邊了,真要做留言評分的話還是用 comment meta 來處理。

wp_insert_comment( $commentdata ) 新增留言

$commentdata 為新增留言需要提供的參數,新增完成後會返回留言 ID,範例如下:

// insert comment - sub comment from parent id
$commentdata = array(
	'comment_post_ID' => $post_id, // 指定文章
	'comment_parent' => $comment_ids[0], // 指定父留言
	'comment_content' => 'That is a pretty good idea...', // 留言內容
);
wp_insert_comment( $commentdata );

其他參數還有:comment_author, comment_author_email, comment_author_url, comment_author_IP, comment_date, comment_date_gmt, comment_karma, comment_approved, comment_agent, comment_type, comment_parent 與 user_id。

wp_delete_comment( $comment_id, $force_delete=false) 刪除留言

需要注意的是第二個參數,為 true 的話就會直接被永久刪除而無法從垃圾桶找回,範例如下:

// delete comment
wp_delete_comment( $comment->comment_ID, true );

(七)wp_commentmeta – 留言自訂欄位

wp_commentmeta 資料表結構

wp_commentmeta 相關的 Function 定義在 wp-include/comment.php,常用的如下:

get_comment_meta( $comment_id, $meta_key, $single = false ) 取得留言自訂欄位

第一個參數為留言 ID,第二個為欄位名稱,如果留空值,會回傳所有相同 $meta_key 的 $meta_value,$single 為 true 的話會以字串回傳符合第一個 $meta_key 的 $meta_value,false 的話則會使用陣列回傳所有符合的 $meta_value,範例如下:

// get comment meta - all keys
$comment_meta = get_comment_meta( $comment_id );
echo '<pre>';
print_r( $comment_meta );
echo '</pre>';

add_comment_meta( $comment_id, $meta_key, $meta_value, $unique=false ) 新增留言自訂欄位

第四個參數 $unique 為 true 時代表不允許有多筆相同的 $meta_key,範例如下:

// add comment meta - meta for view date & IP address
$viewed = array( date( "m.d.y" ), $_SERVER["REMOTE_ADDR"] );
$comment_meta_id = add_comment_meta( $comment_id, 'bwawwp_view_date', $viewed, true );
echo 'comment meta id: ' . $comment_meta_id;

update_comment_meta( $comment_id, $meta_key, $meta_value, $prev_value=”) 更新留言自訂欄位

第四個參數跟其他 xxx_meta 一樣,如果 $meta_key 有多筆符合,在 $prev_value 為空的情況下,$meta_value 只會修改第一筆 $meta_key,如果 $prev_value 有符合多筆 $meta_key 的 $meta_value 其中一筆,則這一筆的 value 會被第三個 $meta_value 給取代掉。範例如下:

// update comment meta - change date format to format like
// October 23, 2020, 12:00 am instead of 10.23.20
$viewed = array( date( "F j, Y, g:i a" ), $_SERVER["REMOTE_ADDR"] );
update_comment_meta( $comment_id, 'bwawwp_view_date', $viewed );

delete_comment_meta( $comment_id, $meta_key, $meta_value=” ) 刪除留言欄位

第三個參數當有指定 $meta_value 只會刪除符合該 value 的 $meta_key,範例如下:

// delete comment meta
delete_comment_meta( $comment_id, 'bwawwp_view_date' );

(八)wp_temrs – 該表放了文章分類 ( Category ) 名稱或是自訂分類項目 ( Term ) 的名稱,每一個分類項目都會綁定一個主分類 ( Taxonomy )。常用的文章分類與文章標籤都是一種主分類,主分類底下新增的叫做分類項目。

這邊很容易讓人搞不清楚,因為不管是 Catergory 還是 Taxonomy 中文都叫「分類」,然後中間還多一個叫 term 的東西 Orz…

後來我的理解方式是只要記得主類別 Taxonomy分類項目 Term 就好,譬如主類別是水果 ( Taxonomy ),分類項目 ( Term ) 有溫熱性水果、涼性水果、中性水果等等,至於 Category 則是文章的主類別,Tag 也是文章的主類別,一個文章類型可以有多個主類別。

順帶一提,Category 與 Tag 在技術面上的差異是前者可以有階層關係,而後者只會有一層。

文章的分類與標籤
wp_terms 資料表結構

wp_terms 相關的 Function 定義在 wp-includes/taxonomy.php,常用的如下:

get_terms( $arg=” ) 取得單一或多個主類別的分類項目

書中說明為 get_terms( $taxonomies, $args= ” ),但查官方文件指出這是 WP 4.5 版之前的寫法,之後的寫法要把 $taxonomies 放在 $args 裡面,該出以官方文件為準。

$arg 參數為帶入篩選屬性,相關屬性有:

  • taxonomy – 主分類名稱,可以用 array 帶入多筆主分類
  • orderby – 排序條件,可以是 name、count、term_group、slug,預設是 name
  • order – 排序方式,可選值為 ASC 升冪與 DESC 降冪預設為 ASC
  • hide_empty – 隱藏所屬文章篇數為 0 的分類項目
  • exclude – 排除分類項目
  • exclude_tree 排除分類項目以及它的子分類項目
  • include – 只顯示指定的分類項目
  • number – 設定顯設筆數
  • offset – 設定跳過筆數
  • fields – 選擇返回分類項目 ID 或是名稱,預設是兩個都返回
  • slug – 只顯示符合指定代稱的分類名稱
  • hierarchical – 顯示所以分類項目的子分類項目,預設為 true
  • search – 搜尋符合指定字串為分類項目名稱的結果,英文字母不區分大小寫
  • name_like – 搜尋符合開頭為指定字串的分類項目名稱結果,英文字母不區分大小寫
  • pad_counts – 預設為 true,會返回每個分類項目帶有多少子項目的數量
  • get – 設定為 all 時,會返回所有父項目或是空的分類項目
  • child_of – 取得特定分類項目的子項目
  • parent – 取得子項目的父分類項目
  • cache_domain – 啟用的話會把查詢結果存在 object cache 之中,以節省重複查詢的時間

範例如下:

$terms = get_terms( array(
    'taxonomy' => array('post_tag','category'),
    'hide_empty' => false,
) );

get_term( $term, $taxonomy, $outpug= OBJECT, $filter=’raw’ ) 取得分類項目的所有資訊

第一個參數可以是 term ID 或是 term Object,預設值為 0,會回傳所有的項目,第二個參數是該項目所屬的主分類,

$output 資料格式可以設定為 OBJECT 或是 ARRAY_A (關聯式陣列) 與 ARRAY_N(索引式陣列)。$filter 參數為設定要 sanitize 的模式,可選值有 raw、edit、db、display、attribute 與 js,這是與安全性有關的議題,會在第八章的時候提到。範例如下:

$term = get_term( 1 , 'category' );
echo $term->name;  // 顯示分類項目名稱

wp_insert_term( $term, $taxonomy, $args=array() ) 新增分類項目

第一個參數為分類項目名稱,如果已經存在的話會更新既有的,第二個參數為所屬主分類,第三個為分類項目的資料,可用參數如下:

  • alias_of – 分類項目的別名
  • description – 分類項目的描述
  • parent – 指定所屬父分類項目 ID
  • slug – 分類項目代稱

範例如下:

$parent_term = term_exists( 'fruits', 'product' ); // array is returned if taxonomy is given
$parent_term_id = $parent_term['term_id'];         // get numeric term id
wp_insert_term(
    'Apple',   // the term 
    'product', // the taxonomy
    array(
        'description' => 'A yummy apple.',
        'slug'        => 'apple',
        'parent'      => $parent_term_id,
    )
);

wp_update_term( $term_id, $taxonomy, $args=array() ) 更新分類項目資料

更新現有分類項目的資料,範例如下:

$update = wp_update_term( 1, 'category', array(
    'name' => 'Non Catégorisé',
    'slug' => 'non-categorise'
) );

wp_delete_term( $term, $taxonomy, $args=array() ) 刪除分類項目

第三個參數帶有兩個屬性,default 以及 force_default,來決定預設的分類項目。


(九)wp_termmeta – 分類項目的自訂欄位

從 WordPress 4.4 版之後就可以自訂分類項目的欄位,運用的場景可以像是決定分類項目的排列順序,或是其他任何需要擴充分類項目欄位的應用上。

wp_termmeta 資料表結構

相關的 Function 與其他 user meta、post meta、comment meta 很像,說明如下:

get_term_meta( $term_id, $meta_key=”, $single=false ) 取得分類項目自訂欄位

第一個參數為留言 ID,第二個為欄位名稱,如果留空值,會回傳所有相同 $meta_key 的 $meta_value,$single 為 true 的話會以字串回傳符合第一個 $meta_key 的 $meta_value,false 的話則會使用陣列回傳所有符合的 $meta_value。

update_term_meta( $term_id, $meta_key, $meta_value, $prev_value=” ) 更新分類項目自訂欄位

第四個參數跟其他 xxx_meta 一樣,如果 $meta_key 有多筆符合,在 $prev_value 為空的情況下,$meta_value 只會修改第一筆 $meta_key,如果 $prev_value 有符合多筆 $meta_key 的 $meta_value 其中一筆,則這一筆的 value 會被第三個 $meta_value 給取代掉。

add_term_meta( $term_id, $meta_key, $meta_value, $unique=false ) 新增分類項目自訂欄位

第四個參數 $unique 為 true 時代表不允許有多筆相同的 $meta_key。

delete_term_meta( $term_id, $meta_key, $meta_value=”) 刪除分類項目自訂欄位

第三個參數當有指定 $meta_value 只會刪除符合該 value 的 $meta_key。


(十)wp_term_taxonomy – 存放主分類 Taxonomy 的資料表

當有分類項目 Term 新增的時候,一定會綁定一個主分類 Taxonomy,WordPress 預設的主分類有 category 與 post_tag。

wp_term_taxonomy 資料表結構

wp_term_taxonomy 相關 Function 定義在 wp-includes/taxonomy.php,常用如下:

get_taxonomies( $args=array(), $output=’names’, $operator=’and’ ) 取得主分類清單

$args 可以帶入參數來篩選清單,詳細用法第五章會說明,$output 為設定返回格式,預設 names 會返回主分類名稱,或是 objects 返回主分類物件。

$operator 參數可以選擇 and 或是 or,差別在於是否完全符合或是部分符合第一個傳入參數的內容,範例如下:

$args = array(
  'public'   => true,
  '_builtin' => false
   
); 
$output = 'names'; // or objects
$operator = 'and'; // 'and' or 'or'
$taxonomies = get_taxonomies( $args, $output, $operator ); 
if ( $taxonomies ) {
    echo '<ul>';
    foreach ( $taxonomies  as $taxonomy ) {
        echo '<li>' . $taxonomy . '</li>';
    }
    echo '</ul>'; 
}

get_taxonomy( $taxonomy ) 取得特定主分類

$taxonomy 為主分類名稱,範例如下:

$rental_features = get_taxonomy( 'features' );
print_r( $rental_features );

這邊提到的主分類名稱或是 name 是指定義 Taxonomy 的英文名,而非顯示在後台的中文名字。

register_taxonomy( $taxonomy, $object_type, $args=array() ) 註冊新的主分類

如果你覺得文章只有 category 跟 post_tag 這兩個主分類不夠用,或是自定義文章需要主分類時,就可以用這支來做新增,$taxonomy 為主分類名稱,必須是英文,中文名字會在 $args 裡面的 label 來定義。

$object_type 是定義要把這個主分類綁定到哪一個文章類型上面,$args 有一堆參數來設定主分類的資料,像是上面提到的中文名字就是在這邊設定,更多詳細內容會在第五章介紹,或是看 Codex 文件有完整的說明。基本範例如下:

add_action( 'init', 'create_book_tax' );

function create_book_tax() {
	register_taxonomy(
		'genre',  // 主分類名稱
		'book',   // 文章類型
		array(
			'label' => __( '書的分類' ), // 主分類顯示名稱
			'rewrite' => array( 'slug' => 'genre' ),
			'hierarchical' => true,
		)
	);
}

書中提到之前有在討論是否該移除 wp_terms 這張表,然後把裡面的欄位移到 wp_terms_taxonomy,但後來還是為了相容性而作罷,還好沒移掉,不然手上一堆網站會爆炸@@


(十一)wp_term_relationships – 紀錄 post 與 Taxonomy 綁定關係的資料表

當使用 register_taxonomy() 的時候,第二個參數會指定文章類型,指定後就會紀錄在這張表之中。

wp_term_relationships 資料表結構

wp_term_relationships 常用 Function 如下:

get_object_taxonomies( $object, $output=’names’ ) 取得特定文章類型所擁有的主分類

第一個參數為文章類型名稱,第二個參數為設定返回格式,可以是 names 或 objects,範例如下:

$taxonomy_names = get_object_taxonomies( 'post' );
print_r( $taxonomy_names);

wp_get_object_terms( $object_ids, $taxonomies, $args= array() ) 取得特定文章類型特定主分類的分類項目

第一個參數為文章 ID,可以是字串或陣列。第二個參數是主分類名稱,可以是字串或陣列,第三個是選填的篩選參數,可以用的屬性有:

  • orderby – 排序條件,可依照 slug、term_group、term_order 來進行排序
  • order – 排序方式,可設定 ASC 升冪與 DESC 降冪
  • fields – 分類項目欄位,可選值有 ids、names、slugs 以及 all_with_object_id

範例如下:

$product_terms = wp_get_object_terms( $post->ID,  'product' );
 
if ( ! empty( $product_terms ) ) {
    if ( ! is_wp_error( $product_terms ) ) {
        echo '<ul>';
            foreach( $product_terms as $term ) {
                echo '<li><a href="' . esc_url( get_term_link( $term->slug, 'product' ) ) . '">' . esc_html( $term->name ) . '</a></li>'; 
            }
        echo '</ul>';
    }
}

wp_set_object_terms( $object_id, $terms, $taxonomy, $append=false ) 新增特定文章特定主分類的分類項目

需要注意的是第四個參數,在預設情況下如果設定的分類項目名撐已經存在,則會自動取代,反之則會保留既有的在新增一筆分類項目。範例如下:

// An array of IDs of categories we want this post to have.
$cat_ids = array( 6, 8 );
 
/*
 * If this was coming from the database or another source, we would need to make sure
 * these were integers:
 
$cat_ids = array_map( 'intval', $cat_ids );
$cat_ids = array_unique( $cat_ids );
 
 */
 
$term_taxonomy_ids = wp_set_object_terms( 42, $cat_ids, 'category' );
 
if ( is_wp_error( $term_taxonomy_ids ) ) {
    // There was an error somewhere and the terms couldn't be set.
} else {
    // Success! The post's categories were set.
}

Hooks,Actions 與 Filters

Hook 說是 WordPress 最重要的機制也不為過,不管是 Theme 還是 Plugin 開發都會需要用到大量的 Hook。什麼是 Hook?簡單說就是先在程式碼裡面貼上一個無痕掛鉤,然後要修改 WordPress 只需把你寫的程式「掛」在這個預先貼好的無痕掛鉤上就可以執行了,外「掛」就是這樣運作的。

跟感冒藥一樣,Hook 也有兩種:Actions 與 Filters。

(ㄧ)Actions – 設計新功能的掛鉤

貼上掛鉤的 Function 叫做 do_action( $tag, $arg ),它可以帶入兩個參數,第一個是掛鉤的名字,第二個是資料的參數,可以有很多個,主要作用是讓新功能掛在這邊的時候可以取得資料。

掛的動作叫做 add_action(),第一個參數是掛鉤名字,第二個是要執行新功能的 Function,下面的例子示範要如何在你的 Theme 或是 Plugin 裡面判斷使用者的登入狀態:

add_action( 'init', 'my_user_check' );

function my_user_check() {
	if ( is_user_logged_in() ) {
		echo "已登入!";
	}
}

在 WordPress 核心裡面有一個叫做 init 的掛鉤,它是被貼在當程式初始化的地方,所以只要當程式一載入,就會執行 my_user_check 這隻 Function,而這段程式碼可以放在 Theme 的 function.php 或是 Plugin 的主程式裡面,這樣要判斷會員登入狀態就不用去改 WordPress 核心程式碼。

所有可以用的 Action 可參考 —> https://adambrown.info/p/wp_hooks/hook/actions,數量足足有七百多個,但常用的大概就那幾個:init、wp_head、wp_footer 等等,其他的就等到需要的時候再去查就好。

(二)Filters – 修改內建資料的掛鉤

跟 Actions 一樣的運作邏輯,但與 Actions 的差異可以從名稱上看出來,Filter 是過濾器的意思,也就是把原本會顯示的內容多裝一個過濾器,去修改資料的最後呈現,相關 Function 說明如下:

apply_filters( $tag, $value) – 裝上過濾器

第一個參數為過濾器的名字,第二個參數決定什麼資料要被過濾,可以有很多個,同樣的,在核心程式碼中一樣有一大堆已經寫好的 Filter 等著你來用。

add_filter( $tag, $function, $priority, $accepted_args ) 使用過濾器

第一個參數為要用哪個過濾器,第二個為要修改資料的 Function,第三個是執行順序,預設值是 10,數字越小越先執行,當有很多人同時在用過濾器的時候,就用這個數字來決定使用順序。

第四個參數是可接受的參數數量,預設值是 1,實際上會根據 apply_filters 的 $value 數量來決定這個數字,下面例子說明如何修改每一篇文章標題的格式:

add_filter( 'the_title', 'my_filtered_title', 10, 2 );

function my_filtered_title( $value, $id ) {
	$value = '[' . $value . ']';
	return $value;
}

add_filter 第一個是過濾器名字,第二個是要執行的 Function,在這範例中是把文章標題左右各加入中括號,my_filtererd_title 要給兩個參數,因為過濾器 the_title 長這樣:apply_filters( ‘the_title’, $title, $id ),然後執行順序是預設值 10,最後的 2 是指定過濾器的 $title 與 $id。

$id 這個參數在這範例中沒用到,它可以拿到文章的 ID,所以可以針對文章來進行標題的過濾,範例補充如下:

add_filter( 'the_title', 'my_filtered_title', 10, 2 );

function my_filtered_title( $value, $id ) {
  if( $id === 1)
	$value = '[' . $value . ']';
	return $value;
}

這樣就只會修改文章 ID 為 1 的標題帶有中括號。

待續…

4 thoughts on “【 書摘 】Building Web Apps with WordPress

Leave a Reply

Your email address will not be published. Required fields are marked *