This is a template for building a Shopify app using PHP and React. It contains the basics for building a Shopify app.
Rather than cloning this repo, you can use your preferred package manager and the Shopify CLI with these steps.
Shopify apps are built on a variety of Shopify tools to create a great merchant experience. The create an app tutorial in our developer documentation will guide you through creating a Shopify app using this template.
The PHP app template comes with the following out-of-the-box functionality:
- OAuth: Installing the app and granting permissions
- GraphQL Admin API: Querying or mutating Shopify admin data
- REST Admin API: Resource classes to interact with the API
- Shopify-specific tooling:
- AppBridge
- Polaris
- Webhooks
This template combines a number of third party open source tools:
- Laravel builds and tests the backend.
- Vite builds the React frontend.
- React Router is used for routing. We wrap this with file-based routing.
- React Query queries the Admin API.
These third party tools are complemented by Shopify specific tools to ease app development:
- Shopify API library adds OAuth to the Laravel backend. This lets users install the app and grant scope permissions.
- App Bridge React adds authentication to API requests in the frontend and renders components outside of the embedded App’s iFrame.
- Polaris React is a powerful design system and component library that helps developers build high quality, consistent experiences for Shopify merchants.
- Custom hooks make authenticated requests to the GraphQL Admin API.
- File-based routing makes creating new pages easier.
- You must create a Shopify partner account if you don’t have one.
- You must create a development store if you don’t have one.
- You must have PHP installed.
- You must have Composer installed.
- You must have Node.js installed.
This template runs on Shopify CLI 3.0, which is a node package that can be included in projects. You can install it using your preferred Node.js package manager:
Using yarn:
yarn create @shopify/app --template php
Using npx:
npm init @shopify/app@latest -- --template php
Using pnpm:
pnpm create @shopify/app@latest --template php
This will clone the template and install the CLI in that project.
Once the Shopify CLI clones the repo, you will be able to run commands on your app. However, the CLI will not manage your PHP dependencies automatically, so you will need to go through some steps to be able to run your app. These are the typical steps needed to set up a Laravel app once it's cloned:
-
Start off by switching to the
web
folder:cd web
-
Install your composer dependencies:
composer install
-
Create the
.env
file:cp .env.example .env
-
Bootstrap the default SQLite database and add it to your
.env
file:touch storage/db.sqlite
NOTE: Once you create the database file, make sure to update your
DB_DATABASE
variable in.env
since Laravel requires a full path to the file. -
Generate an
APP_KEY
for your app:php artisan key:generate
-
Create the necessary Shopify tables in your database:
php artisan migrate
And your Laravel app is ready to run! You can now switch back to your app's root folder to continue:
cd ..
The Shopify CLI connects to an app in your Partners dashboard. It provides environment variables, runs commands in parallel, and updates application URLs for easier development.
You can develop locally using your preferred Node.js package manager. Run one of the following commands from the root of your app:
Using yarn:
yarn dev
Using npm:
npm run dev
Using pnpm:
pnpm run dev
Open the URL generated in your console. Once you grant permission to the app, you can start development.
This template uses Laravel's Eloquent framework to store Shopify session data. It provides migrations to create the necessary tables in your database, and it stores and loads session data from them.
The database that works best for you depends on the data your app needs and how it is queried.
You can run your database of choice on a server yourself or host it with a SaaS company.
Once you decide which database to use, you can update your Laravel app's DB_*
environment variables to connect to it, and this template will start using that database for session storage.
The frontend is a single page React app. It requires the SHOPIFY_API_KEY
environment variable, which you can find on the page for your app in your partners dashboard.
The CLI will set up the necessary environment variables for the build if you run its build
command from your app's root:
Using yarn:
yarn build --api-key=REPLACE_ME
Using npm:
npm run build --api-key=REPLACE_ME
Using pnpm:
pnpm run build --api-key=REPLACE_ME
The app build command will build both the frontend and backend when running as above.
If you're manually building (for instance when deploying the web
folder to production), you'll need to build both of them:
cd web/frontend
SHOPIFY_API_KEY=REPLACE_ME yarn build
cd ..
composer build
When you're ready to set up your app in production, you can follow our deployment documentation to host your app on a cloud provider like Heroku or Fly.io.
When you reach the step for setting up environment variables, you also need to set the following variables:
Variable | Secret? | Required | Value | Description |
---|---|---|---|---|
APP_KEY |
Yes | Yes | string | Run php web/artisan key:generate --show to generate one. |
APP_NAME |
Yes | string | App name for Laravel. | |
APP_ENV |
Yes | "production" |
||
DB_CONNECTION |
Yes | string | Set this to the database you want to use, e.g. "sqlite" . |
|
DB_DATABASE |
Yes | string | Set this to the connection string to your database, e.g. "/app/storage/db.sqlite" |
|
DB_FOREIGN_KEYS |
true |
If your app is using foreign keys. |
When running the app with the CLI in development mode on Firefox, you might see your app constantly reloading when you access it. That happened in previous versions of the CLI, because of the way HMR websocket requests work.
We fixed this issue with v3.4.0 of the CLI, so after updating it, you can make the following changes to your app's web/frontend/vite.config.js
file:
-
Change the definition
hmrConfig
object to be:const host = process.env.HOST ? process.env.HOST.replace(/https?:\/\//, "") : "localhost"; let hmrConfig; if (host === "localhost") { hmrConfig = { protocol: "ws", host: "localhost", port: 64999, clientPort: 64999, }; } else { hmrConfig = { protocol: "wss", host: host, port: process.env.FRONTEND_PORT, clientPort: 443, }; }
-
Change the
server.host
setting in the configs to"localhost"
:server: { host: "localhost", ...
When you’re previewing your app or extension, you might see an ngrok interstitial page with a warning:
You are about to visit <id>.ngrok.io: Visit Site
If you click the Visit Site
button, but continue to see this page, then you should run dev using an alternate tunnel URL that you run using tunneling software.
We've validated that Cloudflare Tunnel works with this template.
To do that, you can install the cloudflared
CLI tool, and run:
# Note that you can also use a different port
cloudflared tunnel --url http://localhost:3000
In the output produced by cloudflared tunnel
command, you will notice a https URL where the domain ends with trycloudflare.com
. This is your tunnel URL. You need to copy this URL as you will need it in the next step.
2022-11-11T19:57:55Z INF Requesting new quick Tunnel on trycloudflare.com...
2022-11-11T19:57:58Z INF +--------------------------------------------------------------------------------------------+
2022-11-11T19:57:58Z INF | Your quick Tunnel has been created! Visit it at (it may take some time to be reachable): |
2022-11-11T19:57:58Z INF | https://randomly-generated-hostname.trycloudflare.com |
2022-11-11T19:57:58Z INF +--------------------------------------------------------------------------------------------+
In a different terminal window, navigate to your app's root and run one of the following commands (replacing randomly-generated-hostname
with the Cloudflare tunnel URL copied from the output of cloudflared
command):
# Using yarn
yarn dev --tunnel-url https://randomly-generated-hostname.trycloudflare.com:3000
# or using npm
npm run dev --tunnel-url https://randomly-generated-hostname.trycloudflare.com:3000
# or using pnpm
pnpm dev --tunnel-url https://randomly-generated-hostname.trycloudflare.com:3000