Instagram グラフ API で投稿画像(タイムライン)を一覧表示

ホームページにインスタグラムのタイムライン(一覧)を埋め込む方法について。

Instagram グラフ API を使ってインスタグラムで投稿した画像やビデオの一覧(タイムライン)をプラグインを使わずに Web ページに表示する方法の解説です。

無期限のアクセストークンと Instagram ビジネスアカウント ID の取得方法や取得したデータを使って PHP や JavaScript で投稿の画像やいいねの数の表示方法などを扱っています。

2024年7月更新

現時点での最新のバージョン(v20.0)に合わせて書き換えました。

作成日:2021年11月28日

概要

インスタグラムで投稿した画像などのメディアを取得してウェブに表示するには「Facebook for Developers」で提供されている Web API を使います。

以下では Instagram グラフ(Graph)API を利用してインスタグラムの一覧をWebページに表示します。

Instagram グラフ API を利用するにはアクセストークンと Instagram ビジネスアカウント ID を取得する必要がありますが、この部分が多少手間がかかります。

この時点のグラフAPIバージョンは v20.0 です。

必要なもの

  • Instagram のアカウント
  • Facebook のアカウントとページ
  • スマートフォンやタブレット(インスタグラムのアプリの操作)

Instagram グラフ API を利用するには Instagram のアカウントの他に Facebook のアカウントも必要になります。これは Instagram グラフ API が Facebook の開発者ツール「Facebook for Developers」に組み込まれているためです。

大まかな流れ

必要なアカウントをセットアップし、Facebook ページを作成して Instagram のアカウントをリンクさせます。そして Facebook 開発者ツール(Facebook for Developers)で Facebook アプリを作成し、アクセストークンや Instagram 表示に必要な ID を取得します。

取得したアクセストークンと ID を使って Instagram の Web API から画像などのデータを取得して Web ページに表示します。以下の例ではデータの取得や Web ページの表示には PHP を使います。

  1. Instagram プロアカウントへ切り替え(インスタグラムのアプリで実行)
  2. Facebook 開発者アカウントの作成(まだ作成していない場合)
  3. Facebook ページの作成
    • Facebook ページと Instagram プロアカウントをリンク(関連付け)
  4. Facebook アプリの作成(Facebook for Developers)
  5. Instagram グラフ API で使用するアクセストークンの取得(Facebook for Developers)
    • 短期アクセストークン(有効期限1時間)の取得
    • 長期アクセストークン(有効期限2ヶ月)の取得
    • 無期限のアクセストークンの取得
  6. Instagram ビジネスアカウント ID の取得
  7. Instagram グラフ API を使ってインスタグラムの一覧のデータを取得して表示(PHP)

無期限のアクセストークンの取得

Instagram グラフ API で使用する無期限(有効期限なし)のアクセストークンを取得するには段階的に取得する必要があります。

試してみたところ、グラフ API エクスプローラを使って短期アクセストークンを取得後、アクセストークンデバッガーを使って延長するのが比較的簡単でした。

参考ドキュメント(Facebook for Developers ドキュメント)

インスタグラムのアカウントをプロアカウントに

Instagram グラフ API を利用するには(個人用アカウントの場合は)プロアカウント(無料)に切り替える必要があります。この作業はスマートフォンやタブレットのインスタグラムのアプリで行います。

但し、プロアカウントではアカウントを非公開にできなくなります。

インスタグラムのアプリにログインし、「設定」→「アカウント」の順に移動し一番下の「プロアカウントに切り替える」を選択し、「OK」をタップします。

「クリエイター」か「ビジネス」の選択はどちらでも構いません。一度選択しても後からアカウントの画面の「アカウントタイプを切り替え」で変更可能です。

Facebook 開発者アカウントの作成

Instagram グラフ API は Facebook アプリを作成して利用します。

Facebook アプリの作成は Facebook の開発者ツール「Facebook for Developers」を使うので、開発者アカウント(無料)が必要です(Facebook アカウントを持っていることが前提)。

開発者アカウントを作成していない場合は Facebook for Developers にアクセスして作成します。

Facebook にログイン済みであれば、自分の Facebook アカウントが表示されるのでアカウントを作成するために「次へ」をクリックします。

電話番号(SMS)でアカウントの認証を行います(Facebook アカウントに電話番号を登録していない場合は電話番号の入力を求められます)。

続いてメールアドレスを確認します。

いずれか当てはまるものを選択すれば登録完了です。

Facebook ページの作成

Instagram グラフ API を利用するには Facebook ページと Instagram のアカウントをリンクさせる必要があるため、Facebook ページを作成します。

Facebook にログインします(個人用アカウントで大丈夫です)。

ログイン後、左側メニューから「ページ」をクリックします。

「+新しいページを作成」をクリックします。

必須項目の「ページ名」と「カテゴリ」を入力し「Facebookページを作成」をクリックします。ページ名には使えない言葉など決まりがあります(どのようなページ名が認められますか)

「ページの設定を完了しよう」と表示されるので、必要に応じて情報を入力し、「次へ」をクリックしていきます。

この例ではサンプルページなので何も入力せず、最後に「完了」をクリックしました。

ウェブサイトを追加

「ページを管理」では「基本データ」タブでインスタグラムで投稿した画像を表示するウェブサイトを追加します(後からこの「ページを管理」→「基本データ」タブで追加することもできます)。

後で Facebook アプリを作成する際に、ここで追加したウェブサイトのプライバシーポリシーページの URL を登録します。

