npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

wp-shopify

v2.1.1

Published

Vue mixin + store module for WP-Shopify. Integrates Vue, WordPress, and Shopify.

Downloads

6

Readme

Vue plugin to ease Shopify products and cart management. Can be combined with WP-Shopify for Vue + WordPress.

Table of Contents

  1. Installation
  2. Reference
    1. Mixin
    2. Store

Installation

If you're combining this plugin with its optional WordPress backend, follow the instructions on that repo first.

  1. Set up a Shopify store and create a new private app.

  2. Go to your Shopify admin panel (your-store.myshopify.com/admin).

  3. Click "Manage Private Apps" at the bottom of the screen. You'll end up on your-store.myshopify.com/admin/apps/private.

  4. Click "Create a new private app."

  5. Keep the default API permissions and make sure Allow this app to access your storefront data using the Storefront API at the bottom of the screen is checked.

  6. Hit Save to continue.

  7. Note the Storefront Token on the bottom of the next page:

    !Image of the Shopify storefront access token location

  1. npm install wp-shopify

  2. Install Vuex.

  3. Before creating your Vue instance, install the plugin with:

    import WpShopify from 'wp-shopify'
    import store from 'your-main-vuex-store'
    
    Vue.use(WpShopify, {
        // your Shopify domain, formatted: my-site.myshopify.com
        // (Vuepress default shown)
        domain: jsonData.site.shopifyDomain,
        // your Shopify storefront access token
        // (Vuepress default shown)
        token: jsonData.site.storefrontToken,
        store: store, // your Vuex store
        wordpress: true // whether or not to include WordPress data - default false
    })

That's it! You've got full access to the store module, mixin, and instance variables below.

The Mixin

The plugin automatically adds the following mixin data on all components:

{
    props: {
        productId: {
            type: String,
            default: ''
        }
    },
    data() {
        return {
            selectedVariantIndex: 0,
            product: null
        }
    },
    async mounted(){
        /*
        The mounted function checks to see if the `productId` prop is set.
        If it is, mounted() sets `this.product` to the result of `this.getProduct(this.productId)`.
        */
    },
    methods: {
        async getProduct(id){
            /*
            `getProduct` fetches and returns the product with the given ID from Shopify.
            First, it checks the cached data in `$store.state.shopify.productData[id]`;
            if nothing is found, it builds and executes a query for the product data from Shopify, caching the result.
            */
        },
        async getVariant(variant, product){
            /*
            TODO
            */
        },
        addToCart(product){
            /*
            TODO
            */
        }
    },
    computed: {
        selectedVariant(){
            /*
            Returns either the currently selected variant or,
            if none is selected or no product is present, null.
            */
        }
    }

}

Product Data

Data fetched with getProduct is formatted like this:

{
    // Shopify ID (base64-encoded string from Shopify)
    id: 'Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0Lzk1NTIzMjI1NjAzNg==',

    // Shopify title
    title: 'My Product',

    // Shopify description as raw HTML
    descriptionHtml: '',

    // List of variants
    variants: [
        {
            // Price for this variant
            price: '30.00',
            
            // Compare to sale price for this variant
            compareAtPrice: '30.00',

            // Variant title
            title: 'Small',

            // Whether or not this variant is available
            availableForSale: true,

            // Variant ID
            id: 'Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC85NDE3NTIzMzMxMTA4'
        }
    ],

    // If `wordpress` was set to `true` when installing plugin:
    wp: {
        // relative path to this product in WordPress
        path: '/store/sample-product/'
    }
}

Store Module

WP-Shopify adds a module called shopify to the Vuex store with the following state, mutations, and actions:

state: {
    // Cache for fetched product data
    productData: {},

    // load initial cart state from localStorage (defaults to empty array)
    cart: loadCart(),

    // domain and token (set in installation)
    domain: '',
    token: '',

    // since we can't deep-watch the cart for quantities, etc, the store
    // watches this value and increment every time the cart is modified
    // (this is for internal use only)
    cartVersion: 0,

    // checkout URL as calculated from cart contents
    checkoutUrl: '',

    // subtotal of all items in cart
    subtotal: ''
},
mutations: {
    UPDATE_CACHED_RESULT({ shopifyId, data }) {
        /*
        Updates `state.productData` entry for `shopifyId` with new `data`
        */
    },
    ADD_TO_CART({ variant, quantity }) {
        /*
        Adds `quantity` (default 1) of the given `variant` to the cart.
        Updates localstorage and the checkout URL.
        */
    },
    SET_QUANTITY({ variant, quantity, changeBy }) {
        /*
        Either set the `variant` to a specific `quantity` or change its current
        `quantity` by `changeBy` units. Updates localstorage and the checkout URL.
        */
    },
    REMOVE_FROM_CART({ variant }) {
        /*
        Removes all of a given `variant` from the cart.
        Updates localstorage and the checkout URL.
        */
    },
    EMPTY_CART() {
        /*
        Removes everything from the cart.
        Updates localstorage and the checkout URL.
        */

    },
    UPDATE_CHECKOUT() {
        /*
        Manually refresh the checkout URL. Usually called internally.
        */
    },
    SET_DOMAIN_AND_TOKEN({ domain, token, force }) {
        /*
        Update the Shopify domain and token.
        Set `force` to `true` to update even if a Shopify domain and token already exist.
        */
    }
},
actions: {
    async GET_PRODUCT_DATA(
        { shopifyId, domain, token }
    ) {
        /*
        Fetch and cache a product's data given its ID.
        Should not be called manually - use `getProduct` from the mixin instead.
        */
    }
}

Product Templating

Basic Templating

All of a product's Shopify data is contained in the product object. If you know the ID of your product, you can retrieve the full object with getProduct.

<template>

    <section>
        {{ product ? product.title : '' }}
    </section>

</template>

<script>
export default {
    mounted() {
        // this is how the WordPress plugin retrieves a product...
        const productId = this.$store.getters.post.productId

        // ...but any valid ID will work
        this.product = this.getProduct(productId)
    }
}
</script>

You can also pass the ID as a prop called product-id to automatically fetch a product on a custom component:

Main.vue

<template>

    <product-example :product-id="'your product ID here'"/>

</template>

ProductExample.vue

<template>

    <div class="product-example">
        {{ product ? product.title : '' }}
    </div>

</template>

Variants

A product usually has at least one variant - different colors, sizes, etc. - that you'll need to account for.

The easiest way to handle this is to use the built-in selectedVariant system. For example:

<template>

    <h2 v-if="!product">Loading...</h2>

    <main v-else>

        <h2>{{ product.title }}</h2>

        <h3>Currently selected: {{ selectedVariant.title }} (${{ selectedVariant.price }})</h3>

        <select v-model="selectedVariantIndex">
            <option
                v-for="(variant, i) in variants"
                :key="i"
                :value="i">

                {{ variant.title }}

            </option>
        </select>

        <button @click="addToCart()">
            Add to Cart
        </button>

    </main>

</template>

And an annotated version of the above:

```html
<template>

    <!-- Product loading state -->
    <h2 v-if="!product">Loading...</h2>

    <!-- Product loaded and ready -->
    <main v-else>

        <h2>{{ product.title }}</h2>

        <h3>Currently selected: {{ selectedVariant.title }} (${{ selectedVariant.price }})</h3>

        <!-- Changing the selectedVariantIndex changes the selectedVariant -->
        <select v-model="selectedVariantIndex">
            <option
                v-for="(variant, i) in variants"
                :key="i"
                :value="i">

                {{ variant.title }}

            </option>
        </select>

        <!-- addToCart is another function from the mixin -->
        <button @click="addToCart()">
            Add to Cart
        </button>

    </main>

</template>

Cart

A shopping cart might look like this:

<template>
    <div class="shopping-cart">
        <ul>

            <li v-for="(product, i) in $store.state.shopify.cart" :key="i">
                <span>{{ product.title }}</span>
                <span>({{ product.quantity }})</span>
            </li>

        </ul>

        <a :href="checkoutUrl" target="_blank" rel="noopener noreferrer">Checkout</a>
    </div>
</template>

Annotated:

<template>
    <div class="shopping-cart">
        <ul>

            <!-- Shopify data is kept in a Vuex module called 'shopify' -->
            <li v-for="(product, i) in $store.state.shopify.cart" :key="i">
                <span>{{ product.title }}</span>
                <span>({{ product.quantity }})</span>
            </li>

        </ul>

        <!-- The checkout URL is automatically updated any time the cart changes -->
        <a :href="checkoutUrl" target="_blank" rel="noopener noreferrer">Checkout</a>
    </div>
</template>