View more

Shopifyアプリで機能拡張!アプリ構築の流れを解説!

Blog

Shopifyアプリで機能拡張!アプリ構築の流れを解説!

ShopifyアプリはShopifyの機能だけでは実現できない部分を拡張することができる仕組みです。 アプリストアではたくさんのアプリがありますし、今回のように自身で開発することも可能です。 本記事ではShopifyアプリを構築し、どのようなことが可能なのかを一部ご紹介します。

Shopifyアプリで機能拡張!アプリ構築の流れを解説!

Shopifyアプリで機能拡張!アプリ構築の流れを解説!

Shopifyアプリとは

Shopifyアプリとは、Shopifyの機能拡張やカスタマイズを行うソフトウェアを指します。

またアプリストアがあり、アプリストアでは6,000以上のShopifyアプリが提供されています。

集客や購入率増加、SNSとの連携、客単価の向上を図る機能など、さまざまな目的に応じたアプリがあり、非常に簡単にインストールすることができます。

Shopifyアプリはどういう時に使う?APIとの違いは?

Shopifyアプリは、Shopifyのストアに対して機能を拡張することを目的としています。

日本向けの配送設定や、ブログ機能を強化するなど、内側に対して機能付与することが主になります。

 

対してAPIは、外部向けに表示や外部でのカート投入など、主にShopifyのデータを外で使うことを想定した機能になります。

HeadlessコマースなどはこのAPIを利用して構築されます。

 

アプリとしてつくるのか、APIを利用するのか、実現したいことに合わせて手法を選択する必要があります。

 

Shopifyアプリをつくるには

Shopifyアプリは、インストール時にアプリとしての認証が必要になり、その認証機能を構築する必要があります。

この認証の機能を用いて、Shopifyストア側とアプリ側とを連携することが可能です。

 

出典:https://shopify.dev/

 

  1. ユーザーはアプリのインストールをリクエストする。
  2. アプリはShopifyにリダイレクトし、OAuth許可画面をロードし、ユーザーに必要なスコープを許可するよう要求する。
  3. ユーザーは、要求されたスコープに同意することで、アプリを承認します。
  4. アプリは認可グラントを受け取ります。これは、認可を表す一時的なクレデンシャルです。
  5. アプリは、Shopify と認証し、認可グラントを提示することで、アクセストークンを要求する。
  6. Shopify はアプリを認証し、認可グラントを検証し、アクセストークンを発行して返します。アプリは Shopify にデータをリクエストできるようになります。
  7. アプリはアクセストークンを使用して、Shopify API にリクエストを行います。
  8. Shopify はアクセストークンを検証し、リクエストされたデータを返します。

 

またアプリの種類としては、公式にも記載がありますが、公開アプリとカスタムアプリがあり、公開アプリはアプリストアに出品し、広く世界中で利用してもらうことができます。

カスタムアプリは自身のストアに対してのみインストールすることを目的としています。

 

そしてその中でも埋め込みアプリという設定にしておくとPolaris、App Bridge、App extensionsというShopifyが提供しているアプリ用のライブラリを使用することができ、Shopifyの管理画面内にアプリ画面が表示され、UIもShopifyと同じUIで構築することができ非常に効率的に構築ができます。

※デフォルトで埋め込みアプリになります。

Shopifyアプリを作ってみた

今回はShopifyアプリを実際に構築してみました。

すごく簡単な機能を実装することをMVP(Minimum Viable Product)と呼ぶことがありますが、外部のWordpressの記事データをWordpressのREST APIから取得し、Shopify内のページへ貼り付けて表示できる機能をMVPとして作成してみました。

 

※一部記事向けにソースコードを編集していますので、参考と考えてもらいご自身のソースコードや実装の機能に合わせてください。

Shopifyアプリ開発準備

Shopify公式にはアプリ構築用のテンプレートがあり、Node.js版やPHP版があります。

今回はPHP版にて構築してみました。

PHP版を選択した場合には、サーバーサイドフレームワークとしてLaravel、フロントエンド部分がReactという構成になります。

 

Shopifyアプリでは、サーバーサイド側(Laravel)はAPIとしての機能をもち、フロントエンド側(React)からそのAPIに対してリクエストをすることでデータの編集などの機能を持たせることができます。

Node.js版ではLaravelの部分がexpress.jsに置き換わるようなイメージです。

 

Shopify公式のドキュメント

https://shopify.dev/docs/apps

 

Shopify公式のPHP版テンプレート

https://github.com/Shopify/shopify-app-template-php

 

Shopifyパートナーアカウントの用意

Shopifyパートナーアカウントが必要になりますので登録をしてください。

 

 

インストール

下記URLの手順でインストールから、PHPなどのテンプレート選択までできます。

https://shopify.dev/docs/apps/getting-started/create

npm init @shopify/app@latest

 