Facebook アプリの作成

Facebook アプリを作成するには Facebook for Developers (Facebook の開発者ツール)にアクセスして右上の「マイアプリ」を選択します。

「アプリを作成」を選択します。すでに作成済みのアプリがあれば表示されます。

「現時点ではビジネスポートフォリオをリンクしない」のまま「次へ」をクリックします。

「その他」を選択して「次へ」をクリックします。

「アプリタイプを選択」では「ビジネス」を選択して「次へ」をクリックします。

アプリ名を入力し、連絡先メールアドレスを確認して、「アプリを作成」をクリックします。

ビジネスポートフォリオは任意ですが、必要に応じてビジネスポートフォリオを選択します。

また、表示名は任意の名前を付けられますが、Instagram や Insta などを含めるとエラーになります(日本語のインスタは大丈夫でした)。

パスワードの入力を求められるので入力して「送信」をクリックするとアプリが作成されます。

基本設定情報

作成した Facebook アプリの基本的な設定情報は、左側メニューの「設定」を展開して「ベーシック」で確認できます。

「アプリ ID」や「app secret」の値を確認することができます。「app secret」 は「表示」をクリックするとパスワードの入力を求められるので入力して表示します。

プライバシーポリシーのURL

上記設定ページの「プライバシーポリシーのURL」や「利用規約のURL」には設置先の該当するページの URL を入力して、ページ右下の「変更を保存」をクリックして保存します。

この設定は後からでも可能ですが、設定していない場合、アプリのモードを「開発」から「ライブ」に変更しようとすると、「アプリをライブで使用するには有効なプライバシーポリシー URL を入力する必要があります」と表示されます。

ライブモードへの切り替え

新しく作成されたすべてのアプリは、最初に開発モードになります。

アプリ開発が完了したらライブモードに切り替えることができますが、前述のプライバシーポリシーのURLに設定したサイトが Facebook のページに追加されている必要があります。

後から、サイトを Facebook ページに追加するには、作成した Facebook ページの「ページを管理」の「基本データ」タブで行います。

※ ライブモードへの切り替えは、アプリ開発が完了してから必要に応じて行います(開発モードでもインスタの画像を表示することはできます)。

Meta ドキュメント:アプリモード

Facebook アプリの削除

テスト用に作成したアプリなど、アプリを削除するには対象のアプリの右下のボタンをクリックして「アプリを削除」を選択します。

アクセストークンの取得

Instagram グラフ API を利用するにはアクセストークを発行して取得する必要があります。

アクセストークンは Facebook for Developers で発行できますが、無期限のアクセストークンを取得するには、短期アクセストークン(有効期限1時間)を取得後、有効期限2ヶ月の長期アクセストークンを取得し、その後無期限のアクセストークンを取得します。

参考(Facebook for Developers ドキュメント):

グラフ API エクスプローラ

アクセストークンの取得にはグラフAPIエクスプローラを使います。

グラフAPIエクスプローラはグラフ API へのクエリを作成して実行し、その応答を表示することができるツールで、自分でブラウザから API にクエリを送信するより便利です。

グラフAPIエクスプローラは Facebook for Developers の上部にある「ツール」→「グラフAPIエクスプローラ」でアクセスできます。または、https://developers.facebook.com/tools/explorer/ からもアクセスできます。

アクセスすると以下のような画面が表示されます。

コンポーネント 概要
クエリ文字列フィールド クエリを入力して右横の「送信」ボタンをクリックして実行することができます
応答ウィンドウ 送信したクエリに対する応答がこのウィンドウに表示されます
アクセストークンフィールド アクセストークンを取得すると、このフィールドに表示されます
アプリドロップダウン 対象の(作成した)アプリを選択します
アクセストークンドロップダウン 取得するトークンの種類を選択します。この例の場合、ユーザートークン。
許可追加ダウン 必要な許可を追加します

参考:グラフAPIエクスプローラガイド

短期ユーザーアクセストークンの取得

最初は有効期限1時間の短期ユーザーアクセストークンを取得します。

Facebook for Developers 上部の「ツール」から「グラフAPIエクスプローラ」を選択すると上記の画面が開きます。

右側の「Metaアプリ」に作成したアプリの名前(この例の場合はインスタフィード)が表示されていることを確認します(表示されていなければドロップダウンから選択します)。

初期状態ではおそらくアクセストークン発行ボタン(Generate Access Token)が無効になっているので、まずアクセス許可を追加します。

アクセス許可を追加

「許可を追加」をクリックすると、以下のような項目が表示され、クリックすると関連する許可(Permission)が表示されます。

ユーザートークンに付与する以下の許可を選択して追加します。

Events Groups Pages を展開
  • business_management
  • pages_manage_ads
  • pages_manage_metadata
  • pages_read_engagement
  • pages_read_user_content
  • pages_show_list
Other を展開
  • instagram_basic
  • instagram_manage_comments
  • instagram_manage_insights

以下はそれぞれの許可の概要です(詳細は:アクセス許可のリファレンス)。付与する許可は必要に応じて変更(追加・削除)します。

アクセス許可 説明
business_management ビジネスマネージャAPIを利用した読み取りや書き込みをアプリが行えるようになる
pages_manage_ads ページに関連付けられた広告をアプリが管理できるようになる
pages_manage_metadata アプリがページでのアクティビティに関するWebhooksを受け取るためにサブスクリプション登録したり、ページの設定をアップデートしたりできるようになる
pages_read_engagement ページに投稿されたコンテンツ(投稿、写真、動画、イベント)、フォロワーのデータやプロフィール写真、ページについてのメタデータやその他のインサイトをアプリが読み取れるようになる
pages_read_user_content アプリがページ上のユーザー作成コンテンツ(投稿、コメント、評価)を読み取り、ページ投稿のユーザーのコメントを削除できるようになる
pages_show_list 利用者が管理しているページのリストにアプリがアクセスできるようになる
instagram_basic アプリがInstagramアカウントのプロフィール情報やメディアを読み取れるようになる
instagram_manage_comments ページにリンクしたInstagramアカウントに代わって、アプリがコメントを作成する、削除する、非表示にすることができるようになる
instagram_manage_insights FacebookページにリンクされたInstagramアカウントのインサイトにアプリがアクセスできるようになる
public_profile 以前は自動的に付与されていたと思うのですが、現在は許可する項目にありません。
トークンを発行

許可を追加したら確認し、「Generate Access Token」をクリックしてトークンを発行します。

以下のようなアカウント切り替えのウィンドウが表示されたら、問題なければ「次へ」をクリックします。

確認のたのウィンドウが表示されるので、問題なければ「...として続行」をクリックします。

続いて以下のような確認ウィンドウが表示されるので、必要に応じてオプションを選択して「続行」をクリックします(以下の「インスタフィード」は作成したアプリの名前です)。

続いて以下のようなアクセス許可の確認ウィンドウが表示されるので、問題がなければ「保存」をクリックします。

続いて以下表示されるので「OK」をクリックします。

アクセストークンフィールドに発行されたトークンが表示されます。

1回目のアクセストークンの有効期間は1時間なので、1時間以内に2回目(有効期間2ヶ月)のアクセストークンを取得します。1時間以内に有効期間2ヶ月のアクセストークンを取得できない場合は再発行する必要があります。

取得したトークンの確認

表示されているアクセストークンの左にあるアイコン をクリックすると以下のような「アクセストークン情報」のウィンドウが表示されます。

アクセストークンデバッガーで延長

「アクセストークン情報」のウィンドウで「アクセストークンツールで開く」をクリックすると、アクセストークンデバッガーのページが表示されます。この画面ではトークンの詳細な情報を確認したり、アクセストークンを延長することができます。

以下の場合、トークンの有効期限が1時間以内であることが確認できます。

ページの下の方にある「アクセストークンを延長」をクリックしてトークンの有効期限を延長します。

パスワードを求められたら、パスワードを入力して送信します。

以下のように画面の下の部分に「この長期アクセストークンはxxxx年xx月xx日に期限切れとなります」と表示されるので、「デバッグ」をクリックします。

有効期限が「約2ヶ月以内」となっていれば延長成功です。

延長されたアクセストークン(長期ユーザーアクセストークン)の値をコピーします。

ユーザーアクセストークンを無期限に延長

グラフ API エクスプローラに戻り、コピーした延長されたアクセストークンの値を「アクセストークン」のフィールドにペーストし、左にあるアイコン をクリックします。

「アクセストークン情報」のウィンドウが開くので「アクセストークンツールで開く」をクリックします。

アクセストークンデバッガーのページが表示され、タイプが「User」で有効期限が「受け取らない」となっていればこのユーザーアクセストークンを無期限に延長できました。

この無期限に延長されたユーザーアクセストークンを使用するのでコピーして保管します。

無期限のページアクセストークン

もし、無期限のページアクセストークンが必要な場合はこのトークンの値を使って「長期ページアクセストークンの取得」を実行します。

Instagram ビジネスアカウント ID の取得

Instagram のメディアの表示に必要な Instagram ビジネスアカウント ID を取得します(ビジネスアカウントとはプロアカウントに切り替えた時点で発行されるアカウント)。

「ツール」→「グラフAPIエクスプローラ」でグラフ API エクスプローラを開き、クエリ文字列フィールド(入力欄)に me?fields=accounts{instagram_business_account} と入力して「送信」をクリックします。

"instagram_business_account" の下の "id" に Instagram ビジネスアカウント ID が表示されます。

※ この値も後で使用するのでコピーして保存しておきます。

インスタグラム投稿の一覧を出力

取得した Instagram ビジネスアカウント ID とアクセストークンを使って Instagram グラフ API からインスタグラムの投稿の一覧のデータを取得することができます。

グラフ API はブラウザー内で URL をリクエストして直接利用できます。

例えば、以下のような URL を作成してブラウザでアクセス(HTTP メソッドの GET でリクエスト)するとインスタグラム投稿(メディア)の JSON データが4件取得できます。

https://graph.facebook.com/v20.0/{instagram_business_account}?fields=media.limit(4){caption,media_url,thumbnail_url,permalink,like_count,comments_count,media_type}&access_token={user_access_token}

https://graph.facebook.com/ はグラフ API の URL(ルートエンドポイント)で、その後に API のバージョン(この時点では v20.0)を指定し、{instagram_business_account} には取得したビジネスアカウント ID を指定します。

? 以降はクエリ部分で、fields パラメーターを使用して media を指定し、.limit(4) で取得する結果を4件に制限し、必要なフィールド(caption や media_url など)をリスティングしています。

また、& access_token パラメータにアクセストークンを指定します。{user_access_token} の部分には取得したアクセストークンの値を指定します。

ブラウザには以下のような JSON 形式のレスポンス(応答)が表示されます。取得した media_url や permalink の URL にアクセスすると投稿された画像や投稿が表示されます。

この例の場合、.limit(4) で取得する結果の数を制限しているので、4件のデータの指定したフィールドが配列で取得されます。

上記 URL のリクエストに対するレスポンスの例
{
   "media": {  //fields パラメーターに指定した media
      "data": [
         {
            "caption": "Test",  //キャプション(もしあれば)
            "media_url": "https://scontent-nrt1-1・・・中略・・・B8", //画像の URL
            "permalink": "https://www.instagram.com/p/xxxxxxxx/",  //投稿の URL
            "like_count": 0,  //like のカウント数
            "comments_count": 0,  //コメントのカウント数
            "media_type": "IMAGE",  //メディアの種類
            "id": "xxxxxxxx"
         },
         {
            "media_url": "https://scontent-nrt1-1・・・中略・・・25",
            "permalink": "https://www.instagram.com/p/xxxxxxxx/",
            "like_count": 0,
            "comments_count": 0,
            "media_type": "IMAGE",
            "id": "xxxxxxxx"
         },
         ・・・残り2件のデータ部分は省略・・・
      ],
      "paging": {
         "cursors": {
            "before": "QVFIUl・・・中略・・・bi1WNGR3",
            "after": "QVFIUlB・・・中略・・・abjNLb0xR"
         }
      }
   },
   "id": "xxxxxxxx"  // Instagram ビジネスアカウント ID
}

参考(Facebook for Developers ドキュメント)

PHP で投稿一覧のデータを取得

ブラウザー内で URL をリクエストして API を利用できますが、Web ページに一覧を表示するには PHP や JavaScript で API にリクエストし、レスポンスの JSON データを使って出力します。

以下ではインスタグラムの投稿一覧のデータを Instagram グラフ API から取得して PHP で出力します。

API からのデータの取得は cURL 関数を使います。cURL は HTTP リクエストにより外部サイトの情報を取得することができる関数です。

cURL 関数の基本的な使用法は以下のようになります。

  1. curl_init() で cURL セッションを初期化
  2. curl_setopt() で転送時のオプションを設定
  3. curl_exec() で転送を実行
  4. curl_close() でセッションを終了

curl_exec() の戻り値はデフォルトでは結果を表す真偽値なので、curl_setopt() で CURLOPT_RETURNTRANSFER を設定して成功した場合に結果(データ)を取得するようにします。

クエリ部分はこの例では配列で作成して、http_build_query() で URL エンコードしてリクエストの URL に設定しています。

以下が一覧表示する部分のコードです。

3行目と5行目の xxxxxx には取得した Instagram ビジネスアカウント ID とアクセストークンを指定します。取得するメディアの件数や API のバージョンは必要に応じて変更します。

また、デフォルトでは取得結果にエラーがあれば、何も表示しません。$show_error を true にすれば、エラーがある場合は「エラーが発生しました」というメッセージとエラーコードを表示します。

<?php
//Instagram ビジネスアカウント ID
$business_id = "xxxxxx";
//アクセストークン
$token = 'xxxxxx';
//グラフAPI ホストURL(ルートエンドポイント)
$api = 'https://graph.facebook.com/';
//API のバージョン
$version = 'v20.0';
//取得するメディアの件数(0 または false を指定した場合は件数の制限なし)
$limit = '4';
//取得するフィールド
$field = 'caption,media_url,thumbnail_url,permalink,like_count,comments_count,media_type';
//クエリ(この場合、配列で記述して後で URL エンコード)
$query = [
  //取得件数の制限と取得するフィールドを指定($countの値が0やfalseの場合は件数の制限なし)
  'fields' => $limit ? 'media.limit(' . $limit . '){' . $field . '}' : 'media{' . $field . '}',
  //アクセストークンを指定
  'access_token' => $token
];
//URL を作成(クエリは http_build_query() で URL エンコード)
$url = $api . $version . '/' . $business_id . '?' . http_build_query($query);

//cURL セッションを初期化
$ch = curl_init();
//取得する URL を指定
curl_setopt($ch, CURLOPT_URL, $url);
//GET メソッドを使用(省略可能)
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
//戻り値を文字列で返す(データを結果として取得)
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//結果を変数に代入(失敗すれば false、成功すれば取得結果が格納される)
$result = curl_exec($ch);
//cURL セッションを終了
curl_close($ch);

//レスポンスを格納する変数の初期化
$insta_response = null;
//エラーを表示するかどうか
$show_error = false;

if ($result) {
  //取得結果(JSON)をデコードしてレスポンスを格納する変数に代入
  $insta_response = json_decode($result);
  if (isset($insta_response->error)) {
    //$show_error が true  であれば
    if ($show_error) {
      //エラーコードとメッセージを表示
      echo '<p>エラーが発生しました</p> ';
      $error = $insta_response->error;
      echo '<p>Error Code :' . $error->code . ' </p> <code>' . $error->message . '</code>';
    }
    //レスポンスを格納する変数 $insta_response を false に
    $insta_response = false;
  } elseif (!isset($insta_response->media)) {
    // 投稿(メディア)が存在しない場合
    $insta_response = false;
  }
}

