Developing Custom WooCommerce Plugins
WooCommerce is built on WordPress hooks and provides its own hook layer on top — actions and filters for every stage of order, product, and payment lifecycle. Custom WooCommerce plugin is business logic not covered by standard WooCommerce or ready add-ons: specific pricing, internal ERP integration, non-standard discount types, custom order statuses. Medium complexity plugin development — 5–10 business days.
Basic Structure and Dependency Checking
<?php
/**
* Plugin Name: My WooCommerce Extension
* WC requires at least: 8.0
* WC tested up to: 9.0
*/
defined('ABSPATH') || exit;
// Check WooCommerce presence before activation
register_activation_hook(__FILE__, function () {
if (!class_exists('WooCommerce')) {
deactivate_plugins(plugin_basename(__FILE__));
wp_die('WooCommerce 8.0+ required');
}
});
// Safe initialization after WooCommerce loads
add_action('woocommerce_loaded', function () {
require_once plugin_dir_path(__FILE__) . 'includes/class-main.php';
My_WC_Plugin::instance();
});
// Declare HPOS (High-Performance Order Storage) compatibility
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
);
}
});
Custom Order Statuses
// Register status
add_action('init', function () {
register_post_status('wc-awaiting-delivery', [
'label' => 'Awaiting Delivery',
'public' => true,
'show_in_admin_status_list' => true,
'show_in_admin_all_list' => true,
'exclude_from_search' => false,
'label_count' => _n_noop(
'Awaiting Delivery <span class="count">(%s)</span>',
'Awaiting Delivery <span class="count">(%s)</span>'
),
]);
});
// Add to WooCommerce list
add_filter('wc_order_statuses', function (array $statuses): array {
$statuses['wc-awaiting-delivery'] = 'Awaiting Delivery';
return $statuses;
});
// Color in order list
add_filter('woocommerce_admin_order_statuses_list_badge', function (array $badges): array {
$badges['awaiting-delivery'] = '#f59e0b'; // amber
return $badges;
});
// Email on status change
add_action('woocommerce_order_status_awaiting-delivery', function (int $order_id): void {
$order = wc_get_order($order_id);
// send customer email
WC()->mailer()->customer_new_account($order->get_billing_email());
});
Custom Discount System
Example: discount based on customer accumulated orders:
add_filter('woocommerce_cart_totals_coupon_label', '__return_false'); // hide standard coupon
add_action('woocommerce_cart_calculate_fees', function (WC_Cart $cart): void {
if (is_admin() && !defined('DOING_AJAX')) return;
$user_id = get_current_user_id();
if (!$user_id) return;
$total_spent = wc_get_customer_total_spent($user_id);
$discount_pct = 0;
if ($total_spent >= 100000) {
$discount_pct = 10;
} elseif ($total_spent >= 50000) {
$discount_pct = 7;
} elseif ($total_spent >= 20000) {
$discount_pct = 5;
}
if ($discount_pct > 0) {
$cart_subtotal = $cart->get_subtotal();
$discount = -($cart_subtotal * $discount_pct / 100);
$cart->add_fee(
sprintf('Accumulated discount %d%%', $discount_pct),
$discount,
true // taxable
);
}
});
Custom Product Fields
Add tab with fields in product editor:
// Add tab
add_filter('woocommerce_product_data_tabs', function (array $tabs): array {
$tabs['production_info'] = [
'label' => 'Production',
'target' => 'production_info_data',
'class' => ['show_if_simple', 'show_if_variable'],
'priority' => 80,
];
return $tabs;
});
// Tab content
add_action('woocommerce_product_data_panels', function (): void {
global $thepostid;
?>
<div id="production_info_data" class="panel woocommerce_options_panel">
<?php
woocommerce_wp_text_input([
'id' => '_manufacturer',
'label' => 'Manufacturer',
'placeholder' => 'Company name',
'value' => get_post_meta($thepostid, '_manufacturer', true),
]);
woocommerce_wp_select([
'id' => '_certification',
'label' => 'Certification',
'options' => [
'' => 'Not specified',
'gost' => 'GOST',
'iso' => 'ISO 9001',
'ce' => 'CE',
],
'value' => get_post_meta($thepostid, '_certification', true),
]);
?>
</div>
<?php
});
// Save
add_action('woocommerce_process_product_meta', function (int $post_id): void {
update_post_meta($post_id, '_manufacturer', sanitize_text_field($_POST['_manufacturer'] ?? ''));
update_post_meta($post_id, '_certification', sanitize_key($_POST['_certification'] ?? ''));
});
Background Tasks and Queues
For heavy operations (stock sync, bulk price updates) use WooCommerce Action Scheduler:
// Schedule task
as_schedule_single_action(
time() + 60,
'my_plugin_sync_stock',
['supplier_id' => 42],
'my-plugin'
);
// Handler
add_action('my_plugin_sync_stock', function (int $supplier_id): void {
$items = fetch_supplier_stock($supplier_id);
foreach ($items as $sku => $qty) {
$product_id = wc_get_product_id_by_sku($sku);
if ($product_id) {
$product = wc_get_product($product_id);
$product->set_stock_quantity($qty);
$product->save();
}
}
});
Action Scheduler is production-ready queue built into WooCommerce. Stores tasks in DB, retries on errors, has UI in /wp-admin → Tools → Scheduled Actions.
Typical timelines: plugin with custom product fields and statuses — 3–4 days. Plugin with custom discount logic, external API integration and background tasks — 8–12 days.