インストールを進めていくとショップとの連携に進み、URLなどを入力すればすんなりサンプルのアプリページが表示されると思います。

Shopifyアプリ開発流れ

設定

今回はDBはsqliteを使用するので、.envの中身を変える必要があり下記のようになります。

DB_CONNECTION=sqlite
DB_DATABASE=/path/to/shopify/your-app/web/storage/db.sqlite

 

.envにはアクセスキーなどの記載も必要になるとおもいますので、下記のコマンドでアクセスキー生成ができます。

php artisan key:generate

 

DBテーブル作成

DBのデータを作成していくにあたり、Modelなどを生成していきます。

php artisan make:model Posts --migration

下記のようなファイルが作成されると思います。

web/app/Models/Posts.phpweb/database/migrations/YYYY_MM_DD_XXXXXX_create_posts_table.php

 

マイグレーションファイルの中身を編集して、登録したいカラムを追加します。

# テーブルの構造の参考例

|name           |type       |
|---------------|-----------|
|id             |increments |
|posts_title    |string     |
|posts_url      |string     |
|posts_api_url  |string     |
|shop_id        |string     |
 

 

idは元から入っているのでその他のデータを追加します。

// web/database/migrations/YYYY_MM_DD_XXXXXX_create_posts_table.php

public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('posts_title');
        $table->string('posts_url');
        $table->string('posts_api_url');
        $table->string('shop_id');
        $table->timestamps();
    });
}

 

マイグレーション

php artisan migrate

今作ったものだけが差分で実行され、DBに追加されました。 DBのデータを見れるツールなどで確認してみてください。

 

DBのファイルがあるところで下記のようにコマンドを実行するとsqliteコマンドを実行できます。

sqlite db.sqlite

スキーマ(構造)の確認は下記のようにコマンドを打てば確認できると思います。 (.schema postsを入力)

sqlite> .schema posts

結果が表示され、先ほど作成したマイグレーションが追加されているのがわかりますね。

CREATE TABLE IF NOT EXISTS "posts" ("id" integer not null primary key autoincrement, "posts_title" varchar not null, "posts_url" varchar not null, "posts_api_url" varchar not null, "shop_id" varchar not null, "deleted_at" datetime, "created_at" datetime, "updated_at" datetime);

 

初期値を入力しておく場合

マイグレーション時に初期値を入力しておくと確認がしやすいと思いますので、 一度コマンドでマイグレーションをロールバックして初期値を設定して再度マイグレーションしてみましょう。

# 念の為ステータスを確認
php artisan migrate:status

# 直前のマイグレーションをロールバック
php artisan migrate:rollback

なかみを書き換えて再度マイグレーションを実行しましょう。

// web/database/migrations/YYYY_MM_DD_XXXXXX_create_posts_table.php

public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('posts_title')->default('記事ページ名');
        $table->string('posts_url')->default('<https://example.com>');
        $table->string('posts_api_url')->default('<https://example.com/api>');
        $table->string('shop_id');
        $table->timestamps();
    });
}

php artisan migrate

 

モデル編集

マイグレーション時にModelが作成されているので、下記ファイルを編集していきます。

// web/app/Models/Posts.php

namespace App\\\\Models;

use Illuminate\\\\Database\\\\Eloquent\\\\Factories\\\\HasFactory;
use Illuminate\\\\Database\\\\Eloquent\\\\Model;
use Illuminate\\\\Database\\\\Eloquent\\\\SoftDeletes;

class Posts extends Model
{
    use HasFactory;
    use SoftDeletes;
    protected $fillable = [
        'posts_title',
        'posts_url',
        'posts_api_url',
        'shop_id',
    ];
}

仮データ作成

LaravelにはSeedsという機能があり、仮データを簡単に作ることができます。 下記のようなコマンドでSeederファイルを作成します。

php artisan make:seeder PostsSeeder

// 作成されるファイル
web/database/seeders/PostsSeeder.php

 

中身を編集していきます。

Carbonを使いますので、run()の中身だけでなくuseの部分なども追記が必要です。

// web/database/seeders/PostsSeeder.php

<?php

namespace Database\\\\Seeders;

use Carbon\\\\Carbon;
use Illuminate\\\\Database\\\\Seeder;
use Illuminate\\\\Support\\\\Facades\\\\DB;

class PostsSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $titles = ['サンプル記事名1', 'サンプル記事名2', 'サンプル記事名3'];

        foreach ($titles as $title) {
            DB::table('posts')->insert([
                'posts_title' => $title,
                'posts_url' => '<https://google.com>',
                'posts_api_url' => '<https://google.com/api>',
                'shop_id' => 'example.myshopify.com',
                'created_at' => Carbon::now(),
                'updated_at' => Carbon::now(),
            ]);
        }
    }
}