if ($insta_response) :  //取得結果にエラーがなく投稿が存在すれば一覧を出力
?>
  <div class="insta-wrapper">
    <h2><span class="insta-icon"></span>Instagram 一覧表示テスト</h2>
    <div class="insta-container">
      <?php
      //レスポンスのデータは配列なので foreach でループ処理
      foreach ($insta_response->media->data as $val) {
        //メディアタイプがビデオの場合
        if ($val->media_type === 'VIDEO') {
          $src = $val->thumbnail_url;
          //ビデオの場合は以下の HTML でアイコンを表示
          $video = '<span class="video-icon"></span>';
        }
        //メディアタイプが画像の場合
        else {
          $src = $val->media_url;
          $video = '';
        }
      ?>
        <div class="insta-media">
          <a href="<?php echo $val->permalink; ?>" target="_blank" rel="noopener">
            <img src="<?php echo $src; ?>" alt="<?php echo isset($val->caption) ? $val->caption : ''; ?>">
            <?php echo $video ? $video : ''; //ビデオの場合は追加の span 要素を出力 ?>
            <span class="like-count"><?php echo $val->like_count; ?></span>
            <span class="comments-count"><?php echo $val->comments_count; ?></span>
          </a>
        </div>
      <?php } ?>
    </div>
  </div>
<?php endif; ?>

上記のコード(13行目)では投稿のメディア表示するために caption, media_url, thumbnail_url, permalink, like_count, comments_count, media_type というフィールドを取得しています。

$field = 'caption,media_url,thumbnail_url,permalink,like_count,comments_count,media_type';

指定できるフィールドには以下のようなものがあります。詳細は「IGメディア」に記載されています。

フィールド 説明
caption キャプション
comments_count メディアに付けられたコメントの数(コメントへの返信を含みます)
like_count メディアに対する「いいね!」の数
media_type メディアタイプ。CAROUSEL_ALBUM、IMAGE、または VIDEO
media_url メディア(画像など)の URL
thumbnail_url メディア(ビデオ)のサムネイルのURL。VIDEO でのみ利用可能
permalink メディア(投稿)を指す URL
timestamp ISO 8601形式のUTCでの作成日付(デフォルトはUTC ±00:00)

この例の場合、curl_exec() の戻り値($result)が false でなければ、$result には JSON 形式の取得結果が入っているので、json_decode() を使って PHP で処理できるように変換して変数 $insta_response に格納しています。

取得結果にエラープロパティが設定されていれば、エラーメッセージを表示し、変数 $insta_response に false を代入して一覧表示の処理は行わないようにしています。また、投稿(メディア)が存在しない場合も同様に一覧表示の処理は行いません。

取得結果にエラーがなく投稿が存在すれば、レスポンスから foreach でそれぞれの投稿のデータを使って画像を出力します。

その際、media_type が VIDEO の場合は img 要素の src 属性には thumbnail_url フィールド(プロパティ)の値を指定し、そうでなければ media_url の値を指定します。

この例ではビデオの場合は、video_icon というクラスを指定した span 要素を出力して CSS でビデオ用のアイコンを表示するようにしていますが、不要であればこの部分(84行目)は削除します。そのままでも73行目で定義した span 要素が出力されるだけなので、CSS で何も指定しなければ問題ありません。

また、表示する画像にはその画像の投稿へのリンクを設定(href 属性に permalink フィールドの値を指定)し、画像の alt 属性には caption フィールドの値が設定されていればその値を設定しています。

そして span 要素で like_count と comments_count の値を使って「いいね!」の数とコメントの数を出力しています。この部分(85,86行目)も不要であれば削除します。

上記の場合、例えば以下のような HTML が出力されます。

<div class="insta-wrapper">
  <h2><span class="insta-icon"></span>Instagram 一覧表示テスト</h2>
  <div class="insta-container">
    <div class="insta-media">
      <a href="https://www.instagram.com/reel/C93YYr.../" target="_blank" rel="noopener">
        <img src="https://scontent-nrt1-2.cdninstagram.com/v/t51.29350-15/45..." alt="">
        <span class="video-icon"></span>
        <span class="like-count">0</span>
        <span class="comments-count">0</span>
      </a>
    </div>
    <div class="insta-media">
      <a href="https://www.instagram.com/p/C93War.../" target="_blank" rel="noopener">
        <img src="https://scontent-nrt1-2.cdninstagram.com/v/t51.29350-15/45,,," alt="">
        <span class="like-count">0</span>
        <span class="comments-count">0</span>
      </a>
    </div>
    <div class="insta-media">
      <a href="https://www.instagram.com/p/C9tsYZ.../" target="_blank" rel="noopener">
        <img src="https://scontent-nrt1-2.cdninstagram.com/v/t51.29350-15/45..." alt="">
        <span class="like-count">0</span>
        <span class="comments-count">0</span>
      </a>
    </div>
    <div class="insta-media">
      <a href="https://www.instagram.com/p/CW9Na.../" target="_blank" rel="noopener">
        <img src="https://scontent-nrt1-2.cdninstagram.com/v/t51.29350-15/26..." alt="Test">
        <span class="like-count">0</span>
        <span class="comments-count">0</span>
      </a>
    </div>
  </div>
</div>

以下は表示例です。

この例では、レイアウトは CSS GridCSS aspect-ratio を利用しています。

.insta-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  grid-auto-rows: minmax(100px, auto);
  gap: 10px;
}

.insta-media {
  position: relative;
}

.insta-media img {
  max-width: 100%;
  aspect-ratio: 1/1;
  object-fit: cover;
  display: block;
  width: 100%;
  height: auto;
}

