WordPress AJAX佈景實作 (以jQuery為例)


作者: | 2012/06/12 16:55:05 | 留言


wordpress ajax

一般使用jQuery實作AJAX的情況

如果你曾經在一般網頁上實作過ajax效果,尤其是使用jQuery (無論是用load(), post()或ajax()…等方式),你一定可以在閱讀本文後很快就理解WP是怎麼處理ajax效果的。

先來看看一個利用AJAX來載入資料的情境:以jQuery實作AJAX為例,我們通常會以送出GET或POST請求的方式,帶上一些參數資料,再丟給一個負責處理的目標網址,而這個目標網址的PHP檔會接收我們傳過去的參數,作為存取DB資料的條件,接著將資料輸出,如此就達成非同步載入資料的效果。

在WP實作AJAX的概述

在WP實作ajax的效果,大致也是採用這種方式,但是無論前台、後台中的任何一個頁面,都統一要將參數資料丟到 /wp-admin/admin-ajax.php 這個目標網址。當你把資料丟過去之後,你就可以在functions.php或者plugin裡利用hook function,去取得丟過來的參數資料,接著如果你要進行資料庫操作,就宣告$wpdb來做事就行了。

請注意,本文以下的例子為求容易理解原理,因此沒有考慮最佳的實作方式,建議你應該在理解運作原理後多多參考其他更好的作法。

在前台佈景實作AJAX效果

為求方便講解,我們直接修改佈景檔中的 header.php (請先確定你的WP網站已有載入jQuery),在<head>裡加入:

<script>
 jQuery(function(){
   // 按下按鈕後開始送出POST要求
   $('.btn_ajax').click(function () {
     $.post('<?php echo admin_url( 'admin-ajax.php' );?>', {
       action: 'my_ajax_action', // 自取一個action的名稱
       post_id: $('#my_id').val() // 附上的參數
     }, function(data) {
       alert(data); // 當AJAX處理完畢,就把回傳的資料alert出來
     });
   });
 });
</script>

裡頭的PHP函式:admin_url(admin-ajax.php)其實就是傳回/wp-admin/admin-ajax.php的完整網址;然後我們要自己取一個action的名稱,之所以叫action,就是表示這裡的名稱會對應到等會要寫的hook function的名稱。接著在header.php下方<body>之後找地方加入:

<input type="text" value="mrmu" id="my_id">
<input type="button" class="btn_ajax" value="按我">

如此前端的配置就完成了,接著到 functions.php找地方加入:

add_action( 'wp_ajax_my_ajax_action', 'ajax_action_stuff' ); // 針對已登入的使用者
add_action( 'wp_ajax_nopriv_my_ajax_action', 'ajax_action_stuff' ); // 針對未登入的使用者
function ajax_action_stuff() {
 $post_id = $_POST['post_id']; // 從ajax POST的請求取得的參數資料
 echo $post_id; // 單純的印出來,如此前端就會收到
 die(); // 一定要加這行,才會完整的處理ajax請求
}

觀察一下上述的程式碼,首先我們加入兩個action hook,第一個是wp_ajax_my_ajax_action,去掉前綴字’wp_ajax_’,剩下的my_ajax_action有沒有很眼熟?就是我們在前端自取的action名稱。
第二個action hook也是拿了我們自取的action加上前綴字’wp_ajax_nopriv_’,代表若使用者未登入,就會觸發這個hook。

當wp_ajax的hook function成功被觸發時,我們就能拿到前端丟過來的參數資料,也就能拿它來作為條件,進一步去存取資料庫,再回傳值至前端,達成ajax的效果。

不過,進一步的看這個例子,其實是很多缺點的。我們的例子是把前端js的部份寫在header.php,所以可以偷吃步的使用php function來取得admin-ajax.php的完整網址,如果要把這段js程式碼整理到.js檔內,就要在functions.php這樣寫了:

add_action('init', 'add_my_ajax_script');
function add_my_ajax_script(){
 wp_enqueue_script( 'my_ajax_script', get_stylesheet_directory_uri().'/js/script.js', array('jquery'), 1.0 );
 wp_localize_script( 'my_ajax_script', 'my_ajax_obj', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) ); // 先將ajaxurl變數設定好
}

如此我們就可以在佈景目錄下的/js/script.js中利用my_ajax_obj.ajaxurl取得admin-ajax.php的完整網址:

(function($) {
 $(function() {
   $('.target').click(function () {
     $.post(my_ajax_obj.ajaxurl, { //取得admin-ajax.php的完整網址
       action: 'ajax_action',
       post_id: $(this).find('input.post_id').attr('value')
     }, function(data) {
       alert(data); // alerts
     });
   });
 });
})(jQuery);

在後台實作AJAX效果

在需要作用的頁面上,註冊需要的style及script

要在wp後台完成ajax效果,我們必須要先在目標頁面加入我們自訂的JS。你可能想在發表文章頁、編輯文章頁加入ajax效果,或者自訂一個後台設定頁面,然後在裡頭使用ajax效果。

你當然可以直接用admin_init這個hook,來將所需的js及css檔加入,但如此一來在後台所有頁面都會匯入你自訂的js及css檔。講究一點的話,你應該只針對想要有效果的頁面來匯入,如果是發表/編輯文章頁面,可以利用這兩個action hook:

add_action('load-post.php', 'reg_admin_scripts_and_styles' ); // 文章編輯頁
add_action('load-post-new.php', 'reg_admin_scripts_and_styles' ); // 文章發表頁

若是自行建立新的後台頁面,則可以在呼叫建立頁面的function後取得page_hook_suffix,並利用它來加入所需的js及css,以建立一個「設定」頁面來舉例:

add_action('admin_menu', '__add_menu' );
function __add_menu()
{
  if (function_exists('add_options_page'))
  {
    $my_opt_page_hook_suffix = add_options_page(
      'Product', //Page Title
      'Tcc CP Product', //Menu Title
      'editor', // Capability
      'my_menu_slug', // Menu Slug
      'panel_ui_rendering' // UI Function
    );

    // 在此頁enqueue頁首script及styles
    add_action("load-{$my_opt_page_hook_suffix}", 'reg_admin_scripts_and_styles' );
  }
}

然後你就可以建立reg_admin_scripts_and_style 這個function,來將所需的scripts及styles註冊及enqueue。

發出及傳送資料給WP

針對特定頁面來匯入所需的js後,就可以進入正題了,要怎麼完成ajax效果?跟前台一樣。

首先,匯入的 js 裡,無論使用jQuery load, ajax, post,都一定要 POST 一個名為action的變數給WP已預先定義的網址:ajaxurl。
跟前台稍微不同的地方是,後台的ajaxurl變數,已經先幫我們取得admin-ajax.php的完整網址了,所以直接拿來用就行了。
action變數的內容需要自訂一個名稱,而WP就會以這個名稱偷偷建立對應的hook action。

除了post action外,可以再自帶需要的參數進去,通常會建立一個名為data的js object,舉例來說,你的js檔內相關處理的code可能會長這樣:

(function($) {
  $(function() {
    // 要POST的資料
    var data = {
      action: 'list_rec',
      arg1: 'arg1 的資料',
      arg2: 'arg2 的資料',
      arg3: 'arg3 的資料',
    };
    // 自 WP 2.8 起ajaxurl 已被定義在 admin header 並指向 admin-ajax.php
    $('#ajax_content_sec').load(ajaxurl, data, function(){
    // 已將data物件POST到ajaxurl,ajax 載入成功!
      alert('載入完畢!');
    });
  });
})(jQuery);

接著在functions.php或plugin裡,就可以直接add你在js裡定義的那個action,只是要記得加上前綴字wp_ajax_:

add_action('wp_ajax_list_rec', 'list_rec_callback');
function list_rec_callback() {
  // 讀取POST資料
  $arg1 = $_POST['arg1'];
  $arg2 = $_POST['arg2'];
  $arg3 = $_POST['arg3'];

  global $wpdb; //可以拿POST來的資料作為條件,撈DB的資料來作顯示
  echo 'arg1: ' . $arg1 . '&lt;br&gt;arg2: '. $arg2 . '&lt;br&gt;arg3: '. $arg3;
  die(); // this is required to return a proper result
}

有了這樣的架構,我們就可以實作ajax效果了。最普遍的例子就是在使用者按下連結或按鈕後,會出現Loading的動畫,然後某個區塊就產生一堆資料。

這樣的行為,需要在js收集好「條件」,可以在js裡針對某個連結來bind一個click事件,然後將dom裡的資料(或url上的GET參數)拿來放進上述的data物件裡,再作ajax post。

post到wp_ajax 對應的hook function裡時,就可以拿到這些「條件」,接著在wp_ajax function裡利用$wpdb撈出所需的資料,再作輸出就打完收工了。


標籤:

分類:, ,

本文作者是Audi Lu

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。

*

*

*

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料