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

Featured Product (Shopify)

★ 0stars

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/iamrmrishan/wp-shopify-featured-product/archive/refs/heads/main.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

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