Skip to content

Instantly share code, notes, and snippets.

@hellofromtonya
Last active June 7, 2019 21:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hellofromtonya/7b6b6e1fdf13da3e05181f21865ddb78 to your computer and use it in GitHub Desktop.
Save hellofromtonya/7b6b6e1fdf13da3e05181f21865ddb78 to your computer and use it in GitHub Desktop.
Hard Unregister for an Object's callback where you do not have access to the instance itself.
/**
* Do a hard unregister of an object's callback for the specified event name
* and priority level.
*
* In WordPress, the callback key (or unique ID) is generated using the hash ID of
* the object concatenated with the method name. In the event that you do not have
* the object itself, then we use this hard approach to first first the callback
* function and then do the remove.
*
* This process works for both filter and action events.
*
* @since 1.0.0
*
* @param string $event_name The name of the filter or action event
* @param integer $priority Priority level
* @param string $method_name Callback's method name
*
* @return void
*/
function do_hard_unregister_object_callback( $event_name, $priority, $method_name ) {
$callback_function = get_object_callback_unique_id_from_registry( $event_name, $priority, $method_name );
if ( ! $callback_function ) {
return false;
}
remove_filter( $event_name, $callback_function, $priority );
}
/**
* Get the object's event registry unique ID for the given event name, priority
* level, and method name.
*
* @since 1.0.0
*
* @param string $event_name The name of the filter or action event
* @param integer $priority Priority level
* @param string $method_name Callback's method name
*
* @return string|boolean
*/
function get_object_callback_unique_id_from_registry( $event_name, $priority, $method_name ) {
global $wp_filter;
if ( ! isset( $wp_filter[ $event_name ][ $priority ] ) ) {
return false;
}
foreach( $wp_filter[ $event_name ][ $priority ] as $callback_function => $registration ) {
if ( strpos( $callback_function, $method_name, 32) !== false) {
return $callback_function;
}
}
return false;
}
@hellofromtonya
Copy link
Author

Line 50 if ( strpos( $callback_function, $method_name, 32) !== false) {} is just one way to do it. The other way is to look into the registration at the function and check the class and method names directly.

@ljsherlock
Copy link

Found this really helpful. Thanks for this!

I found that I was hitting $callback_function strings that did not contain a 32 char long prefix. So I edited the get_object_callback_unique_id_from_registry like below to suppress warnings.

function get_object_callback_unique_id_from_registry( $event_name, $priority, $method_name ) {
	global $wp_filter;

	if ( ! isset( $wp_filter[ $event_name ][ $priority ] ) ) {
		return false;
	}

	foreach( $wp_filter[ $event_name ][ $priority ] as $callback_function => $registration ) {
		if(strlen($callback_function) > 32) {
			if ( strpos( $callback_function, $method_name, 32) !== false) {
				return $callback_function;
			}
		}
	}

	return false;
}
...

@hellofromtonya
Copy link
Author

@ljsherlock - That improves it. Good job.

We strive to keep code levels shifted to the left as much as possible. Right? How can we reduce the levels with the new check? There are a couple strategies.

Option 1: Convert the check into a guard clause like this, where it skips if the string's length is not more than 32.

   foreach ( $wp_filter[ $event_name ][ $priority ] as $callback_function => $registration ) {
   	# Skip if the callback function's strlen is <= 32.
   	if ( strlen( $callback_function ) <= 32 ) {
   		continue;
   	}

   	if ( strpos( $callback_function, $method_name, 32 ) !== false ) {
   		return $callback_function;
   	}
   }

Option 2: Combine the checks.

	foreach ( $wp_filter[ $event_name ][ $priority ] as $callback_function => $registration ) {
		if ( strlen( $callback_function ) > 32 && strpos( $callback_function, $method_name, 32 ) !== false ) {
			return $callback_function;
		}
	}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment