给出以下代码:我的WP网站并登录。我在Admin中浏览了几页。在笔记本电脑电池没电之前,“ init”动作总共触发了100次。
第一个问题:我们寄给奶奶多少钱?是$ 1,$ 2,$ 100还是$ 200(还是其他?)
如果您还可以解释您的答案,那将是很棒的事情。
第二个问题:如果我们想确保我们只寄给奶奶1美元,这样做的最佳方法是什么?全局变量(信号量)在我们第一次发送$ 1时设置为“ true”吗?还是有其他测试来检查某个动作是否已经发生并阻止其多次触发?
第三个问题:插件开发人员是否担心这件事?我意识到我的示例很愚蠢,但我同时考虑了性能问题和其他意外的副作用(例如,如果函数更新/插入数据库)。
#1 楼
以下是对此的一些随机想法:问题#1
我们寄了多少钱给奶奶?
/>对于100页的加载,我们向她发送了100 x $ 1 = $ 100。
这里实际上是指
100 x do_action( 'init' )
调用。 没关系,我们用两次添加了它: br />
我们可以检查
add_action
只是add_filter
的包装器,该包装器构造了全局$wp_filter
数组: :add_action( 'init','send_money_to_grandma' );
add_action( 'init','send_money_to_grandma' );
,那么我们将向她发送2 x每页加载$ 1或每200页加载$ 200。
如果回调函数不同,则相同:
function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
global $wp_filter, $merged_filters;
$idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
$wp_filter[$tag][$priority][$idx] = array(
'function' => $function_to_add,
'accepted_args' => $accepted_args
);
unset( $merged_filters[ $tag ] );
return true;
}
问题#2
如果我们要确保仅发送$ 1的祖母
如果我们只希望在每次页面加载时发送一次,则应该这样做:
因为
init
挂钩仅触发一次。我们可能还有其他每个页面加载会触发多次的钩子。我们打电话给:
add_action( 'init','send_money_to_grandma', 9 );
add_action( 'init','send_money_to_grandma', 10 );
但是如果
someaction
触发10次会发生什么情况每页加载量?我们可以使用
add_action( 'init','send_money_to_grandma_1_dollar' );
add_action( 'init','send_money_to_grandma_also_1_dollar' );
调整
send_money_to_grandma()
函数,或使用静态变量作为计数器: br /> add_action( 'init','send_money_to_grandma' );
如果只想运行一次(曾经!),则可以通过Options API在
wp_options
表中注册一个选项:add_action( 'someaction ','send_money_to_grandma' );
如果我们想每天给她汇款一次,那么我们可以使用Transient API。甚至可以使用wp-cron。
请注意,您可能会调用ajax。
还有一些方法可以检查这些内容,例如使用
DOING_AJAX
还可能存在重定向,这可能会中断流。
然后我们可能只想限制后端,而不是
is_admin()
:! is_admin()
。问题#3
是插件开发人员担心的事情吗?
是的,这很重要。如果我们想让我们的祖母非常我们很乐意做:
function send_money_to_grandma()
{
if( ! did_action( 'someaction' ) )
internetofThings("send grandma","");
}
但这对性能和我们的钱包都非常不利;-)
评论
哇-谢谢你这么详尽的回应;这极大地帮助了!
– C C
15年11月24日在23:05
不用客气-我真的很喜欢你怎么说你的问题;-) @CC
–birgire
2015年11月24日23:26
归根结底,我们要让钱包和奶奶开心,所以这一切都是为了找到完美的和谐/平衡;-)
–Pieter Goosen
2015年11月25日下午4:32
+1是一个非常不错的答案,但是值得一说的是,添加操作的时间还取决于回调id,并且在处理对象时,事情要复杂一些。我会写一个答案...
– gmazzap♦
15年11月25日在12:29
谢谢@gmazzap-是的,那太好了,因为我没有介绍第三个键$ idx和_wp_filter_build_unique_id(),只显示了它;-)
–birgire
2015年11月25日12:50
#2 楼
比起完整的答案,这更像是对Birgire很好的答案的评论,但是必须编写代码,注释不适合。从答案看来,似乎添加动作的唯一原因是即使在示例代码中两次调用了
add_action()
,在OP示例代码中只有一次,这是使用相同优先级的事实。 在
add_filter
的代码中,重要的部分是_wp_filter_build_unique_id()
函数调用,该函数为每个回调创建唯一的ID。如果您使用简单的变量,例如包含函数名称的字符串,例如
"send_money_to_grandma"
,则id将等于字符串本身,因此,如果优先级相同,且id相同,则回调将被添加一次。但是事情并不总是那么简单。回调可以是PHP中的
callable
:函数名称
动态类方法
可调用对象
闭包(匿名函数)
前两个分别由一个字符串和2个字符串数组(
'send_money_to_grandma'
和array('MoneySender', 'send_to_grandma')
)表示,因此id始终相同,并且可以确保添加了回调如果优先级相同,则一次。在所有其他3种情况下,id取决于对象实例(匿名函数是PHP中的一个对象),因此仅当该对象是相同的实例,需要注意的是,相同的实例和相同的类是两个不同的事物。
以这个示例为例:
答案是2,因为WordPress为
$sender1
和$sender2
生成的id不同。 /> class MoneySender {
public function sent_to_grandma( $amount = 1 ) {
// things happen here
}
}
$sender1 = new MoneySender();
$sender2 = new MoneySender();
add_action( 'init', array( $sender1, 'sent_to_grandma' ) );
add_action( 'init', array( $sender1, 'sent_to_grandma' ) );
add_action( 'init', array( $sender2, 'sent_to_grandma' ) );
上面我在闭包内部使用了函数
sent_to_grandma
,即使代码相同,两个闭包也是\Closure
对象的2个不同实例,因此WP将创建2个不同的ID,即使优先级是一样。#3 楼
您不能将具有相同优先级的相同动作添加到相同的动作挂钩。这样做是为了防止多个插件依赖第三方插件的动作发生多次(请考虑woocommerce)以及所有第三方插件,例如网关付款集成等)。
因此,如果不指定优先级,祖母仍然很贫穷: br />
奶奶现在死了,口袋里有4美元(1、2、3和默认值:10)。
评论
必须承认,这是长期以来最好的问题之一;-)