WordPress插件開發(fā)教程手冊(cè) — JavaScript、Ajax 和 jQuery
本教程詳細(xì)介紹了在WordPress插件開發(fā)中使用JavaScript、jQuery和Ajax的方法。內(nèi)容涵蓋jQuery的基本語句、選擇器和事件處理,以及如何通過Ajax實(shí)現(xiàn)異步數(shù)據(jù)交換。適合開發(fā)者學(xué)習(xí)如何高效開發(fā)功能豐富的WordPress插件。
JavaScript 是很多 WordPress插件中重要的一部分,Wordpress 內(nèi)置了一些常用的 JavaScript 庫,來幫助我們減少工作量,其中最常用的就是 jQuery,我們可以使用 jQuery 在 WordPress插件中處理 DOM 對(duì)象、執(zhí)行 Ajax 操作等。
jQuery
使用 jQuery
WordPress 頁面加載完成后,jQuery 將在用戶的瀏覽器中運(yùn)行,一個(gè)基本的 jQuery 語句包含兩部分,一個(gè)選擇器,用于確定代碼將應(yīng)用于哪些 HTML 元素,一個(gè)操作或事件,用于確定執(zhí)行代碼的操作和對(duì)操作的反應(yīng),jQuery 基本語句如下:
jQuery.(selector).event(function);
當(dāng)在選擇器選擇的 HTML 元素上發(fā)生一個(gè)事件(如鼠標(biāo)點(diǎn)擊)時(shí),最后一組括號(hào)里面定義的回調(diào)功能會(huì)被執(zhí)行。
下面的示例代碼是一個(gè) HTML 頁面的部分源代碼,假設(shè)這是一個(gè)由 myplugin_settings.php 文件定義的 WordPress 后臺(tái)頁面,該頁面中包含一個(gè)表單,每個(gè)標(biāo)題旁邊都有一個(gè)單選按鈕。
<form id=radioform>
<table>
<tbody>
<tr>
<td><input class=pref checked=checked name=book type=radio value=Sycamore Row />Sycamore Row</td>
<td>John Grisham</td>
</tr>
<tr>
<td><input class=pref name=book type=radio value=Dark Witch />Dark Witch</td>
<td>Nora Roberts</td>
</tr>
</tbody>
</table>
</form>
在頁面上,上面代碼的輸出看起來應(yīng)該像下圖這樣。

