@neverenn
Новичок

Как удалить хук не статического метода класса (если НЕТ доступа к $this — экземпляру класса) в WP Job Manager Applications?

Доброго времени суток.
Работаю с WP Job Manager. На сайте, с помощью аддона WP Job Manager Applications выводится кнопка для отклика на вакансию, либо уведомление о том, что отклик уже был отправлен.

Обе функции цепляются к хуку 'single_job_listing_meta_after'.

С кнопкой проблем не возникло, т.к. она выводится в шаблоне и хук описан:

/**
* single_job_listing_start hook
 *
 * @hooked job_listing_meta_display - 20
 * @hooked job_listing_company_display - 30
 */
do_action('single_job_listing_sidebar');


Я просто использовал remove_action и создал свой action, чтобы вывести в удобном для меня месте:

remove_action( 'single_job_listing_start', 'job_listing_meta_display', 20);
remove_action( 'single_job_listing_start', 'job_listing_company_display', 30 );
add_action('single_job_listing_sidebar', 'job_listing_company_display', 30);
add_action('single_job_listing_sidebar', 'job_listing_meta_display', 40);


А вот с сообщением о том, то отклик уже был отправлен возникли проблемы.

Ранее я перемещал кнопку с закладками от соседнего аддона WP Job Manager Bookmarks, используя экземпляр класса, который описан в файлах плагина, где выводится нужная мне функция.

Содержание файла:
class WP_Job_Manager_Bookmarks {
...
	public function init_plugin() {
		if ( ! class_exists( 'WP_Job_Manager' ) ) {
			return;
		}

		// Add actions
		add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts' ) );
		add_action( 'wp', array( $this, 'bookmark_handler' ) );
		add_action( 'single_job_listing_meta_after', array( $this, 'bookmark_form' ) );
		add_action( 'single_resume_start', array( $this, 'bookmark_form' ) );
		add_shortcode( 'my_bookmarks', array( $this, 'my_bookmarks' ) );
		add_filter( 'post_class', array( $this, 'already_bookmarked_post_class' ), 20, 2 );

	}
...
}
$GLOBALS['job_manager_bookmarks'] = new WP_Job_Manager_Bookmarks();


С помощью:
remove_action( 'single_job_listing_meta_after', [ $GLOBALS['job_manager_bookmarks'], 'bookmark_form' ]);
add_action('job-add-to-bookmarks',[ $GLOBALS['job_manager_bookmarks'], 'bookmark_form' ], 10);


Я подумал, что в этот раз я смогу сделать так же, но выяснилось, что в файлах плагина с нужной мне функцией, нет доступа к экземпляру класса.

Содержание файла:
class WP_Job_Manager_Applications_Post_Types {

	/**
	 * Constructor
	 */
	public function __construct() {
		add_filter( 'wpjm_the_job_title', [ $this, 'already_applied_title' ], 10, 2 );
		add_action( 'single_job_listing_meta_after', [ $this, 'already_applied_message' ] );
		add_action( 'init', [ $this, 'register_post_types' ], 20 );
		if ( get_option( 'job_application_delete_with_job', 0 ) ) {
			add_action( 'delete_post', [ $this, 'delete_post' ] );
			add_action( 'wp_trash_post', [ $this, 'trash_post' ] );
			add_action( 'untrash_post', [ $this, 'untrash_post' ] );
		}
		add_action( 'before_delete_post', [ $this, 'delete_application_files' ] );
		add_action( 'job_applications_purge', [ $this, 'job_applications_purge' ] );
		add_filter( 'post_class', [ $this, 'add_applied_post_class' ], 10, 3 );
		add_action( 'transition_post_status', [ $this, 'transition_post_status' ], 10, 3 );
	}
       ...
} *тут должен был быть экземпляр*


Я пытался найти информацию в интернете, но все методы, что я нашёл, в моём случае не сработали.
Искал темы wp, которые используют те же плагины и изменяют положение этих элементов, но то что я увидел для меня пока слишком сложно и страшно.
Можете помочь и подсказать как удалить action [ $this, 'already_applied_message' ] в случае, когда нет доступа к экземпляру класса?
  • Вопрос задан
  • 60 просмотров
Решения вопроса 1
@neverenn Автор вопроса
Новичок
Ещё раз перебрал статью от Kama и нашёл свою ошибку.

1. Код плагина, который добавляет функцию и action выглядел так:

class WP_Job_Manager_Applications_Post_Types {

