Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Your own plugin for customizations

A plugin is a folder with a PHP file that WordPress includes on every page load. Shop customizations are kept in a plugin of your own: it does not depend on the theme, survives WooCommerce updates and is switched off with one click.

Creating it

There is no generator command — the folder and the file are created by hand. Create the wp-content/plugins/acme-shop folder and the acme-shop.php file in it:

<?php
// wp-content/plugins/acme-shop/acme-shop.php
/**
 * Plugin Name: Acme Shop
 * Description: Shop customizations.
 * Version: 1.0.0
 * Requires Plugins: woocommerce
 */
 
defined('ABSPATH') || exit;

The comment with Plugin Name is the header: WordPress recognizes the plugin by it. The Requires Plugins line prevents activating it without WooCommerce. The ABSPATH check forbids opening the file directly by its address. The plugin appears in Plugins → Installed Plugins — press Activate.

Checking for WooCommerce

Your code is loaded only when WooCommerce is loaded. Add to the end of acme-shop.php:

// wp-content/plugins/acme-shop/acme-shop.php
add_action('plugins_loaded', function () {
    if (!class_exists('WooCommerce')) {
        return;
    }
 
    require __DIR__ . '/includes/storefront.php';
});

The plugins_loaded hook fires when all plugins are included. If WooCommerce is switched off, the function returns and the site does not crash with a class not found error.

The first code file

Create includes/storefront.php:

// wp-content/plugins/acme-shop/includes/storefront.php
add_action('woocommerce_before_shop_loop', function () {
    echo '<p class="acme-note">Free shipping from 50 €</p>';
});

Open /shop/: the line is now above the product list. Like any PHP file, this one starts with <?php — in the course examples that first line is omitted and the file path is shown instead.

File layout

During the course the plugin grows into this structure:

acme-shop/
├── acme-shop.php          main file: header and includes
├── includes/
│   ├── storefront.php     storefront hooks
│   ├── products.php       working with products
│   ├── cart.php           the cart
│   ├── checkout.php       checkout
│   ├── orders.php         orders
│   └── admin.php          admin fields and settings
├── templates/             your own templates
└── assets/                styles and scripts

Every new file in includes is included with a require line in the main file, next to storefront.php. Later lessons take this for granted.

HPOS compatibility

The plugin must state that it can work with the new order storage. Add to acme-shop.php:

// wp-content/plugins/acme-shop/acme-shop.php
add_action('before_woocommerce_init', function () {
    if (class_exists(\Automattic\WooCommerce\Utilities\FeaturesUtil::class)) {
        \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
            'custom_order_tables',
            __FILE__,
            true
        );
    }
});

Without this declaration WooCommerce shows an incompatible plugin warning in the admin panel. The call must be in the main file: __FILE__ tells which plugin makes the statement.

Where code must not go

PlaceWhy not
wp-content/plugins/woocommerce/An update wipes the edits
The theme's functions.phpThe logic is lost when the theme changes
Snippet plugins in the admin panelThe code does not get into version control

Only appearance stays in the theme: styles and template copies.

Common mistake

WooCommerce functions are called right in the body of the main file: $product = wc_get_product(12); at the top level. At that moment WooCommerce may not be loaded yet — the site crashes. All code must run inside functions attached to hooks.

Thanks for reading!

Donate to the site — we work hard for you.