JavaScript、Ajax 和 jQuery

JavaScript

JavaScript 是许多 WordPress 插件中的重要组件。WordPress 附带了与 core 捆绑在一起的各种 JavaScript 库。WordPress 中最常用的库之一是 jQuery,因为它轻量级且易于使用。jQuery 可以在您的插件中使用来操作 DOM 对象或执行 Ajax 操作。

jQuery

使用 jQuery

收到您的 WordPress 网页后,您的 jQuery 脚本将在用户的浏览器上运行。基本的 jQuery 语句有两部分:一个选择器,用于确定代码应用到哪些 HTML 元素;以及一个操作或事件,用于确定代码的作用或反应。基本的事件语句如下所示:


jQuery.(selector).event(function);

当选择器选择的 HTML 元素中发生事件(例如鼠标单击)时,将执行最后一组括号内定义的函数。

以下所有代码示例均基于此 HTML 页面内容。假设它出现在插件的管理设置屏幕上,由文件定义myplugin_settings.php。这是一个简单的表格,每个标题旁边都有单选按钮。


<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>

输出在您的设置页面上可能看起来像这样。

样本表

有关 AJAX 的文章中,我们将构建一个 AJAX 交换,将用户选择保存在 usermeta 中,并添加标有所选标题的帖子数量。这不是一个非常实际的应用程序,但它说明了所有重要的步骤。jQuery 代码可以驻留在外部文件中,也可以输出到<script>块内的页面。我们将重点关注外部文件变体,因为从 PHP 传递值需要特别注意。如果您认为更方便,可以将相同的代码输出到页面。

选择器和事件

选择器与 CSS 选择器的形式相同:".class""#id"。还有更多形式,但这两种是您会经常使用的。在我们的示例中,我们将使用类“.pref”。还有许多可能的事件,您可能会经常使用的一个事件是“点击”。在我们的示例中,我们将使用“更改”来捕获单选按钮选择。请注意,jQuery 事件的命名通常与 JavaScript 事件的命名有所不同。到目前为止,在我们添加一个空的匿名函数之后,我们的示例语句如下所示:

$.(".pref").change(function(){
	/*do stuff*/
});

当“pref”类的任何元素发生更改时,此代码将“执行操作”。

注意:此代码片段以及本页上的所有示例都是为了说明 AJAX 的使用。该代码不适合生产环境,因为有意省略了相关操作,例如清理安全错误处理国际化。请务必始终在生产代码中解决这些重要操作。
 

AJAX

什么是 AJAX?

AJAX是异步 JavaScript 和 XML 的缩写。XML是一种数据交换格式,UX 是软件开发人员用户体验的简写。Ajax 是一种 Internet 通信技术,它允许用户浏览器中显示的网页向服务器请求特定信息,并在同一页面上显示此新信息,而无需重新加载整个页面。您已经可以想象这将如何改善用户体验。

虽然 XML 是使用的传统数据交换格式,但交换实际上可以是任何方便的格式。在使用PHP代码时,许多开发人员更喜欢JSON,因为从传输的数据流创建的内部数据结构更易于交互。

要查看 AJAX 的实际效果,请转到 WordPress 管理区域并添加类别或标签。单击“添加新”按钮时请密切注意,请注意页面发生变化但实际上并未重新加载。不相信?检查浏览器的后台历史记录,如果页面已重新加载,您将看到该页面的两个条目。

AJAX 甚至不需要用户操作即可工作。Google 文档每隔几分钟就会使用 AJAX 自动保存您的文档,而无需您启动保存操作。

为什么使用 AJAX?

显然,它改善了用户体验。AJAX 允许您呈现动态、响应迅速、用户友好的体验,而不是呈现无聊的静态页面。用户可以立即得到反馈,表明他们采取的某些操作是正确还是错误。在发现某一字段存在错误之前,无需提交整个表格。输入数据后即可验证重要字段。或者可以在用户键入时提出建议。

AJAX 可以显着减少来回流动的数据量。仅需要交换相关数据,而不是所有页面内容,这就是页面重新加载时发生的情况。

特别与 WordPress 插件相关,AJAX 是迄今为止启动独立于 WordPress 内容的流程的最佳方式。如果您以前编写过 PHP,您可能会通过简单地链接到新的 PHP 页面来完成此操作。单击链接的用户启动该过程。这样做的问题是,当您链接到新的外部 PHP 页面时,您无法访问任何 WordPress 功能。过去,开发人员通过wp-load.php在新的 PHP 页面上包含核心文件来访问 WordPress 功能。这样做的问题是您不可能再知道该文件的正确路径。WordPress 架构现在足够灵活,/wp-content/您的插件文件可以从其通常位置移动到安装根目录的一级。你无法知道在哪里wp-load.php是相对于你的插件文件的,你也无法知道安装文件夹的绝对路径。

您可以知道向何处发送 AJAX 请求,因为它是在全局 JavaScript 变量中定义的。您的 PHP AJAX 处理程序脚本实际上是一个操作挂钩,因此与外部 PHP 文件不同,所有 WordPress 功能都自动可用。

如何使用 AJAX?

如果您是 WordPress 新手,但有在其他环境中使用 AJAX 的经验,则需要重新学习一些内容。WordPress 实现 AJAX 的方式很可能与您习惯的不同。如果一切对你来说都是新的,没问题。您将在这里学习基础知识。一旦您开发了基本的 AJAX 交换,就可以轻而易举地扩展该基础并开发具有出色用户界面的杀手级应用程序!

WordPress 中的任何 AJAX 交换都有两个主要组件。客户端 JavaScript 或 jQuery 和服务器端 PHP。所有 AJAX 交换都遵循以下事件顺序。

  1. 某种页面事件会启动 JavaScript 或 jQuery 函数。该函数从页面收集一些数据并通过 HTTP 请求将其发送到服务器。因为使用 JavaScript 处理 HTTP 请求很尴尬,而且 jQuery 无论如何都捆绑到 WordPress 中,所以从现在开始我们将只关注 jQuery 代码。直接使用 JavaScript 进行 AJAX 是可能的,但当 jQuery 可用时就不值得这样做。
  2. 服务器接收请求并对数据执行某些操作。它可以组装相关数据并将其以 HTTP 响应的形式发送回客户端浏览器。这不是必需的,但由于需要让用户了解正在发生的事情,因此很少不发送某种响应。
  3. 发送初始 AJAX 请求的 jQuery 函数接收服务器响应并对其执行某些操作。它可能会更新页面上的某些内容和/或通过某种方式向用户呈现消息。

将 AJAX 与 jQuery 结合使用

现在我们将定义jQuery 文章中的代码片段中的“do stuff”部分。我们将使用$.post()方法,它有 3 个参数:发送 POST 请求的 URL、要发送的数据以及处理服务器响应的回调函数。不过,在此之前,我们需要提前做好一些计划,以免造成阻碍。我们进行以下分配以供稍后在回调函数中使用。其目的在回调部分会更加明显。


var this2 = this;

网址

所有 WordPress AJAX 请求都必须发送到wp-admin/admin-ajax.php. 正确、完整的 URL 需要来自 PHP,jQuery 无法自行确定该值,并且您不能在 jQuery 代码中对 URL 进行硬编码并期望其他人在其站点上使用您的插件。如果页面来自管理区域,WordPress 将在全局 JavaScript 变量ajaxurl中设置正确的 URL 。对于公共区域的页面,您需要自己建立正确的 URL 并使用wp_localize_script() 将其传递给 jQuery 。PHP 部分将对此进行更详细的介绍。现在只需知道适用于前端和后端的 URL 可用作您将在 PHP 段中定义的全局对象的属性。在 jQuery 中,它的引用方式如下:


my_ajax_obj.ajax_url

数据

所有需要发送到服务器的数据都包含在数据数组中。除了应用程序所需的任何数据之外,您还必须发送操作参数。对于可能导致数据库更改的请求,您需要发送一个随机数,以便服务器知道该请求来自合法来源。我们提供给.post()方法的示例数据数组如下所示:


{
  _ajax_nonce: my_ajax_obj.nonce, // nonce
  action: "my_tag_count", // action
  title: this.value // data
}

下面解释每个组件。

随机数

Nonce是“Numberused ONCE”的合成词。它本质上是分配给所服务的任何形式的每个实例的唯一序列号。随机数是使用 PHP 脚本建立的,并以与 URL 相同的方式传递给 jQuery,作为全局对象中的属性。在本例中,它被引用为my_ajax_obj.nonce

笔记

每次使用真正的随机数时都需要刷新,以便下一个 AJAX 调用有一个新的、未使用的随机数来发送作为验证。事实上,WordPress 的随机数实现并不是真正的随机数。除非您注销,否则在 24 小时内可以根据需要多次使用相同的随机数。使用相同的种子短语生成随机数将在 12 小时内始终产生相同的数字,之后最终将生成新的数字。

如果您的应用程序需要严格的安全性,请实现一个真正的随机数系统,其中服务器发送一个新的随机数来响应 Ajax 请求,以便脚本用于验证下一个请求。

如果将此随机数值键入_ajax_nonce ,这是最简单的。如果它与验证随机数的 PHP 代码协调,您可以使用不同的密钥,但仅使用默认值而不用担心协调会更容易。以下是该键值对的声明方式:


_ajax_nonce: my_ajax_obj.nonce

行动

所有 WordPress AJAX 请求都必须在数据中包含操作参数。该值是一个任意字符串,部分用于构造用于挂钩 AJAX 处理程序代码的操作标记。该值作为 AJAX 调用目的的非常简短的描述很有用。毫不奇怪,这个值的关键是'action'。在此示例中,我们将使用“my_tag_count”作为我们的操作值。该键值对的声明如下所示:


action: "my_tag_count"

服务器完成其任务所需的任何其他数据也包含在该数组中。如果有很多字段需要传输,有两种常见的格式可以将数据字段组合成单个字符串以方便传输:XML 和 JSON。使用这些格式是可选的,但无论您做什么都需要与服务器端的 PHP 脚本协调。有关这些格式的更多信息可在以下回调部分中找到。接收这种格式的数据比发送数据更常见,但两种方式都可以。

在我们的示例中,服务器只需要一个值,即所选书名的单个字符串,因此我们将使用键'title'。在 jQuery 中,触发事件的对象始终包含在变量this中。因此,所选元素的值为this.value。我们对该键值对的声明如下所示:


title: this.value

回调函数

回调处理程序是在发出请求后从服务器返回响应时执行的函数。再次,我们通常会在这里看到匿名函数。该函数传递一个参数,即服务器响应。响应可以是任何内容,从是或否到庞大的 XML 数据库。JSON 格式的数据也是一种有用的数据格式。甚至不需要响应。如果没有,则不需要指定回调。为了用户体验的利益,让用户知道任何请求发生了什么总是一个好主意,因此建议始终响应并提供一些发生情况的指示。

在我们的示例中,我们将无线电输入后面的当前文本替换为服务器响应,其中包括由书名标记的帖子数量。这是我们的匿名回调函数:


function( data ) {
  this2.nextSibling.remove();
  $( this2 ).after( data );
}

数据包含整个服务器响应。之前我们使用var this2 = this;行将触发更改事件的对象(引用为this )分配给this2 。。这是因为闭包中的变量作用域仅扩展了一级。通过在事件处理程序中分配this2 (最初只包含“/* do stuff */”的部分),我们可以在回调中使用它,而this超出了范围。

服务器响应可以采用任何形式。应将大量数据编码到数据流中以便于处理。XML 和 JSON 是两种常见的编码方案。

XML

XML 是 AJAX 的旧数据交换格式。毕竟它是 AJAX 中的“X”。尽管使用本机 PHP 函数可能很困难,但它仍然是一种可行的交换格式。出于这个原因,许多 PHP 程序员更喜欢 JSON 交换格式。如果您确实使用 XML,则解析方法取决于所使用的浏览器。对 Internet Explorer 使用 Microsoft.XMLDOM ActiveX,对其他所有内容使用 DOMParser。请注意,自 5.8 版本以来,WordPress 不再支持 Internet Explorer

JSON

JSON 通常因其轻量级和易用性而受到青睐。您实际上可以使用eval()解析 JSON ,但不要这样做!使用eval()会带来重大的安全风险。相反,使用专用的解析器,这也更快。使用解析器对象JSON的全局实例。为了确保它可用,请确保它与页面上的其他脚本一起排队。有关排队的更多信息将包含在稍后的PHP 部分中。

其他

只要数据格式与 PHP 处理程序协调,它可以是您喜欢的任何格式,例如逗号分隔、制表符分隔或任何适合您的结构。

客户端总结

现在我们已经将回调添加为$.post()函数的最终参数,我们已经完成了示例 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
			}
		);
	} );
} );

该脚本可以输出到网页上的块中,也可以包含在其自己的文件中。该文件可以驻留在 Internet 上的任何位置,但大多数插件开发人员将其放置在/js/插件主文件夹的子文件夹中。除非你有理由不这样做,否则你最好遵循惯例。对于这个例子,我们将命名我们的文件myjquery.js

 

服务器端 PHP 和排队

实现 AJAX 通信需要服务器端 PHP 脚本的两个部分。首先,我们需要将 jQuery 脚本排入网页并本地化 jQuery 脚本所需的任何 PHP 值。其次是 AJAX 请求的实际处理。

入队脚本

本节介绍了 WordPress 中 AJAX 的两个主要怪癖,这些怪癖可能会让刚接触 WordPress 的经验丰富的程序员感到困惑。一是需要将脚本排入队列,以使元链接正确显示在页面的头部部分。另外就是所有的AJAX请求都需要通过wp-admin/admin-ajax.php. 切勿直接向您的插件页面发送请求。

入队

使用该函数wp_enqueue_script()让 WordPress 在页面部分插入指向脚本的元链接。切勿在标题模板中对此类链接进行硬编码。作为插件开发人员,您无法随时访问标头模板,但无论如何这条规则都值得一提。

enqueue 函数接受五个参数,如下所示:


wp_enqueue_script(
	'ajax-script',
	plugins_url( '/js/myjquery.js', __FILE__ ),
	array( 'jquery' ),
	'1.0.,0',
	array(
	   'in_footer' => true,
	)
);

加载插件代码页时,您无法直接将脚本排入队列。脚本必须从几个动作钩子之一排队——哪一个取决于脚本需要链接到哪种类型的页面。对于管理页面,请使用admin_enqueue_scripts. 对于前端页面,请使用wp_enqueue_scripts,但登录页面除外,在这种情况下,请使用login_enqueue_scripts

admin_enqueue_scripts钩子将当前页面文件名传递给您的回调。使用此信息仅将脚本排队到需要的页面上。前端版本没有传递任何东西。is_home()在这种情况下,请使用、等模板标签is_single()来确保您仅将脚本排入需要的位置。这是我们示例的完整排队代码:


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' ),
		'1.0.0',
		array(
		   'in_footer' => true,
		)
	);
}

为什么我们在这里使用命名函数,而在 jQuery 中使用匿名函数?因为 PHP 最近才支持闭包。jQuery 对它们的支持已经有一段时间了。由于有些人可能仍在运行旧版本的 PHP,因此我们始终使用命名函数以获得最大兼容性。如果您有最新的 PHP 版本并且仅为您自己的安装进行开发,如果您愿意,可以继续使用闭包。

注册与入队

您将在其他教程中看到大量使用wp_register_script(). 这很好,但它的使用是可选的。不可选的是wp_enqueue_script()。必须调用此函数才能使您的脚本文件在网页上正确链接。那么为什么要注册脚本呢?它创建一个有用的标记或句柄,您可以根据需要轻松地在代码的各个部分引用脚本。如果您只需要加载脚本并且不在代码中的其他位置引用它,则无需注册它。

延迟脚本加载

WordPress 支持通过wp_register_script()和函数通过 WordPress 6.3 中引入的新数组参数中的键wp_enqueue_script()来指定脚本加载策略。strategy$args

支持的策略如下:

以下是为我们的插件中的附加脚本队列指定加载策略的示例:


wp_register_script(
    'ajax-script-two',
    plugins_url( '/js/myscript.js', __FILE__ ),
    array( ajax-script ),
    '1.0.,0',
    array(
          'strategy' => 'defer',
     )
);

使用时也适用相同的方法wp_enqueue_script()。在上面的示例中,我们表明我们打算'ajax-script-two'以延迟的方式加载脚本。

在指定延迟脚本加载策略时,在决定“合格策略”时会考虑脚本的依赖关系树(其依赖关系和/或依赖关系),以免导致应用对一个脚本有效的策略但会导致意外的执行顺序混乱,从而对树中的其他人有害。由于这种逻辑,您通过$args参数传递的预期加载策略可能不是最终(选择的)策略,但它永远不会对预期策略有害(或更严格)。

随机数

您需要创建一个随机数,以便可以将 jQuery AJAX 请求验证为合法请求,而不是来自某些未知不良行为者的潜在恶意请求。只有您的 PHP 脚本和 jQuery 脚本才会知道该值。收到请求后,您可以验证它是否与此处创建的值相同。这是为我们的示例创建随机数的方法:


$title_nonce = wp_create_nonce( 'title_example' );

该参数title_example可以是任意字符串。建议该字符串与随机数的用途相关,但它实际上可以是适合您的任何内容。

本地化

如果您还记得jQuery 部分,由 PHP 创建供 jQuery 使用的数据是在名为 的全局对象中传递的my_ajax_obj。在我们的示例中,此数据是一个随机数和 的完整 URL admin-ajax.php。分配对象属性和创建全局 jQuery 对象的过程称为本地化。这是我们示例中使用的本地化代码,它使用wp_localize_script().


wp_localize_script(
	'ajax-script',
	'my_ajax_obj',
	array(
		'ajax_url' => admin_url( 'admin-ajax.php' ),
		'nonce'    => $title_nonce,
	)
);

ajax-script请注意如何使用我们的脚本句柄,以便将全局对象分配给正确的脚本。该对象对于我们的脚本来说是全局的,而不是对于所有脚本来说。还可以从用于将脚本排队的同一个挂钩调用本地化。创建随机数也是如此,尽管该特定函数几乎可以在任何地方调用。所有这些组合在一个钩子回调中,如下所示:


add_action( 'admin_enqueue_scripts', 'my_enqueue' );

/**
 * Enqueue my scripts and assets.
 *
 * @param $hook
 */
function my_enqueue( $hook ) {
	if ( 'myplugin_settings.php' !== $hook ) {
		return;
	}
	wp_enqueue_script(
		'ajax-script',
		plugins_url( '/js/myjquery.js', __FILE__ ),
		array( 'jquery' ),
		'1.0.0',
		true
	);

	wp_localize_script(
		'ajax-script',
		'my_ajax_obj',
		array(
			'ajax_url' => admin_url( 'admin-ajax.php' ),
			'nonce'    => wp_create_nonce( 'title_example' ),
		)
	);
}
笔记:请记住仅将此随机数本地化添加到所需的页面,不要向不应该使用它的人显示随机数。current_user_can()并记住与能力或角色一起使用来完成安全性。

AJAX 操作

服务器端 PHP 代码的另一个主要部分是实际的 AJAX 处理程序,它接收 POST 数据,对其执行某些操作,然后将适当的响应发送回浏览器。它采用 WordPress操作挂钩的形式。您使用哪个挂钩标记取决于用户是否登录以及您的 jQuery 脚本作为action: value 传递的值。

笔记:$_GET、$_POST 和 $_COOKIE 与 $_REQUEST

您可能使用过一个或多个 PHP 超级全局变量,例如$_GET$_POST从表单或 cookie 中检索值(使用$_COOKIE)。也许您$_REQUEST更喜欢,或者至少已经看到过它的使用。这有点酷——无论请求方法是什么,POST或者GET,它都会有表单值。对于使用这两种方法的页面非常有效。最重要的是,它还有 cookie 值。一站式购物!这就是它的悲剧性缺陷。在名称冲突的情况下,cookie 值将覆盖任何表单值。因此,不良行为者很容易在浏览器上制作伪造的 cookie,这将覆盖您可能期望从请求中获得的任何表单值。$_REQUEST是黑客向您的表单值注入任意数据的简单途径。为了更加安全,请遵循特定变量并避免一刀切。