編集できたら下記のコマンドでデータを入れてみましょう。 エラーが出たらエラーの内容とSeederの中身を再度確認してみてください。

php artisan db:seed --class=PostsSeeder

 

 

コントローラー作成

コントローラーはweb/routes/web.phpに書いてもいいのですが、 専用のコントローラーファイルを作っておくとわかりやすいと思いますので、 下記コマンドで作成し、app/Http/Controllers/Api配下に設置していきます。

php artisan make:controller PostsController

 

中身は下記のような感じにCRUDの処理を書いていきます。

// web/app/Http/Controllers/Api/PostsController.php

<?php

namespace App\\\\Http\\\\Controllers\\\\Api;

use App\\\\Http\\\\Controllers\\\\Controller;
use App\\\\Models\\\\Posts;
use Illuminate\\\\Http\\\\Request;

class PostsController extends Controller
{
    /**
     * 記事作成.
     *
     * @return void
     */
    public function create(Request $request)
    {
        $posts = Posts::create([
            'posts_title' => $request->posts_title,
            'posts_url' => $request->posts_url,
            'posts_api_url' => $request->posts_api_url,
            'shop_id' => $request->shop,
        ]);

        return response()->json($posts);
    }

    /**
     * 記事取得.
     *
     * @return void
     */
    public function fetch(Request $request)
    {
        // データからshop_idでフィルターしたjsonを返す
        function getPosts($shop_id)
        {
            $posts = Posts::where('shop_id', $shop_id)->get();
            $json = response()->json($posts);

            return $json;
        }

        // shopのIDをpostで受け取る
        if (isset($_GET['shop_id']) && $_GET['shop_id'] != '') {
            return getPosts($_GET['shop_id']);
        } else {
            header('HTTP/1.1 403 Forbidden');
        }
    }

    /**
     * 記事更新.
     *
     * @return void
     */
    public function update(Request $request)
    {
        $posts = Posts::find($request->post_id);
        $posts->update([
            'posts_title' => $request->posts_title,
            'posts_url' => $request->posts_url,
            'posts_api_url' => $request->posts_api_url,
        ]);

        return response()->json($posts);
    }

    /**
     * 記事削除.
     *
     * @return void
     */
    public function delete(Request $request)
    {
        $posts = Posts::find($request->post_id);
        $posts->delete();

        return response()->json();
    }
}

web/routes/web.phpでコントローラーを読み込み、下記のようにそれぞれのメソッド毎に実行するようにすることで機能します。

// web/routes/web.php

use App\\\\Http\\\\Controllers\\\\Api\\\\PostsController;

// Posts API Controller
Route::post('/api/posts', [PostsController::class, 'create']);
Route::get('/api/posts', [PostsController::class, 'fetch']);
Route::put('/api/posts', [PostsController::class, 'update']);
Route::delete('/api/posts', [PostsController::class, 'delete']);

開発中はエラーでgetじゃないと動作しない可能性がありますので、 その場合は下記のようにURLを分けても良いと思います。

// web/routes/web.php

Route::get('/api/posts/create', [PostsController::class, 'create']);
Route::get('/api/posts', [PostsController::class, 'fetch']);
Route::get('/api/posts/update', [PostsController::class, 'update']);
Route::get('/api/posts/delete', [PostsController::class, 'delete']);

 

アプリ管理画面

アプリ管理画面側はReactで作成していきます。 LaravelのルートでReactは動作していますのでweb/routes/web.phpでの定義は特に変更せず、 web/frontend内のPages内にページを作成します。

 

Shopifyのアプリテンプレートには、React側で独自のRouterが設定されていますので、Next.jsのようにPagesディレクトリ内にファイルを作成していくことでページとして反映されます。

コンポーネントに関しては、PolarisやAppBridgeから提供されているものを使うことで、ShopifyのUIそのものでアプリ画面が作成できます。

テンプレート内にサンプルのページがありますので、参考にしてみてください。

 

AppBridgeでは、fetchなどの機能に関してHooksが用意されているので、そちらを使うとshopifyの認証情報を自動で処理してくれたりLaravel側で作成したAPIエンドポイントに対してアクセスできます。

 

Polarisドキュメント

https://polaris.shopify.com/

下記がReact側とLaravel側をPolarisコンポーネントを使いながら繋ぎ込んだ最終的な画面になります。

 

 

今回は下記のような埋め込みコードを発行し、Shopify内のページ作成にてソースコードを貼り付けることでページに対して外部の記事を表示させてみました。

 

 

 

まとめ

ShopifyアプリはShopifyの機能だけでは実現できない部分を拡張することができる仕組みです。

アプリストアではたくさんのアプリがありますし、今回のように自身で開発することも可能です。

 

Shopifyの機能拡張や実現したいことなど、アプリ開発としてチャレンジしてみてはいかがでしょうか?

DEPARTではShopifyに関するご相談も可能です!