skills/mindrally/skills/woocommerce

woocommerce

SKILL.md

WooCommerce Development

E-commerce development with WooCommerce for WordPress.

Essential Hooks

Product Hooks

// Modify product price display
add_filter( 'woocommerce_get_price_html', function( $price_html, $product ) {
    if ( $product->is_on_sale() ) {
        $price_html .= '<span class="sale-badge">Sale!</span>';
    }
    return $price_html;
}, 10, 2 );

// Add custom field to product
add_action( 'woocommerce_product_options_general_product_data', function() {
    woocommerce_wp_text_input( array(
        'id'          => '_custom_field',
        'label'       => __( 'Custom Field', 'textdomain' ),
        'description' => __( 'Enter custom value', 'textdomain' ),
        'desc_tip'    => true,
    ) );
} );

// Save custom field
add_action( 'woocommerce_process_product_meta', function( $post_id ) {
    $value = isset( $_POST['_custom_field'] ) ? sanitize_text_field( $_POST['_custom_field'] ) : '';
    update_post_meta( $post_id, '_custom_field', $value );
} );

Cart Hooks

// Add fee to cart
add_action( 'woocommerce_cart_calculate_fees', function( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    $subtotal = $cart->get_subtotal();

    // Add handling fee for orders under $50
    if ( $subtotal < 50 ) {
        $cart->add_fee( __( 'Handling Fee', 'textdomain' ), 5.00 );
    }
} );

// Validate cart items
add_action( 'woocommerce_check_cart_items', function() {
    $cart = WC()->cart;

    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        $product = $cart_item['data'];

        // Check stock or custom validation
        if ( ! $product->is_in_stock() ) {
            wc_add_notice(
                sprintf( __( '%s is out of stock.', 'textdomain' ), $product->get_name() ),
                'error'
            );
        }
    }
} );

// Modify cart item data
add_filter( 'woocommerce_add_cart_item_data', function( $cart_item_data, $product_id, $variation_id ) {
    if ( isset( $_POST['custom_option'] ) ) {
        $cart_item_data['custom_option'] = sanitize_text_field( $_POST['custom_option'] );
    }
    return $cart_item_data;
}, 10, 3 );

Checkout Hooks

// Add custom checkout field
add_action( 'woocommerce_after_order_notes', function( $checkout ) {
    woocommerce_form_field( 'delivery_date', array(
        'type'        => 'date',
        'class'       => array( 'form-row-wide' ),
        'label'       => __( 'Preferred Delivery Date', 'textdomain' ),
        'required'    => true,
    ), $checkout->get_value( 'delivery_date' ) );
} );

// Validate custom field
add_action( 'woocommerce_checkout_process', function() {
    if ( empty( $_POST['delivery_date'] ) ) {
        wc_add_notice( __( 'Please select a delivery date.', 'textdomain' ), 'error' );
    }
} );

// Save custom field to order
add_action( 'woocommerce_checkout_update_order_meta', function( $order_id ) {
    if ( ! empty( $_POST['delivery_date'] ) ) {
        update_post_meta( $order_id, '_delivery_date', sanitize_text_field( $_POST['delivery_date'] ) );
    }
} );

Order Hooks

// After order is completed
add_action( 'woocommerce_order_status_completed', function( $order_id ) {
    $order = wc_get_order( $order_id );

    // Send to external system
    $data = array(
        'order_id'    => $order_id,
        'customer'    => $order->get_billing_email(),
        'total'       => $order->get_total(),
        'items'       => array(),
    );

    foreach ( $order->get_items() as $item ) {
        $data['items'][] = array(
            'product_id' => $item->get_product_id(),
            'quantity'   => $item->get_quantity(),
            'total'      => $item->get_total(),
        );
    }

    // Send to webhook
    wp_remote_post( 'https://api.example.com/orders', array(
        'body'    => wp_json_encode( $data ),
        'headers' => array( 'Content-Type' => 'application/json' ),
    ) );
} );

// Order status change
add_action( 'woocommerce_order_status_changed', function( $order_id, $old_status, $new_status, $order ) {
    // Custom notification logic
}, 10, 4 );

Custom Product Types

// Register custom product type
add_action( 'init', function() {
    class WC_Product_Subscription extends WC_Product {
        public function __construct( $product = 0 ) {
            $this->product_type = 'subscription';
            parent::__construct( $product );
        }

        public function get_type() {
            return 'subscription';
        }

        // Custom methods
        public function get_subscription_period() {
            return $this->get_meta( '_subscription_period' );
        }
    }
} );

// Add to product type selector
add_filter( 'product_type_selector', function( $types ) {
    $types['subscription'] = __( 'Subscription', 'textdomain' );
    return $types;
} );

// Show price fields
add_action( 'woocommerce_product_options_general_product_data', function() {
    global $product_object;

    if ( 'subscription' === $product_object->get_type() ) {
        woocommerce_wp_select( array(
            'id'      => '_subscription_period',
            'label'   => __( 'Billing Period', 'textdomain' ),
            'options' => array(
                'month' => __( 'Monthly', 'textdomain' ),
                'year'  => __( 'Yearly', 'textdomain' ),
            ),
        ) );
    }
} );

Payment Gateways

class WC_Gateway_Custom extends WC_Payment_Gateway {
    public function __construct() {
        $this->id                 = 'custom_gateway';
        $this->icon               = '';
        $this->has_fields         = true;
        $this->method_title       = __( 'Custom Gateway', 'textdomain' );
        $this->method_description = __( 'Custom payment gateway.', 'textdomain' );

        $this->supports = array(
            'products',
            'refunds',
        );

        $this->init_form_fields();
        $this->init_settings();

        $this->title       = $this->get_option( 'title' );
        $this->description = $this->get_option( 'description' );
        $this->enabled     = $this->get_option( 'enabled' );
        $this->api_key     = $this->get_option( 'api_key' );

        add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
    }

    public function init_form_fields() {
        $this->form_fields = array(
            'enabled' => array(
                'title'   => __( 'Enable/Disable', 'textdomain' ),
                'type'    => 'checkbox',
                'label'   => __( 'Enable Custom Gateway', 'textdomain' ),
                'default' => 'no',
            ),
            'api_key' => array(
                'title'       => __( 'API Key', 'textdomain' ),
                'type'        => 'password',
                'description' => __( 'Enter your API key', 'textdomain' ),
            ),
        );
    }

    public function process_payment( $order_id ) {
        $order = wc_get_order( $order_id );

        // Process payment with external API
        $response = wp_remote_post( 'https://api.payment.com/charge', array(
            'body' => array(
                'amount'   => $order->get_total(),
                'currency' => $order->get_currency(),
                'token'    => sanitize_text_field( $_POST['payment_token'] ),
            ),
            'headers' => array(
                'Authorization' => 'Bearer ' . $this->api_key,
            ),
        ) );

        $body = json_decode( wp_remote_retrieve_body( $response ), true );

        if ( isset( $body['success'] ) && $body['success'] ) {
            $order->payment_complete( $body['transaction_id'] );
            WC()->cart->empty_cart();

            return array(
                'result'   => 'success',
                'redirect' => $this->get_return_url( $order ),
            );
        } else {
            wc_add_notice( $body['error'] ?? __( 'Payment failed', 'textdomain' ), 'error' );
            return array( 'result' => 'fail' );
        }
    }

    public function process_refund( $order_id, $amount = null, $reason = '' ) {
        $order = wc_get_order( $order_id );

        $response = wp_remote_post( 'https://api.payment.com/refund', array(
            'body' => array(
                'transaction_id' => $order->get_transaction_id(),
                'amount'         => $amount,
            ),
        ) );

        $body = json_decode( wp_remote_retrieve_body( $response ), true );

        if ( isset( $body['success'] ) && $body['success'] ) {
            return true;
        }

        return new WP_Error( 'refund_failed', $body['error'] ?? 'Refund failed' );
    }
}

// Register gateway
add_filter( 'woocommerce_payment_gateways', function( $gateways ) {
    $gateways[] = 'WC_Gateway_Custom';
    return $gateways;
} );

REST API

Custom Endpoints

add_action( 'rest_api_init', function() {
    register_rest_route( 'custom/v1', '/products/featured', array(
        'methods'             => 'GET',
        'callback'            => 'get_featured_products',
        'permission_callback' => '__return_true',
    ) );
} );

function get_featured_products( WP_REST_Request $request ) {
    $args = array(
        'post_type'      => 'product',
        'posts_per_page' => $request->get_param( 'per_page' ) ?: 10,
        'tax_query'      => array(
            array(
                'taxonomy' => 'product_visibility',
                'field'    => 'name',
                'terms'    => 'featured',
            ),
        ),
    );

    $products = wc_get_products( $args );

    return array_map( function( $product ) {
        return array(
            'id'         => $product->get_id(),
            'name'       => $product->get_name(),
            'price'      => $product->get_price(),
            'image'      => wp_get_attachment_url( $product->get_image_id() ),
            'permalink'  => $product->get_permalink(),
        );
    }, $products );
}

