PHP code example of esign / laravel-shopify

1. Go to this page and download the library: Download esign/laravel-shopify library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

esign / laravel-shopify example snippets


'routes' => [
    'enabled' => true,          // false = the package registers no routes at all
    'app_home' => true,         // false = skip only the "GET /" app home route
    'app_home_path' => '/',     // relocate the app home, e.g. '/shopify-app'
    'prefix' => 'shopify',      // prefix for the auth routes
    'webhooks_prefix' => 'webhooks',
],

use Esign\LaravelShopify\Http\Controllers\AppController;
use Esign\LaravelShopify\Http\Controllers\AuthController;

Route::get('/shopify/auth/token-refresh', [AuthController::class, 'tokenRefresh'])
    ->name('shopify.auth.token-refresh');

Route::middleware('shopify.verify.embedded-app')
    ->get('/my-app', [AppController::class, 'home'])
    ->name('shopify.app.home');



namespace App\GraphQL\Queries;

use Esign\LaravelShopify\GraphQL\Contracts\Query;
use Shopify\App\Types\GQLResult;

class GetProductQuery implements Query
{
    public function __construct(private string $productId) {}

    public function query(): string
    {
        return <<<'GQL'
            query getProduct($id: ID!) {
                product(id: $id) {
                    id
                    title
                    description
                }
            }
        GQL;
    }

    public function variables(): array
    {
        return ['id' => $this->productId];
    }

    public function mapFromResponse(GQLResult $response): mixed
    {
        return $response->data['product'];
    }
}

use Esign\LaravelShopify\Facades\Shopify;
use App\GraphQL\Queries\GetProductQuery;

// In a controller or job (a shop must be authenticated via Auth::user())
$product = Shopify::query(new GetProductQuery('gid://shopify/Product/123'));



namespace App\GraphQL\Mutations;

use Esign\LaravelShopify\GraphQL\Contracts\Mutation;
use Shopify\App\Types\GQLResult;

class CreateProductMutation implements Mutation
{
    public function __construct(
        private string $title,
        private string $description
    ) {}

    public function query(): string
    {
        return <<<'GQL'
            mutation createProduct($input: ProductInput!) {
                productCreate(input: $input) {
                    product { id title }
                    userErrors { field message }
                }
            }
        GQL;
    }

    public function variables(): array
    {
        return [
            'input' => [
                'title' => $this->title,
                'descriptionHtml' => $this->description,
            ],
        ];
    }

    public function mapFromResponse(GQLResult $response): mixed
    {
        return $response->data['productCreate']['product'];
    }
}



namespace App\GraphQL\Queries;

use Esign\LaravelShopify\GraphQL\Contracts\PaginatedQuery;
use Shopify\App\Types\GQLResult;

class GetAllProductsQuery implements PaginatedQuery
{
    private ?string $cursor = null;

    public function query(): string
    {
        return <<<'GQL'
            query getAllProducts($cursor: String) {
                products(first: 50, after: $cursor) {
                    edges { node { id title } }
                    pageInfo { hasNextPage endCursor }
                }
            }
        GQL;
    }

    public function variables(): array
    {
        return ['cursor' => $this->cursor];
    }

    // Must return an array; every page's array is merged into the final result.
    public function mapFromResponse(GQLResult $response): array
    {
        return $response->data['products']['edges'];
    }

    public function hasNextPage(GQLResult $response): bool
    {
        $pageInfo = $response->data['products']['pageInfo'];
        $this->cursor = $pageInfo['endCursor'] ?? null;

        return $pageInfo['hasNextPage'] ?? false;
    }
}

// Executes every page and returns the merged array of edges
$allProducts = Shopify::queryPaginated(new GetAllProductsQuery());



use Esign\ShopifyData\Inputs\CustomerInput;
use Esign\ShopifyData\Inputs\MailingAddressInput;

$customerInput = new CustomerInput(
    email: '[email protected]',
    firstName: 'John',
    lastName: 'Doe',
    addresses: [
        new MailingAddressInput(
            address1: '123 Main St',
            city: 'Toronto',
            countryCode: 'CA',
            provinceCode: 'ON',
            zip: 'M5H 2N2',
        ),
    ],
);

// Use in your mutation
$variables = [
    'input' => $customerInput->toArray(), // null properties are omitted
];

use Esign\ShopifyData\DTOs\ProductDto;

public function mapFromResponse(GQLResult $response): ProductDto
{
    return ProductDto::from($response->data['product']);
}

'webhooks' => [
    'routes' => [
        // Built-in handlers (already configured)
        // 'app/uninstalled' => [...]
        // 'customers/data_request' => [...]
        // 'customers/redact' => [...]
        // 'shop/redact' => [...]
        
        // Add your custom handlers:
        'orders/create' => [
            'job' => \App\Jobs\Shopify\OrdersCreateJob::class,
            'queue' => 'webhooks',
        ],
        'products/update' => [
            'job' => \App\Jobs\Shopify\ProductsUpdateJob::class,
            'queue' => 'webhooks',
        ],
    ],
],



namespace App\Jobs\Shopify;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class OrdersCreateJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(
        public string $shopDomain,
        public array $webhookData,
    ) {}

    public function handle(): void
    {
        Log::info('Order created', [
            'shop' => $this->shopDomain,
            'order_id' => $this->webhookData['id'],
        ]);

        // Process order data
        // YourOrder::create([...]);
    }
}

// In EventServiceProvider or via Event::listen()
use Esign\LaravelShopify\Events\AppInstalledEvent;
use Esign\LaravelShopify\Events\AppUninstalledEvent;

Event::listen(AppInstalledEvent::class, function (AppInstalledEvent $event) {
    // $event->shop contains the Shop model
    Log::info('New shop installed', ['domain' => $event->shop->domain]);
    
    // Dispatch a job if heavy processing is needed
    dispatch(new SetupNewShopJob($event->shop));
});

Event::listen(AppUninstalledEvent::class, function (AppUninstalledEvent $event) {
    // Clean up external resources, notify team, etc.
});

// config/shopify.php
'webhooks' => [
    'routes' => [
        'customers/redact' => [
            'job' => \App\Jobs\Shopify\CustomersRedactJob::class,
            'queue' => 'gdpr',
        ],
        // ...same for customers/data_request and shop/redact
    ],
],

use Esign\LaravelShopify\Models\Shop;

// Get authenticated shop
$shop = Auth::user(); // Returns Shop model

// Check installation status
if ($shop->isInstalled()) {
    // Shop is currently installed
}

// Mark as uninstalled (soft delete)
$shop->markAsUninstalled();

// Mark as reinstalled (restore from soft delete); the access token is set
// separately via token exchange on the next embedded-app request.
$shop->markAsReinstalled();

// Access token (encrypted in database)
$token = $shop->access_token;

'logging' => [
    'enabled' => true,          // master switch — false disables all package logging
    'channel' => 'stack',

    // Per-category toggles (only apply when 'enabled' is true)
    'log_graphql_queries' => true,
    'log_graphql_mutations' => true,
    'log_webhooks' => true,
    'log_token_lifecycle' => true,
    'log_shop_lifecycle' => true,
    'log_gdpr_events' => true,
    'log_rate_limiting' => true,
],
bash
php artisan vendor:publish --provider="Esign\LaravelShopify\ShopifyServiceProvider"
php artisan migrate
bash
php artisan shopify:make-webhook OrdersCreateJob --topic=orders/create