在介紹 Ajax 的文章中,我們將構(gòu)建一個(gè) Ajax 請(qǐng)求,將用戶選擇的選項(xiàng)保存在 user_meta 中,并添加包含所選標(biāo)簽的文章數(shù)量。這個(gè)示例沒什么實(shí)際意義,卻可以說明執(zhí)行 Ajax 操作的重要步驟,jQuery 代碼可以包含在外部文件中,也可以直接寫到頁面里面的 <script> 代碼塊中。下面示例中,我們將代碼放到了外部文件中,如果放到 PHP 頁面中,傳遞來自 PHP 的變量時(shí)很容易出錯(cuò)。如果你更喜歡直接放到頁面里,效果是一樣的。
選擇器和事件
jQuery 選擇器和 CSS 選擇器類似,包含 .class 或 #id 或其他 jQuery 選擇器,但是我們最常使用的還是這兩個(gè),在我們的示例中,我們將使用 .pref 類選擇器。jQuery 事件也很多,我們使用最多的是 “click”,在我們的示例中,我們會(huì)使用 “change” 事件來捕獲用戶點(diǎn)擊單選按鈕的動(dòng)作。請(qǐng)注意,jQuery 事件的命名規(guī)則通常和 JavaScript 不同,到目前為止,在示例中,我們添加了一個(gè)空的匿名函數(shù)。
$.(.pref).change(function(){
/*do stuff*/
});
任何一個(gè) “pref” 類改變時(shí),此代碼將 “執(zhí)行一些操作”。
Ajax
什么是 Ajax?
Ajax 是 Asynchronous JavaScript And XML 的縮寫。XML 是一種數(shù)據(jù)交換格式,Ajax 是一種互聯(lián)網(wǎng)通信技術(shù),可以讓用戶在一個(gè)頁面上請(qǐng)求服務(wù)器的特定信息,然后不用刷新整個(gè)頁面,就可以更新頁面上的一些信息??梢韵胂笠幌?,Ajax 都可以在哪些地方提升用戶體驗(yàn)。
XML 是一種比較傳統(tǒng)數(shù)據(jù)交換格式,實(shí)際上,通過 Ajax 交換的可以是任何格式的數(shù)據(jù)。在使用 PHP 開發(fā)頁面時(shí),許多開發(fā)人員更喜歡 JSON,因?yàn)?JSON 是一個(gè)簡單方便的數(shù)據(jù)格式,PHP 和 JSON 之間的相互轉(zhuǎn)換也非常簡單。
如果想親身體驗(yàn)一下 Ajax,我們可以打開一個(gè) WordPress 分類管理頁面,添加分類時(shí),新添加的分類馬上出現(xiàn)在了右側(cè)分類列表中,而整個(gè)過程中,頁面沒有刷新。Ajax 甚至不需要用戶操作就可以工作,我們編輯 WordPress 文章或頁面時(shí),不用點(diǎn)擊保存按鈕,每隔幾分鐘,頁面就會(huì)自動(dòng)保存。
為什么使用 Ajax?
顯然,Ajax 改善了用戶體驗(yàn),Ajax 幫助我們?yōu)橛脩籼峁┮粋€(gè)及時(shí)響應(yīng)動(dòng)態(tài)頁面給用戶,而不是展現(xiàn)一個(gè)無聊的靜態(tài)頁面。用戶在頁面上執(zhí)行了一些操作的時(shí)候,他們可以及時(shí)得到反饋,操作的結(jié)果是什么,操作正確與否。一些重要的表單字段可以在用戶輸入的時(shí)候就被驗(yàn)證,或者根據(jù)用戶的輸入提供一些建議,用戶填寫表單的時(shí)候,無需提交整個(gè)表單即可知道每個(gè)字段是否輸入正確。
Ajax 可以明顯減少數(shù)據(jù)的傳輸量,只有必須的數(shù)據(jù)會(huì)被傳輸,而不用重新加載整個(gè)頁面,傳輸頁面上的所有內(nèi)容。
特別是在開發(fā)WordPress插件時(shí),Ajax 是與內(nèi)容交互比較好的一種方式。如果我們之前編寫過 PHP,我們可能需要把內(nèi)容提交到一個(gè)外部 PHP 頁面,通過外部頁面進(jìn)行內(nèi)容的交互。這樣做的問題是,我們不能通過這個(gè)外部 PHP 頁面訪問 WordPress 的功能,如果真的要這樣做,可以在外部 PHP 中包含 WordPress 的核心引導(dǎo)文件 wp-load.php 來訪問 WordPress 的核心功能,
WordPress 的架構(gòu)現(xiàn)在已經(jīng)非常靈活,允許我們把 wp-content 目錄移動(dòng)到其他位置,這樣的話,我們可能就不知道 wp-load.php 的準(zhǔn)確路徑了。與此不同的是,而我們可以知道發(fā)送 Ajax 請(qǐng)求的準(zhǔn)確位置,因?yàn)樗呀?jīng)被定義到了全局 JavaScript 變量中。而我們通過 PHP 開發(fā) Ajax 處理程序其實(shí)就是把處理函數(shù)掛載到了一個(gè)是 Action 鉤子上,因此,與外部 PHP 文件不同,通過 Ajax 處理程序,我們可以使用 WordPress 的所有功能。
怎么使用 Ajax?
如果我們是一個(gè) WordPress 新手,但有在其他環(huán)境中使用 Ajax 的經(jīng)驗(yàn),我們需要重新學(xué)習(xí)一些新東西。WordPress 實(shí)現(xiàn) Ajax 的方式可能與我們習(xí)慣的不同,如果我們剛剛接觸 Ajax 開發(fā),就不會(huì)有這個(gè)問題了。我們會(huì)在這里學(xué)習(xí)基礎(chǔ)知識(shí),一旦我們開發(fā)了一個(gè)基本的 Ajax 處理程序,在這個(gè)基礎(chǔ)上進(jìn)行擴(kuò)展并且用一個(gè)優(yōu)秀的界面來開發(fā)一個(gè)殺手級(jí)的應(yīng)用便是一間非常簡單的事情了。
WordPress 中,任何 Ajax 處理程序都有兩個(gè)主要組件,客戶端 JavaScript 和服務(wù)器端的 PHP 處理程序,所有 Ajax 處理程序遵循以下兩個(gè)步驟。
- 某個(gè)頁面事件啟動(dòng)了 JavaScript 函數(shù),該函數(shù)從頁面中收集一些數(shù)據(jù),通過 HTTP 請(qǐng)求發(fā)送到服務(wù)器。直接使用 JavaScript 代碼來處理 HTTP 請(qǐng)求比較麻煩,所以 WordPress 捆綁了 jQuery 庫,我們可以直接使用 jQuery 提供的 Ajax 方法來實(shí)現(xiàn) HTTP 請(qǐng)求。當(dāng)然,如果我們是一個(gè) JavaScript 高手,直接使用原生 JavaScript 代碼發(fā)送 HTTP 請(qǐng)求也是可以的。
- 服務(wù)器收到請(qǐng)求后,會(huì)對(duì)數(shù)據(jù)進(jìn)行一些處理,然后把處理結(jié)果以 HTTP 響應(yīng)的形式發(fā)送給客戶端瀏覽器。也不一定非要返回結(jié)果,但是為了讓用戶知道處理的結(jié)果,返回結(jié)果是比較常見的做法。
- 發(fā)送 Ajax 請(qǐng)求的 jQuery 函數(shù)接收到服務(wù)器的響應(yīng)后,會(huì)執(zhí)行一些操作,比如更新頁面上的內(nèi)容或者以其他方式向用戶提供通知消息。
通過 jQuery 使用 Ajax
現(xiàn)在,我們將開發(fā)前面代碼中的 “do_stuff” 函數(shù),我們將使用 $.post 方法來發(fā)送數(shù)據(jù),該方法有三個(gè)參數(shù):發(fā)送 POST 請(qǐng)求的 URL,需要發(fā)送的數(shù)據(jù),以及處理服務(wù)器端返回?cái)?shù)據(jù)的回調(diào)函數(shù)名稱。在這之前,有一些事情需要提前處理一下,我們定義一個(gè)如下變量,這樣會(huì)使下面的回調(diào)部分更加方便理解。
var this2 = this;
URL
所有 WordPress Ajax 請(qǐng)求都必須發(fā)送到 wp-admin/admin-ajax.php 中,正確、完整的 URL 需要 PHP 輸出一個(gè)值,jQuery 沒辦法自己確定這個(gè)值,所以,我們不能在 jQuery 中寫死這個(gè)值,也不會(huì)希望其他人通過插件發(fā)送 Ajax 請(qǐng)求到你自己的網(wǎng)站上,如果發(fā)送 Ajax 請(qǐng)求的頁面是后臺(tái)頁面,WordPress 已經(jīng)通過 JavaScript 全局變量幫助我們?cè)O(shè)置了正確的 ajaxurl。如果頁面來自前端,我們則需要使用 wp_localize_script() 自己設(shè)置 ajaxurl 全局變量的值,具體方法會(huì)在 PHP 部分詳細(xì)介紹,現(xiàn)在我們只需要知道,正確的 Ajax URL 是一個(gè) Javascript 全局變量,我們可以通過 PHP 定義并輸入這個(gè)全局變量。在 jQuery 中,我們是這樣使用這個(gè)變量的。
my_ajax_obj.ajax_url
數(shù)據(jù)
所有需要發(fā)送到服務(wù)器的數(shù)據(jù)都包含在一個(gè) JavaScript 數(shù)組中,此外,我們還需要發(fā)送一個(gè) action 參數(shù),來幫助服務(wù)端 PHP 判斷使用掛載到哪個(gè) Ajax 鉤子上的 Action 來處理這些數(shù)據(jù)。對(duì)于可能導(dǎo)致數(shù)據(jù)庫更改的請(qǐng)求,我們還需要發(fā)送一個(gè)隨機(jī)數(shù),以便服務(wù)器驗(yàn)證請(qǐng)求的來源是合法的,傳遞給 $.post() 方法的數(shù)據(jù)示例如下。
{
_ajax_nonce: my_ajax_obj.nonce, //nonce
action: my_tag_count, //action
title: this.value //data
}
下面我們來看一下這些數(shù)據(jù)。
Nonce 隨機(jī)數(shù)
Nonce?是 “Number used ONCE” 的縮寫。他本質(zhì)上是一個(gè)唯一的十六進(jìn)制序列號(hào),可以分配給任何形式的實(shí)例,Nonce 使用 PHP 建立,并作為全局對(duì)象的一個(gè)屬性,和 Ajax URL 以相同的方式傳遞給 jQuery,所以,我們?cè)?Ajax 中使用 Nonce 的方法為?my_ajax_obj.nonce。
Action
所有 WordPress Ajax 請(qǐng)求都必須在數(shù)據(jù)中包含一個(gè) action 參數(shù),這個(gè)值可以是任意字符串,需要和 PHP 后端用于掛載 Ajax 處理程序的鉤子名稱一樣,該值的名稱建議是對(duì) Ajax 操作目的的簡單描述,在這里,我們使用 “my_tag_count” 作為 action 的值。
action: my_tag_count
其他數(shù)據(jù)
除了上面兩個(gè)特殊數(shù)據(jù),服務(wù)器需要完成此 Ajax 操作的的其他數(shù)據(jù)也包含在這個(gè) JavaScript 數(shù)組中,如果我們需要傳輸很多字段,可以使用 XML 或 JSON 格式把這些字段合并程一個(gè),在 WordPress 中,我們用的比較多的是 JSON 格式。
在我們的例子中,服務(wù)器只需要一個(gè)值,一個(gè)字符串為選擇的名稱,我們將使用 “title” 作為該值的名稱,在 jQuery 中,觸發(fā)事件的對(duì)象總是包含在變量 this 中,因此,所選元素的值是 this.value。我們對(duì)這個(gè)值的聲明如下。
title: this.value
回調(diào)
回調(diào)處理程序是在請(qǐng)求發(fā)出后,接收服務(wù)器響應(yīng)參數(shù)并進(jìn)行處理的函數(shù),回調(diào)函數(shù)通常為匿名函數(shù),接收的響應(yīng)值可以是 yes 或 no 或者較大的 JSON 或 XML 數(shù)據(jù)。在我們的例子中,我們使用服務(wù)端返回的數(shù)據(jù)替換單選按鈕后面的文字。下面是我們的回調(diào)函數(shù)。
function(data) {
this2.nextSibling.remove();
$(this2).after(data);
}
data 包含了服務(wù)端的返回?cái)?shù)據(jù),在上面,我們?yōu)?this2 分配了觸發(fā) change 事件的對(duì)象,這是因?yàn)?this 只能在匿名函數(shù)之外只用,在匿名函數(shù)中,this 就失效了,所以我們要使用 this2 來代替 this 使用。
服務(wù)器響應(yīng)可以是任何格式的數(shù)據(jù),如果服務(wù)器響應(yīng)的數(shù)據(jù)量比較大,建議使用 XML 或 JSON 這兩種數(shù)據(jù)格式中的一種。
XML
XML 是開發(fā) AJAX 時(shí),較經(jīng)典數(shù)據(jù)交換格式。畢竟 AJAX 中的 “X” 就是指 XML。然而使用 PHP 處理 XML 比較麻煩,所以,很多 PHP 程序員更喜歡 JSON 交換格式。
JSON
JSON 比較輕量和易用,所以受到了廣大程序員的歡迎。我們可以使用 eval()來解析 JSON ,但是不要那樣做!使用 eval()會(huì)帶來重大的安全風(fēng)險(xiǎn)。建議使用專用的 JSON 解析器。使用解析器時(shí),首先要確保我們?cè)陧撁嬷幸肓诉@個(gè)解析器。有關(guān)在頁面中引入 JavaScript 庫的更多信息將在后面的 PHP部分中介紹。
其他
只要數(shù)據(jù)格式可以在 JavaScript 和 PHP 中協(xié)調(diào)使用,我們都可以使用這種數(shù)據(jù)格式。
小結(jié)
現(xiàn)在,我們已經(jīng)將匿名回調(diào)函數(shù)添加為 $.post 方法的最終參數(shù),我們已經(jīng)完成了示例 jQuery Ajax 腳本,所有部分放在一起,看起來影響像下面這樣。
jQuery(document).ready(function($) { //wrapper
$(.pref).change(function() { //event
var this2 = this; //use in callback
$.post(my_ajax_obj.ajax_url, { //POST request
_ajax_nonce: my_ajax_obj.nonce, //nonce
action: my_tag_count, //action
title: this.value //data
}, function(data) { //callback
this2.nextSibling.remove(); //remove current title
$(this2).after(data); //insert server response
});
});
});
上面的腳本可以輸出到網(wǎng)頁上的任何部分,或者放到外部 js 文件中,我們可以把 js 文件放到任何地方,只要能通過 url 訪問即可,大多數(shù)插件開發(fā)人員喜歡把 js 文件放在插件主目錄的 /js/ 子目錄中,除非你有理由不這樣做,否則遵循慣例是一個(gè)好選擇,在這個(gè)例子中,我們把我們的 js 文件命名為 myjquery.js
服務(wù)器端 PHP 和 注入前端文件
為了在服務(wù)端處理 Ajax 請(qǐng)求,我們需要在 PHP 中做兩個(gè)工作,一個(gè)是把 jQuery 到前端,并把轉(zhuǎn)換 PHP 變量為 JS 數(shù)據(jù)的全局 JavaScript 變量加入頁面中。另一個(gè)就編寫處理 Ajax 請(qǐng)求的函數(shù)。
注入 JavaScript 腳本
本節(jié)將介紹 WordPress 中 Ajax 的兩個(gè)特性,他們可能會(huì)讓經(jīng)驗(yàn)豐富的開發(fā)者感到困惑,一個(gè)是注入腳本,以 meta 鏈接的形式顯示在頁面的 <head> 部分,另一個(gè)是所有的 Ajax 請(qǐng)求都發(fā)送到 wp-admin/admin-ajax.php 中,千萬不要把請(qǐng)求直接發(fā)送到插件頁面。
注入
在 WordPress 中,我們使用 wp_enqueue_script() 函數(shù)在頁面的 head 中插入一個(gè) meta js 鏈接,不要在 head 中寫死這些鏈接,開發(fā)插件的時(shí)候,我們一般不需要修改主題的 head 部分,但是還是要提一下這個(gè)規(guī)則。
wp_enqueue_script() 函數(shù)接受 3 個(gè)參數(shù),第一個(gè)是在其他函數(shù)中引用此 JS 的名稱。第二個(gè)是 JS 的 URL,我們可以使用 plugins_url() 函數(shù)構(gòu)建正確的 URL,如果我們需要注入插件之外的 JS,請(qǐng)確保我們的 URL 是正確的。第三個(gè)參數(shù)是 JS 所依賴的其他 JS 的名稱數(shù)組。由于我們使用 jQuery 發(fā)送 Ajax 請(qǐng)求,因此,請(qǐng)至少在數(shù)組中列出 ‘jquery’,即便只有一個(gè)依賴,也要寫成數(shù)組的形式。示例如下:
wp_enqueue_script( 'ajax-script',
plugins_url( '/js/myjquery.js', __FILE__ ),
array('jquery')
);
WordPress 加載時(shí),我們必須從幾個(gè) Action 鉤子中把腳本注入頁面,使用哪一個(gè)取決于腳本需要注入的頁面,對(duì)于后臺(tái)頁面,使用 admin_enqueue_scripts 鉤子,前端頁面,使用 wp_enqueue_scripts, 登錄頁面使用 login_enqueue_scripts 鉤子。
admin_enqueue_scripts 鉤子把當(dāng)前頁面的文件名傳遞給了我們的回調(diào),我們可以使用此信息只在需要的頁面上注入我們的 JS。wp_enqueue_scripts 鉤子沒有傳遞任何變量給我們的回調(diào)函數(shù),不過我們可以使用模版判斷函數(shù)來確保只在需要的地方注入我們的 JS,示例如下。
add_action( 'admin_enqueue_scripts', 'my_enqueue' );
function my_enqueue( $hook ) {
if( 'myplugin_settings.php' != $hook ) return;
wp_enqueue_script( 'ajax-script',
plugins_url( '/js/myjquery.js', __FILE__ ),
array( 'jquery' )
);
}
注冊(cè) VS 注入
我們可能在其他教程中看到了 wp_register_script() 的使用方法,這是一種不錯(cuò)的處理方法,注冊(cè)之后,我們還需要使用 wp_enqueue_scripts 函數(shù)把腳本注入前端。為什么要多此一舉呢?因?yàn)樽?cè)腳本可以提供一個(gè)腳本名稱,讓我們?cè)谄渌胤阶⑷脒@個(gè)腳本,WordPress 捆綁的 jQuery 就是在 WordPress 內(nèi)核中事先注冊(cè)好的腳本,我們直接使用 「jQuery」 這個(gè)名稱就可以引入這個(gè)腳本了,我們自己注冊(cè)的腳本也一樣。當(dāng)然,如果我們只需要在自己的插件中引入腳本文件,注冊(cè)腳本這一步是完全可以省略的。
Nonce 隨機(jī)數(shù)
我們需要?jiǎng)?chuàng)建一個(gè)隨機(jī)數(shù),這樣就可以驗(yàn)證 jQuery Ajax 發(fā)送的請(qǐng)求是非合法了,只有 PHP 和 jQuery 腳本可以獲取這個(gè)隨機(jī)數(shù),收到請(qǐng)求后,我們可以驗(yàn)證這個(gè)隨機(jī)數(shù)和我們創(chuàng)建的值是否一樣,我們使用下面的示例創(chuàng)建了一個(gè)隨機(jī)數(shù)。
$title_nonce = wp_create_nonce( 'title_example' );
參數(shù) title_example 可以是任何字符串,建議遵循語義化原則,通過這個(gè)字符串可以看出來這個(gè)隨機(jī)數(shù)是用來做什么的。
轉(zhuǎn)換 PHP 變量為 JavaScript 全局變量
我們回想一下前面 jQuery 的部分,由 PHP 創(chuàng)建的供 jQuery 使用的數(shù)據(jù)被傳入名稱為 my_ajax_obj 的全局對(duì)象中。在我們的例子中,這個(gè)數(shù)據(jù)是一個(gè)隨機(jī)數(shù)和 admin-ajax.php 的完整 URL。分配對(duì)象屬性和創(chuàng)建全局 JavaScript 對(duì)象的過程,我們稱之為本地化,下面是我們使用 wp_localize_script() 本地化代碼的示例代碼。
wp_localize_script( 'ajax-script', 'my_ajax_obj', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => $title_nonce, // It is common practice to comma after
) );
請(qǐng)注意,我們的代碼是如何處理 ajax-script 的,該對(duì)象對(duì)于我們的腳本來說是全局的,而不是對(duì)所有腳本。本地化也可以中注入腳本的同一個(gè)鉤子中調(diào)用。創(chuàng)建隨機(jī)數(shù)也是一樣的,盡管這個(gè)特定的函數(shù)幾個(gè)可以在任何地方調(diào)用。在一個(gè)鉤子中完成所有處理的代碼如下:
add_action( 'admin_enqueue_scripts', 'my_enqueue' );
function my_enqueue( $hook ) {
if( 'myplugin_settings.php' != $hook ) return;
wp_enqueue_script( 'ajax-script',
plugins_url( '/js/myjquery.js', __FILE__ ),
array( 'jquery' )
);
$title_nonce = wp_create_nonce( 'title_example' );
wp_localize_script( 'ajax-script', 'my_ajax_obj', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => $title_nonce,
) );
}
Ajax 動(dòng)作
服務(wù)端 PHP 代碼的另一個(gè)主要組成部分是處理 Ajax 提交數(shù)據(jù)的程序,該處理函數(shù)接收 POST 數(shù)據(jù),執(zhí)行某些操作,然后將處理的結(jié)果返回給瀏覽器。函數(shù)掛載到哪個(gè)鉤子上決定了 Ajax 請(qǐng)求處理函數(shù)是否要求用戶登錄,使用哪個(gè)程序處理 Ajax 請(qǐng)求取決于 jQuery 腳本的 action 參數(shù)傳遞了什么值。
因?yàn)槲覀兊?Ajax 交互是在插件的設(shè)置頁面使用的,所以必須要求用戶登錄才可以發(fā)送 Ajax 請(qǐng)求,回憶一下前面的 jQuery 部分,Ajax 的值action 為 “my_tag_action”,那么我們后端處理 Ajax 請(qǐng)求的鉤子標(biāo)簽將是 wp_ajax_my_tag_count。如果我們的 Ajax 交互可以允許未登錄的用戶使用,這個(gè)鉤子標(biāo)簽就是 wp_ajax_nopriv_my_tag_count,示例如下。
add_action( 'wp_ajax_my_tag_count', 'my_ajax_handler' );
function my_ajax_handler() {
// Handle the ajax request
wp_die(); // All ajax handlers die when finished
}
我們的 Ajax 處理程序需要做的第一件事就是使用 check_ajax_referer() 函數(shù)驗(yàn)證 Ajax 請(qǐng)求發(fā)送的隨機(jī)數(shù),就是我們上面創(chuàng)建的隨機(jī)數(shù)的值。
check_ajax_referer( 'title_example' );
上面函數(shù)的參數(shù)必須于前面 wp_create_nonce 的參數(shù)相同,如果 Nonce 不一致,該處理函數(shù)就會(huì)自動(dòng)結(jié)束,如果這是一個(gè)真正的隨機(jī)數(shù),這里的驗(yàn)證就通不過了。我們可以創(chuàng)建一個(gè)新的隨機(jī)數(shù)并且發(fā)送給回調(diào)腳本,以便回調(diào)腳本在下一個(gè)請(qǐng)求中使用,但是由于隨機(jī)數(shù)的有效期是 24 小時(shí),所以,我們不需要這用做了,只要執(zhí)行檢查操作就好了。
數(shù)據(jù)
隨機(jī)數(shù)驗(yàn)證之后,下一步,我們就需要處理 jQuery 發(fā)送過來的 $_POST[‘title’] 數(shù)據(jù)了,我們可以使用 update_user_meta() 函數(shù)保存為用戶的元數(shù)據(jù)。
update_user_meta( get_current_user_id(), 'title_preference', $_POST['title']);
然后,我們創(chuàng)建一個(gè)查詢,獲取標(biāo)簽為所選標(biāo)題的文章數(shù)。
$args = array(
'tag' => $_POST['title'],
);
$the_query = new WP_Query( $args );
太棒了,我們終于可以將響應(yīng)發(fā)回給 jQuery 腳本了,我們有幾種方法傳輸數(shù)據(jù),我們先來看一下這幾種格式。
XML
PHP 對(duì) XML 格式的支持不夠好,幸運(yùn)的是,WordPress 提供了WP_Ajax_Response 類來讓我們的工作更輕松一點(diǎn),WP_Ajax_Response 會(huì)生成一個(gè) XML 格式的響應(yīng),為頭部設(shè)置正確的內(nèi)容類型,輸出 XML,然后結(jié)束,確保正確的 XML 響應(yīng)。
JSON
這種格式輕量且易用,WordPress 提供了 wp_send_json 函數(shù)來幫我們把數(shù)據(jù)轉(zhuǎn)換成 JSON,發(fā)送給客戶端,然后結(jié)束。該函數(shù)有效的取代了 WP_Ajax_response。此外,WordPress還提供了 wp_send_json_success 和 wp_send_json_error 函數(shù),允許我們?cè)?JS 中觸發(fā)適當(dāng)?shù)?done() 和 fail() 回調(diào)。
其他
只要能被客戶端 jQuery 處理,我們還可返回其他任何格式的數(shù)據(jù),比如以逗號(hào)分隔的數(shù)據(jù),或一段 HTML 字符串。
echo $_POST['title'].' ('.$the_query->post_count.') ';
在真實(shí)的應(yīng)用程序中,我們必須考慮由于某種原因引起失敗操作的可能性,服務(wù)端響應(yīng)應(yīng)該考慮到這個(gè)意外,并且 jQuery 也要能夠正確的處理這種意外,并在需要的時(shí)候提示用戶。
結(jié)束
當(dāng)處理程序處理完所有任務(wù)的時(shí)候,我們需要結(jié)束掉這個(gè)程序,如果我們使用 WP_Ajax_Response 或 wp_send_json 函數(shù)發(fā)送響應(yīng),程序會(huì)被自動(dòng)結(jié)果,如果不是,我們需要使用 wp_die() 函數(shù)手動(dòng)結(jié)束。
Ajax 處理程序總結(jié)
一個(gè)完整的 Ajax 處理程序看起來應(yīng)該像下面這樣。
//JSON
function my_ajax_handler() {
check_ajax_referer( 'title_example' );
update_user_meta( get_current_user_id(), 'title_preference', $_POST['title'] );
$args = array(
'tag' => $_POST['title'],
);
$the_query = new WP_Query( $args );
wp_send_json( $_POST['title'] . ' (' . $the_query->post_count . ') ' );
}
//Other
function my_ajax_handler() {
check_ajax_referer( 'title_example' );
update_user_meta( get_current_user_id(), 'title_preference', $_POST['title'] );
$args = array(
'tag' => $_POST['title'],
);
$the_query = new WP_Query( $args );
echo $_POST['title'].' ('.$the_query->post_count.') ';
wp_die(); // All ajax handlers should die when finished
}
心跳 API
心跳 API 是一個(gè)內(nèi)置于 WordPress 的服務(wù)器輪詢 API,讓我們可以近乎實(shí)時(shí)的更新前端。
心跳 API 是怎么工作的
當(dāng)頁面加載時(shí),客戶端心跳代碼設(shè)置了一個(gè)時(shí)間間隔(稱為“打勾”),每隔 15-60 秒運(yùn)行一次。運(yùn)行時(shí),心跳 API 收集數(shù)據(jù)并通過 jQuery 事件發(fā)送到服務(wù)器,然后等待服務(wù)器響應(yīng)。在服務(wù)端,ajax-admin 處理程序獲取 jQuery 傳遞的值數(shù)據(jù),處理后以 JSON 格式返回,客戶端接收到處理程序返回的數(shù)據(jù)后,觸發(fā)一個(gè) jQuery 事件來表明數(shù)據(jù)已經(jīng)被接收。
自定義心跳事件的基本過程是:
- 給需要發(fā)送的數(shù)據(jù)添加額外的字段(JS
heartbeat-send事件 ) - 在 PHP 中檢測(cè)發(fā)送的字段,并添加額外的響應(yīng)字段(
heartbeat_receivedfilter 鉤子) - 在 JS(JS
heartbeat-tick)中處理返回?cái)?shù)據(jù)。
我們可以選擇性的使用其中一個(gè)或兩個(gè)事件,具體取決于我們需要的功能。
使用心跳 API
使用心跳 API 需要兩個(gè)獨(dú)立的功能:在 JavaScript 中發(fā)送和接收回調(diào),以及在 PHP 中處理傳遞數(shù)據(jù)的服務(wù)端 Filter 鉤子。
發(fā)送數(shù)據(jù)到服務(wù)器
當(dāng)心跳向服務(wù)器發(fā)送數(shù)據(jù)時(shí),可以包含任意格式的自定義數(shù)據(jù),或表示我們需要數(shù)據(jù)的布爾值。
jQuery( document ).on( 'heartbeat-send', function ( event, data ) {
// 添加附加數(shù)據(jù)到心跳數(shù)據(jù)
data.myplugin_customfield = 'some_data';
});
在服務(wù)器上獲取數(shù)據(jù)并返回響應(yīng)
在服務(wù)器端,我們可以獲取這些數(shù)據(jù),并把其他數(shù)據(jù)添加到響應(yīng)中。
// 添加 Filter 到接收鉤子
add_filter( 'heartbeat_received', 'myplugin_receive_heartbeat', 10, 2 );
/**
* 獲取心跳數(shù)據(jù)然后返回響應(yīng)
*
* @param array $response Heartbeat response data to pass back to front end.
* @param array $data Data received from the front end (unslashed).
*/
function myplugin_receive_heartbeat( $response, $data ) {
// 如果沒有接收到數(shù)據(jù),直接返回原始響應(yīng)
if ( empty( $data['myplugin_customfield'] ) ) {
return $response;
}
// 處理數(shù)據(jù)并附加到響應(yīng)
$received_data = $data['myplugin_customfield'];
$response['myplugin_customfield_hashed'] = sha1( $received_data );
return $response;
}
處理服務(wù)器響應(yīng)
回到前端,我們可以接收并處理服務(wù)器返回的響應(yīng)數(shù)據(jù)。
jQuery( document ).on( 'heartbeat-tick', function ( event, data ) {
// Check for our data, and use it.
if ( ! data.myplugin_customfield_hashed ) {
return;
}
c-alert( 'The hash is ' + data.myplugin_customfield_hashed );
});
并不是每個(gè)功能都需要這三個(gè)步驟,例如,如果我們不需要將任何數(shù)據(jù)發(fā)送到服務(wù)器,則只需要使用后面兩個(gè)步驟就可以了。
總結(jié)
這里是我們前面討論的所有示例代碼片段的總結(jié),一個(gè)用于 jQuery,一個(gè)用于 PHP。
php
下面代碼應(yīng)該位于插件的某個(gè) PHP 文件中。
<?php add_action('admin_enqueue_scripts', 'my_enqueue');
function my_enqueue($hook) {
if( 'myplugin_settings.php' != $hook) return;
wp_enqueue_script( 'ajax-script',
plugins_url( '/js/myjquery.js', __FILE__ ),
array('jquery')
);
$title_nonce = wp_create_nonce('title_example');
wp_localize_script('ajax-script', 'my_ajax_obj', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => $title_nonce,
));
}
add_action('wp_ajax_my_tag_count', 'my_ajax_handler');
function my_ajax_handler() {
check_ajax_referer('title_example');
update_user_meta( get_current_user_id(), 'title_preference', $_POST['title']);
$args = array(
'tag' => $_POST['title'],
);
$the_query = new WP_Query( $args );
echo $_POST['title'].' ('.$the_query->post_count.') ';
wp_die(); // all ajax handlers should die when finished
}
jQuery
下面的代碼位于插件文件夾下的文件 js/myjquery.js 中。
jQuery(document).ready(function($) { //wrapper
$(.pref).change(function() { //event
var this2 = this; //use in callback
$.post(my_ajax_obj.ajax_url, { //POST request
_ajax_nonce: my_ajax_obj.nonce, //nonce
action: my_tag_count, //action
title: this.value //data
}, function(data) { //callback
this2.nextSibling.remove(); //remove the current title
$(this2).after(data); //insert server response
});
});
});