.like-count,
.comments-count {
  position: absolute;
  bottom: 10px;
  color: #fff;
  filter: drop-shadow(1px 1px 1px #333);
}

.like-count {
  right: 25%;
}

.comments-count {
  right: 5%;
}

.like-count::before {
  content: "";
  display: inline-block;
  height: 18px;
  width: 18px;
  vertical-align: -3px;
  margin-right: 5px;
  background-repeat: no-repeat;
  /*アイコンのSVG画像*/
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23ffffff' viewBox='0 0 16 16'%3E  %3Cpath d='M8.864.046C7.908-.193 7.02.53 6.956 1.466c-.072 1.051-.23 2.016-.428 2.59-.125.36-.479 1.013-1.04 1.639-.557.623-1.282 1.178-2.131 1.41C2.685 7.288 2 7.87 2 8.72v4.001c0 .845.682 1.464 1.448 1.545 1.07.114 1.564.415 2.068.723l.048.03c.272.165.578.348.97.484.397.136.861.217 1.466.217h3.5c.937 0 1.599-.477 1.934-1.064a1.86 1.86 0 0 0 .254-.912c0-.152-.023-.312-.077-.464.201-.263.38-.578.488-.901.11-.33.172-.762.004-1.149.069-.13.12-.269.159-.403.077-.27.113-.568.113-.857 0-.288-.036-.585-.113-.856a2.144 2.144 0 0 0-.138-.362 1.9 1.9 0 0 0 .234-1.734c-.206-.592-.682-1.1-1.2-1.272-.847-.282-1.803-.276-2.516-.211a9.84 9.84 0 0 0-.443.05 9.365 9.365 0 0 0-.062-4.509A1.38 1.38 0 0 0 9.125.111L8.864.046zM11.5 14.721H8c-.51 0-.863-.069-1.14-.164-.281-.097-.506-.228-.776-.393l-.04-.024c-.555-.339-1.198-.731-2.49-.868-.333-.036-.554-.29-.554-.55V8.72c0-.254.226-.543.62-.65 1.095-.3 1.977-.996 2.614-1.708.635-.71 1.064-1.475 1.238-1.978.243-.7.407-1.768.482-2.85.025-.362.36-.594.667-.518l.262.066c.16.04.258.143.288.255a8.34 8.34 0 0 1-.145 4.725.5.5 0 0 0 .595.644l.003-.001.014-.003.058-.014a8.908 8.908 0 0 1 1.036-.157c.663-.06 1.457-.054 2.11.164.175.058.45.3.57.65.107.308.087.67-.266 1.022l-.353.353.353.354c.043.043.105.141.154.315.048.167.075.37.075.581 0 .212-.027.414-.075.582-.05.174-.111.272-.154.315l-.353.353.353.354c.047.047.109.177.005.488a2.224 2.224 0 0 1-.505.805l-.353.353.353.354c.006.005.041.05.041.17a.866.866 0 0 1-.121.416c-.165.288-.503.56-1.066.56z'/%3E%3C/svg%3E");
}

.comments-count::before {
  content: "";
  display: inline-block;
  height: 18px;
  width: 18px;
  vertical-align: -3px;
  margin-right: 5px;
  background-repeat: no-repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23ffffff' viewBox='0 0 16 16'%3E  %3Cpath d='M2.678 11.894a1 1 0 0 1 .287.801 10.97 10.97 0 0 1-.398 2c1.395-.323 2.247-.697 2.634-.893a1 1 0 0 1 .71-.074A8.06 8.06 0 0 0 8 14c3.996 0 7-2.807 7-6 0-3.192-3.004-6-7-6S1 4.808 1 8c0 1.468.617 2.83 1.678 3.894zm-.493 3.905a21.682 21.682 0 0 1-.713.129c-.2.032-.352-.176-.273-.362a9.68 9.68 0 0 0 .244-.637l.003-.01c.248-.72.45-1.548.524-2.319C.743 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7-3.582 7-8 7a9.06 9.06 0 0 1-2.347-.306c-.52.263-1.639.742-3.468 1.105z'/%3E%3C/svg%3E");
}

.video-icon {
  position: absolute;
  top: 3px;
  right: 5px;
  filter: drop-shadow(1px 1px 1px #333);
}

.video-icon::before {
  content: "";
  display: inline-block;
  height: 18px;
  width: 18px;
  vertical-align: -3px;
  background-repeat: no-repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23ffffff' viewBox='0 0 16 16'%3E  %3Cpath fill-rule='evenodd' d='M0 5a2 2 0 0 1 2-2h7.5a2 2 0 0 1 1.983 1.738l3.11-1.382A1 1 0 0 1 16 4.269v7.462a1 1 0 0 1-1.406.913l-3.111-1.382A2 2 0 0 1 9.5 13H2a2 2 0 0 1-2-2V5zm11.5 5.175 3.5 1.556V4.269l-3.5 1.556v4.35zM2 4a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h7.5a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H2z'/%3E%3C/svg%3E");
}

.insta-icon::before {
  content: "";
  display: inline-block;
  height: 30px;
  width: 30px;
  vertical-align: -6px;
  background-repeat: no-repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23a41867' viewBox='0 0 448 512'%3E%3Cpath d='M194.4 211.7a53.3 53.3 0 1 0 59.3 88.7 53.3 53.3 0 1 0 -59.3-88.7zm142.3-68.4c-5.2-5.2-11.5-9.3-18.4-12c-18.1-7.1-57.6-6.8-83.1-6.5c-4.1 0-7.9 .1-11.2 .1c-3.3 0-7.2 0-11.4-.1c-25.5-.3-64.8-.7-82.9 6.5c-6.9 2.7-13.1 6.8-18.4 12s-9.3 11.5-12 18.4c-7.1 18.1-6.7 57.7-6.5 83.2c0 4.1 .1 7.9 .1 11.1s0 7-.1 11.1c-.2 25.5-.6 65.1 6.5 83.2c2.7 6.9 6.8 13.1 12 18.4s11.5 9.3 18.4 12c18.1 7.1 57.6 6.8 83.1 6.5c4.1 0 7.9-.1 11.2-.1c3.3 0 7.2 0 11.4 .1c25.5 .3 64.8 .7 82.9-6.5c6.9-2.7 13.1-6.8 18.4-12s9.3-11.5 12-18.4c7.2-18 6.8-57.4 6.5-83c0-4.2-.1-8.1-.1-11.4s0-7.1 .1-11.4c.3-25.5 .7-64.9-6.5-83l0 0c-2.7-6.9-6.8-13.1-12-18.4zm-67.1 44.5A82 82 0 1 1 178.4 324.2a82 82 0 1 1 91.1-136.4zm29.2-1.3c-3.1-2.1-5.6-5.1-7.1-8.6s-1.8-7.3-1.1-11.1s2.6-7.1 5.2-9.8s6.1-4.5 9.8-5.2s7.6-.4 11.1 1.1s6.5 3.9 8.6 7s3.2 6.8 3.2 10.6c0 2.5-.5 5-1.4 7.3s-2.4 4.4-4.1 6.2s-3.9 3.2-6.2 4.2s-4.8 1.5-7.3 1.5l0 0c-3.8 0-7.5-1.1-10.6-3.2zM448 96c0-35.3-28.7-64-64-64H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96zM357 389c-18.7 18.7-41.4 24.6-67 25.9c-26.4 1.5-105.6 1.5-132 0c-25.6-1.3-48.3-7.2-67-25.9s-24.6-41.4-25.8-67c-1.5-26.4-1.5-105.6 0-132c1.3-25.6 7.1-48.3 25.8-67s41.5-24.6 67-25.8c26.4-1.5 105.6-1.5 132 0c25.6 1.3 48.3 7.1 67 25.8s24.6 41.4 25.8 67c1.5 26.3 1.5 105.4 0 131.9c-1.3 25.6-7.1 48.3-25.8 67z'/%3E%3C/svg%3E");
  margin-right: 5px;
}

アイコンは Bootstrap Icon の SVG を CSS で使って表示しています。

関連ページ:CSS で svg 要素を表示

ID やトークンを別ファイルに保存

前述の例ではビジネスアカウント ID やアクセストークンの値をファイルに直接記述していますが、別ファイルに記述して別途読み込むこともできます。

例えば、パブリックからアクセスできない場所に配置するか .htaccess でアクセス制御すれば安全です。

以下は insta_vars.php というファイルにビジネスアカウント ID とアクセストークンの値を記述しておき、それらの値を require で読み込む例です。

libs というディレクトリを作成し、その中に insta_vars.php を保存します。

├── libs
│   ├── .htaccess  //libs ディレクトリへのアクセスを制御
│   └── insta_vars.php //ビジネスアカウント ID とアクセストークンの値を記述
└── insta_sample.php //インスタグラム投稿の一覧を出力するファイル

この例では、insta_vars.php を配置するディレクトリ(libs)に以下のような内容の .htaccess を配置してこのディレクトリにアクセスできないようにします。

deny from all

insta_vars.php ではビジネスアカウント ID とアクセストークンの値を define() で定数として定義しておきます。

<?php
// Instagram ビジネスアカウント ID
define('IGBA_ID', '123456789');
// Instagram ユーザーアクセストークン
define('INSTA_TOKEN', 'EAAFPcGBdBr0BAPuJxgo..........Y3kT4ZBf');

require で insta_vars.php からビジネスアカウント ID とアクセストークンの値を読み込みます。

<?php
//ビジネスアカウント ID とアクセストークンを記述したファイルの読み込み
require 'libs/insta_vars.php';
//Instagram ビジネスアカウント ID
$business_id = IGBA_ID;
// ユーザーアクセストークン
$token = INSTA_TOKEN;

//以下は前述のコードと同じなので省略
//グラフAPI ホストURL(ルートエンドポイント)
$api = 'https://graph.facebook.com/';
//API のバージョン
$version = 'v20.0';
...

JavaScript で投稿一覧のデータを取得

以下は JavaScript/fetch() を使ってインスタグラムの投稿一覧のデータを Instagram グラフ API から取得して出力する例です(出力する HTML マークアップと CSS は前述の PHP の場合と同じ)。

この例ではページに id 属性が insta-div の要素があれば、そこに取得した投稿一覧を表示します。

<div id="insta-div"></div>

<script src="js/insta-feeds.js"></script>
├── js
│   └── insta-feeds.js //投稿一覧のデータを取得して表示する JavaScript
└── sample.html //インスタグラム投稿の一覧を表示するファイル

出力先の要素(id 属性が insta-div の要素)が存在すれば、fetch() でデータを取得しています。

以下が一覧表示するコードです。

PHP の場合同様、表示件数や取得したアクセストークン、Instagram ビジネスアカウント IDを使って fetch() に渡す URL を組み立て、PHP の cURL 関数の代わりに JS の fetch() でデータを取得します。

7行目と9行目の xxxxxx には取得した Instagram ビジネスアカウント ID とアクセストークンを指定します。取得するメディアの件数や API のバージョンは必要に応じて変更します。

// 出力先の要素を取得
const target = document.getElementById('insta-div');
//import {accessToken, businessID} from './modules/insta-val.js';
if (target) {
  // Instagram ビジネスアカウント ID
  const businessID = "xxxxxx";
  // アクセストークン
  const accessToken = 'xxxxxx';
  //グラフAPI ホストURL(ルートエンドポイント)
  const api = 'https://graph.facebook.com/';
  //API のバージョン
  const version = 'v20.0';
  //表示件数
  const limit = 4;
  //取得するフィールド
  const field = 'caption,media_url,thumbnail_url,permalink,like_count,comments_count,media_type';
  // fields パラメータ
  const fields = limit ? `media.limit(${limit}){${field}}`: `media{${field}}`;
  // 渡したいパラメータ(パラメーターを表すオブジェクト)
  const params = {
    fields,
    access_token: accessToken,
  };
  // オブジェクト形式のパラメータをクエリ文字列に変換
  const query = new URLSearchParams(params);
  // fetch() に渡す URL の組み立て
  const url = `${api}/${version}/${businessID}?${query}`;

  fetch(url)
    .then((response) => {
      // ステータスが ok であればレスポンスを JSON として解析
      if (response.ok) {
        return response.json();
      } else {
        // ステータスが ok でなければエラーにする
        throw new Error(`リクエスト失敗:${response.status} ${response.statusText}`);
      }
    }).then((instaResponse) => {
      // 引数で受け取った json オブジェクトの media.data
      const data = instaResponse.media.data;
      // 出力する値を入れる変数
      let instaFeeds = '';  // フィード部分の HTML
      let src = '';  // img の src
      let video = ''; // メディアタイプがビデオの場合に出力する要素
      // レスポンスのデータ(media.data)は配列なので forEach でループ処理
      data.forEach(item => {
        // メディアタイプがビデオの場合
        if (item.media_type === 'VIDEO') {
          src = item.thumbnail_url;
          // ビデオの場合は以下の span 要素でアイコンを表示
          video = '<span class="video-icon"></span>';
        }
        // メディアタイプが画像の場合
        else {
          src = item.media_url;
          video = '';
        }
        // フィード部分の HTML を作成
        const instaMediaDiv =
          `<div class="insta-media">
  <a href="${item.permalink}" target="_blank" rel="noopener">
    <img src="${src}" alt="${item.caption ? item.caption : ''}">
    ${video ? video : ''}
    <span class="like-count">${item.like_count}</span>
    <span class="comments-count">${item.comments_count}</span>
  </a>
</div>
`;
        instaFeeds += instaMediaDiv;
      });
      // 取得した画像データと見出しなどを出力
      target.innerHTML = `<div class="insta-wrapper">
<h2><span class="insta-icon"></span>インスタ一覧表示テスト JS</h2>
<div class="insta-container">${instaFeeds}</div>`;
    });
}
ID やトークンを別ファイルに保存

ビジネスアカウント ID やアクセストークンの値を別ファイルに記述して別途読み込むこともできます。

以下はビジネスアカウント ID とアクセストークンの値を insta-val.js というファイルに記述しておき、それらの値を import で読み込む例です。

但し、この例の場合、SetEnvIf Referer を使って insta-val.js へのアクセスを制御しているので、完全にアクセスを防ぐことはできません(自サイトや特定のURLを経由したアクセスのみ許可)。

├── js
│   ├── .htaccess  //insta-val.js へのアクセスを制御
│   ├── insta-feeds.js //投稿一覧のデータを取得して表示する JavaScript
│   └── insta-val.js //ビジネスアカウント ID とアクセストークンの値を記述した JavaScript
└── sample.html //インスタグラム投稿の一覧を表示するファイル

この例では以下のような内容の .htaccess を配置して insta-feeds.js 以外からは insta-val.js にアクセスできないようにしています(完全に制御できるわけではありませんが)。

SetEnvIf Referer "^http(s)?://example.com/js/insta-feeds\.js$" allow_access
<Files insta-val.js>
  order deny,allow
  deny from all
  allow from env=allow_access
</Files>

insta-val.js ではビジネスアカウント ID とアクセストークンの値をエクスポートしています。

// Instagram ユーザーアクセストークン
export const accessToken = "xxxxxxxxxx";
// Instagram ビジネスアカウント ID
export const businessID = "xxxxxx";

import で insta_vars.php からビジネスアカウント ID とアクセストークンの値を読み込み、変数に代入します(その他の部分は前述のコードと同じ)。

// 別ファイルに記述されたアクセストークン と Instagram ビジネスアカウント ID をインポートして変数に代入
import {accessToken, businessID} from './insta-val.js';
// 出力先の要素を取得
const target = document.getElementById('insta-div');
if (target) {
  //グラフAPI ホストURL(ルートエンドポイント)
  const api = 'https://graph.facebook.com/';
  //API のバージョン
  const version = 'v20.0';
  //表示件数
  const limit = 4;
  ・・・以下省略・・・
}

また、JavaScript の読み込みでは import を使っているので type="module" を指定します。

<script src="js/insta-feeds.js" type="module"></script>