由于我们的 AJAX 交换是针对插件的设置页面的,因此用户必须登录。如果您还记得jQuery 部分,该action:值是"my_tag_count"。这意味着我们的操作挂钩标签将是wp_ajax_my_tag_count. 如果我们的 AJAX 交换由当前未登录的用户使用,则操作挂钩标记将是wp_ajax_nopriv_my_tag_count用于挂钩操作的基本代码如下所示:


add_action( 'wp_ajax_my_tag_count', 'my_ajax_handler' );

/**
 * Handles my AJAX request.
 */
function my_ajax_handler() {
	// Handle the ajax request here

	wp_die(); // All ajax handlers die when finished
}

AJAX 处理程序应该做的第一件事是验证 jQuery 发送的随机数check_ajax_referer(),该随机数应该与脚本排队时本地化的值相同。


check_ajax_referer( 'title_example' );

提供的参数必须与之前提供的参数相同wp_create_nonce()。如果随机数没有签出,该函数就会终止。如果这是一个真正的随机数,那么既然它被使用了,那么它的价值就不再有任何好处了。然后,您将生成一个新的并将其发送到回调脚本,以便它可以用于下一个请求。但由于 WordPress 随机数的有效期为 24 小时,因此您只需检查它即可。

数据

随着随机数的出现,我们的处理程序可以处理$_POST['title']. 首先,我们将值分配给一个新变量,运行完后wp_unslash() 删除任何意外的引号。


$title = wp_unslash( $_POST['title'] );

我们可以使用以下命令将用户的选择保存在用户元中update_user_meta()


update_user_meta( get_current_user_id(), 'title_preference', sanitize_post_title( $title ) );

然后我们构建一个查询来获取所选标题标签的帖子计数。


$args      = array(
	'tag' => $title,
);
$the_query = new WP_Query( $args );

最后我们可以将响应发送回 jQuery 脚本。传输数据的方式有多种。在讨论示例的具体细节之前,让我们先看看一些选项。

XML

PHP 对 XML 的支持还有一些不足之处。幸运的是,WordPress 提供了该类WP_Ajax_Response来使任务变得更容易。WP_Ajax_Response类将生成 XML 格式的响应,为标头设置正确的内容类型,输出响应 xml,然后结束 — 确保正确的 XML 响应

JSON

这种格式是轻量级且易于使用的,WordPress 提供了wp_send_json对您的响应进行 json 编码、打印和消亡的功能 - 有效地替换了WP_Ajax_Response。WordPress 还提供了wp_send_json_successwp_send_json_error函数,允许在 JS 中触发适当的 done() 或 failed() 回调。

其他

只要发送者和接收者协调一致,您就可以以任何您喜欢的方式传输数据。逗号分隔或制表符分隔等文本格式是多种可能性之一。对于少量数据,发送原始流可能就足够了。这就是我们将在示例中执行的操作 – 我们将发送实际的替换 HTML,仅此而已。


echo esc_html( $title ) . ' (' . $the_query->post_count . ') ';

在现实世界的应用程序中,您必须考虑操作可能因某种原因失败的可能性,例如数据库服务器可能已关闭。响应应该考虑到这种意外情况,并且接收响应的 jQuery 脚本应该采取相应的行动,也许会告诉用户稍后再试。

当处理程序完成所有任务后,它需要死亡。如果您使用WP_Ajax_Response或 wp_send_json* 函数,则会自动为您处理。如果没有,只需使用 WordPresswp_die() 功能即可。

AJAX 处理程序摘要

我们示例的完整 AJAX 处理程序如下所示:


/**
 * AJAX handler using JSON
 */
function my_ajax_handler__json() {
	check_ajax_referer( 'title_example' );
	$title = wp_unslash( $_POST['title'] );

	update_user_meta( get_current_user_id(), 'title_preference', sanitize_post_title( $title ) );

	$args      = array(
		'tag' => $title,
	);
	$the_query = new WP_Query( $args );
	wp_send_json( esc_html( $title ) . ' (' . $the_query->post_count . ') ' );
}

