什么是自定義post?
不要想當(dāng)然的認(rèn)為這里的post就是就是指博客中的文章,它只不過(guò)是一個(gè)文章類的代理詞而已,甚至你還可以認(rèn)為它是內(nèi)容。
自定義模型是沒(méi)有一個(gè)很標(biāo)準(zhǔn)的什么規(guī)定的,文章模型可以是你想的任何一個(gè)內(nèi)容模型,就拿wordpress本身來(lái)說(shuō)就內(nèi)置了以下幾個(gè)內(nèi)容文章模型:
- 博客文章
- 頁(yè)面
- 附件
- 修正
- 導(dǎo)航等
你可以這樣去理解:它只要是想我們使用博客文章那樣用來(lái)創(chuàng)建、編輯和儲(chǔ)存數(shù)據(jù)的一種很靈活的內(nèi)容形式。
不過(guò)在這里我還是需要提醒下,博客內(nèi)置的post還是有點(diǎn)點(diǎn)不同的,你可以利用它含有分類、標(biāo)簽等去標(biāo)識(shí)內(nèi)容的!
為什么要自定義文章模型?
wordpress已經(jīng)提供一些完善的默認(rèn)文章模型,并適用于大多數(shù)站點(diǎn),但我們還是需要更多的選擇。我列舉了一些我想到的一些可能有用內(nèi)容模型,并鏈接到相對(duì)應(yīng)的例子。
- 房產(chǎn)清單
- 活動(dòng)日歷(我知道很多人對(duì)這個(gè)感興趣)
- 影視資料庫(kù)
- 書(shū)籍資料庫(kù)
- 沒(méi)有很多集成問(wèn)題的論壇系統(tǒng)
- 類似wordpress trac的票務(wù)系統(tǒng)
- 設(shè)計(jì)相冊(cè)或作品集
你還可以想到我列舉之外的更多內(nèi)容模型。而且我也想在以后學(xué)習(xí)更多關(guān)于論壇和票務(wù)系統(tǒng)的想法。這兩個(gè)系統(tǒng)我已經(jīng)實(shí)現(xiàn)并希望的得到一些反饋。
創(chuàng)建一個(gè) post type
創(chuàng)建一個(gè)新的 post type 需要使用 register_post_type 函數(shù)來(lái)注冊(cè)一下。需要在你主題的 functions.php 文件下調(diào)用該函數(shù):
1
|
register_post_type( $post_type , $args ); |
$post_type 參數(shù)就是你自定義 post type 的名稱,post type 可以自定義的功能非常多,所以這個(gè)函數(shù)里面的 $args 參數(shù)會(huì)很多。所以通常會(huì)用下面這種格式來(lái)注冊(cè):
1
2
3
4
5
|
function my_custom_post_product() { $args = array (); register_post_type( 'product' , $args ); } add_action( 'init' , 'my_custom_post_product' ); |
包裹在一個(gè)函數(shù)中,定義一個(gè)數(shù)組,然后掛靠到 init 這個(gè) action 上。這樣 wordpress 在初始化的時(shí)候,就會(huì)執(zhí)行這個(gè)函數(shù)注冊(cè)一個(gè)自定義 post type,因?yàn)檎{(diào)用 register_post_type() 的時(shí)候,必須要在 admin_menu action 之前,在 after_setup_theme action 之后,所以這里最好掛靠到 init action 上。
參數(shù)很多,為了寫(xiě)教程方便,只列出比較常用的參數(shù),大體結(jié)構(gòu)如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
function my_custom_post_movie() { $labels = array ( 'name' => _x( 'movies' , 'post type 名稱' ), 'singular_name' => _x( 'movie' , 'post type 單個(gè) item 時(shí)的名稱,因?yàn)橛⑽挠袕?fù)數(shù)' ), 'add_new' => _x( '新建電影' , '添加新內(nèi)容的鏈接名稱' ), 'add_new_item' => __( '新建一個(gè)電影' ), 'edit_item' => __( '編輯電影' ), 'new_item' => __( '新電影' ), 'all_items' => __( '所有電影' ), 'view_item' => __( '查看電影' ), 'search_items' => __( '搜索電影' ), 'not_found' => __( '沒(méi)有找到有關(guān)電影' ), 'not_found_in_trash' => __( '回收站里面沒(méi)有相關(guān)電影' ), 'parent_item_colon' => '' , 'menu_name' => 'movies' ); $args = array ( 'labels' => $labels , 'description' => '我們網(wǎng)站的電影信息' , 'public' => true, 'menu_position' => 5, 'supports' => array ( 'title' , 'editor' , 'thumbnail' , 'excerpt' , 'comments' ), 'has_archive' => true ); register_post_type( 'movie' , $args ); } add_action( 'init' , 'my_custom_post_movie' ); |
這里為了直觀方便,我直接使用了中文,更好的應(yīng)該是使用英文然后通過(guò)本地化函數(shù)來(lái)翻譯成中文。
參數(shù)有點(diǎn)多,也可以使用 generatewp 工具自定義參數(shù),然后改改,會(huì)稍微方便一點(diǎn)。
從上面代碼可以看到 $args 數(shù)組里面有一個(gè) labels 配置項(xiàng),用來(lái)配置顯示文案有關(guān)的內(nèi)容,為了清晰所以單獨(dú)拿出來(lái)創(chuàng)建了一個(gè)數(shù)組。其他配置項(xiàng)看下英文也能猜出大體意思,如果想要詳細(xì)了解,可以看下官方文檔:register_post_type 。
將上面代碼加到主題 functions.php 的最下面,進(jìn)入后臺(tái)你會(huì)發(fā)現(xiàn)多出了 movies 選項(xiàng),這樣表示注冊(cè)成功:
這時(shí)候我們可以新建 movie 發(fā)表一篇電影類型的文章了。但是這樣與文章類型基本相同,我們需要更多的自定義來(lái)完善我們的 movie 類型。
為 post type 添加分類功能
就電影來(lái)說(shuō),可以分為科幻、動(dòng)作、戰(zhàn)爭(zhēng)等類別,那么我們就為自定義的 movie 添加分類功能,這樣就可以編輯新分類以及歸類我們的電影了。這個(gè)分類跟文章里面的分類性質(zhì)是一樣的。
添加分類功能需要使用函數(shù) register_taxonomy,使用方法也很簡(jiǎn)單,跟注冊(cè) post type 函數(shù)類似,只不過(guò)多了一個(gè)參數(shù)用來(lái)指定對(duì)應(yīng)的 post type :
1
|
register_taxonomy( $taxonomy , $object_type , $args ); |
就本例而言,可以配置如下常用參數(shù):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
function my_taxonomies_movie() { $labels = array ( 'name' => _x( '電影分類' , 'taxonomy 名稱' ), 'singular_name' => _x( '電影分類' , 'taxonomy 單數(shù)名稱' ), 'search_items' => __( '搜索電影分類' ), 'all_items' => __( '所有電影分類' ), 'parent_item' => __( '該電影分類的上級(jí)分類' ), 'parent_item_colon' => __( '該電影分類的上級(jí)分類:' ), 'edit_item' => __( '編輯電影分類' ), 'update_item' => __( '更新電影分類' ), 'add_new_item' => __( '添加新的電影分類' ), 'new_item_name' => __( '新電影分類' ), 'menu_name' => __( '電影分類' ), ); $args = array ( 'labels' => $labels , 'hierarchical' => true, ); register_taxonomy( 'movie_category' , 'movie' , $args ); } add_action( 'init' , 'my_taxonomies_movie' , 0 ); |
添加到主題之后,我們看到出現(xiàn)了熟悉的文章分類功能,只不過(guò)上面的文案全部變成我們自定義的內(nèi)容了:
這里我們添加兩個(gè)分類作為演示。
為 post type 添加自定義 meta box
我們想要添加的電影類型不能僅僅只有正文內(nèi)容,我們還需要額外添加一些 導(dǎo)演 之類的有關(guān)內(nèi)容。那么就需要添加自定義 meta box,meta box 可以在文章發(fā)表頁(yè)面中添加自定義的表單,編寫(xiě)文章的時(shí)候可以填寫(xiě)額外的信息然后在前端調(diào)用出來(lái)。
自定義 meta box 需要用到 add_meta_box 函數(shù):
1
|
add_meta_box( $id , $title , $callback , $post_type , $context , $priority , $callback_args ); |
老規(guī)矩,具體參數(shù)內(nèi)容查看官方文檔,這里只介紹常用用法。我們注冊(cè)一個(gè) meta box :
1
2
3
4
5
6
7
8
9
10
11
|
add_action( 'add_meta_boxes' , 'movie_director' ); function movie_director() { add_meta_box( 'movie_director' , '電影導(dǎo)演' , 'movie_director_meta_box' , 'movie' , 'side' , 'low' ); } |
然后在配置參數(shù)里面指定了回調(diào)函數(shù) movie_director_meta_box,我們需要在這個(gè)函數(shù)里面創(chuàng)建表單:
1
2
3
4
5
6
7
8
9
10
|
function movie_director_meta_box( $post ) { // 創(chuàng)建臨時(shí)隱藏表單,為了安全 wp_nonce_field( 'movie_director_meta_box' , 'movie_director_meta_box_nonce' ); // 獲取之前存儲(chǔ)的值 $value = get_post_meta( $post ->id, '_movie_director' , true ); ?> <label for = "movie_director" ></label> <input type= "text" id= "movie_director" name= "movie_director" value= "<?php echo esc_attr( $value ); ?>" placeholder= "輸入導(dǎo)演名稱" > <?php } |
這樣就可以在文章界面邊欄顯示出來(lái)剛剛創(chuàng)建的表單了:
但是這時(shí)候,你的表單是沒(méi)法用的,因?yàn)槟闾峤晃恼轮蟛](méi)有保存這個(gè) meta box 的內(nèi)容,下面是驗(yàn)證保存內(nèi)容的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
add_action( 'save_post' , 'movie_director_save_meta_box' ); function movie_director_save_meta_box( $post_id ){ // 安全檢查 // 檢查是否發(fā)送了一次性隱藏表單內(nèi)容(判斷是否為第三者模擬提交) if ( ! isset( $_post [ 'movie_director_meta_box_nonce' ] ) ) { return ; } // 判斷隱藏表單的值與之前是否相同 if ( ! wp_verify_nonce( $_post [ 'movie_director_meta_box_nonce' ], 'movie_director_meta_box' ) ) { return ; } // 判斷該用戶是否有權(quán)限 if ( ! current_user_can( 'edit_post' , $post_id ) ) { return ; } // 判斷 meta box 是否為空 if ( ! isset( $_post [ 'movie_director' ] ) ) { return ; } $movie_director = sanitize_text_field( $_post [ 'movie_director' ] ); update_post_meta( $post_id , '_movie_director' , $movie_director ); } |
雖然最關(guān)鍵的函數(shù)就在最后一句,但是一定要注意安全的校驗(yàn)。把這些代碼添加進(jìn) functions.php 文件之后,你的 meta box 就可以正常工作了。如果你需要更多表單,按照這個(gè)模式自定義表單結(jié)構(gòu),然后添加保存函數(shù)即可。
下面,我們迫不及待的添加兩部電影《魚(yú)與鍋之戰(zhàn):宿命對(duì)決》 和 《魚(yú)與鍋之戰(zhàn):我愛(ài)水煮魚(yú)》 內(nèi)容如下:
添加完之后,我們可以看下所有電影:
列表空蕩蕩的,好難看,我可不可以加上導(dǎo)演字段?當(dāng)然可以,使用 [manage $post type posts custom column](http://codex.wordpress.org/plugin_api/action_reference/manage_$post_type_posts_custom_column) 即可實(shí)現(xiàn),我們添加:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
add_action( "manage_posts_custom_column" , "movie_custom_columns" ); add_filter( "manage_edit-movie_columns" , "movie_edit_columns" ); function movie_custom_columns( $column ){ global $post ; switch ( $column ) { case "movie_director" : echo get_post_meta( $post ->id, '_movie_director' , true ); break ; } } function movie_edit_columns( $columns ){ $columns [ 'movie_director' ] = '導(dǎo)演' ; return $columns ; } |
即添加了列導(dǎo)演字段,并從每篇文章中讀取出來(lái)。這樣我們的列表就變成了:
ok,我們的后端部分就這樣愉快的完成了。打開(kāi)生成好的鏈接看下,咦,not found?是這樣的,如果你的網(wǎng)站設(shè)置了固定連接,當(dāng)你新建了 post type 之后,你必須要在后臺(tái)更新一下固定連接設(shè)置才行。找到后臺(tái)固定連接,再點(diǎn)擊一下下面的“保存設(shè)置”,之后就可以正常訪問(wèn)了。
展示 post type 的內(nèi)容
單純創(chuàng)建 post type 只是可以讓你輸入內(nèi)容,沒(méi)有什么意義,我們還需要在前臺(tái)輸出自定義 post type 的內(nèi)容。
自定義 post type 的模板和樣式
根據(jù) wordpress 的模板調(diào)用規(guī)則 我們可以得知,我們只需要?jiǎng)?chuàng)建 archive-[post_type].php 和 single-[post_type].php 就可以實(shí)現(xiàn)該 post type 的列表自定義和文章自定義。當(dāng)訪問(wèn) post type,wordpress 會(huì)優(yōu)先調(diào)用這些模板來(lái)渲染。
需要注意的是,你需要在注冊(cè) post type 的時(shí)候設(shè)置 'has_archive' => true 才會(huì)有列表。
現(xiàn)在我們就把主題里自帶的 archive.php 和 single.php 文件復(fù)制一份命名為 archive-movie.php 和 single-movie.php,為了演示,這里我不做很多自定義,只是輸出導(dǎo)演信息表示一下。
我們分別在 l.56 和 l.23 附近的合適位置輸出 meta box 信息:
1
|
echo '導(dǎo)演:' .get_post_meta( get_the_id(), '_movie_director' , true ); |
然后刷新訪問(wèn)電影列表和具體的電影就可以看到輸出的導(dǎo)演信息了。
這里只是舉個(gè)例子,實(shí)際中往往會(huì)自定義結(jié)構(gòu)和輸出的信息格式等,這里不再進(jìn)一步修改。這里不再麻煩演示了。
調(diào)用 wp_query 高度自定義調(diào)用 post type 的內(nèi)容
上面操作依賴模板,如果需要高度自定義或者在頁(yè)面的某個(gè)模塊中調(diào)用列表,就需要用到 wp_query 類來(lái)調(diào)用:
1
2
3
4
5
6
7
8
|
$args = array ( 'post_type' => 'product' , 'posts_per_page' => 10 ); $loop = new wp_query( $args ); while ( $loop ->have_posts() ) : $loop ->the_post(); the_title(); echo '<div class="entry-content">' ; the_content(); echo '</div>' ; endwhile ; |
查詢出來(lái)之后就跟常規(guī)的主循環(huán)一樣了,自定輸出結(jié)構(gòu)即可。
在首頁(yè)列表中顯示自定義 post type 的內(nèi)容
雖然我們自定義好了 post type 同時(shí)也編寫(xiě)了一些內(nèi)容,但是在首頁(yè)的列表里面并沒(méi)有顯示出來(lái)。自定義的 post type 的內(nèi)容不會(huì)自動(dòng)混入主循環(huán)里面。那如何讓自定義 post type 的內(nèi)容顯示出來(lái)?
你需要使用 pre_get_posts 這個(gè) action 來(lái)做一些處理:
1
2
3
4
5
6
|
add_action( 'pre_get_posts' , 'add_my_post_types_to_query' ); function add_my_post_types_to_query( $query ) { if ( is_home() && $query ->is_main_query() ) $query ->set( 'post_type' , array ( 'post' , 'page' , 'movie' ) ); return $query ; } |
在上面的 $query 變量里面設(shè)置的 post_type 數(shù)組就是要在主循環(huán)里面展示的內(nèi)容,將你的自定義 post type 填寫(xiě)進(jìn)去就可以在首頁(yè)中顯示出來(lái)了。
設(shè)置自定義 post type 的固定連接
創(chuàng)建一個(gè)新的 post type 有時(shí)候也是為了更方便做 seo,所以設(shè)置它的固定連接也非常重要。這里主要用到注冊(cè) post type 的參數(shù)數(shù)組里面的 rewrite 參數(shù),常用以下幾兩項(xiàng):
slug =》自定義固定連接結(jié)構(gòu)別名,默認(rèn)是使用 post type 名(例如本例的 movie),可以被翻譯。一般來(lái)說(shuō) post type 名可能與實(shí)際需要的 url 不一樣( post type 為 movie,但 url 可能需要 movies),就可使用該項(xiàng)自定義。
with_front =》 固定連接是否以根目錄為基礎(chǔ)路徑。如果你在固定連接設(shè)置頁(yè)面設(shè)置你的結(jié)構(gòu)為 /archives/,那么你的 post type 生成的連接默認(rèn)為 /archives/movie 如果設(shè)置該項(xiàng)為 false 即可去掉前面的 /archives/ 直接基于根路徑生成固定連接。
大功告成,但這只是 post type 最基礎(chǔ)的用法,post type 還有其他更高級(jí)的用法,更詳細(xì)的參數(shù)配置還需要你去進(jìn)一步挖掘來(lái)適應(yīng)你網(wǎng)站的功能需求。