I got a call from a client in a panic. Their custom inventory sync plugin was failing silently on the live site. No errors, no logs, nothing. It just wasn’t working. Of course, on my local machine, it ran perfectly. It’s a classic WordPress development problem, and it’s a total nightmare to debug something you can’t see.
My first thought was to just pepper the code with error_log() calls to see what was going on. And yeah, that can work in a pinch, but it’s messy. You end up with a log file full of noise, you have to SSH in to see it, and you’ll inevitably forget to remove one of the debug lines. Not a professional look. I knew there had to be a more structured way to handle this, a way to tap into the WordPress Plugin API without making the core code even messier.
A Better Way: The “Event Listener” Pattern
The problem with hooks, especially in classes, is that developers often jam the add_action or add_filter calls right into the constructor. This makes your class a tangled mess of responsibilities. It’s doing its main job, AND it’s in charge of wiring itself into WordPress. That’s a violation of the Single Responsibility Principle, and it makes the class a pain to test or reuse.
The better approach is to create a dedicated “listener” class. Its only job is to listen for specific WordPress events (actions and filters) and then trigger the appropriate logic from another class. This separates the “when” from the “what.” This idea builds on a concept I first saw explained by Carl Alexander as “aspects” on his blog, which is a great way to think about it.
For my client’s problem, I built a simple LoggingListener. It has one job: listen for specific events in their plugin and email me a neat log when the request finishes. No more guessing.
class LoggingListener
{
private $emails;
private $log_entries;
public function __construct(array $emails)
{
$this->emails = $emails;
$this->log_entries = array();
}
public static function init(array $emails)
{
$self = new self($emails);
// Listen for a specific, custom hook in the plugin
add_action('myplugin_inventory_sync_failed', array($self, 'log_sync_failure'), 10, 1);
// Also log when a specific option changes
add_action('updated_option', array($self, 'log_option_change'), 10, 3);
// On shutdown, send the email
add_action('shutdown', array($self, 'email_log_entries'));
return $self;
}
public function log_sync_failure($error_message)
{
$this->log_entries[] = sprintf('Inventory sync failed: %s', $error_message);
}
public function log_option_change($option, $old_value, $value)
{
// Only log changes to our plugin's options
if (0 !== strpos($option, 'myplugin_')) {
return;
}
$old_value = maybe_serialize($old_value);
$value = maybe_serialize($value);
$this->log_entries[] = sprintf('Option "%s" changed from "%s" to "%s".', $option, $old_value, $value);
}
public function email_log_entries()
{
if (empty($this->log_entries)) {
return;
}
$message = "Log Entries for MyPlugin:\r\n\r\n";
$message .= implode("\r\n", $this->log_entries);
foreach($this->emails as $email) {
wp_mail($email, sprintf('MyPlugin Log [%s]', date('Y-m-d H:i:s')), $message);
}
}
}
// To use it:
// LoggingListener::init(['your-email@example.com']);So, What’s the Point?
This approach completely decouples the logging functionality from the inventory syncing functionality. Here’s the kicker:
- It’s Clean: The main plugin classes aren’t littered with logging code or
add_actioncalls. They just do their job. - It’s Maintainable: If you need to change how logging works, you only touch one file. You can easily add more event listeners for different hooks without touching the core logic.
- It’s Testable: You can instantiate your core classes in a test environment without them trying to hook into a WordPress instance that doesn’t exist.
Look, this stuff gets complicated fast. If you’re tired of debugging someone else’s mess and just want your site to work, drop my team a line. We’ve probably seen it before.
Thinking this way changes how you use the Plugin API. It’s not just a way to hack things in; it’s a tool for building clean, decoupled, and professional-grade plugins. Trust me on this.
Leave a Reply