在开始开发金流外挂的後台设定页面前,我们先来快速认识一下 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 这些资料表,看前缀後面的名称就好。接下来介绍五个表,分别是与设定、订单、以及会员资料相关的表。
该表存放全站设定相关的资料,也就是在後台左侧选单 > 设定里面的设定都会存在这张表里面,我们要开发的 WooCommerce 金流外挂,也是把相关的变数存在这个表中。为了节省效能,在写入时可以先把设定的值组成阵列再进行 INSERT。
# | column_name | data_type | character_set | collation | is_nullable | column_default | extra | foreign_key | comment |
---|---|---|---|---|---|---|---|---|---|
1 | option_id | bigint(20) unsigned | NULL | NULL | NO | NULL | auto_increment | ||
2 | option_name | varchar(191) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
3 | option_value | longtext | utf8mb4 | utf8mb4_unicode_ci | NO | NULL | |||
4 | autoload | varchar(20) | utf8mb4 | utf8mb4_unicode_ci | NO | yes |
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' );
存放文章、页面、选单、文章版本、以及自定义文章的资料表,而自定义文章就是用这个表里面的 post_type 栏位来纪录不同的文章类型,WooCommerce 商品的 post_type 为 proudct,订单则为 shop_order,它并没有新建资料表来存放,而是放在 wp_posts 里面。
# | column_name | data_type | character_set | collation | is_nullable | column_default | extra | foreign_key | comment |
---|---|---|---|---|---|---|---|---|---|
1 | ID | bigint(20) unsigned | NULL | NULL | NO | NULL | auto_increment | ||
2 | post_author | bigint(20) unsigned | NULL | NULL | NO | NULL | |||
3 | post_date | datetime | NULL | NULL | NO | 0000-00-00 00:00:00 | |||
4 | post_date_gmt | datetime | NULL | NULL | NO | 0000-00-00 00:00:00 | |||
5 | post_content | longtext | utf8mb4 | utf8mb4_unicode_ci | NO | NULL | |||
6 | post_title | text | utf8mb4 | utf8mb4_unicode_ci | NO | NULL | |||
7 | post_excerpt | text | utf8mb4 | utf8mb4_unicode_ci | NO | NULL | |||
8 | post_status | varchar(20) | utf8mb4 | utf8mb4_unicode_ci | NO | publish | |||
9 | comment_status | varchar(20) | utf8mb4 | utf8mb4_unicode_ci | NO | open | |||
10 | ping_status | varchar(20) | utf8mb4 | utf8mb4_unicode_ci | NO | open | |||
11 | post_password | varchar(255) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
12 | post_name | varchar(200) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
13 | to_ping | text | utf8mb4 | utf8mb4_unicode_ci | NO | NULL | |||
14 | pinged | text | utf8mb4 | utf8mb4_unicode_ci | NO | NULL | |||
15 | post_modified | datetime | NULL | NULL | NO | 0000-00-00 00:00:00 | |||
16 | post_modified_gmt | datetime | NULL | NULL | NO | 0000-00-00 00:00:00 | |||
17 | post_content_filtered | longtext | utf8mb4 | utf8mb4_unicode_ci | NO | NULL | |||
18 | post_parent | bigint(20) unsigned | NULL | NULL | NO | NULL | |||
19 | guid | varchar(255) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
20 | menu_order | int(11) | NULL | NULL | NO | NULL | |||
21 | post_type | varchar(20) | utf8mb4 | utf8mb4_unicode_ci | NO | post | |||
22 | post_mime_type | varchar(100) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
23 | comment_count | bigint(20) | NULL | NULL | NO | NULL |
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 );
如果内建的文章栏位不够用,想要新增其他栏位的话就会写在这张表中。WordPress 提供很方便的作法让你不用再自行增加资料表,每个 postmeta 使用 post_id 来对应到文章。
如果你需要新增栏位但又不想让使用者在文章编辑画面看到该栏位,可以用下底线开头的栏位名称,这样 WordPress 会自动在後台隐藏这个栏位而不被使用者看见。
在开发金流外挂时会需要新增一些订单栏位,像是从金流商回传的订单资料、卡号末四码、以及相关资讯,而这些资料就可以放在 postmeta。
| # | column_name | data_type | character_set | collation | is_nullable | column_default | extra | foreign_key | comment |
|---|-------------|---------------------|---------------|--------------------|-------------|----------------|----------------|-------------|---------|
| 1 | meta_id | bigint(20) unsigned | NULL | NULL | NO | NULL | auto_increment | | |
| 2 | post_id | bigint(20) unsigned | NULL | NULL | NO | NULL | | | |
| 3 | meta_key | varchar(255) | utf8mb4 | utf8mb4_unicode_ci | YES | NULL | | | |
| 4 | meta_value | longtext | utf8mb4 | utf8mb4_unicode_ci | YES | NULL | | | |
相关函式如下:
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' );
存放使用者帐密与基本资料,如果要从资料库修改使用者相关资讯,像是客户忘记密码或是要新增一个管理员帐号,就可以在这个表进行处理。
# | column_name | data_type | character_set | collation | is_nullable | column_default | extra | foreign_key | comment |
---|---|---|---|---|---|---|---|---|---|
1 | ID | bigint(20) unsigned | NULL | NULL | NO | NULL | auto_increment | ||
2 | user_login | varchar(60) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
3 | user_pass | varchar(255) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
4 | user_nicename | varchar(50) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
5 | user_email | varchar(100) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
6 | user_url | varchar(100) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
7 | user_registered | datetime | NULL | NULL | NO | 0000-00-00 00:00:00 | |||
8 | user_activation_key | varchar(255) | utf8mb4 | utf8mb4_unicode_ci | NO | ||||
9 | user_status | int(11) | NULL | NULL | NO | NULL | |||
10 | display_name | varchar(250) | utf8mb4 | utf8mb4_unicode_ci | NO |
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' => '[email protected]',
'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!@#$', '[email protected]' );
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', '[email protected]' );
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_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。
本文同步发表於:https://oberonlai.blog/tw/woocommerce-payment-database/
<<: Day 04 : 找不出的零钱 Non-constructible Change
Chap.O 程序基础 & 简介: Part 1. 常用於演算法的开发程序,有以下几种: 1...
一、前言 上一篇文章的结尾有提到大家可以在职场上定时自我检视的小习惯,这边分享我自己维持几个月後...
传递机制听起来非常没有画面感,於是擅自替传递机制取了绰号叫回力镖,如同回力镖有去程,回程以及猎捕到猎...
对元素设置.font-weight-normal可以让文字和符号以预设呈现。 <p clas...
很快地已经学了十天,今天又是一个新的开始,今天要来认识「阵列」。 阵列(Array)是由同型别的相关...