Edit Shopify Products with Remix.js and Polaris | Simple Variant Updates | Shopify App Development

Shopify is a leading eCommerce platform that allows developers to create powerful custom apps, extending the functionality of online stores. One of the common tasks for Shopify developers is building features that allow store owners to manage and update their products efficiently. In this article, we will explore how to create a custom Shopify app that enables simple variant updates for products using Remix.js and Shopify Polaris. By the end of this tutorial, you will understand how to implement product editing features in your Shopify app, empowering merchants to manage their inventory with ease.

Why Use Remix.js and Polaris for Shopify App Development?

Before we dive into the technical aspects, it’s important to understand why Remix.js and Shopify Polaris are excellent tools for Shopify app development:

  • Remix.js: Remix is a powerful framework for building modern web applications, offering server-side rendering and optimized data loading. It’s ideal for creating fast, dynamic, and SEO-friendly Shopify apps that can handle complex data interactions, such as product variant updates.
  • Shopify Polaris: Polaris is Shopify’s design system, providing a set of React components that help developers create consistent, accessible, and professional user interfaces. Using Polaris ensures that your app’s UI aligns with Shopify’s design guidelines, offering a seamless experience for users.

Setting Up Your Development Environment

Before implementing the product editing functionality, you need to set up your development environment. Here’s how to get started:

  1. Install Node.js: Ensure that Node.js and npm (Node Package Manager) are installed on your machine.
  2. Create a New Shopify App with Remix.js: Use the Shopify CLI to create a new app with Remix.js:bashCopy codeshopify app create node -t remix This command initializes a new Shopify app using Remix.js, setting the foundation for our product editing features.
  3. Install Shopify Polaris: Navigate to your app’s directory and install Polaris components:bashCopy codenpm install @shopify/polaris
  4. Set Up Remix.js: Ensure that your Remix.js environment is properly configured, including setting up routes, loaders, and actions for handling data and user interactions.

Fetching Product Data from Shopify API

To edit product variants, we first need to fetch the relevant product data from the Shopify API.

Step 1: Set Up Shopify API Access

Ensure your Shopify app is configured to access the Shopify API. In your shopify.config.js file, include the necessary API credentials:

javascriptCopy codemodule.exports = {
  apiKey: process.env.SHOPIFY_API_KEY,
  apiSecretKey: process.env.SHOPIFY_API_SECRET,
  scopes: ['read_products', 'write_products'],
  shop: process.env.SHOPIFY_SHOP,
  accessToken: process.env.SHOPIFY_ACCESS_TOKEN,
};

Make sure to store your API key and access token securely in environment variables.

Step 2: Create a Function to Fetch Product Details

Create a utility function to fetch product details, including its variants, from the Shopify API. In your utils directory, create a file named fetchProduct.js:

javascriptCopy codeimport { gql } from 'graphql-request';
import { shopifyClient } from './shopifyClient';

export async function fetchProduct(productId) {
  const query = gql`
    query GetProduct($id: ID!) {
      product(id: $id) {
        id
        title
        variants(first: 10) {
          edges {
            node {
              id
              title
              price
              inventoryQuantity
            }
          }
        }
      }
    }
  `;

  const variables = { id: productId };
  const response = await shopifyClient.request(query, variables);
  return response.product;
}

This function sends a GraphQL query to Shopify’s API to retrieve the product details and its variants.

Displaying and Editing Product Variants

With the product data fetched, the next step is to display it in a form that allows users to update variant information.

Step 1: Create the Product Edit Page

Create a new component, ProductEditPage.jsx, in your components or pages directory. This component will display the product and its variants, allowing users to edit them:

javascriptCopy codeimport { Page, Card, FormLayout, TextField, Button, Stack } from '@shopify/polaris';
import { useLoaderData, useFetcher } from '@remix-run/react';
import { fetchProduct } from '../utils/fetchProduct';

export async function loader({ params }) {
  const productId = params.productId;
  const product = await fetchProduct(productId);
  return product;
}

