MySQL,最熟悉的陌生人


最近深切感受到不懂資料庫語法要做一些複雜的查詢時會是一件多麼棘手的事,只能說這些年都被 WordPress 寵壞了XD,不用下任何語法只靠 PHP 就能搞定,就算搞不定用 phpMyAdmin 也是可以組成一些簡單的語法來使用,更不用說 Stackoverflow 還有一堆現成的可以貼。

而我在開發 LINE 對話機器人推播的時候碰到下圖的這個難題:

我希望可以撈出符合這些規則的 WooCommerce 訂單:訂單狀態為處理中、配送中、保留,並且付款方式為銀行轉帳或是透過 7-11 超商代碼,同時運送方式是超商取貨或是自行取貨,實際情況下使用者還可以再新增更多條件。

一開始的想法是把每所有條件組成一個大陣列然後去帶入 WP Query 的查詢參數,但之後或許還會加入其他非訂單的條件,像是以顧客的行為來做推播,因此可能會牽涉到不同的資料表。由於這功能我是參考 AutomateWoo 的介面設計的,翻了他們的程式碼讓我體認到一件事,那就是真的需要好好的從零開始學習資料庫了…

逛了一下書店找到這本「[圖解 SQL 查詢的基礎知識以 MySQL 為例](https://www.tenlong.com.tw/products/9789865028602?list_name=srh)」,由於是日本人寫的看了預覽覺得圖表很清楚,就立刻跑去圖書館借(?),最近的睡前讀物就決定是它了,希望能把資料庫的基礎知識建立起來。

你是怎麼學習資料庫的?有推薦的學習資源或書籍嗎?有的話煩請務必推薦給我!感恩啦~

前情提要:上一篇文章測試了所有在結帳流程中會使用到的 WooCommerce Store API,我們知道了該傳哪些參數以及請求方法,同時也知道了它的限制,因此我們需要自己設計新的 API 來滿足之後開發購物車外掛的需求

Store API 沒有提供以下三種我們需要的資料:付款方式列表、運送方式的附加資料像是滿額免運的金額,以及會員登入註冊功能。從前幾篇的文章我們可以知道前兩個需求是用 GET 方法來取得,而會員登入註冊需要用 POST 方法來寫入資料。

我們先從第一個取得付款方式來說明如何建立自己的 API。

取得付款方式列表

新增 API 的步驟有三個,第一步先使用 register_rest_route() 來設定 API 的請求網址、請求方法、以及處理任務的回呼函式:

woocat/v1/gateway 是我的請求網址,method 用 GET 來取得資料,callback 為要取得付款列表的函式,我們這邊先回傳 Hello World 就好,rest_ensure_response() 是 WP REST API 專用的回應方法,裡面可以接受的參數是 WP_REST_ResponseWP_ErrorWP_HTTP_Response 或是純文字與陣列,而他最後會回傳 WP_REST_Response 這個 API 專用的回應物件。

第二個步驟我們把這個函式掛在勾點 rest_api_init 上面:

php add_action( 'rest_api_init', 'register_woocat_api_route' );

這樣當我們用 Postman 以 GET 方法請求網址 https://wc.test/wp-json/woocat/v1/gateway 就可以看到輸出 Hello World 的回傳結果:

最後一個步驟我們來取得 WooCommerce 已啟用的付款方式列表,我把回呼函式改成以下內容:

使用 WC()->payment_gateways->payment_gateways() 來取得所有的付款方式,然後把有啟用的放到要回傳的陣列裡面,這個陣列由付款方式的 ID 以及標題組成的,完成後再次請求相同的 API 位置就可以得到下圖中的結果:

這邊需要注意的是「綠界信用卡(分期)」這個付款方式還需要加入分期期數的資料,而從資料庫裡面得知這個期數資料是放在 wp_optionwoocommerce_ry_ecpay_credit_installment_settings 裡面,並且用序列化的方式保存:

number_of_periods 就是分期期數資料,而裡面似乎還有其他我們可能會需要的資訊,像是付款方式名稱、描述,最小訂購金額等等,這些也許之後會派得上用場,另一方面從資料庫裡面也可以觀察到每個付款方式的設定欄位名稱都是以 woocommerce_ + gateway ID + _settings 所組成的,因此乾脆改成回傳付款方式所有的設定內容而不只有付款名稱。

再次回到 API 的回呼函式,將 $enable 陣列的內容修改如下:

再次請求 API 就能看到該付款方式的相關設定,連我們需要的分期期數都在裡面了:

透過以上步驟就完成了我們第一支自己設計的 API,但為了更融入 WooCommerce Store API 的體系之中,我們來學習一下該如何採用官方的邏輯來新增 API 。

StoreAPI 資料夾結構

撰文的當下採用的是 WooCommerce Blocks 8.1.0 版本來進行說明。

不管是在 WooCommerce Blocks 還是 WooCommerce 本身都可以看到 StoreAPI 的資料夾,它已經內建在 WooCommerce 的主程式之中,路徑位於 plugins/woocommerce/packages/woocommerce-blokcs/src/StoreApi,結構如下:

首先,StoreApi.php 是載入所有功能的主程式,RoutesController.php 控制所有 Store API 的請求路徑,Routes 資料夾是所有請求路徑的實作:

每個檔案定義了該路徑的請求方法與可接收參數,而 AbstractRoute.php 為請求路徑的抽象類別,其他所有的路徑都是透過它繼承而來,因此假設我們需要增加自己的路徑,看起來可能就是要繼承該類別來進行處理。

至於請求該路徑後會回傳什麼資料主要定義在 SchemaController.phpSchemas 資料夾之中:

結構描述 ( Schema ) 是一種說明資料格式的文件,我們在註冊 register_rest_route() 的時候可以帶入結構描述,它的主要用途是讓開發人員可以預期回傳資料的內容,藉此在處理前端時能將各種情境考量進去,另外一個好處是他能擴充同一個請求路徑的回傳資料,以及做資料過濾與驗證。

Store API 採用的是 JSON Schema 第四版,更多詳細解釋可以參考這篇: https://github.com/Hsueh-Jen/blog/issues/2

至於其他的檔案跟我們的需求好像沒有直接相關,所以先跳過等有需要的時候再回來爬吧XD,我們先來看看主程式裡面做了什麼事情~

主程式 StoreApi.php

可以看到我們上面使用過的勾點 resp_api_init 註冊了三個功能,分別是 AuthenticationLegacy 以及 RoutesController

Authentication 負責登入會員的 Cookie 設定,通常在會員已登入的情況下會產生一組 LOGGED_IN_COOKIE,而這 Cookie 必須在登入後頁面重整後才拿得到,而隨機數產生的函式 wp_create_nonce() 會根據會員 ID 來做加密,因此為了讓 Store API 不用重整頁面就能拿到這個 Cookie 來做隨機數的驗證就必須手動將 LOGGED_IN_COOKIE 寫入:

Legacy 負責相容性的部分,主要是針對在沒有支援 Checkout API 付款方式的狀況下來做相容處理,但之前實測 WooCommerce 內建的付款方法都已經可以透過 Store API 完成結帳了,在想這支類別應該是早期開發 WooCommerce Block 所使用的,我們就先忽略它吧。

另外就是 RoutesController 這個類別,它的 register_all_routes() 就是註冊所有 Store API 的方法,這邊一直讓我看不懂的地方在於 self::container->get( RouterContorller )->regiseter_all_routes() 這樣的寫法,往下看到有一個靜態方法叫做 container(),裡面宣告了 Container 類別。

回想起曾經看過的文章,發現到這應該就是傳說中的 Registry 設計模式,而 Store API 這邊是以依賴注入容器的方式來使用,目的在於雖然 Store API 已經內建在 WooCommerce 之中,但還是以 packages 的形式存放,萬一哪天要把它整合進核心檔案就可以只更換 WooCommerce 所使用的容器,藉此達成更改檔案目錄卻不用重寫類別之間的組合。

容器的 register() 方法把類別連同命名空間一起存進去,存進去的值則是該類別的實例,因此之後就可以用 get() 來呼叫已經註冊類別的實例,也就是 rest_api_init 裡面的用法。而 Store API 主要由四個類別相互依賴:

  • 建立請求路徑 Routes 需要結構資料 Schema
  • 建立結構資料 Schema 需要結構資料擴充 ExtendSchema
  • 建立結構資料擴充 ExtendSchema 需要格式化 Formatters

因此在註冊 RoutesController 實例時,需要將 SchemaController 做為參數傳入,同理,在註冊 SchemaController 也需要將 ExtendSchema 傳入:

一個接一個就像是列車一樣,好羨慕可以寫出如此精簡的結構,能將整個架構簡化成幾個類別就能搞定這背後不知道做花了多少時間與心血,也有可能重構了 N 次才能變成現在的結果。總之我們已經掌握到要新增路徑的關鍵就是在 Routes 以及 Schemas 裡面,接下來我們就把取得付款列表的路徑用繼承的方式改寫。

在 WooCommerce Blocks 存放庫裡面有 Handbook 可以參考,也有說明該如何利用 ExtendSchema 來新增回傳資料,讓我們可以在既有的路徑底下新增付款方式列表,這樣就不用再建立新的,也許這也是一條可行的路,實作看看就知道了,我們下週見!

WordPress 開發日常

Read more from WordPress 開發日常

自從 LINE Notify 終止服務後所有站長都在找尋替代方案,如果還是想在 LINE 裡面收到管理員的訂單通知,只能採用與一般顧客相同的方式,也就是申請官方帳號接收通知,雖然一樣有免費額度可以使用,但對於量大的站長來說又是一筆新的支出成本。 如果不想要新增這筆開銷,勢必要尋找其他即時通訊軟體來接收通知,像是採用 Discord 或是 Telegram,如果站長本身就沒有在使用這些軟體需要額外安裝,安裝後還需要申請開發者帳號取得金鑰,而網站這邊也要另外使用外掛或是請工程師進行串接。 難道沒有更方便、更優雅的方式來解決這個問題嗎?不僅可以在桌機上收到通知,同時還能推播到手機甚至是穿戴型裝置上,最重要的是每一則推播不會被收費、也不用擔心原本免費的方案終止服務或是漲價,而這解決方案我們在各大新聞網站都曾見過它,那就是網頁推播通知技術 ( Web Push Notification )。 外掛介紹 DWP 網站助理整合網頁推播通知,可以讓訂閱者在訂單狀態改變時收到推播訊息,支援所有平台,包含 Windows、MacOS、Android 以及 iOS...

這禮拜有幸約到網路創業家蕭上農 Fox 大大進行一對一的創業諮詢面談,從我小時候就是看著他的創業故事長大的,一直有持續在關注他分享的內容,現在自己也走在創業的這條路上,想說何不約一下已經走過這一遭的 Fox,想知道他是怎麼看 WooCommerce 外掛創業的機會。 我們談到三個大主題:OrderNotify 現況分析、創業主題的選擇、AI 浪潮下產品開發的思維。 OrderNotify 現況分析 根據我提供的銷售狀況來看,Fox 覺得這個產品在這些年的業績已經足以代表市場不夠大,目前針對的使用者族群太細了,要有使用 WooCommerce 架站又要有認真經營 LINE 官方帳號的商家數量群體本身就不夠大。 以漏斗的角度來看,這已經是最最下面的底層,業績無法有突破純粹是市場太小,如果是鎖定更大的市場,像是支援 Whatsapp 或是開發 Shopify 的 App 才有足夠大的量能讓個人開發者過活,或是要把眼光放在海外而非僅限於台灣,朝著漏斗的上方移動才行。 我用 Built with 查了一下台灣 WooCommerce 的網站數量是 10,610,以我目前的顧客數量 120...

創業是一場實驗,可以依照自己的想法去實踐的過程非常有趣,雖然免不了許多挫折失敗的時刻,但只要一想到令人興奮的點子又是希望破表。我從這篇文章開始紀錄創業的過程,希望一年後回過頭來看可以回憶起一年前的自己都在想些什麼五四三XD 上一次完全沒有案件收入的狀況要回朔到十幾年前,當時不知道該怎麼找案子,手邊的生活急用金只有兩個月,在時間壓力下只能重回職場先求溫飽。這一次從接案者的身份「離職」,為此我做足了準備,希望在資金燒完前可以找到合適自己的商業模式, 三月份我將心力放在產品的更新與行銷上,做了很多以前沒做過的事,處處充滿了新鮮感,但也因為都沒做過,不曉得哪些有效哪些沒效,所以打算以後在每個月的最後一週寫一篇創業日記,紀錄做對跟做錯了哪些事,算是幫自己回顧這一路上的過程。 第一個月設定的主要目標:行銷,在與 ChatGPT 諮詢過後,它給我的建議是公司產品是有市場的,但因為曝光量不足,所以營收無法提升,要增加曝光度為首要目標。剛好這個月 LINE Notify 停用,就決定以這個切入點來強化產品功能並撰寫行銷內容。 三月份的總工作時數為 41.12 小時,加上客服時間總計約 48...