I was working on a WooCommerce plugin for a client to sync their product inventory with a third-party API. Total classic scenario. The problem was, I had two ways of getting product data: either as a standard WP_Post object when kicking off the sync from the admin, or as a decoded JSON object when the API sent us a webhook. Two completely different data structures that needed to end up as the same, clean Product object in my code.
My first thought was to just handle it all in the constructor. You know, make a big, smart __construct() method that could figure out what kind of data it was given. It started with a simple if ($data instanceof WP_Post)… but then it grew. Soon I had nested checks for arrays, stdClass objects, and property names like ‘product_name’ vs ‘post_title’. It worked, but man, it was ugly. A total mess to read and a nightmare to maintain. That’s a classic sign you’re fighting the language, and when it comes to object creation in PHP, the static factory method is often the right tool for the job.
Why Your Constructor Gets Complicated
The core of the problem is that PHP only lets you have one constructor per class. One. In other languages, you can have multiple constructors with different signatures (a concept called constructor overloading), but not PHP. So, when you need to build an object from different sources, you’re tempted to cram all that logic into the one __construct method you’re allowed to have. This is a trap. The constructor’s real job is simple: take some data and assign it to the object’s properties. It shouldn’t be a complex switchboard of conditional logic.
This is where the static factory method pattern comes in. Instead of one messy constructor, you create multiple, clearly named static methods that prepare the data and then call the real constructor. It’s an elegant solution I first saw detailed over on carlalexander.ca, and it’s been a staple in my toolkit ever since.
Using a Static Factory Method in WordPress
Let’s refactor that product scenario. We want one Product class, but we need to create instances from both a WP_Post object and an API response. Instead of a monster constructor, we’ll make the constructor private and add two public static methods.
class MyPlugin_Product
{
private $id;
private $name;
private $type;
/**
* Constructor is private to force creation via static methods.
*/
private function __construct($id, $name, $type)
{
$this->id = $id;
$this->name = $name;
$this->type = $type;
}
/**
* Creates a new product from a WP_Post object.
*
* @param WP_Post $post
* @return self|null
*/
public static function from_post(WP_Post $post)
{
$product_id = get_post_meta($post->ID, '_myplugin_product_id', true);
$product_type = get_post_meta($post->ID, '_myplugin_product_type', true);
if (empty($product_id) || empty($product_type)) {
return null;
}
return new self($product_id, $post->post_title, $product_type);
}
/**
* Creates a new product from API data.
*
* @param stdClass $api_data
* @return self|null
*/
public static function from_api(stdClass $api_data)
{
if (!isset($api_data->id, $api_data->name, $api_data->type)) {
return null;
}
return new self($api_data->id, $api_data->name, $api_data->type);
}
}
// Now creating objects is clean and predictable:
$product_from_post = MyPlugin_Product::from_post($some_wp_post_object);
$product_from_api = MyPlugin_Product::from_api($some_api_response_object);
So, What’s the Point?
Look at how clean that is. The code that creates the object now tells a story. MyPlugin_Product::from_post() is self-documenting. You know exactly what it does. Here’s the kicker: we made the constructor private. This forces anyone using the class (including your future self) to use one of the static factory methods. No more guesswork. You’ve created a clear, maintainable, and professional API for your own code.
- Clarity: The method name describes the source of the object’s data.
- Simplicity: The constructor stays simple and dumb. Its only job is to assign properties.
- Flexibility: You can add more factory methods (e.g.,
from_csv(),from_xml()) without ever touching the constructor or breaking existing code.
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.
Stop fighting with constructors. Use static factory methods to bring some sanity back to your object-oriented WordPress code. Trust me on this, it’s a pattern that pays for itself the first time you have to debug object creation logic.
Leave a Reply