最近項目需要,分析了一下Wordpress的特色圖像 Feature Image的上傳、保存方式,這一分析覺得Wordpress的數據結構設計還真是有想法。
先簡單說一下結論:
Wordpress中圖像物理文件保存在
wp-content/uploads
目錄下,相關信息保存在 wp_posts 表中。post_type 是 attachment,post-mime-type 是 image/png。通過 post_parent 與文章關聯。
我原來以為圖片信息會有單獨的表存放,沒想到都放在 wp_posts 中,於是分析了這樣做有什么好處。
wp_posts 表
首先來看看 wp_posts 表。該表用來存放文章信息,如文章標題、正文、摘要、作者、發布時間、訪問密碼、評論數、修改時間、文章地址(非靜態化之前的,帶?和數字ID)等。這些屬性都是與文章相關的,同時根據 post_type的不同,該表還能用來存儲特色圖像 Featured Image。
字段 | 含義 |
---|---|
ID | 自增唯一ID |
post_author | 對應作者ID |
post_date | 發布時間 |
post_date_gmt | 發布時間(GMT+0時間) |
post_content | 正文 |
post_title | 標題 |
post_excerpt | 摘錄 |
post_status | 文章狀態(publish |
comment_status | 評論狀態(open |
ping_status | PING/Trackback狀態(open/closed) |
post_password | 文章密碼 |
post_name | 文章縮略名 |
to_ping | 要引用的URL鏈接 |
pinged | 已經PING過的鏈接 |
post_modified | 修改時間 |
post_modified_gmt | 修改時間(GMT+0時間) |
post_content_filtered | 未知 |
post_parent | 父文章,主要用於PAGE |
guid | 文章的一個鏈接。注意:不能將GUID作為永久鏈接(雖然在2.5之前的版本中它的確被當作永久鏈接),也不能將它作為文章的可用鏈接。GUID是一種獨有的標識符,只是目前恰巧成為文章的一個鏈接。 |
menu_order | 排序ID |
post_type | 文章類型(post/page/attachment/revision等) |
post_mime_type | MIME類型 |
comment_count | 評論總數 |
由此可以看到,Wordpress 利用 post_type 可以在該表中存儲草稿、文章、頁面、附件等豐富的信息,一張表就搞定了。
wp_postmeta 表
與這張表相關聯的,還有一個 wp_postmeta 表,用來存儲與文章相關的元數據。這個表的表結構比較簡單。
字段 | 含義 |
---|---|
meta_id | 元數據記錄的ID。 |
post_id | 就是元數據相關聯的post,用戶(user),評論(comment)的ID。 |
meta_key | 元鍵(meta key)(這個值在不同的記錄中經常是重復的)。 |
meta_value | 元值(meta value)(往往是唯一的)。 |
如何獲取特色圖像 Featured Image
那么,對於一個文章,是如何來獲取特色圖像 Featured Image的,下面來看一下。在后台的文章編輯界面,特色圖像顯示在這個位置。
對應的后台代碼是 wp-admin/includes/meta-boxes.php
/**
* Display post thumbnail meta box.
*
* @since 2.9.0
*
* @param WP_Post $post A post object.
*/
function post_thumbnail_meta_box( $post ) {
$thumbnail_id = get_post_meta( $post->ID, '_thumbnail_id', true ); //獲取特色圖像對應的ID
echo _wp_post_thumbnail_html( $thumbnail_id, $post->ID ); //輸出HTML
}
繼續找 get_post_meta ,在wp-includes/post.php中。
/**
* Retrieve post meta field for a post.
*
* @since 1.5.0
*
* @param int $post_id Post ID.
* @param string $key Optional. The meta key to retrieve. By default, returns
* data for all keys. Default empty.
* @param bool $single Optional. Whether to return a single value. Default false.
* @return mixed Will be an array if $single is false. Will be value of meta data
* field if $single is true.
*/
function get_post_meta( $post_id, $key = '', $single = false ) {
return get_metadata('post', $post_id, $key, $single);
}
繼續找 get_metadata 在 wp-includes/meta.php 中。
/**
* Retrieve metadata for the specified object.
*
* @since 2.9.0
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for
* the specified object.
* @param bool $single Optional, default is false.
* If true, return only the first value of the specified meta_key.
* This parameter has no effect if meta_key is not specified.
* @return mixed Single metadata value, or array of values
*/
function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) {
if ( ! $meta_type || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
//echo $object_id . ':' . $meta_type . '-' . $meta_key . '-' . $single . '<br />';
/**
* Filters whether to retrieve metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|array|string $value The value get_metadata() should return - a single metadata value,
* or an array of values.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param bool $single Whether to return only the first value of the specified $meta_key.
*/
$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single );
if ( null !== $check ) {
if ( $single && is_array( $check ) )
return $check[0];
else
return $check;
}
$meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
if ( !$meta_cache ) {
$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
$meta_cache = $meta_cache[$object_id];
}
if ( ! $meta_key ) {
return $meta_cache;
}
if ( isset($meta_cache[$meta_key]) ) {
if ( $single )
return maybe_unserialize( $meta_cache[$meta_key][0] );
else
return array_map('maybe_unserialize', $meta_cache[$meta_key]);
}
if ($single)
return '';
else
return array();
}
這個函數中會根據 $meta_key 和 $object_id 、$meta_type 取出特色圖像對應的ID。為了避免重復讀取數據庫,這里用了緩存,我們可以看 update_meta_cache 這個函數。
/**
* Update the metadata cache for the specified objects.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int|array $object_ids Array or comma delimited list of object IDs to update cache for
* @return array|false Metadata cache for the specified objects, or false on failure.
*/
function update_meta_cache($meta_type, $object_ids) {
global $wpdb;
if ( ! $meta_type || ! $object_ids ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key($meta_type . '_id');
if ( !is_array($object_ids) ) {
$object_ids = preg_replace('|[^0-9,]|', '', $object_ids);
$object_ids = explode(',', $object_ids);
}
$object_ids = array_map('intval', $object_ids);
$cache_key = $meta_type . '_meta';
$ids = array();
$cache = array();
foreach ( $object_ids as $id ) {
$cached_object = wp_cache_get( $id, $cache_key );
if ( false === $cached_object )
$ids[] = $id;
else
$cache[$id] = $cached_object;
}
if ( empty( $ids ) )
return $cache;
// Get meta info
$id_list = join( ',', $ids );
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
echo "SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC" . "<br />";
$meta_list = $wpdb->get_results( "SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC", ARRAY_A );
if ( !empty($meta_list) ) {
foreach ( $meta_list as $metarow) {
$mpid = intval($metarow[$column]);
$mkey = $metarow['meta_key'];
$mval = $metarow['meta_value'];
// Force subkeys to be array type:
if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) )
$cache[$mpid] = array();
if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) )
$cache[$mpid][$mkey] = array();
// Add a value to the current pid/key:
$cache[$mpid][$mkey][] = $mval;
}
}
foreach ( $ids as $id ) {
if ( ! isset($cache[$id]) )
$cache[$id] = array();
wp_cache_add( $id, $cache[$id], $cache_key );
}
return $cache;
}
關鍵的語句在這里
SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (21) ORDER BY meta_id ASC
可以看到結果如下,_thumbnail_id 對應的就是 wp_posts 中的記錄ID,從而可以取到圖片對應的地址和相關信息。
本文內容基於 Wordpress 4.8版本
參考資料:
1、如何設置Wordpress的特色圖像
2、WordPress數據庫表及字段詳解
3、理解和利用 WordPress 中的元數據(Metadata)