/**
 * AJAX handler not using JSON.
 */
function my_ajax_handler() {
	check_ajax_referer( 'title_example' );
	$title = wp_unslash( $_POST['title'] );

	update_user_meta( get_current_user_id(), 'title_preference', sanitize_post_title( $title ) );

	$args      = array(
		'tag' => $title,
	);
	$the_query = new WP_Query( $args );
	echo esc_html( $title ) . ' (' . $the_query->post_count . ') ';
	wp_die(); // All ajax handlers should die when finished
}
 

心跳API

Heartbeat API 是 WordPress 内置的一个简单的服务器轮询 API,允许近乎实时的前端更新。

怎么运行的

页面加载时,客户端心跳代码会设置一个间隔(称为“tick”),每 15-120 秒运行一次。当它运行时,heartbeat 收集数据并通过 jQuery 事件发送,然后将其发送到服务器并等待响应。在服务器上,admin-ajax 处理程序获取传递的数据,准备响应,过滤响应,然后以 JSON 格式返回数据。客户端接收此数据并触发最终 jQuery 事件以指示数据已收到。

自定义Heartbeat事件的基本流程是:

  1. 向要发送的数据添加附加字段(JSheartbeat-send事件)
  2. 检测 PHP 中的发送字段,并添加额外的响应字段(heartbeat_received过滤器)
  3. 在JS中处理返回的数据(JS heartbeat-tick)

(您可以选择仅使用其中一个或两个事件,具体取决于您需要的功能。)

使用API

使用心跳 API 需要两个独立的功能:JavaScript 中的发送和接收回调,以及 PHP 中处理传递数据的服务器端过滤器。

发送数据到服务器

当 Heartbeat 向服务器发送数据时,您可以包含自定义数据。这可以是您想要发送到服务器的任何数据,也可以是一个简单的真值来指示您正在等待数据。


jQuery( document ).on( 'heartbeat-send', function ( event, data ) {
	// Add additional data to Heartbeat data.
	data.myplugin_customfield = 'some_data';
});

在服务器上接收并响应

然后,您可以在服务器端检测此数据,并向响应添加其他数据。


/**
 * Receive Heartbeat data and respond.
 *
 * Processes data received via a Heartbeat request, and returns additional data to pass back to the front end.
 *
 * @param array $response Heartbeat response data to pass back to front end.
 * @param array $data     Data received from the front end (unslashed).
 *
 * @return array
 */
function myplugin_receive_heartbeat( array $response, array $data ) {
	// If we didn't receive our data, don't send any back.
	if ( empty( $data['myplugin_customfield'] ) ) {
		return $response;
	}

	// Calculate our data and pass it back. For this example, we'll hash it.
	$received_data = $data['myplugin_customfield'];

	$response['myplugin_customfield_hashed'] = sha1( $received_data );
	return $response;
}
add_filter( 'heartbeat_received', 'myplugin_receive_heartbeat', 10, 2 );

处理响应

回到前端,您可以处理接收这些数据。


jQuery( document ).on( 'heartbeat-tick', function ( event, data ) {
	// Check for our data, and use it.
	if ( ! data.myplugin_customfield_hashed ) {
		return;
	}

	alert( 'The hash is ' + data.myplugin_customfield_hashed );
});


并非每个功能都需要所有这三个步骤。例如,如果您不需要向服务器发送任何数据,则可以仅使用后两个步骤。

概括

以下是前面讨论中的所有示例代码片段,它们被组装成两个完整的代码页:一个用于 jQuery,另一个用于 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' ),
      '1.0.0',
      true
   );

   $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' );

   $title = wp_unslash( $_POST['title'] );

   update_user_meta( get_current_user_id(), 'title_preference', $title );

   $args = array(
      'tag' => $title,
   );

   $the_query = new WP_Query( $args );

   echo esc_html( $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
		});
	});
});

存储首选项后,生成的帖子计数将添加到所选标题中。

更多信息