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 操作的使用方法,不適用于生產(chǎn)環(huán)境,因?yàn)橥暾僮魉枰拇a如:消毒, 安全, 錯(cuò)誤處理和國際化 被故意省略了,請(qǐng)務(wù)必在生產(chǎn)代碼中處理這些重要操作。

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è)步驟。

  1. 某個(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)求也是可以的。
  2. 服務(wù)器收到請(qǐng)求后,會(huì)對(duì)數(shù)據(jù)進(jìn)行一些處理,然后把處理結(jié)果以 HTTP 響應(yīng)的形式發(fā)送給客戶端瀏覽器。也不一定非要返回結(jié)果,但是為了讓用戶知道處理的結(jié)果,返回結(jié)果是比較常見的做法。
  3. 發(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。

WordPress 的 Nonce 不是一個(gè)真正的隨機(jī)數(shù),真正的隨機(jī)數(shù)需要每次都刷新,在 WordPress 中,使用相同字符生成的隨機(jī)數(shù)在 12 個(gè)在小時(shí)以內(nèi)是相同的,如果我們需要一個(gè)真正的隨機(jī)數(shù),可以使用自定義方法自己生成一個(gè)。

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ù)量比較大,建議使用 XMLJSON 這兩種數(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ù)傳遞了什么值。

$_GET、$_POST 和 $_COOKIE、_REQUEST:我們可以已經(jīng)在前面使用了一個(gè)或多個(gè) PHP 超級(jí)全局變,如 $_GET 或 $_POST 獲取值,使用 $_COOKIE 獲取瀏覽器 Cookies,也可能你更喜歡使用 $_REQUEST,或者你至少已經(jīng)看到了他們是怎么使用的。無論使用哪種請(qǐng)求方法,我們都能獲取到表單值。$_REQUEST 方法的一個(gè)缺陷是:該方法包含了 Cookie 值,如果 Cookie 值和表單值有沖突的情況下,Cookie 值將覆蓋表單值,這就給不懷好意的人留下了作弊的空間,Cookie 的值是非常容易偽造的,如果 Cookie 被篡改了,服務(wù)器接收的表單值可能并不是我們所提交的。所以,為了安全,避免使用 $_REQUEST 方法。

因?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)被接收。

自定義心跳事件的基本過程是:

  1. 給需要發(fā)送的數(shù)據(jù)添加額外的字段(JS heartbeat-send 事件 )
  2. 在 PHP 中檢測(cè)發(fā)送的字段,并添加額外的響應(yīng)字段(heartbeat_received filter 鉤子)
  3. 在 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
        });
    });
});

更多信息

我們提供 WordPress主題和插件定制開發(fā)服務(wù)

本站長期承接 WordPress主題、插件、基于 WooCommerce 的商店商城開發(fā)業(yè)務(wù)。 我們有 10 年WordPress開發(fā)經(jīng)驗(yàn),如果你想 用WordPress開發(fā)網(wǎng)站, 請(qǐng)聯(lián)系微信: iwillhappy1314,或郵箱: [email protected] 咨詢。

發(fā)表回復(fù)

您的郵箱地址不會(huì)被公開。 必填項(xiàng)已用 * 標(biāo)注

*