WooCommerce 金流串接實戰(四)- 資料庫結構

目錄

在開始開發金流外掛的後台設定頁面前,我們先來快速認識一下 WordPress 的資料表,同時介紹讀取寫入會用到的函式,以下為有安裝 WooCommerce 的 WordPress 網站所有的資料表:

wp_actionscheduler_actions
wp_actionscheduler_claims
wp_actionscheduler_groups
wp_actionscheduler_logs
* wp_commentmeta
* wp_comments
* wp_links
* wp_options
* wp_postmeta
* wp_posts
* wp_term_relationships
* wp_term_taxonomy
* wp_termmeta
* wp_terms
* wp_usermeta
* wp_users
wp_wc_admin_note_actions
wp_wc_admin_notes
wp_wc_category_lookup
wp_wc_customer_lookup
wp_wc_download_log
wp_wc_order_coupon_lookup
wp_wc_order_product_lookup
wp_wc_order_stats
wp_wc_order_tax_lookup
wp_wc_product_meta_lookup
wp_wc_reserved_stock
wp_wc_tax_rate_classes
wp_wc_webhooks
wp_woocommerce_api_keys
wp_woocommerce_attribute_taxonomies
wp_woocommerce_downloadable_product_permissions
wp_woocommerce_log
wp_woocommerce_order_itemmeta
wp_woocommerce_order_items
wp_woocommerce_payment_tokenmeta
wp_woocommerce_payment_tokens
wp_woocommerce_sessions
wp_woocommerce_shipping_zone_locations
wp_woocommerce_shipping_zone_methods
wp_woocommerce_shipping_zones
wp_woocommerce_tax_rate_locations
wp_woocommerce_tax_rates

WordPress 本身預設的資料表只有 * 註記的那幾個,其他都是 WooCommerce 產生的,每張表都有 wp_ 的前綴,這可以在 wp-config.php 裡面透過以下變數來修改:

$table_prefix = 'wp_'; // 在第一次安裝還沒有建立庫時修改

如果你的 WordPress 是使用套裝軟體安裝的,因為安全性考量他們會自動幫你修改資料表前綴,所以當你進入資料庫要找的是 xxx_options、xxx_posts 這些資料表,看前綴後面的名稱就好。接下來介紹五個表,分別是與設定、訂單、以及會員資料相關的表。

wp_options

該表存放全站設定相關的資料,也就是在後台左側選單 > 設定裡面的設定都會存在這張表裡面,我們要開發的 WooCommerce 金流外掛,也是把相關的變數存在這個表中。為了節省效能,在寫入時可以先把設定的值組成陣列再進行 INSERT。

#column_namedata_typecharacter_setcollationis_nullablecolumn_defaultextraforeign_keycomment
1option_idbigint(20) unsignedNULLNULLNONULLauto_increment
2option_namevarchar(191)utf8mb4utf8mb4_unicode_ciNO
3option_valuelongtextutf8mb4utf8mb4_unicode_ciNONULL
4autoloadvarchar(20)utf8mb4utf8mb4_unicode_ciNOyes

wp_options 相關的函式定義在 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( '@abc', '@cde', '@fgh' );// 用陣列來整理 option_value
add_option( 'irp_twitter_accounts', $twitters );

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

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

// update option
$twitters = array_merge(
    $twitters,
    array(
        '@ijk',
        '@lmn'
    )
);
update_option( 'irp_twitter_accounts', $twitters );

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

範例如下:

// get option
$irp_twitter_accounts = get_option( 'irp_twitter_accounts' );
foreach( $irp_twitter_accounts as $account ){
    echo $account.', '; // 輸出 @abc, @cde, @fgh, @ijk, @lmn
}

delete_option( $option_name ) 刪除設定欄位

範例如下:

// delete option
delete_option( 'irp_twitter_accounts' );

wp_posts

存放文章、頁面、選單、文章版本、以及自定義文章的資料表,而自定義文章就是用這個表裡面的 post_type 欄位來紀錄不同的文章類型,WooCommerce 商品的 post_type 為 proudct,訂單則為 shop_order,它並沒有新建資料表來存放,而是放在 wp_posts 裡面。

#column_namedata_typecharacter_setcollationis_nullablecolumn_defaultextraforeign_keycomment
1IDbigint(20) unsignedNULLNULLNONULLauto_increment
2post_authorbigint(20) unsignedNULLNULLNONULL
3post_datedatetimeNULLNULLNO0000-00-00 00:00:00
4post_date_gmtdatetimeNULLNULLNO0000-00-00 00:00:00
5post_contentlongtextutf8mb4utf8mb4_unicode_ciNONULL
6post_titletextutf8mb4utf8mb4_unicode_ciNONULL
7post_excerpttextutf8mb4utf8mb4_unicode_ciNONULL
8post_statusvarchar(20)utf8mb4utf8mb4_unicode_ciNOpublish
9comment_statusvarchar(20)utf8mb4utf8mb4_unicode_ciNOopen
10ping_statusvarchar(20)utf8mb4utf8mb4_unicode_ciNOopen
11post_passwordvarchar(255)utf8mb4utf8mb4_unicode_ciNO
12post_namevarchar(200)utf8mb4utf8mb4_unicode_ciNO
13to_pingtextutf8mb4utf8mb4_unicode_ciNONULL
14pingedtextutf8mb4utf8mb4_unicode_ciNONULL
15post_modifieddatetimeNULLNULLNO0000-00-00 00:00:00
16post_modified_gmtdatetimeNULLNULLNO0000-00-00 00:00:00
17post_content_filteredlongtextutf8mb4utf8mb4_unicode_ciNONULL
18post_parentbigint(20) unsignedNULLNULLNONULL
19guidvarchar(255)utf8mb4utf8mb4_unicode_ciNO
20menu_orderint(11)NULLNULLNONULL
21post_typevarchar(20)utf8mb4utf8mb4_unicode_ciNOpost
22post_mime_typevarchar(100)utf8mb4utf8mb4_unicode_ciNO
23comment_countbigint(20)NULLNULLNONULL

wp_posts 相關的函式定義在 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 ) 取得文章列表

當要取得文章清單時,像是最新文章列表、特定分類列表就可以使用這支函式。它是根據 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 提供很方便的作法讓你不用再自行增加資料表,每個 postmeta 使用 post_id 來對應到文章。

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

在開發金流外掛時會需要新增一些訂單欄位,像是從金流商回傳的訂單資料、卡號末四碼、以及相關資訊,而這些資料就可以放在 postmeta。

#column_namedata_typecharacter_setcollationis_nullablecolumn_defaultextraforeign_keycomment
1meta_idbigint(20) unsignedNULLNULLNONULLauto_increment
2post_idbigint(20) unsignedNULLNULLNONULL
3meta_keyvarchar(255)utf8mb4utf8mb4_unicode_ciYESNULL
4meta_valuelongtextutf8mb4utf8mb4_unicode_ciYESNULL

相關函式如下:

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, 'irp_order', 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, 'irp_displayed_field', $content );