function ProductEditPage() {
  const product = useLoaderData();
  const fetcher = useFetcher();

  const handleInputChange = (variantId, field, value) => {
    fetcher.submit(
      { variantId, field, value },
      { method: 'post', action: '/products/edit' }
    );
  };

  return (
    <Page title={`Edit Product: ${product.title}`}>
      <Card sectioned>
        {product.variants.edges.map(({ node: variant }) => (
          <Stack vertical key={variant.id}>
            <FormLayout>
              <TextField
                label="Variant Title"
                value={variant.title}
                onChange={(value) => handleInputChange(variant.id, 'title', value)}
              />
              <TextField
                label="Price"
                value={variant.price}
                type="number"
                onChange={(value) => handleInputChange(variant.id, 'price', value)}
              />
              <TextField
                label="Inventory Quantity"
                value={variant.inventoryQuantity}
                type="number"
                onChange={(value) => handleInputChange(variant.id, 'inventoryQuantity', value)}
              />
            </FormLayout>
          </Stack>
        ))}
      </Card>
      <Button primary submit>Save Changes</Button>
    </Page>
  );
}

export default ProductEditPage;

In this code:

  • FormLayout and TextField: These Polaris components are used to create input fields for editing variant details like the title, price, and inventory quantity.
  • handleInputChange Function: This function triggers an API call to update the product variant whenever an input field is changed.

Step 2: Implement the Update Action

Create the action that handles updating the product variant. In your routes directory, create a file named products.edit.js:

javascriptCopy codeimport { redirect } from '@remix-run/node';
import { shopifyClient } from '../../utils/shopifyClient';
import { gql } from 'graphql-request';

export async function action({ request }) {
  const formData = await request.formData();
  const variantId = formData.get('variantId');
  const field = formData.get('field');
  const value = formData.get('value');

  const mutation = gql`
    mutation UpdateProductVariant($id: ID!, $input: ProductVariantInput!) {
      productVariantUpdate(id: $id, input: $input) {
        productVariant {
          id
        }
      }
    }
  `;

  const input = { [field]: value };
  await shopifyClient.request(mutation, { id: variantId, input });

  return redirect(`/products/${variantId.split('/').pop()}/edit`);
}

This action performs the following steps:

  • Receive the Variant ID and Field Data: It receives the variant ID, field name, and updated value from the form data.
  • Update the Product Variant: It uses a GraphQL mutation to update the product variant in Shopify.
  • Redirect: After updating, the user is redirected back to the product edit page.

Enhancing the User Experience

To improve the user experience, consider adding the following features:

  1. Optimistic UI Updates: Update the UI immediately after a change is made, without waiting for the server response, to make the app feel more responsive.
  2. Validation and Error Handling: Implement validation for the input fields and handle errors gracefully by displaying error messages to the user if the update fails.
  3. Confirmation Dialog: Before making changes, especially for critical fields like price or inventory, display a confirmation dialog to avoid accidental updates.
javascriptCopy codefunction ProductEditPage() {
const product = useLoaderData();
const [variants, setVariants] = useState(product.variants.edges);
const fetcher = useFetcher();

const handleInputChange = (variantId, field, value) => {
setVariants(prevVariants =>
prevVariants.map(variant =>
variant.node.id === variantId
? { ...variant, node: { ...variant.node, [field]: value } }
: variant
)
);

fetcher.submit(
{ variantId, field, value },
{ method: 'post', action: '/products/edit' }
);
};

return (
<Page title={`Edit Product: ${product.title}`}>
<Card sectioned>
{variants.map(({ node: variant }) => (
<Stack vertical key={variant.id}>
<FormLayout>
<TextField
label="Variant Title"
value={variant.title}
onChange={(value) => handleInputChange(variant.id, 'title', value)}
/>
<TextField
label="Price"
value={variant.price}
type="number"
onChange={(value) => handleInputChange(variant.id, 'price', value)}
/>
<TextField
label="Inventory Quantity"
value={variant.inventoryQuantity}
type="number"
onChange={(value) => handleInputChange(variant.id, '

Leave a Reply

Your email address will not be published. Required fields are marked *