25% off ProSNIPC25OFF

Wishlist / Save-for-Later Button

Adds a cookie-based wishlist heart button to product pages and archive cards, with an [scseed_wishlist] shortcode to display saved items.

Module3 parts · by SnipCraft

PHPPHP

php
<?php
if ( ! class_exists( 'WooCommerce' ) ) { return; }

/* Output AJAX vars once per page */
add_action( 'wp_footer', 'scseed_wl_footer_vars', 1 );
function scseed_wl_footer_vars() {
    echo '<script>window.scWL=' . wp_json_encode( array(
        'ajax'  => admin_url( 'admin-ajax.php' ),
        'nonce' => wp_create_nonce( 'scseed_wl' ),
    ) ) . ';</script>';
}

/* Heart button — single product and archive */
add_action( 'woocommerce_after_add_to_cart_button', 'scseed_wl_button', 10 );
add_action( 'woocommerce_after_shop_loop_item', 'scseed_wl_button', 12 );
function scseed_wl_button() {
    global $product;
    if ( ! $product ) { return; }
    $id = $product->get_id();
    echo '<button type="button" class="scseed-wl-btn" data-pid="' . esc_attr( $id ) . '" '
       . 'aria-label="' . esc_attr__( 'Add to wishlist', 'scseed' ) . '">'
       . '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true" focusable="false">'
       . '<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>'
       . '</svg></button>';
}

/* AJAX: return HTML for wishlist product grid */
add_action( 'wp_ajax_scseed_wl_items', 'scseed_ajax_wl_items' );
add_action( 'wp_ajax_nopriv_scseed_wl_items', 'scseed_ajax_wl_items' );
function scseed_ajax_wl_items() {
    check_ajax_referer( 'scseed_wl', 'nonce' );
    $raw = sanitize_text_field( wp_unslash( $_POST['ids'] ?? '' ) );
    $ids = array_filter( array_map( 'absint', explode( ',', $raw ) ) );
    if ( empty( $ids ) ) {
        wp_send_json_success( '' );
    }
    ob_start();
    echo '<ul class="products scseed-wl__grid">';
    foreach ( $ids as $id ) {
        $p = wc_get_product( $id );
        if ( ! $p || 'publish' !== $p->get_status() ) { continue; }
        echo '<li class="product">';
        echo '<a href="' . esc_url( $p->get_permalink() ) . '">';
        echo $p->get_image( 'woocommerce_thumbnail' );
        echo '<h2 class="woocommerce-loop-product__title">' . esc_html( $p->get_name() ) . '</h2>';
        echo '</a>';
        echo '<span class="price">' . $p->get_price_html() . '</span>';
        echo '<a href="' . esc_url( $p->add_to_cart_url() ) . '" class="button add_to_cart_button">'
           . esc_html( $p->add_to_cart_text() ) . '</a>';
        echo '</li>';
    }
    echo '</ul>';
    wp_send_json_success( ob_get_clean() );
}

/* Shortcode: [scseed_wishlist] */
add_shortcode( 'scseed_wishlist', 'scseed_wl_shortcode' );
function scseed_wl_shortcode() {
    return '<div id="scseed-wl-page" class="scseed-wl__page">'
         . '<p class="scseed-wl__empty">'
         . esc_html__( 'Your wishlist is empty.', 'scseed' )
         . '</p></div>';
}

CSSStyles

css
/* ── Wishlist Button ── */
.scseed-wl-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    background: none;
    border: none;
    padding: .4rem;
    color: #bbb;
    transition: color .2s, transform .15s;
    vertical-align: middle;
}
.scseed-wl-btn svg { fill: currentColor; display: block; pointer-events: none; }
.scseed-wl-btn:hover { color: #e91e63; transform: scale(1.18); }
.scseed-wl-btn.scseed-wl--active { color: #e91e63; }
.scseed-wl-btn:focus-visible { outline: 2px solid #e91e63; outline-offset: 2px; border-radius: 50%; }

/* ── Wishlist Page ── */
.scseed-wl__page { min-height: 4rem; }
.scseed-wl__empty { color: #777; font-style: italic; }

JavaScriptScript

js
(function () {
    var COOKIE = 'scseed_wl';
    var DAYS   = 365;

    function readIds() {
        var m = document.cookie.match('(?:^|;)\s*scseed_wl=([^;]*)');
        if (!m) { return []; }
        try { return JSON.parse(decodeURIComponent(m[1])); } catch (e) { return []; }
    }
    function writeIds(ids) {
        var d = new Date();
        d.setDate(d.getDate() + DAYS);
        document.cookie = COOKIE + '=' + encodeURIComponent(JSON.stringify(ids))
            + '; path=/; expires=' + d.toUTCString() + '; SameSite=Lax';
    }
    function toggleId(id) {
        var ids = readIds();
        var idx = ids.indexOf(id);
        if (idx === -1) { ids.push(id); } else { ids.splice(idx, 1); }
        writeIds(ids);
        return ids.indexOf(id) !== -1;
    }

    /* Initialise buttons */
    var saved = readIds();
    document.querySelectorAll('.scseed-wl-btn').forEach(function (btn) {
        var pid = parseInt(btn.getAttribute('data-pid'), 10);
        if (saved.indexOf(pid) !== -1) { btn.classList.add('scseed-wl--active'); }
        btn.addEventListener('click', function () {
            var active = toggleId(pid);
            btn.classList.toggle('scseed-wl--active', active);
            btn.setAttribute('aria-label', active ? 'Remove from wishlist' : 'Add to wishlist');
        });
    });

    /* Populate wishlist page */
    var page = document.getElementById('scseed-wl-page');
    if (page && typeof scWL !== 'undefined') {
        var ids = readIds();
        if (!ids.length) { return; }
        var body = new URLSearchParams({
            action: 'scseed_wl_items',
            nonce: scWL.nonce,
            ids: ids.join(',')
        });
        fetch(scWL.ajax, { method: 'POST', body: body })
            .then(function (r) { return r.json(); })
            .then(function (res) { if (res.success && res.data) { page.innerHTML = res.data; } });
    }
})();
#ux#woocommerce#product#cookie#wishlist