(本文最初由Torque Magazine發表,經許可轉載。)
近年來,筆者在Torque雜誌上撰寫了大量關於面向對象PHP和WordPress REST API的文章,也涉及到使用Composer進行依賴管理和自動加載,以及單元測試。所有文章的核心觀點是:通過將已建立的軟件開發最佳實踐應用到WordPress開發中,我們可以創建更好的插件。
這是一系列文章中的第一篇,它將在一個實際的、功能性的示例中整合這些概念。我將逐步講解如何創建一個WordPress插件來修改WordPress REST API端點的功能,以便更好地優化搜索。該插件可在GitHub上找到。您可能需要瀏覽提交日誌以了解我的構建過程。
在本系列文章中,我將介紹如何使用現代面向對象PHP構建插件和類,以及如何使其可測試,以及如何為其編寫自動化測試。我將介紹單元測試、集成測試和驗收測試之間的區別,並向您展示如何編寫和自動化運行每種類型的測試。本文首先介紹如何使用面向對象的方法使用過濾器修改WordPress REST API。
關鍵要點
post_type
,從而實現更靈活和強大的搜索功能。 使用REST API改進WordPress搜索
通常使用SearchWP或Relevansi之類的插件,或與ElasticSearch(一種使用與WordPress完全不同的堆棧的技術)集成(使用Jetpack或ElasticPress),來改進WordPress搜索。這些類型的插件提供更好的搜索結果,並且通常與多方面搜索界面配合使用,這對於電子商務應用程序非常有用。
通過WordPress REST API進行搜索繼承了所有這些相同的問題和相同的解決方案。在這篇文章中,我將首先介紹搜索的默認工作方式以及其局限性。然後,我們將研究如何使用兩種不同的方法修改搜索並與SearchWP集成。
WordPress內置的搜索功能通常需要使用外部服務來改進。雖然本文是關於修改WordPress REST API帖子路由工作方式的面向對象方法,但實際示例將是改進搜索。
當WordPress用作解耦前端(例如原生移動應用程序或Web應用程序,可能使用Vue、React或Angular構建)的後端時,通過REST API進行高質量搜索非常重要。本文介紹的代碼將有助於您,如果您的應用程序用戶需要查找正確的產品變體或根據基於多個分類法的複雜算法搜索內容,並且您正在編寫自定義代碼,而不僅僅是安裝插件。
使用WordPress REST API搜索帖子
如果您想在一個站點上搜索所有帖子類型為“product”的帖子,使用搜索詞“Taco Shirts”,您將向/wp/v2/product?s=Taco Shirt
端點發出請求。如果您想提高結果的質量,上面列出的解決方案將有所幫助。
如上所述,WP_Query(WordPress REST API的帖子端點使用的東西)並不是一個很好的搜索工具。更具體地說,WP_Query可能由於其對MySQL的依賴性,不如那些傾向於使用NoSQL數據庫構建的專用搜索工具。
首先,讓我們看看如何在進行REST API請求時繞過WP_Query與WordPress數據庫的交互。
這是許多搜索插件用來替換其自身搜索系統結果(對於WP_Query默認生成的)的策略。搜索系統可以使用相同的數據庫。它也可以連接到其他數據庫,可能通過API請求,例如到ElasticSearch或Apache Solr服務器。
如果您查看WordPress核心代碼,您會發現過濾器“posts_pre_query”在WP_Query查詢數據庫之前運行,但在SQL查詢準備之後運行。此過濾器默認返回null。如果該值為null,WordPress將繼續其默認行為:查詢WordPress數據庫並將結果作為簡單的WP_Post對像數組返回。
另一方面,如果此過濾器的返回值是一個數組(希望包含WP_Post對象),則不使用WordPress的默認行為。
讓我們看看如何使用posts_pre_query返回一個模擬WP_Post。此策略對於測試非常有用,但相同模式的更複雜版本可用於將單獨的數據庫與您的WordPress站點集成:
// ... (代码示例与原文相同) ...
在此示例中,我們使用的是模擬數據,但我們可以使用SearchWP的查詢類或其他任何東西。關於這段代碼需要注意的另一件事是,它將在任何WP_Query上運行,而不僅僅是WordPress REST API創建的WP_Query對象。讓我們對其進行修改,以便除非它是WordPress REST API請求,否則我們不使用過濾器:
// ... (代码示例与原文相同) ...
修改WordPress REST API端點參數
我們剛剛研究瞭如何更改WordPress REST API請求的搜索結果生成方式。這允許我們優化查詢以獲得更好的搜索效果,但它可能會暴露出對端點不同模式的需求。
例如,如果您希望允許對產品端點的搜索可選地允許將其他帖子類型包含在搜索中,我去年介紹了另一種解決同一問題的方法。
橫切關注點
我們即將研究如何修改允許的端點參數以及如何使用它們來創建WP_Query參數。這是兩個單獨的關注點,單一職責原則指出我們需要為每個關注點創建一個類。但是這兩個類將具有共享的關注點。
例如,如果我們想允許按不同的帖子類型進行查詢,我們需要知道哪些是公共帖子類型,以及它們的slug和rest_base參數是什麼。所有這些信息都可以從函數get_post_types中獲得。
該函數的輸出並不完全是我們需要的。因此,讓我們設計一個類來根據我剛才列出的需求格式化數據,並為我們提供訪問它的輔助方法。
將其視為所有我們需要在可用容器中使用的帖子類型數據的通用形狀:
// ... (代码示例与原文相同) ...
請注意,我們沒有在類中調用get_post_types(),而是將其用作依賴項,通過構造函數注入。因此,此類可以在不加載WordPress的情況下進行測試。
這就是為什麼我會將此類描述為“單元可測試”的原因。它不依賴於任何其他API,我們也不擔心副作用。我們可以將其作為一個單獨的、隔離的單元進行測試。將關注點分離並將其功能隔離成小的部分,一旦我們有了單元測試覆蓋率,就可以使代碼易於維護。我將在我的下一篇文章中介紹如何測試這種類型的類。
請記住,此類確實依賴於WP_Post_Type。我的單元測試將沒有定義該類,因為只有集成測試才可以使用WordPress或任何其他外部依賴項。該類僅用於表示數據,而不是執行任何操作。因此,我們可以說它的使用不會產生任何副作用。因此,我很樂意在單元測試中使用模擬來代替真實的WP_Post_Type。
說到依賴注入,那些需要此新類的對象的類,我們想遵循相同的模式。我們不會在需要它們的類中實例化PreparedPostTypes,而是傳入一個實例。這意味著使用PreparedPostTypes和PreparedPostType的類保持隔離,並且可以單獨測試。
它還可以導致代碼重用,因為我們必須使依賴注入成為可能,並為此對象設置一個屬性。我們可以使用剪切和粘貼,或者我們可以使用PHP Trait,這是一種更高級、更可擴展的方法,用於在類之間複製方法和屬性。
這是一個Trait,它建立了將PreparedPostTypes對象注入其他類的模式:
// ... (代码示例与原文相同) ...
我們的另一個關注點是,我們需要在多個地方了解帖子類型的一些信息。例如帖子類型的slug。這與之前的橫切關注點略有不同。我們解決的最後一個問題涉及動態數據。現在我們只需要在一個地方更改我們在多個地方使用的字符串即可。
一個具有類常量的類為我們簡單地解決了這個問題:
// ... (代码示例与原文相同) ...
現在我們可以使這些字符串在整個代碼中保持一致。這似乎是不必要的步驟。但是我的示例代碼適用於帖子帖子類型。如果您想更改使用的帖子類型,則此類需要更改,而無需更改其他任何內容。這是遵循Tom McFarlin在他撰寫“一個類應該只有一個更改原因”時對單一職責原則的首選定義。
修改REST API端點模式
現在我們需要修改帖子類型端點的模式。通過這樣做,WordPress將向REST API端點傳達帖子類型參數是允許的,並且在解析請求時,允許新的端點參數。
這是我們的類,用於添加post_type屬性。請注意,它使用了我們剛才討論過的trait UsesPreparedPostTypes:
// ... (代码示例与原文相同) ...
在此屬性的設置中,我們告訴WordPress此屬性是一個數組屬性,我們使用數組的“enum”索引指定允許的值。
在“enum”中,我們枚舉允許的值。在這種情況下,PreparedPostTypes類提供了允許值的數組,因為這是一個先前解決的橫切關注點。
請注意,此類沒有與任何帖子類型甚至此特定用例耦合。我們將很快回到使用哪些鉤子來使此類適用於特定帖子類型。
修改REST API WP_Query參數
上一節介紹瞭如何使新的端點屬性post_type可用。這實際上並沒有更改WordPress REST API生成的WP_Query參數。除了最後一個過濾器之外,我們已經擁有所需的一切。
帖子類型是核心代碼專門不允許通過REST API請求更改的一個WP_Query參數。我們有一個動態命名的過濾器——rest_{$post_type}_query——可以覆蓋任何WP_Query參數。
這是我們的類,它注入我們的post_type參數,這些參數以前是不允許的:
// ... (代码示例与原文相同) ...
大部分內容只是驗證我們是否應該進行更改,然後使用WP_Rest_Request的get_param方法從請求中獲取值。大部分是自動的,因為我們首先修改模式以匹配。
修改WordPress REST API請求的WP_Query對象
我已經在本文的第一部分介紹瞭如何做到這一點。這是一個實現相同模式的類:
// ... (代码示例与原文相同) ...
我希望您注意到這段代碼與WordPress緊密相關,並且不可測試。它使用來自WordPress的WP_Post,它正在檢查WordPress的常量,並與WordPress的插件API交互。我們可以模擬WP_Post,並且我們可以自己設置常量。但是插件的API——這是需要測試的重要功能。在我的接下來的幾篇文章中,我將介紹如何重構此類,以便我們可以使用單元測試來涵蓋除刪除該過濾器的效果之外的所有內容,並使用集成測試來檢查該效果。
我選擇使用靜態方法有兩個原因。首先,它使在多個位置添加和刪除它變得很容易。例如,在ModifyQuery類中,我只在需要時才掛鉤此過濾器:
// ... (代码示例与原文相同) ...
此外,在使用此過濾器時很容易創建遞歸循環。能夠像在此示例代碼中一樣輕鬆地刪除它非常不錯。
我選擇使用靜態方法的另一個原因是該函數與其他API交互。它永遠不會真正可進行單元測試。這種模式,一個具有靜態方法的類,使得在集成測試中模擬該類變得非常容易,從而最大限度地減少了在這個系統的一個部分中缺乏強隔離的影響。
使所有內容協同工作
到目前為止,我們看到的代碼與WordPress非常脫鉤。這有很多好處。但這意味著它本身什麼也不做。這很好。我們到目前為止只處理了業務邏輯需求。現在我們需要考慮集成。
這並不難,只需要添加一些鉤子即可。哪些鉤子?與我們為ModifyQuery和ModifySchema類設計的完全相同的兩個鉤子。對解耦業務邏輯的渴望並不意味著我們在設計其公共接口時不能考慮編寫代碼的實際原因。否則,我們只會毫無理由地為我們的代碼增加額外的複雜性。
一般來說,我盡量只在它使生活更輕鬆時才增加軟件複雜性。我過去偏離了這條道路。我們都有過,沒關係,練習寬恕。
我們即將掛鉤的類中的方法與鉤子使用完全相同的參數和返回類型。它們的工作是將這些值分派給其他組件。
// ... (代码示例与原文相同) ...
下一步:測試
這已經足夠接近了。它會起作用。由於缺乏添加鉤子的正式系統,這是我們可以為初始化做的最好的事情。這很好。我將在未來關於WordPress集成測試的文章中介紹如何創建一個更複雜和可擴展的引導過程。
在這篇文章中,我們研究了創建代碼來修改模式、WP_Query參數生成和帖子類型的底層WP_Query。我鼓勵您將此代碼轉換為插件,使用Composer進行自動加載。在我的下一篇文章中,我們將研究單元測試以涵蓋這些類。
(以下為原文FAQ部分,已根據原文內容進行偽原創)
關於WordPress中高級OOP和自定義REST API端點的常見問題解答
面向對象編程(OOP)在WordPress中的意義是什麼?
面向對象編程(OOP)是一種使用“對象”設計應用程序和軟件的編程範式。在WordPress環境中,OOP為開發複雜的應用程序提供了一種簡潔、高效和健壯的方法。它允許開發人員將相關任務分組到類和對像中,使代碼更易於閱讀、重用和維護。 OOP還通過封裝數據並防止外部直接訪問來增強應用程序的安全性。
如何在WordPress中自定義REST API端點?
WordPress REST API提供了一組用於不同類型數據的默認端點。但是,您可以自定義這些端點或創建新的端點以滿足您的特定需求。這可以通過在您的插件或主題中使用register_rest_route()
函數來完成。此函數允許您指定端點的路由或URL,並定義它應該響應的方法(GET、POST等)。
自定義WordPress REST API端點的優勢是什麼?
自定義WordPress REST API端點允許您創建更高效、更靈活和更安全的應用程序。您可以調整端點返回的數據,減少通過網絡發送的不必要數據量。您還可以創建執行特定任務的端點,例如處理表單提交或生成報告,從而使您的應用程序更具交互性和用戶友好性。
OOP如何增強WordPress應用程序的安全性?
OOP通過將數據和方法封裝在對像中來增強WordPress應用程序的安全性。這意味著對象的屬性(數據)和方法(函數)對應用程序的其餘部分隱藏,並且只能通過對象的方法訪問。這可以防止未經授權訪問和操作數據,從而降低安全漏洞的風險。
OOP可以與舊版本的WordPress一起使用嗎?
是的,您可以將OOP與舊版本的WordPress一起使用。但是,需要注意的是,較新版本的WordPress對OOP的支持有所改進,並且包含許多功能,使使用此範式進行開發更容易。因此,雖然可以使用OOP與舊版本一起使用,但通常建議使用最新版本的WordPress以獲得最佳的開發體驗。
類和對像在OOP中的作用是什麼?
在OOP中,類是創建對象的藍圖或模板。它定義了對象應該具有的屬性(數據)和方法(函數)。另一方面,對像是類的實例。它具有自己的一組屬性和方法,這些屬性和方法可能與同一類的其他對像不同。類和對象的使用使代碼更具組織性、可重用性和易於維護性。
如何在WordPress中創建一個新類?
您可以使用class
關鍵字,後跟類名和一組花括號{}
來在WordPress中創建一個新類。在括號內,您可以定義類的屬性和方法。要創建類的對象,您可以使用new
關鍵字,後跟類名。
WordPress中的REST API是什麼?
WordPress中的REST API是一個接口,允許您使用HTTP請求與WordPress站點交互。它為不同類型的數據(例如帖子、評論和用戶)提供了一組端點,您可以使用標準HTTP方法(如GET、POST、PUT和DELETE)來訪問這些端點。 REST API使您可以更輕鬆地從外部應用程序創建、讀取、更新和刪除WordPress站點中的數據。
如何在WordPress中訪問REST API?
您可以通過向相應的端點發送HTTP請求來訪問WordPress中的REST API。每個端點對應於特定類型的數據,並支持某些HTTP方法。例如,要檢索帖子列表,您可以向/wp/v2/posts
端點發送GET請求。 REST API將以JSON格式返回數據,然後您可以在應用程序中處理和顯示這些數據。
我可以將REST API與非WordPress應用程序一起使用嗎?
是的,您可以將REST API與非WordPress應用程序一起使用。 REST API是平台無關的,這意味著它可以與任何可以發送HTTP請求和處理JSON數據的應用程序一起使用。這使其成為將WordPress站點與其他應用程序(例如移動應用程序、桌面應用程序和其他Web服務)集成的強大工具。
以上是WordPress的高級OOP:自定義REST API端點的詳細內容。更多資訊請關注PHP中文網其他相關文章!