	/**
	 * Constructor
	 */
	public function __construct() {
		add_filter( 'wpjm_the_job_title', [ $this, 'already_applied_title' ], 10, 2 );
		add_action( 'single_job_listing_meta_after', [ $this, 'already_applied_message' ] );
		add_action( 'init', [ $this, 'register_post_types' ], 20 );
		if ( get_option( 'job_application_delete_with_job', 0 ) ) {
			add_action( 'delete_post', [ $this, 'delete_post' ] );
			add_action( 'wp_trash_post', [ $this, 'trash_post' ] );
			add_action( 'untrash_post', [ $this, 'untrash_post' ] );
		}
		add_action( 'before_delete_post', [ $this, 'delete_application_files' ] );
		add_action( 'job_applications_purge', [ $this, 'job_applications_purge' ] );
		add_filter( 'post_class', [ $this, 'add_applied_post_class' ], 10, 3 );
		add_action( 'transition_post_status', [ $this, 'transition_post_status' ], 10, 3 );
	}
...
}


2. Использовал кастомные функции (Спасибо, kama!), которые помогают удалять хуки/фильтры без доступа к экземпляру класса. Вставляйте (например в functions.php) или любой другой файл, который используете для добавления подобного рода функций в теме.

/**
 * Remove filter without access to class object (instance).
 *
 * In order to use the core WordPress remove_filter() on a filter added with the callback
 * to a class, you either have to have access to that class object, or it has to be a call
 * to a static method. This function allows you to remove filters with a callback to a class
 * you don't have access to.
 *
 * @param string       $hook_name          Filter to remove.
 * @param string|array $class_method_name  Class and Method for the filter's callback.
 *                                         Eg: [ '\Space\My_Class', 'my_method' ] OR '\Space\My_Class::my_method'.
 * @param int          $priority           Priority of the filter (default 10).
 *
 * @return bool Whether the hook is removed.
 *
 * @requires WP 4.7+
 * @author  Kama (wp-kama.com)
 * @version 1.0
 */
function remove_object_filter( string $hook_name, $class_method_name, $priority = 10 ): bool {
	global $wp_filter;

	if( empty( $wp_filter[ $hook_name ]->callbacks[ $priority ] ) ){
		return false;
	}

	$wp_hooks = & $wp_filter[ $hook_name ];
	$hooks = $wp_hooks->callbacks[ $priority ];

	[ $class_name, $method_name ] = is_string( $class_method_name )
		? explode( '::', $class_method_name ) + [ '', '' ] // '\Space\My_Class::my_method'
		: $class_method_name;

	$class_name = ltrim( $class_name, '\\' ); //> \Space\My_Class >>> Space\My_Class

	foreach( $hooks as $hook ){

		if( ! isset( $hook['function'] ) || ! is_array( $hook['function'] ) ){
			continue;
		}

		[ $object, $current_method ] = $hook['function'];

		if( $current_method !== $method_name ){
			continue;
		}

		$is_our_object = is_object( $object ) && get_class( $object ) === $class_name;

		if( ! $is_our_object ){
			continue;
		}

		return $wp_hooks->remove_filter( $hook_name, $hook['function'], $priority );
	}

	return false;
}

/**
 * Remove Class Action Without Access to Class Object
 *
 * @param string       $hook_name          Action to remove.
 * @param string|array $class_method_name  Class and Method for the filter's callback.
 *                                         Eg: [ '\Space\My_Class', 'my_method' ] OR '\Space\My_Class::my_method'.
 * @param int          $priority           Priority of the action (default 10)
 *
 * @return bool Whether the hook is removed.
 */
function remove_object_action( $hook_name, $class_method_name, $priority = 10 ): bool {
	return remove_object_filter( $hook_name, $class_method_name, $priority );
}


3. Удалил ненужное мне

remove_object_action( 'single_job_listing_meta_after', [ 'WP_Job_Manager_Applications_Post_Types', 'already_applied_message' ] );


3.1. Ещё варианты по удалению action и filter:

remove_object_action( 'some_action_hook', [ 'My\Space\MyClass', 'my_method' ], 11 );
remove_object_action( 'some_action_hook', [ '\My\Space\MyClass', 'my_method' ], 11 );
remove_object_action( 'some_action_hook', [ '\\My\\Space\\MyClass', 'my_method' ], 11 );
remove_object_action( 'some_action_hook', [ \My\Space\MyClass::class, 'my_method' ], 11 );
remove_object_action( 'some_action_hook', '\My\Space\MyClass::my_method', 11 );
remove_object_action( 'some_action_hook', 'My\Space\MyClass::my_method', 11 );

// или аналогично для фильтров
remove_object_filter( 'some_filter_hook', [ 'My\Space\MyClass', 'my_method' ], 11 );
// etc...


Моя ошибка заключалась в том, что я добавлял кастомные функции для удаления хуков в файле, который не был подключен. Поэтому ничего не работало. Надеюсь это поможет кому-то в будущем, будьте внимательны!

p.s. как добавить удалённый таким образом хук я не знаю.

upd: Всё же появилась необходимость добавить удалённый хук в другом месте, для этого продублировал исходную функцию и прицепил к хуку.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы