πŸ“„ shopify-checkout-for-woo/shopify-checkout-for-woo.php FILE 1 β€” Main Plugin File
<?php
/**
 * Plugin Name:       Shopify Checkout for WooCommerce
 * Plugin URI:        https://example.com/shopify-checkout-for-woo
 * Description:       Replaces the default WooCommerce checkout with a modern, Shopify-style single-page checkout experience.
 * Version:           1.0.0
 * Requires at least: 6.0
 * Requires PHP:      7.4
 * Author:            Your Name
 * Author URI:        https://example.com
 * License:           GPL v2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       shopify-checkout-woo
 * Domain Path:       /languages
 * WC requires at least: 7.0
 * WC tested up to:   9.0
 */

defined( 'ABSPATH' ) || exit;

// ─────────────────────────────────────────────
// Constants
// ─────────────────────────────────────────────
define( 'SCW_VERSION',     '1.0.0' );
define( 'SCW_PLUGIN_FILE', __FILE__ );
define( 'SCW_PLUGIN_DIR',  plugin_dir_path( __FILE__ ) );
define( 'SCW_PLUGIN_URL',  plugin_dir_url( __FILE__ ) );

// ─────────────────────────────────────────────
// WooCommerce 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',
            SCW_PLUGIN_FILE,
            true
        );
        \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
            'cart_checkout_blocks',
            SCW_PLUGIN_FILE,
            false // We override the classic checkout template; blocks not supported
        );
    }
} );

// ─────────────────────────────────────────────
// Activation hook β€” verify WooCommerce is active
// ─────────────────────────────────────────────
register_activation_hook( SCW_PLUGIN_FILE, 'scw_activate' );
function scw_activate() {
    if ( ! class_exists( 'WooCommerce' ) ) {
        deactivate_plugins( plugin_basename( SCW_PLUGIN_FILE ) );
        wp_die(
            esc_html__(
                'Shopify Checkout for WooCommerce requires WooCommerce to be installed and active.',
                'shopify-checkout-woo'
            ),
            esc_html__( 'Plugin Activation Error', 'shopify-checkout-woo' ),
            array( 'back_link' => true )
        );
    }
    // Flush rewrite rules on activation
    flush_rewrite_rules();
}

// ─────────────────────────────────────────────
// Deactivation hook
// ─────────────────────────────────────────────
register_deactivation_hook( SCW_PLUGIN_FILE, 'scw_deactivate' );
function scw_deactivate() {
    flush_rewrite_rules();
}

// ─────────────────────────────────────────────
// Guard: only run plugin logic if WooCommerce is active
// ─────────────────────────────────────────────
add_action( 'plugins_loaded', 'scw_init', 20 );
function scw_init() {
    if ( ! class_exists( 'WooCommerce' ) ) {
        add_action( 'admin_notices', function () {
            echo '<div class="notice notice-error"><p>'
                . esc_html__(
                    'Shopify Checkout for WooCommerce requires WooCommerce. Please install and activate WooCommerce.',
                    'shopify-checkout-woo'
                )
                . '</p></div>';
        } );
        return;
    }

    // Load text domain
    load_plugin_textdomain(
        'shopify-checkout-woo',
        false,
        dirname( plugin_basename( SCW_PLUGIN_FILE ) ) . '/languages'
    );

    // Hook everything in
    scw_register_hooks();
}

// ─────────────────────────────────────────────
// Register all plugin hooks
// ─────────────────────────────────────────────
function scw_register_hooks() {
    // Template override
    add_filter( 'woocommerce_locate_template',      'scw_override_checkout_template', 10, 3 );

    // Scripts & styles
    add_action( 'wp_enqueue_scripts',               'scw_enqueue_assets', 20 );
    add_action( 'wp_enqueue_scripts',               'scw_dequeue_the7_styles', 100 );

    // Body class
    add_filter( 'body_class',                       'scw_body_classes' );

    // Checkout fields
    add_filter( 'woocommerce_checkout_fields',      'scw_modify_checkout_fields' );

    // AJAX β€” coupon (logged-in)
    add_action( 'wp_ajax_scw_apply_coupon',         'scw_ajax_apply_coupon' );
    add_action( 'wp_ajax_scw_remove_coupon',        'scw_ajax_remove_coupon' );

    // AJAX β€” coupon (guest / not logged-in)
    add_action( 'wp_ajax_nopriv_scw_apply_coupon',  'scw_ajax_apply_coupon' );
    add_action( 'wp_ajax_nopriv_scw_remove_coupon', 'scw_ajax_remove_coupon' );
}

// ─────────────────────────────────────────────
// 1. Template override: redirect checkout.php to plugin template
// ─────────────────────────────────────────────
function scw_override_checkout_template( $template, $template_name, $template_path ) {
    // Only override the checkout template (not order-received / thankyou)
    if ( 'checkout/form-checkout.php' !== $template_name ) {
        return $template;
    }

    $plugin_template = SCW_PLUGIN_DIR . 'templates/checkout.php';

    if ( file_exists( $plugin_template ) ) {
        return $plugin_template;
    }

    return $template;
}

// ─────────────────────────────────────────────
// 2. Enqueue CSS & JS on checkout (not order-received)
// ─────────────────────────────────────────────
function scw_enqueue_assets() {
    if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
        return;
    }

    // Do NOT enqueue on the order-received (thank-you) page
    if ( is_wc_endpoint_url( 'order-received' ) ) {
        return;
    }

    // ── CSS ──────────────────────────────────
    wp_enqueue_style(
        'scw-checkout',
        SCW_PLUGIN_URL . 'assets/css/checkout.css',
        array( 'woocommerce-layout', 'woocommerce-general' ),
        SCW_VERSION
    );

    // ── JS ───────────────────────────────────
    wp_enqueue_script(
        'scw-checkout',
        SCW_PLUGIN_URL . 'assets/js/checkout.js',
        array( 'jquery', 'wc-checkout' ),
        SCW_VERSION,
        true // load in footer
    );

    // ── Localize ─────────────────────────────
    wp_localize_script(
        'scw-checkout',
        'scwData',
        array(
            'ajaxUrl' => esc_url( admin_url( 'admin-ajax.php' ) ),
            'nonce'   => wp_create_nonce( 'scw_nonce' ),
            'i18n'    => array(
                'applying'       => esc_html__( 'Applying…',          'shopify-checkout-woo' ),
                'removing'       => esc_html__( 'Removing…',          'shopify-checkout-woo' ),
                'couponApplied'  => esc_html__( 'Coupon applied!',    'shopify-checkout-woo' ),
                'couponRemoved'  => esc_html__( 'Coupon removed.',    'shopify-checkout-woo' ),
                'errorGeneric'   => esc_html__( 'Something went wrong. Please try again.', 'shopify-checkout-woo' ),
                'enterCoupon'    => esc_html__( 'Enter coupon code', 'shopify-checkout-woo' ),
                'applyCoupon'    => esc_html__( 'Apply',             'shopify-checkout-woo' ),
                'removeCoupon'   => esc_html__( 'Remove',            'shopify-checkout-woo' ),
                'showOrderSummary' => esc_html__( 'Show order summary', 'shopify-checkout-woo' ),
                'hideOrderSummary' => esc_html__( 'Hide order summary', 'shopify-checkout-woo' ),
            ),
        )
    );
}

// ─────────────────────────────────────────────
// 3. Dequeue The7 theme conflicting styles (priority 100)
// ─────────────────────────────────────────────
function scw_dequeue_the7_styles() {
    if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
        return;
    }
    if ( is_wc_endpoint_url( 'order-received' ) ) {
        return;
    }

    $conflicting_handles = array(
        'the7-woocommerce',
        'the7-woocommerce-checkout',
        'dt-woocommerce',
        'presscore-woocommerce',
    );

    foreach ( $conflicting_handles as $handle ) {
        wp_dequeue_style( $handle );
        wp_deregister_style( $handle );
    }
}

// ─────────────────────────────────────────────
// 4. Body class filter
// ─────────────────────────────────────────────
function scw_body_classes( $classes ) {
    if ( function_exists( 'is_checkout' ) && is_checkout() && ! is_wc_endpoint_url( 'order-received' ) ) {
        $classes[] = 'scw-checkout-page';
        $classes[] = 'scw-no-sidebar';
    }
    return $classes;
}

// ─────────────────────────────────────────────
// 5. Checkout fields: move email to priority 5, phone to 100
// ─────────────────────────────────────────────
function scw_modify_checkout_fields( $fields ) {
    // Move billing email to priority 5 (top of billing section)
    if ( isset( $fields['billing']['billing_email'] ) ) {
        $fields['billing']['billing_email']['priority'] = 5;
    }

    // Move billing phone to priority 100 (bottom of billing section)
    if ( isset( $fields['billing']['billing_phone'] ) ) {
        $fields['billing']['billing_phone']['priority'] = 100;
    }

    return $fields;
}

// ─────────────────────────────────────────────
// 6. AJAX: Apply coupon
// ─────────────────────────────────────────────
function scw_ajax_apply_coupon() {
    // Verify nonce
    if ( ! check_ajax_referer( 'scw_nonce', 'nonce', false ) ) {
        wp_send_json_error(
            array( 'message' => esc_html__( 'Security check failed.', 'shopify-checkout-woo' ) ),
            403
        );
    }

    $coupon_code = isset( $_POST['coupon_code'] ) ? sanitize_text_field( wp_unslash( $_POST['coupon_code'] ) ) : '';

    if ( empty( $coupon_code ) ) {
        wp_send_json_error(
            array( 'message' => esc_html__( 'Please enter a coupon code.', 'shopify-checkout-woo' ) )
        );
    }

    // WooCommerce cart apply coupon
    if ( ! WC()->cart ) {
        wp_send_json_error(
            array( 'message' => esc_html__( 'Cart not available.', 'shopify-checkout-woo' ) )
        );
    }

    // Check if coupon already applied
    if ( WC()->cart->has_discount( $coupon_code ) ) {
        wp_send_json_error(
            array( 'message' => esc_html__( 'Coupon code already applied!', 'shopify-checkout-woo' ) )
        );
    }

    $result = WC()->cart->apply_coupon( $coupon_code );

    if ( $result ) {
        // Recalculate totals
        WC()->cart->calculate_totals();

        ob_start();
        scw_render_order_summary();
        $order_summary_html = ob_get_clean();

        wp_send_json_success(
            array(
                'message'      => esc_html__( 'Coupon applied successfully!', 'shopify-checkout-woo' ),
                'orderSummary' => $order_summary_html,
            )
        );
    } else {
        // WooCommerce adds notices; grab the last one
        $notices = wc_get_notices( 'error' );
        $message = ! empty( $notices )
            ? wp_strip_all_tags( $notices[0]['notice'] )
            : esc_html__( 'Invalid coupon code.', 'shopify-checkout-woo' );

        wc_clear_notices();

        wp_send_json_error( array( 'message' => $message ) );
    }
}

// ─────────────────────────────────────────────
// 7. AJAX: Remove coupon
// ─────────────────────────────────────────────
function scw_ajax_remove_coupon() {
    // Verify nonce
    if ( ! check_ajax_referer( 'scw_nonce', 'nonce', false ) ) {
        wp_send_json_error(
            array( 'message' => esc_html__( 'Security check failed.', 'shopify-checkout-woo' ) ),
            403
        );
    }

    $coupon_code = isset( $_POST['coupon_code'] ) ? sanitize_text_field( wp_unslash( $_POST['coupon_code'] ) ) : '';

    if ( empty( $coupon_code ) ) {
        wp_send_json_error(
            array( 'message' => esc_html__( 'No coupon code provided.', 'shopify-checkout-woo' ) )
        );
    }

    if ( ! WC()->cart ) {
        wp_send_json_error(
            array( 'message' => esc_html__( 'Cart not available.', 'shopify-checkout-woo' ) )
        );
    }

    $result = WC()->cart->remove_coupon( $coupon_code );

    if ( $result ) {
        WC()->cart->calculate_totals();

        ob_start();
        scw_render_order_summary();
        $order_summary_html = ob_get_clean();

        wp_send_json_success(
            array(
                'message'      => esc_html__( 'Coupon removed.', 'shopify-checkout-woo' ),
                'orderSummary' => $order_summary_html,
            )
        );
    } else {
        wp_send_json_error(
            array( 'message' => esc_html__( 'Could not remove coupon.', 'shopify-checkout-woo' ) )
        );
    }
}

// ─────────────────────────────────────────────
// 8. Helper: Render order summary HTML
//    Outputs: cart items (image, name, variant, qty, price),
//             coupon rows with remove button,
//             subtotal / tax / total rows.
// ─────────────────────────────────────────────
function scw_render_order_summary() {
    if ( ! WC()->cart ) {
        return;
    }

    $cart = WC()->cart;
    ?>
    <div class="scw-order-summary">

        <!-- ── Cart Items ─────────────────────────────── -->
        <ul class="scw-order-summary__items">
            <?php foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) :
                /** @var WC_Product $product */
                $product   = $cart_item['data'];
                $quantity  = (int) $cart_item['quantity'];
                $item_name = $product->get_name();
                $item_id   = $product->get_id();

                // Thumbnail
                $thumbnail_id  = $product->get_image_id();
                $thumbnail_url = $thumbnail_id
                    ? wp_get_attachment_image_url( $thumbnail_id, 'thumbnail' )
                    : wc_placeholder_img_src( 'thumbnail' );

                // Line total
                $line_total = wc_price( $cart_item['line_total'] + $cart_item['line_tax'] );

                // Variation attributes
                $variation_data = array();
                if ( ! empty( $cart_item['variation'] ) ) {
                    foreach ( $cart_item['variation'] as $attr_key => $attr_value ) {
                        if ( '' === $attr_value ) {
                            continue;
                        }
                        $taxonomy = str_replace( 'attribute_', '', $attr_key );
                        $label    = wc_attribute_label( $taxonomy );
                        $term     = get_term_by( 'slug', $attr_value, $taxonomy );
                        $value    = $term ? $term->name : $attr_value;
                        $variation_data[] = esc_html( $label ) . ': ' . esc_html( $value );
                    }
                }
            ?>
            <li class="scw-order-summary__item">
                <div class="scw-item__image-wrap">
                    <img
                        src="<?php echo esc_url( $thumbnail_url ); ?>"
                        alt="<?php echo esc_attr( $item_name ); ?>"
                        class="scw-item__image"
                        width="64"
                        height="64"
                        loading="lazy"
                    />
                    <span class="scw-item__qty-badge" aria-label="<?php echo esc_attr( sprintf(
                        /* translators: %d: item quantity */
                        __( 'Quantity: %d', 'shopify-checkout-woo' ),
                        $quantity
                    ) ); ?>">
                        <?php echo esc_html( $quantity ); ?>
                    </span>
                </div>

                <div class="scw-item__details">
                    <span class="scw-item__name"><?php echo esc_html( $item_name ); ?></span>
                    <?php if ( ! empty( $variation_data ) ) : ?>
                        <span class="scw-item__variant">
                            <?php echo esc_html( implode( ' / ', $variation_data ) ); ?>
                        </span>
                    <?php endif; ?>
                </div>

                <div class="scw-item__price">
                    <?php echo wp_kses_post( $line_total ); ?>
                </div>
            </li>
            <?php endforeach; ?>
        </ul>

        <!-- ── Coupon Rows ─────────────────────────────── -->
        <?php $applied_coupons = $cart->get_applied_coupons(); ?>
        <?php if ( ! empty( $applied_coupons ) ) : ?>
        <ul class="scw-order-summary__coupons">
            <?php foreach ( $applied_coupons as $coupon_code ) :
                $coupon        = new WC_Coupon( $coupon_code );
                $discount_amt  = wc_price( $cart->get_coupon_discount_amount( $coupon_code, $cart->display_cart_ex_tax ) );
            ?>
            <li class="scw-order-summary__coupon-row">
                <span class="scw-coupon__label">
                    <?php
                    echo esc_html__(
                        'Discount',
                        'shopify-checkout-woo'
                    );
                    echo ' (<code>' . esc_html( strtoupper( $coupon_code ) ) . '</code>)';
                    ?>
                </span>
                <span class="scw-coupon__amount">
                    &minus;<?php echo wp_kses_post( $discount_amt ); ?>
                </span>
                <button
                    type="button"
                    class="scw-coupon__remove"
                    data-coupon="<?php echo esc_attr( $coupon_code ); ?>"
                    aria-label="<?php echo esc_attr( sprintf(
                        /* translators: %s: coupon code */
                        __( 'Remove coupon %s', 'shopify-checkout-woo' ),
                        strtoupper( $coupon_code )
                    ) ); ?>"
                >
                    <?php esc_html_e( 'Remove', 'shopify-checkout-woo' ); ?>
                </button>
            </li>
            <?php endforeach; ?>
        </ul>
        <?php endif; ?>

        <!-- ── Totals ─────────────────────────────────── -->
        <table class="scw-order-summary__totals" role="presentation">
            <tbody>

                <!-- Subtotal -->
                <tr class="scw-totals__row scw-totals__subtotal">
                    <th scope="row"><?php esc_html_e( 'Subtotal', 'shopify-checkout-woo' ); ?></th>
                    <td><?php echo wp_kses_post( wc_price( $cart->get_subtotal() ) ); ?></td>
                </tr>

                <!-- Shipping (if applicable) -->
                <?php if ( $cart->needs_shipping() && $cart->show_shipping() ) : ?>
                <tr class="scw-totals__row scw-totals__shipping">
                    <th scope="row"><?php esc_html_e( 'Shipping', 'shopify-checkout-woo' ); ?></th>
                    <td>
                        <?php
                        $packages = WC()->shipping()->get_packages();
                        if ( ! empty( $packages ) ) {
                            foreach ( $packages as $package ) {
                                $chosen_method = isset( WC()->session )
                                    ? WC()->session->get( 'chosen_shipping_methods' )
                                    : array();
                                if ( ! empty( $chosen_method[0] ) && isset( $package['rates'][ $chosen_method[0] ] ) ) {
                                    $rate = $package['rates'][ $chosen_method[0] ];
                                    echo wp_kses_post( wc_price( $rate->get_cost() ) );
                                } else {
                                    esc_html_e( 'Calculated at next step', 'shopify-checkout-woo' );
                                }
                            }
                        } else {
                            esc_html_e( 'Free', 'shopify-checkout-woo' );
                        }
                        ?>
                    </td>
                </tr>
                <?php endif; ?>

                <!-- Tax -->
                <?php if ( wc_tax_enabled() && ! $cart->display_prices_including_tax() ) : ?>
                <tr class="scw-totals__row scw-totals__tax">
                    <th scope="row"><?php echo esc_html( WC()->countries->tax_or_vat() ); ?></th>
                    <td><?php echo wp_kses_post( wc_price( $cart->get_total_tax() ) ); ?></td>
                </tr>
                <?php endif; ?>

                <!-- Total -->
                <tr class="scw-totals__row scw-totals__total">
                    <th scope="row"><strong><?php esc_html_e( 'Total', 'shopify-checkout-woo' ); ?></strong></th>
                    <td><strong><?php echo wp_kses_post( $cart->get_total() ); ?></strong></td>
                </tr>

            </tbody>
        </table>

    </div><!-- .scw-order-summary -->
    <?php
}