// update post meta - hidden metadata
$content = str_replace( 'SHOULD', 'SHOULD NOT', $content );
update_post_meta( $post_id, '_irp_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, 'irp_orders', $orders, true );

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

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

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

wp_users

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

#column_namedata_typecharacter_setcollationis_nullablecolumn_defaultextraforeign_keycomment
1IDbigint(20) unsignedNULLNULLNONULLauto_increment
2user_loginvarchar(60)utf8mb4utf8mb4_unicode_ciNO
3user_passvarchar(255)utf8mb4utf8mb4_unicode_ciNO
4user_nicenamevarchar(50)utf8mb4utf8mb4_unicode_ciNO
5user_emailvarchar(100)utf8mb4utf8mb4_unicode_ciNO
6user_urlvarchar(100)utf8mb4utf8mb4_unicode_ciNO
7user_registereddatetimeNULLNULLNO0000-00-00 00:00:00
8user_activation_keyvarchar(255)utf8mb4utf8mb4_unicode_ciNO
9user_statusint(11)NULLNULLNONULL
10display_namevarchar(250)utf8mb4utf8mb4_unicode_ciNO

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

wp_insert_user( $userdata ) 新增使用者

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

// insert user
$userdata = array(
    'user_login'    => 'oberon',
    'user_pass'     => '!@oberon!@#$',
    'user_nicename' => 'oberon',
    'user_url'      => 'https://oberonlai.blog/',
    'user_email'    => 'm615926@gmail.com',
    'display_name'  => 'Oberon Lai',
    'nickname'      => 'Oberon',
    'first_name'    => 'Oberoni',
    'last_name'     => 'Lai',
    '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( 'oberon', '!@oberon!@#$', 'm615926@gmail.com' );

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,
    'user_pass'  => '!@oberon!@#$',
    'first_name' => 'Oberon',
    'last_name'  => 'Lai',
    'user_url'   => 'https://oberonlai.blog',
    'role'       => 'administrator',
);
wp_update_user( $userdata );

如果要用這個函式來讓使用者在前台更新登入密碼,記得要在 init 執行,因為它會觸發登出再登入的動作,這個動作需要清除與設定 Cookie,因此必須放在頁面的最前面來執行,也就是要比 get_header() 還要前面。

此外,重設密碼後的登入是分三個動作:wp_set_password()、wp_set_auth_cookie()、wp_set_current_user(),wp_update_user() 把這些動作都封裝起來可以直接使用。

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', 'm615926@gmail.com' );
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_usermeta

記錄使用者更多更詳細的資料,也就是除了 wp_user 已經內建的欄位以外的使用者資料,可自行新增使用者欄位,相關函式常用的如下:

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
$oberon_id = get_user_by( 'login', 'oberon' )->ID;
$oberons_wife = get_user_meta( $brian_id, 'oberon_wife', true); // Wife 可能有多個(?),true 的話回傳第一個
echo "Oberon's wife: " . $oberons_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 oberon to oberon jr.
update_user_meta( $oberon_id, 'oberon_kid', 'Oberon Jr', 'Miffy' ); // Oberon 有多個小孩(多筆相同的 meta_key),名字叫做 Miffy 的會被修改為 Oberon 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( $oberon_id, 'oberon_kid', 'Dalya' );
add_user_meta( $oberon_id, 'oberon_kid', 'Oberon Jr' );
add_user_meta( $oberon_id, 'oberon_kid', 'Nina' );
add_user_meta( $oberon_id, 'oberon_kid', 'Cam' );
add_user_meta( $oberon_id, 'oberon_kid', 'Aksel' );

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

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

// delete oberon's user meta
delete_user_meta( $oberon_id, 'oberon_wife' );
delete_user_meta( $oberon_id, 'oberon_kid', 'Miffy' ); // 沒指定 Miffy 的話則所有小孩都會被刪除

關於 WordPress 資料庫還有很多部分可以介紹,像是自訂資料表以及全域變數 \$wpdb 等等,現階段我們把焦點先放在開發金流的設定頁面上,下一篇會介紹 WooCommerce API。

目錄

賴俊吾 / Oberon Lai
賴俊吾 / Oberon Lai

現為全職 WordPress 工程師,網站開發經歷 11 年,專攻前端工程與 WordPress 佈景主題、外掛客製化開發

訂閱電子報

Hi,我是 Oberon,我會固定在每週五早上發送接案心得以及與 WordPress 相關的電子報,同時也會分享一些實用的開發知識,讓你在 WordPress 的接案路上不孤單!

覺得文章寫得好再幫我鼓個掌吧!

相關文章

WooCommerce Cat 外掛開發 (一) – 設計規劃

前情提要:WooCommerce 除了 Store API 以外,還有已經存在很久的 REST API,其強大的功能可以補足 St...

WooCommerce Store API 實戰(七)- WC REST API

前情提要:上一篇文章我們成功用 shipping meta 來增加我們所需要的資訊到 Store API 裡面,對於 Store ...

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料

專注於分享 WordPress 開發、接案技巧、專案管理等自由工作者必備知識與心得

© 2022 想點創意科技有限公司

Designed by Hend Design | 隱私權政策

訂閱電子報

Hi,我是 Oberon,我會固定在每週五早上發送接案心得以及與 WordPress 相關的電子報,同時也會分享一些實用的開發知識,讓你在 WordPress 的接案路上不孤單!