Extend Existing Endpoints

// Add custom field to product API response
add_filter( 'woocommerce_rest_prepare_product_object', function( $response, $product, $request ) {
    $response->data['custom_field'] = $product->get_meta( '_custom_field' );
    $response->data['stock_status_label'] = $product->is_in_stock() ? 'Available' : 'Out of Stock';
    return $response;
}, 10, 3 );

// Allow updating custom field via API
add_action( 'woocommerce_rest_insert_product_object', function( $product, $request, $creating ) {
    if ( isset( $request['custom_field'] ) ) {
        $product->update_meta_data( '_custom_field', sanitize_text_field( $request['custom_field'] ) );
        $product->save();
    }
}, 10, 3 );

Performance

Query Optimization

// Disable unnecessary features
add_filter( 'woocommerce_background_image_regeneration', '__return_false' );
add_filter( 'woocommerce_enable_nocache_headers', '__return_false' );

// Limit product queries
add_filter( 'loop_shop_per_page', function() {
    return 24; // Products per page
} );

// Cache expensive queries
function get_best_sellers( $limit = 5 ) {
    $cache_key = 'wc_best_sellers_' . $limit;
    $products  = get_transient( $cache_key );

    if ( false === $products ) {
        global $wpdb;

        $products = $wpdb->get_results( $wpdb->prepare( "
            SELECT p.ID, p.post_title, SUM(oim.meta_value) as total_sales
            FROM {$wpdb->posts} p
            INNER JOIN {$wpdb->prefix}woocommerce_order_items oi ON p.ID = oi.order_item_name
            INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id
            WHERE oim.meta_key = '_qty'
            AND p.post_type = 'product'
            AND p.post_status = 'publish'
            GROUP BY p.ID
            ORDER BY total_sales DESC
            LIMIT %d
        ", $limit ) );

        set_transient( $cache_key, $products, HOUR_IN_SECONDS );
    }

    return $products;
}

// Clear cache on order
add_action( 'woocommerce_order_status_completed', function() {
    delete_transient( 'wc_best_sellers_5' );
} );

AJAX Cart

// Update cart via AJAX
add_action( 'wp_ajax_update_cart_item', 'ajax_update_cart_item' );
add_action( 'wp_ajax_nopriv_update_cart_item', 'ajax_update_cart_item' );

function ajax_update_cart_item() {
    check_ajax_referer( 'wc_cart_nonce', 'nonce' );

    $cart_item_key = sanitize_text_field( $_POST['cart_item_key'] );
    $quantity      = absint( $_POST['quantity'] );

    if ( $quantity > 0 ) {
        WC()->cart->set_quantity( $cart_item_key, $quantity );
    } else {
        WC()->cart->remove_cart_item( $cart_item_key );
    }

    WC_AJAX::get_refreshed_fragments();
}

Email Customization

// Add content to order emails
add_action( 'woocommerce_email_order_details', function( $order, $sent_to_admin, $plain_text, $email ) {
    if ( 'customer_completed_order' === $email->id ) {
        echo '<h2>Thank you for your order!</h2>';
        echo '<p>Your order will be shipped within 2-3 business days.</p>';
    }
}, 5, 4 );

// Custom email
class WC_Email_Custom extends WC_Email {
    public function __construct() {
        $this->id             = 'custom_email';
        $this->title          = __( 'Custom Email', 'textdomain' );
        $this->description    = __( 'Custom email notification', 'textdomain' );
        $this->template_html  = 'emails/custom-email.php';
        $this->template_plain = 'emails/plain/custom-email.php';

        parent::__construct();
    }

    public function trigger( $order_id ) {
        if ( ! $order_id ) return;

        $this->object = wc_get_order( $order_id );
        $this->recipient = $this->object->get_billing_email();

        if ( ! $this->is_enabled() || ! $this->get_recipient() ) return;

        $this->send(
            $this->get_recipient(),
            $this->get_subject(),
            $this->get_content(),
            $this->get_headers(),
            $this->get_attachments()
        );
    }
}

add_filter( 'woocommerce_email_classes', function( $emails ) {
    $emails['WC_Email_Custom'] = new WC_Email_Custom();
    return $emails;
} );
Weekly Installs
1
Installed on
windsurf1
opencode1
codex1
claude-code1
antigravity1
gemini-cli1