接上一篇 《WordPress插件开发入门教程》,送上一篇中级教程。
暂且不谈什么是中级,这次我想创建一个原始的数据库(表),并使其可读可写。
创建与 postmeta 表关联的数据库
创建一个完全独立的表难度很大,所以让我们创建一个与帖子数据相关联的表(postsmeta)。
WordPress有一个叫做custom field的功能,但是它保存在一个叫做postmeta的表中,所以我们要创建一个和它相关的表。
在原始表中存储自定义字段的优点
当我们创建一个自定义字段时,我们设置了一个关键键,比如“price”或“pdf”,但这都保存在“postmeta”表的“meta_key”列中。这很好,因为它很灵活,但查询性不够好。所以我们把这个做成原来的表,把key设置到原来的列,如下图。
启用插件时创建数据库
您可以直接编辑数据库,但如果您的目标是分发,则从插件自动创建它会更方便。WordPress 对此具有有用的功能。首先我们要创建一个名为「custom-meta-table」的插件。
让我们在插件文件夹中创建一个文件夹和一个文件。「plugins」→「custom-meta-table」→「custom-meta-table.php」
创建插件骨架和构造函数。
<?php
/*
Plugin Name: Custom Meta Table
Description: 将自定义的项目值储存到自制的table里。
Author: SunnyDP
Version: 0.1
Author URI: https://www.flashyonder.com/
*/
class CustomMetaTable {
//插件的名称
var $table_name;
public function __construct()
{
global $wpdb;
// 在新建table上加前缀(wp_)
$this->table_name = $wpdb->prefix . 'ex_meta';
// 插件有效时,运行。
register_activation_hook (__FILE__, array($this, 'cmt_activate'));
}
}
$exmeta = new CustomMetaTable;
在[construct]中,我们指定了表名并编写了「register_activation_hook」挂钩。
「register_activation_hook」是一个仅在插件激活时运行的挂钩。
由于「cmt_activate」被指定为自变量,您可以使用该方法编写创建表的过程。
以下所有代码都将写在这个Class中。
function cmt_activate() {
global $wpdb;
//DB的版本
$cmt_db_version = '1.0';
//取得現在DB版本
$installed_ver = get_option( 'cmt_meta_version' );
// 生成新的DB版本
if( $installed_ver != $cmt_db_version ) {
$sql = "CREATE TABLE " . $this->table_name . " (
meta_id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
post_id bigint(20) UNSIGNED DEFAULT '0' NOT NULL,
item_name text,
price int(11),
UNIQUE KEY meta_id (meta_id)
)
CHARACTER SET 'utf8';";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
//在option中保存DB版本
update_option('cmt_meta_version', $cmt_db_version);
}
}
数据库版本存储在[option]表中供以后考虑。
如果“$cmt_db_version”的版本与此“选项”不同,则创建并更新数据库。
从第9行开始是实际建表的SQL语句。
在这里,我设置了[meta_id]列来保存自己的 ID,[post_id]列与帖子表相关联,[item_name]和[price]是自定义字段值。使用第 18 行的[dbDelta],它比较数据库差异并根据需要添加或更正表。
如果在此状态下激活插件,将添加一个新表,其名称为[wp_ex_meta]。
为自定义字段创建输入字段
接下来,为文章帖子创建一个自定义字段表单。
public function __construct()
{
・・・・・
// 设定自定义字段
add_action( 'add_meta_boxes', array($this, 'ex_metabox'));
}
function ex_metabox( $post ) {
add_meta_box(
'exmeta_sectionid',
'other_column',
array($this, 'ex_meta_html'),
'post'
);
}
function ex_meta_html () {
wp_nonce_field( plugin_basename( __FILE__ ), $this->table_name );
global $post;
global $wpdb;
$get_meta = $wpdb->get_results(
$wpdb->prepare( "SELECT * FROM
".$this->table_name. " WHERE
post_id = %d", $post->ID
)
);
$get_meta = isset($get_meta[0]) ? $get_meta[0] : null;
$item_name = isset($get_meta->item_name) ? $get_meta->item_name : null;
$price = isset($get_meta->price) ? $get_meta->price : null;
?>
<div>
<table>
<tr>
<th>商品名称</th>
<td><input name="item_name" value="<?php echo $item_name ?>" /></td>
</tr>
<tr>
<th>价格</th>
<td><input name="price" value="<?php echo $price ?>" /></td>
</tr>
</table>
</div>
<?php
}
[construct]函数添加一个名为[add_meta_boxes]的动作挂钩。
在[ex_metabox]中,指定自定义字段的部分名称,和要显示的帖子类型。
在[ex_meta_html]中,描述要显示的表单。
这部分将在编辑屏幕和新帖子上显示相同的内容,因此如果数据库中有数据,它将读取数据并显示它。
保存记录
public function __construct()
{
・・・・・
add_action ('save_post', array($this, 'save_meta'));
}
function save_meta($post_id) {
if (!isset($_POST[$this->table_name])) return;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( !wp_verify_nonce( $_POST[$this->table_name], plugin_basename( __FILE__ ) ) ) return;
global $wpdb;
global $post;
//不保存重复版本
if ($post->ID != $post_id) return;
$temp_item_name = isset($_POST['item_name']) ? $_POST['item_name'] : null;
$temp_price = isset($_POST['price']) ? $_POST['price'] : null;
//保存到Array中
$set_arr = array(
'item_name' => $temp_item_name,
'price' => $temp_price
);
$get_id = $wpdb->get_var(
$wpdb->prepare( "SELECT post_id FROM
". $this->table_name ." WHERE
post_id = %d", $post_id)
);
//如果没有record添加record,如果有record,更新。
if ($get_id) {
$wpdb->update( $this->table_name, $set_arr, array('post_id' => $post_id));
} else {
$set_arr['post_id'] = $post_id;
$wpdb->insert( $this->table_name, $set_arr);
}
$wpdb->show_errors();
}
保存过程要启用挂钩,操作[save_post]。使用[$wpdb->update]更新数据,使用[$wpdb->insert]等方法保存新数据,所以我们在上一行中确认是否有数据库记录 。
第16行返回,如果是修改则不离开。
删除记录
删除帖子时,还应删除自定义字段值。
public function __construct()
{
・・・・・
add_action ('delete_post', array($this, 'dalete_meta'));
}
function dalete_meta($post_id) {
global $wpdb;
$wpdb->query( $wpdb->prepare( "DELETE FROM $this->table_name WHERE post_id = %d", $post_id) );
}
保存过程挂钩到操作[delete_post]。
有专门的保存方法,但删除可能没有,所以使用MySQL的DELETE命令。
在模板中显示
现在我们已经创建了管理屏幕的“创建”、“更新”和“删除”部分,让我们创建在模板中显示它们的方法。
function get_meta($post_id) {
if (!is_numeric($post_id)) return;
global $wpdb;
$get_meta = $wpdb->get_results(
$wpdb->prepare( "SELECT * FROM
".$this->table_name. " WHERE
post_id = %d", $post_id
)
);
return isset($get_meta[0]) ? $get_meta[0] : null;
}
当[$post_id]作为参数传递时,这将返回自定义字段的值作为对象。
例如,如果你想用[single.php]来显示,它会是这样的。
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<?php the_content(); ?>
<h4>自定义字段</h4>
<?php
$get_meta = $exmeta->get_meta($post->ID);
$item_name = isset($get_meta->item_name) ? $get_meta->item_name : null;
$price = isset($get_meta->price) ? $get_meta->price : null;
echo esc_html($item_name );
echo esc_html($price);
?>
<?php endwhile; else: ?>
<p>没有文章</p>
<?php endif; ?>
反过来也有欠缺的部分,但是我觉得整体的流程是这样的。整个代码发布如下。
<?php
/*
Plugin Name: Custom Meta Table
Plugin URI: http://www.flashyonder.com
Description:自定义的字段值保存到自制的table里
Author: SunnyDP
Version: 0.1
Author URI: http://www.flashyonder.com
*/
class CustomMetaTable {
//插件的Table名称
var $table_name;
public function __construct()
{
global $wpdb;
// 制作table的开头添加(wp_)
$this->table_name = $wpdb->prefix . 'ex_meta';
// 在插件有效时,运行
register_activation_hook (__FILE__, array($this, 'cmt_activate'));
// 制作自定义字段
add_action( 'add_meta_boxes', array($this, 'ex_metabox'));
add_action ('save_post', array($this, 'save_meta'));
add_action ('delete_post', array($this, 'dalete_meta'));
}
function cmt_activate() {
global $wpdb;
$cmt_db_version = '1.0';
$installed_ver = get_option( 'cmt_meta_version' );
// 如果table的版本不一样,执行以下程序。
if( $installed_ver != $cmt_db_version ) {
$sql = "CREATE TABLE " . $this->table_name . " (
meta_id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
post_id bigint(20) UNSIGNED DEFAULT '0' NOT NULL,
item_name text,
price int(11),
UNIQUE KEY meta_id (meta_id)
)
CHARACTER SET 'utf8';";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
update_option('cmt_meta_version', $cmt_db_version);
}
}
function ex_metabox( $post ) {
add_meta_box(
'exmeta_sectionid',
'Other_Items',
array($this, 'ex_meta_html'),
'post'
);
}
function ex_meta_html () {
wp_nonce_field( plugin_basename( __FILE__ ), $this->table_name );
global $post;
global $wpdb;
$get_meta = $wpdb->get_results(
$wpdb->prepare( "SELECT * FROM
".$this->table_name. " WHERE
post_id = %d", $post->ID
)
);
$get_meta = isset($get_meta[0]) ? $get_meta[0] : null;
$item_name = isset($get_meta->item_name) ? $get_meta->item_name : null;
$price = isset($get_meta->price) ? $get_meta->price : null;
?>
<div>
<table>
<tr>
<th>商品名称</th>
<td><input name="item_name" value="<?php echo $item_name ?>" /></td>
</tr>
<tr>
<th>价格</th>
<td><input name="price" value="<?php echo $price ?>" /></td>
</tr>
</table>
</div>
<?php
}
function save_meta($post_id) {
if (!isset($_POST[$this->table_name])) return;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( !wp_verify_nonce( $_POST[$this->table_name], plugin_basename( __FILE__ ) ) ) return;
global $wpdb;
global $post;
//不留下重复的版本
if ($post->ID != $post_id) return;
$temp_item_name = isset($_POST['item_name']) ? $_POST['item_name'] : null;
$temp_price = isset($_POST['price']) ? $_POST['price'] : null;
//为了保存,制作Array
$set_arr = array(
'item_name' => $temp_item_name,
'price' => $temp_price
);
$get_id = $wpdb->get_var(
$wpdb->prepare( "SELECT post_id FROM
". $this->table_name ." WHERE
post_id = %d", $post_id)
);
//如果没有Record,追加,如果有record,更新。
if ($get_id) {
$wpdb->update( $this->table_name, $set_arr, array('post_id' => $post_id));
} else {
$set_arr['post_id'] = $post_id;
$wpdb->insert( $this->table_name, $set_arr);
}
$wpdb->show_errors();
}
function dalete_meta($post_id) {
global $wpdb;
$wpdb->query( $wpdb->prepare( "DELETE FROM $this->table_name WHERE post_id = %d", $post_id) );
}
function get_meta($post_id) {
if (!is_numeric($post_id)) return;
global $wpdb;
$get_meta = $wpdb->get_results(
$wpdb->prepare( "SELECT * FROM
".$this->table_name. " WHERE
post_id = %d", $post_id
)
);
return isset($get_meta[0]) ? $get_meta[0] : null;
}
}
$exmeta = new CustomMetaTable;