简介
Ajax(异步JavaScript与XML)是一种允许网页在没有完全重新加载的情况下更新某些信息的技术。WordPress管理面板用Ajax来自动保存日志、添加新分类等。一些WordPress插件也用AJAX来计算日志投票数和镜像更新。
这篇文章向插件开发人员介绍了怎样在插件中添加Ajax。继续阅读前,最好对下面这些内容有所了解:
- Ajax——Ajax技术简介
- 插件开发——插件编写方法
- 插件API—介绍过滤器钩子和动作钩子及其用法
- 怎样在适当的WordPress页面、日志或界面中添加HTML代码——例如,如果希望在自己创建的管理界面上加入Ajax,首先需要了解怎样为WordPress添加管理菜单;如果需要用Ajax来显示某篇特殊日志,则必须要学会用适当的过滤器函数和动作函数将HTML添加到访问者正浏览的博客页面上。本文不涉及此类内容。
- 要在WordPress中使用Ajax,还需要熟悉客户端的Javascript、PHP和HTML编程语言。
试验表明,在插件中加入Ajax并非易事,这取决于我们需要将Ajax的功能整合到WordPress后台,还是利用Ajax为WordPress网站/博客的访问者展示信息。(介绍一些常见问题后)本文将分别讨论这两种情况。
Ajax基本知识
总体来说,进行一次Ajax请求需要三个步骤:
1. 用户执行某个操作(如点击或拖拽鼠标),之后嵌套在网页HTML中的Javascript会生成一个“请求”并将请求发送到web服务器上某个特定URL,以此响应用户的操作。考虑到安全因素,接收请求的URL与存储Javascript的文件必须位于同一台web服务器上。
2. web服务器上的某个脚本或程序(在WordPress中通常是一个或一个以上的PHP函数)处理请求并将信息传回浏览器。
3. 利用Javascript显示返回的信息。
令人遗憾的是,大多数运行在用户的web浏览器中的Ajax都是Javascript,有些web浏览器甚至不能执行Ajax调用或响应Ajax调用。为方便起见,大多数Ajax开发人员选择使用经过测试的跨浏览器库,这个浏览器库利用一个带有文件记录的标准类来包装浏览器特质。在这篇文章中我们也利用WordPress中一个类似的浏览器库——SACK(简易Ajax代码工具包)展开说明。文章的延伸阅读部分(见文章最下方)中也介绍了一些用JQuery来执行AJAX的资料——JQuery也是WordPress中的浏览器库,JQuery和SACK基本原理大致相同,只是在句法上有些差别。
首先我们需要确定,组成Ajax请求的SACK库和Javascript函数都已经被包含在网页的HTML的head版块中,Ajax请求会在这个网页上触发;之后我们会分别介绍怎样在WordPress后台和访问者浏览页面上执行Ajax。
用SACK库生成Ajax请求时,我们还需要提供以下信息;文章稍后会详细说明这些信息在WordPress后台和访问者浏览页面上的作用:
- 请求URL:服务器上用以处理Ajax请求的URL
- 自定义请求变量:SACK允许用户设置任意请求变量,变量将通过POST或GET传输到服务器上。POST和GET还能够传输cookie信息。
- 出错时如何继续:出现Ajax错误时调用特定Javascript函数。
默认情况下SACK假定服务器返回的信息为进入(异步)服务器后已被执行的Javascript代码。在下面的示例中,我们遵循SACK的假定,因此(处理Ajax请求的)PHP函数需要将其结果形成Javascript命令。我们打算在插件中对返回的信息进行其它操作前,可能还需要进入SACK的主页下载压缩文件并阅读说明文档,了解相关信息。
还有一个细节需要注意:处理Ajax请求的PHP函数应使用PHP die函数来传回Javascript信息。示例:die("javascript_commands_here")。
稍后的两个示例以上述Ajax基本知识为起点,分别介绍了怎样在WordPress后台和访问者浏览页面上使用Ajax。两个示例部分都是独立存在的,读者可以选择性阅读。
WordPress后台的Ajax
Ajax已经存在于WordPress管理界面中,因此在插件中添加管理界面端的Ajax功能相当容易,接下来我们会详细介绍添加过程。如果要在WordPress网站/博客的访问者浏览页面上使用Ajax,可以跳过这部分内容。
假设目前有一个地域标签插件,用户会在插件中为日志设置经度和纬度,然后插件利用一项网络服务来查看日志所在地点的海拔。我们将这个插件作为在WordPress插件后台使用Ajax的实例。进行Ajax编程前,首先要提供一些字段,让用户能够输入日志的经纬度,一个用来查询海拔的按钮,以及一个显示海拔高度的字段。假设我们已经知道怎样在适当位置上添加Ajax,怎样按照自己的喜好调整字段宽度、文本以及字段样式;然后在后台的HTML表中加入以下代码:
Latitude: <input type="text" name="latitude_field" /> Longitude: <input type="text" name="longitude_field" /> <input type="button" value="Look Up Elevation" onclick="myplugin_ajax_elevation(this.form.latitude_field, this.form.longitude_field, this.form.elevation_field);" /> Elevation: <input type="text" name="elevation_field" id="elevation_field" />
接下来我们需要定义Javascript函数myplugin_ajax_elevation,而OnClick动作函数则会读取用户输入的信息,用SACK生成一个请求,然后将请求发送给插件进行处理。之前也曾提到,这个Javascript函数和SACK库都需要被包含在相应管理界面HTML代码的head版块中;最简单的方法是利用admin_print_scripts动作钩子函数将JavaScript函数添加到所有管理界面中:
add_action('admin_print_scripts', 'myplugin_js_admin_header' ); function myplugin_js_admin_header() // this is a PHP function { // use JavaScript SACK library for Ajax wp_print_scripts( array( 'sack' )); // Define custom JavaScript function ?> <script type="text/javascript"> //<![CDATA[ function myplugin_ajax_elevation( lat_field, long_field, elev_field ) { // function body defined below } // end of JavaScript function myplugin_ajax_elevation //]]> </script> <?php } // end of PHP function myplugin_js_admin_header
下一步需要填写JavaScript函数myplugin_ajax_elevation的主体部分,该部分需要能够从表单域中读取经纬度,用SACK生成一个AJAX请求,然后将请求发送给服务器。在这个例子中,我们需要设置以下信息:
- 请求URL:我们要将请求发送到特定URL中,WordPress管理菜单系统已经定义了这个URL:(bloghome)/wp-admin/admin-ajax.php。下面我们介绍怎样将某个Ajax动作钩子添加到WordPress中,告诉脚本接收到请求时应该调用哪个插件PHP函数。为方便叙述,我们假设动作钩子名为"myplugin_elev_lookup"。
- 自定义请求变量:我们要将经纬度发送给服务器;我们也需要要将动作钩子名称发送给admin-ajax.php脚本。此外,我们还需要发送当前页面的cookies(其中包含登录信息)。最后,由于服务器端函数需要返回JavaScript以显示结果,我们还需要将海拔字段ID发送到服务器端函数上。
整合所有信息后,JavaScript函数的主体显示如下:
function myplugin_ajax_elevation( lat_field, long_field, elev_field ) { var mysack = new sack( "<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php" ); mysack.execute = 1; mysack.method = 'POST'; mysack.setVar( "action", "myplugin_elev_lookup" ); mysack.setVar( "latitude", lat_field.value ); mysack.setVar( "longitude", long_field.value ); mysack.setVar( "elev_field_id", elev_field.id ); mysack.encVar( "cookie", document.cookie, false ); mysack.onError = function() { alert('Ajax error in looking up elevation' )}; mysack.runAJAX(); return true; } // end of JavaScript function myplugin_ajax_elevation
接下来是最后一步——定义Ajax请求到达服务器时的反应。根据文章之前的描述,我们将请求发送到(bloghome)/wp-admin/admin-ajax.php,动作函数的参数为"myplugin_elev_lookup"。我们用 wp_ajax_*动作函数告诉WordPress接收到Ajax请求时应该调用插件中的哪个PHP函数。
PHP函数将经纬度发送给海拔查询服务器,等待响应并解析返回的结果,最终根据JavaScript的指令传回返回的信息。我们用web请求PHP类“Snoopy”(WordPress内置类)来发送web请求。步骤如下:
add_action('wp_ajax_myplugin_elev_lookup', 'myplugin_ajax_elev_lookup' ); function myplugin_ajax_elev_lookup() { // read submitted information $lat = $_POST['latitude']; $long = $_POST['longitude']; $field_id = $_POST['elev_field_id']; $units = "FEET"; // Build Snoopy URL request require_once( ABSPATH . WPINC . '/class-snoopy.php' ); $sno = new Snoopy(); $sno->agent = 'WordPress/' . $wp_version; $sno->read_timeout = 2; $reqURL = "http://gisdata.usgs.gov/XMLWebServices/TNM_Elevation_Service.asmx/getElevation?Y_Value=$lat&X_Value=$long&Elevation_Units=$units&Source_Layer=-1&Elevation_Only=1"; // Send request to elevation server if( !$sno->fetchtext( $reqURL )) { die( "alert('Could not connect to lookup host.')" ); } // Parse response if( !preg_match("|<Elevation>([d.-]+)</Elevation>|",$sno->results)){ die( "alert('Could not find elevation in lookup results.')" ); } $matches=preg_split( "|<Elevation>([d.-]+)</Elevation>|",$sno->results); //REGEX BUG: but it'll return info // Compose JavaScript for return die( "document.getElementById('$field_id').value = " . $matches[1] ); } // end of myplugin_axax_elev_lookup function
OK!这时我们还需要加入一些细节内容,像是Ajax请求是否来自正确地址的检查和验证等,希望大家能够通过这个例子对WordPress后台上的Ajax用法有基本了解。
访问者页面上的Ajax
在访问者所浏览的WordPress网页上使用Ajax与在WordPress后台使用Ajax略有不同。这是因为WordPress本身不存在内置的访问者页面Ajax,但这并不重要,接下来我们会介绍怎样在访问者页面上使用Ajax。如果要在WordPress后台上使用Ajax,可以忽略这部分内容。
在这个示例中我们假设目前有一个插件,网站/博客访问者可以对某项内容投票或评分。这可以是一个投票插件、日志评分插件或者其它类似插件。我们希望达到的效果是:通过Ajax提交访问者的投票,这样访问者就不需要等待页面刷新;投票被计入结果后,更新显示当前投票总数。为方便起见,我们假设投票和显示结果都是基于文本的,并且假设我们已经编辑了主题或用WordPress过滤器函数或动作函数在WordPress访问者页面适当的位置上添加了HTML代码。所添加的代码内容如下:
<form> Your vote: <input type="text" name="uservote" /> <input type="button" value="Vote!" onclick="myplugin_cast_vote(this.form.uservote,'voteresults');" /> <div id="voteresults"> (previous results output from your PHP function) </div> </form>
接下来我们需要定义Javascript函数 myplugin_cast_vote,而OnClick动作函数则会读取用户输入的信息,用SACK生成一个请求,然后将请求发送给插件进行处理。我们在简介中提到,这个Javascript函数和SACK库都需要被包含在访问者浏览页面的HTML代码的head版块中。我们可以利用wp_head动作钩子函数(当然也可以使用条件标签is_xyz()中的某些函数)将JavaScript函数添加到所有访问者浏览页面中:
add_action('wp_head', 'myplugin_js_header' ); function myplugin_js_header() // this is a PHP function { // use JavaScript SACK library for Ajax wp_print_scripts( array( 'sack' )); // Define custom JavaScript function ?> <script type="text/javascript"> //<![CDATA[ function myplugin_cast_vote( vote_field, results_div ) { // function body defined below } // end of JavaScript function myplugin_cast_vote //]]> </script> <?php } // end of PHP function myplugin_js_header
之后需要填写JavaScript函数myplugin_cast_vote的主体部分,该部分需要能够从表单域中读取投票信息,用SACK生成一个Ajax请求,然后将请求发送给服务器。在这个例子中,我们需要设置以下信息:
- 请求URL:我们要将请求发送到某个插件PHP文件中,可能是插件主PHP文件,也可能是独立PHP文件。在独立PHP文件中发送请求相对方便。为方便叙述,我们假设这个独立PHP文件名是"myplugin_ajax.php",位于WordPress标准目录wp-content/plugins中。
- 自定义请求变量:在这个例子中我们只需要发送投票信息和div的ID(返回的结果将进入服务器)。
整合所有信息后,JavaScript函数的主体显示如下:
function myplugin_cast_vote( vote_field, results_div ) { var mysack = new sack( "<?php bloginfo( 'wpurl' ); ?>/wp-content/plugins/myplugin_ajax.php" ); mysack.execute = 1; mysack.method = 'POST'; mysack.setVar( "vote", vote_field.value ); mysack.setVar( "results_div_id", results_div ); mysack.onError = function() { alert('Ajax error in voting' )}; mysack.runAJAX(); return true; } // end of JavaScript function myplugin_cast_vote
接下来是最后一步——对Ajax请求到达服务器时的反应进行定义。这将会在myplugin_ajax.php文件中完成,该文件读取已提交的投票信息,确认投票的有效性,将投票信息存入数据库,统计最新投票结果,最终将统计信息返回浏览器。如果暂时不考虑投票的处理过程,myplugin_ajax.php文件中应包含以下信息:
<?php // Put your author and license information here // TO DO! // Check request came from valid source here // TO DO! // read submitted information $vote = $_POST['vote']; $results_id = $_POST['results_div_id']; // Put your vote processing code here // In this example, assume // a) The processing code sets global // variable $error to a message if there is an error // b) If there is no error, $results contains // the HTML to put into the results DIV on the screen if( $error ) { die( "alert('$error')" ); } // Compose JavaScript for return die( "document.getElementById('$results_id').innerHTML = '$results'" ); ?>
OK!这时我们还需要加入一些细节内容,像是Ajax请求是否来自正确地址的检查和验证等,希望大家能够通过这个例子对WordPress访问者页面上的Ajax用法有基本了解。
延伸阅读
- Simplified AJAX For WordPress Plugin Developers using Jquery
- jQuery and Ajax in WordPress Administration Plugins
- jQuery and Ajax in Plugins for Public Pages
- Make your WordPress plugin talk AJAX
分类:中文手册