WP Manifestindependent plugin directory
manifest / ecommerce / wp-shopify-featured-product

Featured Product (Shopify)

A Featured Product card block powered by the Shopify Storefront API.

by Development and Digital · github.com/iamrmrishan/wp-shopify-featured-product

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/iamrmrishan/wp-shopify-featured-product/archive/refs/heads/main.zip

Featured Product (WordPress + React + Shopify)

A lean WordPress plugin that renders a Featured Product card on any page. Product data comes from the Shopify Storefront API; the card is a TypeScript React component inside a native Gutenberg block.

Integration method (and why)

Custom plugin → PHP fetches Shopify → SSR HTML → React hydrates → cart via a small REST proxy → Shopify hosted checkout.

Approach Why not (for this task)
Sell on WordPress (official) Right for a real client; this assessment asks for your React + Storefront build
Buy Button / JS embed Product HTML is injected after JS — poor SEO, stale SDK
Client-side Storefront calls Token in the page + extra request waterfall after paint
ShopWP / page builders Stacked plugins; against the brief’s restraint

What we chose instead

  1. PHP calls Storefront GraphQL (product query) and caches the result in a WP transient (10 min).
  2. render.php outputs real HTML (title, price, image) plus data-product JSON for React.
  3. view.tsx hydrates FeaturedProductCard — UI copy and demo fallback live in src/config.ts.
  4. Add to cart posts to POST /wp-json/featured-product/v1/cart (WP nonce). PHP runs cartCreate / cartLinesAdd, stores the cart id in an HttpOnly cookie, returns checkoutUrl.
  5. Checkout is Shopify’s hosted checkout — we do not build our own.

The Storefront token stays in Settings → Featured Product (wp_options), never in JavaScript. For production, Shopify also supports a private Storefront token with a Shopify-Storefront-Buyer-IP header on server requests; this repo uses the public token in PHP only to keep Partner-store setup to one field.

Requirements

  • Node.js 18+
  • Docker (for @wordpress/env)
  • A free Shopify Partner development store (optional for demo fallback)

Quick start

cd wp-shopify-featured-product
npm install
npm run build
npx wp-env start

Shopify setup

  1. Create a Partner development store and add at least one product.
  2. In Shopify admin: Settings → Apps and sales channels → Develop apps (or install the Headless channel).
  3. Create a Storefront API access token with scopes for:
    • Read products (unauthenticated_read_product_listings or equivalent)
    • Cart / checkout write (unauthenticated_write_checkouts and cart scopes)
  4. Copy the product handle from the URL (/products/your-handle).

WordPress setup

  1. Settings → Featured Product — enter shop domain, token, and handle.
  2. Create a page and insert the Featured Product block (or shortcode [featured_product]).
  3. View the page — live title, price, and image when Shopify is configured; demo fallback otherwise.
  4. Click Add to cart, then Checkout to open Shopify’s test checkout (use bogus gateway on dev stores).

Development

npx wp-env start
npm run start   # webpack watch for src/

Stop environment: npx wp-env stop

Project structure

featured-product.php          Plugin bootstrap
includes/
  class-shopify-client.php    Storefront GraphQL (product + cart)
  class-cart-rest.php         POST /cart REST endpoint
  class-settings.php          Admin settings
  class-block.php             Block + shortcode SSR
src/
  block.json                  Block metadata
  render.php                  Server-side render
  index.tsx                   Block editor
  view.tsx                    Frontend hydrate
  featured-product-card.tsx   React card UI
  config.ts                   Copy + fallback product (imported by card)
  style.css
build/                        Compiled assets (commit after build)

Development plan

This is the Cursor plan used to build the plugin (4–6 hour hiring scope). Todos below were completed as listed.

Overview: TypeScript React Featured Product card in WordPress. PHP SSR/caches Storefront product data; React renders the card and adds the first variant to a Storefront cart, then Shopify hosted checkout.

  • [x] Scaffold plugin bootstrap, block.json, .wp-env.json, package.json, tsconfig, gitignore
  • [x] Shopify GraphQL client (product + cartCreate/cartLinesAdd), transients for product only, settings, render.php data-product, REST POST cart + cart-id cookie
  • [x] TypeScript card + src/config.ts (copy, fallback product); hydrate from data-product; Add to cart then Checkout; editor ServerSideRender
  • [x] README (run + method + why, including cart) and DECISIONS.md (three half-page answers)

Assessment fit

Cart is in the brief as a bonus; this plan treats Add to cart + hosted checkout as required, still scoped to one product / first variant so it stays inside 4–6 hours.

Brief Plan
Single Featured Product card One product, one card, one handle in settings
React component inside a WordPress page FeaturedProductCard mounts via a native block (plus a thin shortcode alias)
Live title, price, image Storefront product(handle:) fields
Shopify Storefront API PHP GraphQL to {shop}/api/2026-07/graphql.json
Integration method is your call Custom plugin; README explains why vs official plugin / Buy Button
Cart/checkout Required: Storefront Cart API → Shopify checkoutUrl
Core = live data rendering cleanly PHP puts product in the HTML; React renders the card from that payload
README: how to run + method + why Yes
Decisions doc, ½ page × 3 DECISIONS.md
4–6 hours, restraint, no page builders One plugin, no Elementor/Divi, no stacked Shopify plugins
Free tools, Partner store, local WP wp-env (Docker), free React/@wordpress/scripts, Partner store placeholders
Note assumptions README

Not contradictions:

  • PHP calls Storefront for product + cart writes; React renders and posts Add to cart. Token stays off the page. Cart is buyer state (cookie + REST), not cached like the product.
  • Gutenberg is not a page builder. One core block is the WP-native mount.
  • config.ts fallback vs “live data”. Live Shopify wins when settings are filled; fallback is unconfigured local demo. Add to cart is disabled or errors cleanly without a real variant GID.
  • DECISIONS.md recommending Sell on WordPress for a real client does not fight the build.

Keep React as the card UI (title, price, image, add to cart). PHP is host + Storefront + product cache + cart proxy.

What we chose not to copy from the web

  • Sell on WordPress (official) — default for a real merchant; wrong for this brief (they asked us to build React + Storefront API).
  • Buy Button / JS Buy SDK — client-injected card, not indexable. Do not ship a JS-only product card.
  • Custom Storefront API — query GraphQL, cache product in WP transients, inject HTML in PHP. Cart: Storefront Cart API then Shopify hosted checkoutUrl. Do not build a custom checkout.

Shopify.dev Storefront auth: public token is for the browser; private token + buyer IP is for servers. This plugin keeps the public token in PHP only (one settings field). README notes the private-token pattern for production.

Integration method (plan)

Custom dynamic Gutenberg block. PHP fetches/caches the product (SSR). React renders the card. Add to cart goes through a small WP REST proxy to the Storefront Cart API, then Shopify checkout.

  • Settings: shop domain, Storefront token, product handle.
  • Block featured-product/card: render.php queries product (cached ~10 min), prints card shell + data-product JSON including variantId (first variant GID) and available.
  • TypeScript viewScript mounts FeaturedProductCard. Copy + fallbackProduct from src/config.ts.
  • Editor: @wordpress/server-side-render. Add to cart is frontend-only.
  • Product read: no REST. Cart write: POST /wp-json/featured-product/v1/cart with WP nonce. PHP cartCreate or cartLinesAdd, cart id in an HttpOnly cookie, response { checkoutUrl, totalQuantity }. Expired cart → create a new one.
  • Token in wp_options. Public Storefront token header. API version 2026-07.
  • Thin [featured_product] shortcode alias.

Cart scope (restraint): one Add to cart control, quantity default 1; Checkout uses Shopify checkoutUrl; first variant only. No variant picker, no mini-cart, no Customer Account API.

flowchart LR
  Editor["Gutenberg block"]
  PHP["render.php + product transient"]
  Shopify["Storefront GraphQL"]
  HTML["SSR + data-product"]
  React["TS card"]
  CartRest["POST cart REST"]
  Checkout["Shopify checkoutUrl"]
  Editor --> PHP
  PHP --> Shopify
  PHP --> HTML
  HTML --> React
  React --> CartRest
  CartRest --> Shopify
  CartRest --> Checkout

Product query: title, featuredImage { url altText }, priceRange.minVariantPrice { amount currencyCode }, onlineStoreUrl, variants(first: 1) { nodes { id availableForSale } }.

Cart mutations: cartCreate / cartLinesAdd with merchandiseId; return checkoutUrl and totalQuantity.

Out of scope

No cart drawer, cart page, variant picker, Customer Account API, custom checkout, tests, Tailwind/page builder, product picker, Hydrogen/Next.

Verify

Placeholders: settings save; card shows fallback from config.ts; Add to cart errors or stays disabled without a live variant. With a real store: SSR title/price/image; Add to cart returns checkoutUrl; Checkout opens Shopify checkout.

Assumptions

  • One featured product (first variant only; no variant picker).
  • English UI strings in config.ts.
  • Docker available for wp-env (Local WP / Studio also work if you copy the plugin into wp-content/plugins).
  • Partner-store checkout uses Shopify’s test payment flow, not real charges.
  • config.ts provides demo data when Shopify is not configured; live fields replace it once settings are saved.

Loom talk track (~3–5 min)

  1. Goal — one card, three systems: React, WordPress, Shopify.
  2. Why custom plugin — assessment wants your integration; official plugin is the real-client default (see DECISIONS.md).
  3. Data flow — settings → PHP GraphQL + transient → SSR HTML → React hydrate from data-product.
  4. config.ts — copy and fallback; secrets stay in WP settings.
  5. Cart — REST proxy, cookie, Storefront Cart API, hosted checkout.
  6. Trade-offs — no cart drawer/page; first variant only; scoped for 4–6 hours.

License

GPL-2.0-or-later