如何删除动作挂钩非静态方法和 class 无法实例化
How to remove action hooking non static method and class can not be instantiated
我正在使用 woocommerce 产品供应商插件,在单个产品页面中有 .我想将其替换为 ;
加起来像
class WC_Product_Vendors_Vendor_Frontend {
public static function init() {
$self = new self();
add_action( 'woocommerce_single_product_summary', array( $self, 'add_sold_by_single' ), 39 );
return true;
}
public function add_sold_by_cart( $values, $cart_item ) {
$sold_by = get_option( 'wcpv_vendor_settings_display_show_by', 'yes' );
if ( 'yes' === $sold_by ) {
$sold_by = WC_Product_Vendors_Utils::get_sold_by_link( $cart_item['data']->id );
$values[] = array(
'name' => apply_filters( 'wcpv_sold_by_text', esc_html__( 'Sold By', 'woocommerce-product-vendors' ) ),
'display' => '<em class="wcpv-sold-by-cart"><a href="' . esc_url( $sold_by['link'] ) . '" title="' . esc_attr( $sold_by['name'] ) . '">' . $sold_by['name'] . '</a></em>',
);
}
return $values;
}
}
WC_Product_Vendors_Vendor_Frontend::init();
我试着像
那样解开它
1)
add_action( 'wp_head', 'my_remove_actions', 39 );
function my_remove_actions(){
remove_action( 'woocommerce_single_product_summary', array( 'WC_Product_Vendors_Vendor_Frontend', 'add_sold_by_single' ), 39 );
}
2)
add_action( 'wp_head', 'my_remove_actions', 39 );
function my_remove_actions(){
global $wc_product_vendors_vendor_frontend;
$wc_product_vendors_vendor_frontend = new WC_Product_Vendors_Vendor_Frontend();
remove_action( 'woocommerce_single_product_summary', array( $wc_product_vendors_vendor_frontend, 'add_sold_by_single' ), 39 );
}
3)
class XWC_Product_Vendors_Vendor_Frontend extends WC_Product_Vendors_Vendor_Frontend{
public function __construct(){}
}
add_action( 'wp_head', 'my_remove_actions', 39 );
function my_remove_actions(){
global $xwc_product_vendors_vendor_frontend;
$xwc_product_vendors_vendor_frontend = new XWC_Product_Vendors_Vendor_Frontend();
remove_action( 'woocommerce_single_product_summary', array( $xwc_product_vendors_vendor_frontend, 'add_sold_by_single' ), 39 );
}
4)
class XWC_Product_Vendors_Vendor_Frontend extends WC_Product_Vendors_Vendor_Frontend{
public function __construct() {
remove_action( 'woocommerce_single_product_summary', array( $this, 'add_sold_by_single' ), 39 );
}
}
new XWC_Product_Vendors_Vendor_Frontend();
5)
class XWC_Product_Vendors_Vendor_Frontend extends WC_Product_Vendors_Vendor_Frontend{
public static function init() {
$self = new self();
remove_action( 'woocommerce_single_product_summary', array( $self, 'add_sold_by_single' ), 39 );
}
}
XWC_Product_Vendors_Vendor_Frontend::init();
但是无法删除!请指导我这样做。
更新
我得到了
的输出
print_r($wp_filter['woocommerce_single_product_summary']);
Array
(
[10] => Array
(
[woocommerce_template_single_price] => Array
(
[function] => woocommerce_template_single_price
[accepted_args] => 1
)
)
[20] => Array
(
[woocommerce_template_single_excerpt] => Array
(
[function] => woocommerce_template_single_excerpt
[accepted_args] => 1
)
)
[40] => Array
(
[woocommerce_template_single_meta] => Array
(
[function] => woocommerce_template_single_meta
[accepted_args] => 1
)
)
[50] => Array
(
[woocommerce_template_single_sharing] => Array
(
[function] => woocommerce_template_single_sharing
[accepted_args] => 1
)
)
[30] => Array
(
[woocommerce_template_single_add_to_cart] => Array
(
[function] => woocommerce_template_single_add_to_cart
[accepted_args] => 1
)
)
[39] => Array
(
[00000000262d19ef000000007f4708faadd_sold_by_single] => Array
(
[function] => Array
(
[0] => WC_Product_Vendors_Vendor_Frontend Object
(
)
[1] => add_sold_by_single
)
[accepted_args] => 1
)
[le_child_add_sold_by_single] => Array
(
[function] => le_child_add_sold_by_single
[accepted_args] => 1
)
)
)
试试这个:
add_action( 'woocommerce_before_single_product', 'my_remove_actions' );
function my_remove_actions(){
remove_action( 'woocommerce_single_product_summary', array( 'WC_Product_Vendors_Vendor_Frontend', 'add_sold_by_single' ), 39 );
}
显示此过滤器的所有挂钩函数:
add_action( 'woocommerce_before_single_product', 'lets_have_a_look' );
function lets_have_a_look(){
global $wp_filter;
print_r($wp_filter['woocommerce_single_product_summary']);
}
为什么这些解决方案对您不起作用?
为了注销回调,您必须获取对象的实例。这个插件的问题是:它没有通过为您提供获取实例的方法来正确使用 Singleton。因此,您无法获取实例。嘘
变通
我们需要解决方法。让我解释一下,以备日后使用。
WordPress Core 将所有已注册的回调与其事件注册表一起存储。当您执行 add_action
或 add_filter
时,回调将存储在此事件注册表中 table(这是一个大型多维数组)。为了取消注册(或删除)作为特定对象(而不是静态方法)中的方法的回调,您必须拥有该对象的实例。这意味着您需要代表您要定位的对象的变量。
在此示例中,您没有直接拥有它。但是 WordPress 使用它的对象哈希 ID 与方法名称连接来存储方法的密钥。我们可以使用该模式来获取事件注册表中的记录(元素)table。
/**
* #EXPLANATION#
* The plugin loads the file using `plugins_loaded` with a priority of 0. Here
* we are doing the same thing but after the file is loaded, meaning after the
* events are registered.
*/
add_action( 'plugins_loaded', 'remove_woocommerce_add_sold_by_single_callback', 1 );
/**
* Unregister the WooCommerce `WC_Product_Vendors_Vendor_Frontend::add_sold_by_single` from the
* event `woocommerce_single_product_summary`.
*
* #EXPLANATION#
* I'm adding comments in the code only to illustrate what is happening and why. Please
* remove the inline comments when using this code. Thank you.
*
* @since 1.0.0
*
* @return void
*/
function remove_woocommerce_add_sold_by_single_callback() {
/**
* #EXPLANATION#
* WordPress keeps an event registry table for the callbacks that
* are pre-registered to each event name. The format of the table is:
*
* $wp_filter[ event name ][ priority number ][ callback name ]
*
* The registry table is a global variable called $wp_filter. You need to include
* that global into this function's scope.
*/
global $wp_filter;
/**
* #EXPLANATION#
* Let's make sure that the event name has a callback registered to the priority
* number of 39. If no, then return early (bail out).
*/
if ( ! isset( $wp_filter['woocommerce_single_product_summary']['39'] ) ) {
return;
}
/**
* #EXPLANATION#
* We will loop through each of the registered callbacks for the priority of 39. Why?
* You can't assume that only that one function is registered at 39. There may be more.
* Therefore, let's loop.
*
* We are grabbing the callback function that is registered. This is a unique key. For
* objects, WordPress uses the PHP construct spl_object_hash() to grab its hash ID. Then it
* concatenates it together with the method's name. You are not going to know what the unique
* ID is. Why? The first 32 characters are the hash ID, which is a memory location and not
* relative to the human readable name of `WC_Product_Vendors_Vendor_Frontend`. Rather, it's
* related to its object.
*/
foreach( $wp_filter['woocommerce_single_product_summary']['39'] as $callback_function => $registration ) {
/**
* #EXPLANATION#
* Give that we don't know what the first 32 characters of the object's hash ID is, we need
* to check if the callback function includes the method we are looking for. This line
* of code says: "Hey, do you contain the method name `add_sold_by_single` starting at
* the 32's character." If yes, then this is the one we want.
*/
if ( strpos( $callback_function, 'add_sold_by_single', 32) !== false) {
/**
* #EXPLANATION#
* Now we have the actual callback function key that is registered in the
* event registry. We can use remove_action to unregister it.
*/
remove_action( 'woocommerce_single_product_summary', $callback_function, 39 );
break;
}
}
}
这段代码基本上是这样的:
- 检查是否已将任何内容注册到事件名称和优先级编号。如果否,则无事可做。让我们摆脱困境。
- 我们需要获取唯一 ID,或者 WordPress 称之为
$idx
。这是回调的唯一键,由哈希 ID 组成。方法名称。
- 一旦我们有了唯一的 ID,您就可以使用
remove_action
注销回调。它也适用于 remove_filter
。
可重用代码
上面的代码是为了说明如何做以及它是如何工作的。但是该代码不可重用,因为参数是硬编码的。相反,您需要使用 this code 然后像这样调用它(在插件中时):
add_action( 'plugins_loaded', 'remove_woocommerce_add_sold_by_single_callback', 1 );
/**
* Unregister the WooCommerce `WC_Product_Vendors_Vendor_Frontend::add_sold_by_single` from the
* event `woocommerce_single_product_summary`.
*
* @since 1.0.0
*
* @return void
*/
function remove_woocommerce_add_sold_by_single_callback() {
do_hard_unregister_object_callback( 'woocommerce_single_product_summary', 39, 'add_sold_by_single');
}
哪个事件?
如果您在插件中使用此代码(您应该这样做),请使用 plugins_loaded
。
如果将它放入主题中,则不能使用 plugins_loaded
,因为它在主题加载之前就已触发。对于主题,您需要使用 after_setup_theme
而不是 plugins_loaded
。
测试
为了测试,让我们转储之前和之后的注册表,看看它是否确实删除了它。执行以下操作:
function remove_woocommerce_add_sold_by_single_callback() {
global $wp_filter;
var_dump( $wp_filter['woocommerce_single_product_summary'][39] );
do_hard_unregister_object_callback( 'woocommerce_single_product_summary', 39, 'add_sold_by_single');
if ( ! isset( $wp_filter['woocommerce_single_product_summary'][39] ) ) {
var_dump( $wp_filter['woocommerce_single_product_summary'] );
} else {
var_dump( $wp_filter['woocommerce_single_product_summary'][39] );
}
}
结果会让我们看看它是否从那里开始并在之后消失。
或者您可以通过 javascript 完成。
add_action( 'woocommerce_archive_description', "move_author_summary_to_image");
/**
* Move the author summary right after the image so we can float them left and right.
*/
function move_author_summary_to_image() {
?>
<script>
$('document').ready (function () {
var summary = $("#isle_body .wcpv-vendor-profile.entry-summary").html();
$("#isle_body .wcpv-vendor-profile.entry-summary").hide();
$(summary).addClass("author_summary").insertAfter($("#isle_body p.wcpv-vendor-logo"));
});
</script>
<?php
}
我正在使用 woocommerce 产品供应商插件,在单个产品页面中有 .我想将其替换为 ;
加起来像
class WC_Product_Vendors_Vendor_Frontend {
public static function init() {
$self = new self();
add_action( 'woocommerce_single_product_summary', array( $self, 'add_sold_by_single' ), 39 );
return true;
}
public function add_sold_by_cart( $values, $cart_item ) {
$sold_by = get_option( 'wcpv_vendor_settings_display_show_by', 'yes' );
if ( 'yes' === $sold_by ) {
$sold_by = WC_Product_Vendors_Utils::get_sold_by_link( $cart_item['data']->id );
$values[] = array(
'name' => apply_filters( 'wcpv_sold_by_text', esc_html__( 'Sold By', 'woocommerce-product-vendors' ) ),
'display' => '<em class="wcpv-sold-by-cart"><a href="' . esc_url( $sold_by['link'] ) . '" title="' . esc_attr( $sold_by['name'] ) . '">' . $sold_by['name'] . '</a></em>',
);
}
return $values;
}
}
WC_Product_Vendors_Vendor_Frontend::init();
我试着像
那样解开它1)
add_action( 'wp_head', 'my_remove_actions', 39 );
function my_remove_actions(){
remove_action( 'woocommerce_single_product_summary', array( 'WC_Product_Vendors_Vendor_Frontend', 'add_sold_by_single' ), 39 );
}
2)
add_action( 'wp_head', 'my_remove_actions', 39 );
function my_remove_actions(){
global $wc_product_vendors_vendor_frontend;
$wc_product_vendors_vendor_frontend = new WC_Product_Vendors_Vendor_Frontend();
remove_action( 'woocommerce_single_product_summary', array( $wc_product_vendors_vendor_frontend, 'add_sold_by_single' ), 39 );
}
3)
class XWC_Product_Vendors_Vendor_Frontend extends WC_Product_Vendors_Vendor_Frontend{
public function __construct(){}
}
add_action( 'wp_head', 'my_remove_actions', 39 );
function my_remove_actions(){
global $xwc_product_vendors_vendor_frontend;
$xwc_product_vendors_vendor_frontend = new XWC_Product_Vendors_Vendor_Frontend();
remove_action( 'woocommerce_single_product_summary', array( $xwc_product_vendors_vendor_frontend, 'add_sold_by_single' ), 39 );
}
4)
class XWC_Product_Vendors_Vendor_Frontend extends WC_Product_Vendors_Vendor_Frontend{
public function __construct() {
remove_action( 'woocommerce_single_product_summary', array( $this, 'add_sold_by_single' ), 39 );
}
}
new XWC_Product_Vendors_Vendor_Frontend();
5)
class XWC_Product_Vendors_Vendor_Frontend extends WC_Product_Vendors_Vendor_Frontend{
public static function init() {
$self = new self();
remove_action( 'woocommerce_single_product_summary', array( $self, 'add_sold_by_single' ), 39 );
}
}
XWC_Product_Vendors_Vendor_Frontend::init();
但是无法删除!请指导我这样做。
更新
我得到了
的输出print_r($wp_filter['woocommerce_single_product_summary']);
Array
(
[10] => Array
(
[woocommerce_template_single_price] => Array
(
[function] => woocommerce_template_single_price
[accepted_args] => 1
)
)
[20] => Array
(
[woocommerce_template_single_excerpt] => Array
(
[function] => woocommerce_template_single_excerpt
[accepted_args] => 1
)
)
[40] => Array
(
[woocommerce_template_single_meta] => Array
(
[function] => woocommerce_template_single_meta
[accepted_args] => 1
)
)
[50] => Array
(
[woocommerce_template_single_sharing] => Array
(
[function] => woocommerce_template_single_sharing
[accepted_args] => 1
)
)
[30] => Array
(
[woocommerce_template_single_add_to_cart] => Array
(
[function] => woocommerce_template_single_add_to_cart
[accepted_args] => 1
)
)
[39] => Array
(
[00000000262d19ef000000007f4708faadd_sold_by_single] => Array
(
[function] => Array
(
[0] => WC_Product_Vendors_Vendor_Frontend Object
(
)
[1] => add_sold_by_single
)
[accepted_args] => 1
)
[le_child_add_sold_by_single] => Array
(
[function] => le_child_add_sold_by_single
[accepted_args] => 1
)
)
)
试试这个:
add_action( 'woocommerce_before_single_product', 'my_remove_actions' );
function my_remove_actions(){
remove_action( 'woocommerce_single_product_summary', array( 'WC_Product_Vendors_Vendor_Frontend', 'add_sold_by_single' ), 39 );
}
显示此过滤器的所有挂钩函数:
add_action( 'woocommerce_before_single_product', 'lets_have_a_look' );
function lets_have_a_look(){
global $wp_filter;
print_r($wp_filter['woocommerce_single_product_summary']);
}
为什么这些解决方案对您不起作用?
为了注销回调,您必须获取对象的实例。这个插件的问题是:它没有通过为您提供获取实例的方法来正确使用 Singleton。因此,您无法获取实例。嘘
变通
我们需要解决方法。让我解释一下,以备日后使用。
WordPress Core 将所有已注册的回调与其事件注册表一起存储。当您执行 add_action
或 add_filter
时,回调将存储在此事件注册表中 table(这是一个大型多维数组)。为了取消注册(或删除)作为特定对象(而不是静态方法)中的方法的回调,您必须拥有该对象的实例。这意味着您需要代表您要定位的对象的变量。
在此示例中,您没有直接拥有它。但是 WordPress 使用它的对象哈希 ID 与方法名称连接来存储方法的密钥。我们可以使用该模式来获取事件注册表中的记录(元素)table。
/**
* #EXPLANATION#
* The plugin loads the file using `plugins_loaded` with a priority of 0. Here
* we are doing the same thing but after the file is loaded, meaning after the
* events are registered.
*/
add_action( 'plugins_loaded', 'remove_woocommerce_add_sold_by_single_callback', 1 );
/**
* Unregister the WooCommerce `WC_Product_Vendors_Vendor_Frontend::add_sold_by_single` from the
* event `woocommerce_single_product_summary`.
*
* #EXPLANATION#
* I'm adding comments in the code only to illustrate what is happening and why. Please
* remove the inline comments when using this code. Thank you.
*
* @since 1.0.0
*
* @return void
*/
function remove_woocommerce_add_sold_by_single_callback() {
/**
* #EXPLANATION#
* WordPress keeps an event registry table for the callbacks that
* are pre-registered to each event name. The format of the table is:
*
* $wp_filter[ event name ][ priority number ][ callback name ]
*
* The registry table is a global variable called $wp_filter. You need to include
* that global into this function's scope.
*/
global $wp_filter;
/**
* #EXPLANATION#
* Let's make sure that the event name has a callback registered to the priority
* number of 39. If no, then return early (bail out).
*/
if ( ! isset( $wp_filter['woocommerce_single_product_summary']['39'] ) ) {
return;
}
/**
* #EXPLANATION#
* We will loop through each of the registered callbacks for the priority of 39. Why?
* You can't assume that only that one function is registered at 39. There may be more.
* Therefore, let's loop.
*
* We are grabbing the callback function that is registered. This is a unique key. For
* objects, WordPress uses the PHP construct spl_object_hash() to grab its hash ID. Then it
* concatenates it together with the method's name. You are not going to know what the unique
* ID is. Why? The first 32 characters are the hash ID, which is a memory location and not
* relative to the human readable name of `WC_Product_Vendors_Vendor_Frontend`. Rather, it's
* related to its object.
*/
foreach( $wp_filter['woocommerce_single_product_summary']['39'] as $callback_function => $registration ) {
/**
* #EXPLANATION#
* Give that we don't know what the first 32 characters of the object's hash ID is, we need
* to check if the callback function includes the method we are looking for. This line
* of code says: "Hey, do you contain the method name `add_sold_by_single` starting at
* the 32's character." If yes, then this is the one we want.
*/
if ( strpos( $callback_function, 'add_sold_by_single', 32) !== false) {
/**
* #EXPLANATION#
* Now we have the actual callback function key that is registered in the
* event registry. We can use remove_action to unregister it.
*/
remove_action( 'woocommerce_single_product_summary', $callback_function, 39 );
break;
}
}
}
这段代码基本上是这样的:
- 检查是否已将任何内容注册到事件名称和优先级编号。如果否,则无事可做。让我们摆脱困境。
- 我们需要获取唯一 ID,或者 WordPress 称之为
$idx
。这是回调的唯一键,由哈希 ID 组成。方法名称。 - 一旦我们有了唯一的 ID,您就可以使用
remove_action
注销回调。它也适用于remove_filter
。
可重用代码
上面的代码是为了说明如何做以及它是如何工作的。但是该代码不可重用,因为参数是硬编码的。相反,您需要使用 this code 然后像这样调用它(在插件中时):
add_action( 'plugins_loaded', 'remove_woocommerce_add_sold_by_single_callback', 1 );
/**
* Unregister the WooCommerce `WC_Product_Vendors_Vendor_Frontend::add_sold_by_single` from the
* event `woocommerce_single_product_summary`.
*
* @since 1.0.0
*
* @return void
*/
function remove_woocommerce_add_sold_by_single_callback() {
do_hard_unregister_object_callback( 'woocommerce_single_product_summary', 39, 'add_sold_by_single');
}
哪个事件?
如果您在插件中使用此代码(您应该这样做),请使用 plugins_loaded
。
如果将它放入主题中,则不能使用 plugins_loaded
,因为它在主题加载之前就已触发。对于主题,您需要使用 after_setup_theme
而不是 plugins_loaded
。
测试
为了测试,让我们转储之前和之后的注册表,看看它是否确实删除了它。执行以下操作:
function remove_woocommerce_add_sold_by_single_callback() {
global $wp_filter;
var_dump( $wp_filter['woocommerce_single_product_summary'][39] );
do_hard_unregister_object_callback( 'woocommerce_single_product_summary', 39, 'add_sold_by_single');
if ( ! isset( $wp_filter['woocommerce_single_product_summary'][39] ) ) {
var_dump( $wp_filter['woocommerce_single_product_summary'] );
} else {
var_dump( $wp_filter['woocommerce_single_product_summary'][39] );
}
}
结果会让我们看看它是否从那里开始并在之后消失。
或者您可以通过 javascript 完成。
add_action( 'woocommerce_archive_description', "move_author_summary_to_image");
/**
* Move the author summary right after the image so we can float them left and right.
*/
function move_author_summary_to_image() {
?>
<script>
$('document').ready (function () {
var summary = $("#isle_body .wcpv-vendor-profile.entry-summary").html();
$("#isle_body .wcpv-vendor-profile.entry-summary").hide();
$(summary).addClass("author_summary").insertAfter($("#isle_body p.wcpv-vendor-logo"));
});
</script>
<?php
}