Ready to get started?

Check out the plugin on GitHub and start using it today.

O

Open/Closed Principle in WordPress

Software entities should be open for extension, but closed for modification

The Open/Closed Principle (OCP) ensures your WordPress code can grow and adapt without breaking existing functionality. Instead of modifying working code, you extend it – adding new features through hooks, filters, inheritance, or composition.

Open for Extension

Modular Plugins

Plugin Architecture

Open for Extension

Your code should be designed so new functionality can be added easily without touching existing code. In WordPress, this means:

Using do_action() and apply_filters()

Creating plugin APIs with hooks

Using class inheritance and interfaces

Implementing Strategy pattern for variations

Closed for Modification

Once code is tested and working, you shouldn’t need to change it to add features. Benefits include:

No risk of breaking existing functionality

Easier to maintain and test

Child themes can extend parents safely

Plugins can hook into core without editing it

WordPress Examples: Violation vs Compliance

See how OCP applies in real WordPress development scenarios

Violating OCP

Modifying plugin code directly

// In vendor plugin file - BAD!
function send_order_email($order_id) {
    $order = get_order($order_id);
    $email = $order->customer_email;
    send_sms($order->phone, "Order placed!");
    wp_mail($email, "Order Confirmed",
        get_email_body($order));
}

PROBLEMS:

Modification gets lost on plugin update

Can’t disable SMS without editing

Breaks warranty and support; hard to test

Following OCP

Using hooks to extend behavior

// Original plugin - stays closed
function send_order_email($order_id) {
    $order = get_order($order_id);
    do_action('before_order_email', $order_id, $order);
    wp_mail($email, "Order Confirmed", get_email_body($order));
}
// Your plugin - extends
add_action('before_order_email', 'send_order_sms', 10, 2);
function send_order_sms($order_id, $order) {
    send_sms($order->phone, "Order #$order_id placed!");
}

BENEFITS:

Original code never modified

Can enable/disable via plugin

Update-safe extension; easy to test independently

Violating OCP

Hardcoded payment logic with if/else

class PaymentProcessor {
    public function process($order, $method) {
        if ($method === 'paypal') return $this->process_paypal($order);
        elseif ($method === 'stripe') return $this->process_stripe($order);
        // Adding crypto? Modify this file!
    }
}

PROBLEMS:

Must edit core class for new gateway

Growing if/else; tight coupling

Following OCP

Strategy pattern with gateway registration

interface PaymentGateway { public function process($order); }
class PaymentProcessor {
    private $gateways = [];
    public function register($name, $gateway) { $this->gateways[$name] = $gateway; }
    public function process($order, $method) { return $this->gateways[$method]->process($order); }
}
// Add crypto without touching processor!
class CryptoGateway implements PaymentGateway { public function process($order) { /*...*/ } }

BENEFITS:

Add gateways via registration

Core processor never changes

Test each gateway independently

Violating OCP

Modifying parent theme directly

// In parent theme - BAD!
function theme_setup() {
    add_theme_support('post-thumbnails');
    add_theme_support('custom-logo');
    register_nav_menus(['primary' => 'Primary', 'social' => 'Social']);
}

PROBLEMS:

Changes lost on theme update

Can’t share between sites; violates update workflow

Following OCP

Using child theme to extend parent

// Parent - stays closed
function theme_setup() {
    add_theme_support('post-thumbnails');
    register_nav_menus(['primary' => 'Primary']);
    do_action('after_theme_setup');
}
add_action('after_setup_theme', 'theme_setup');
// Child theme - extends
add_action('after_theme_setup', 'child_theme_setup');
function child_theme_setup() {
    add_theme_support('custom-logo');
    register_nav_menu('social', 'Social Menu');
}

BENEFITS:

Parent theme stays untouched

Update parent safely; portable customizations

Real-World Example: WooCommerce Extension

How WooCommerce follows OCP to allow thousands of extensions without modifying core

WooCommerce’s Extension Architecture

Open for Extension

  • 700+ action hooks in core
  • 400+ filter hooks for customization
  • Abstract classes for payment gateways
  • Abstract classes for shipping methods
  • Template override system

Closed for Modification

  • Core checkout flow stays stable
  • Payment processing logic protected
  • Order management untouched
  • Backward compatibility maintained
// Example: Adding custom field to checkout

// WooCommerce core provides hook - closed for modification
do_action('woocommerce_after_order_notes', $checkout);

// Your plugin extends - open for extension
add_action('woocommerce_after_order_notes', 'add_gift_message_field');

function add_gift_message_field($checkout) {
    echo '<div class="gift-message">';
    woocommerce_form_field('gift_message', array(
        'type' => 'textarea',
        'label' => 'Gift Message',
        'placeholder' => 'Optional message...'
    ), $checkout->get_value('gift_message'));
    echo '</div>';
}

// Save the field
add_action('woocommerce_checkout_create_order', 'save_gift_message', 10, 2);

function save_gift_message($order, $data) {
    if (!empty($data['gift_message'])) {
        $order->update_meta_data('_gift_message', 
            sanitize_textarea_field($data['gift_message']));
    }
}

Result: WooCommerce has 1000+ extensions without changing a single line of core code. Subscriptions, memberships, bookings, custom payment gateways ? all added through hooks and abstract classes.

Common OCP Violations in WordPress

Avoid these frequent mistakes that break the Open/Closed Principle

Editing Core/Vendor Files

Modifying WordPress core, plugins, or themes directly to add features

Why it’s bad:

Updates overwrite your changes, breaking your site. Use hooks, filters, or child themes instead.

No Extension Points

Creating plugins/themes without hooks or filters for others to extend

Why it’s bad:

Creating plugins/themes without hooks or filters for others to extend

Hardcoded Conditionals

Using if/else chains for variations instead of extensible patterns

Why it’s bad:

Every new variation requires modifying the same function. Use strategy pattern or hooks instead.

Static Functions Everywhere

Using static methods that can’t be extended or overridden

Why it’s bad:

Static methods can’t be overridden in child classes. Use instance methods or provide hooks.

Frequently Asked Questions

A: Add hooks at logical extension points – before/after major operations, when data changes, or when rendering output. Follow WordPress core’s approach: do_action('before_save_')apply_filters('the_content'), etc. Don’t overdo it – too many hooks make code hard to follow.

A: Initially yes, but it pays off as the project grows. Start simple – a few hooks are enough for small plugins. Add interfaces and abstract classes when you have 3+ similar implementations. The complexity is justified when it prevents breaking existing functionality while adding features.

A: Absolutely! WordPress hooks (add_actionadd_filter) are a perfect OCP implementation using procedural code. Your functions stay closed (working code), others extend via hooks (adding functionality). OOP adds more tools, but hooks alone achieve OCP beautifully.

A: No, OCP is about adding features, not fixing bugs. Bug fixes are legitimate modifications. The principle means “don’t modify working code to add new features” – fixing broken code is different. After the fix, that code should be closed for new features again.

A: OCP is crucial for plugin compatibility. If your plugin follows OCP (provides hooks), users can extend it safely. When you update, their extensions keep working because they’re not modifying your code. This is why editing vendor plugin files is dangerous – updates erase custom changes.

A: No, only functions that return data users might want to modify. Use filters for content transformation (apply_filters('post_title', $title)), use actions for event notifications (do_action('post_saved', $id)). Internal helper functions don’t need hooks.

Official WordPress Resources

Learn how OCP aligns with WordPress plugin and theme development standards

Plugin Handbook

Learn about hooks, filters, and creating extensible plugins

Theme Handbook

Child themes, template hierarchy, and theme extensibility

Hook Reference

Complete list of WordPress actions and filters

Following the Open/Closed Principle creates WordPress themes and plugins that can grow without breaking, making your code professional and future-proof

Extensions survive updates because they don’t modify core code

Add features without touching tested code, reducing bugs

Others can extend your plugins without needing your permission