Link rewriting for affiliate codes

はい、可能です。まずは簡単なところから始めましょう。新しいテーマコンポーネントの「ヘッダー」タブに、以下のコードを追加します。

<script type="text/discourse-plugin" version="0.8.42">

</script>

これは何をするものなのでしょうか?Discourse が特別に処理するスクリプトタグの一種です。そのメリットは何でしょうか?プラグイン API のメソッドにアクセスできるようになります。

あなたは一部のリンクにアフィリエイトコードを追加したいと考えています。つまり、投稿の内容を変更したいということです。プラグイン API を確認すると、確かにそのためのメソッドが存在することがわかります。

https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/lib/plugin-api.js#L224-L262

使い方は以下の通りです。

api.decorateCookedElement(
  element =\u003e {
    // ここで処理を行います。
    // ここに渡される element は、レンダリング済みの投稿の HTML ノードです
  },
  {
    // オプションをここに記述します
  }
);

これは、投稿がレンダリングされたときにコードが実行されるようにするためのラッパーです。では、実際に試してみましょう。

あなたのコードをそのまま追加します。

api.decorateCookedElement(
  element =\u003e {
++  // 以下の "my-affiliate-id" を実際のアフィリエイト ID に変更してください
++  const aid = "my-affiliate-id";
++
++  // リンク内にアフィリエイト ID がまだ含まれていない場合のみ、スラッシュとアフィリエイト ID を追加します
++  const goglinks = document.querySelectorAll('a[href*="gog.com"]');
++  goglinks.forEach(function (el) {
++    if (!el.href.includes("pp=")) {
++      el.href = el.href.replace(/\?.*$/, "") + "?pp=" + aid;
++    }
++  });
  },
  {
    // オプションをここに記述します
  }
);

これで動作しますか?はい、動作しますが、リンクを取得するために document をクエリしているため、重複した処理も行われています。では、それをどう修正すればよいでしょうか?

メソッドに渡した element 引数を覚えていますか?ここでそれが役立ちます。

document をクエリする代わりに、ターゲットとする element をクエリします。つまり、以下のように変更します。

const goglinks = document.querySelectorAll('a[href*="gog.com"]');

const goglinks = element.querySelectorAll('a[href*="gog.com"]');

に変更します。

最終的なコードは以下のようになります。

api.decorateCookedElement(
  element =\u003e {
    // 以下の "my-affiliate-id" を実際のアフィリエイト ID に変更してください
    const aid = "my-affiliate-id";

    // リンク内にアフィリエイト ID がまだ含まれていない場合のみ、スラッシュとアフィリエイト ID を追加します
--  const goglinks = document.querySelectorAll('a[href*="gog.com"]');
++  const goglinks = element.querySelectorAll('a[href*="gog.com"]');
    goglinks.forEach(function (el) {
      if (!el.href.includes("pp=")) {
        el.href = el.href.replace(/\?.*$/, "") + "?pp=" + aid;
      }
    });
  },
  {
    // オプションをここに記述します
  }
);

これで問題なく動作しますが、さらに改善できます。リンクにアフィリエイト ID を追加するだけなので、コンポーザー内ではこのコードを実行する必要はありません。ここでメソッドのオプションが役立ちます。

メソッドに渡せるオプションの一つに onlyStream があります。

これは何をするものなのでしょうか?このメソッドに、コードがトピック内で投稿がレンダリングされた場合のみ実行されるように指示します。このオプションを追加しましょう。

api.decorateCookedElement(
  element =\u003e {
    // 以下の "my-affiliate-id" を実際のアフィリエイト ID に変更してください
    const aid = "my-affiliate-id";

    // リンク内にアフィリエイト ID がまだ含まれていない場合のみ、スラッシュとアフィリエイト ID を追加します
    const goglinks = element.querySelectorAll('a[href*="gog.com"]');
    goglinks.forEach(function (el) {
      if (!el.href.includes("pp=")) {
        el.href = el.href.replace(/\?.*$/, "") + "?pp=" + aid;
      }
    });
  },
  {
++  onlyStream: true
  }
);

これで、最後にやるべきことは、先ほど説明した特別なスクリプトタグにこのコードを記述することだけです。

<script type="text/discourse-plugin" version="0.8.42">
api.decorateCookedElement(
  element =\u003e {
    // 以下の "my-affiliate-id" を実際のアフィリエイト ID に変更してください
    const aid = "my-affiliate-id";

    // リンク内にアフィリエイト ID がまだ含まれていない場合のみ、スラッシュとアフィリエイト ID を追加します
    const goglinks = element.querySelectorAll('a[href*="gog.com"]');
    goglinks.forEach(function (el) {
      if (!el.href.includes("pp=")) {
        el.href = el.href.replace(/\?.*$/, "") + "?pp=" + aid;
      }
    });
  },
  {
    onlyStream: true
  }
);
</script>

これをコンポーネントの「ヘッダー」タブに追加すれば、準備完了です。この例では GOG を使用しましたが、URL 構造がわかれば、このパターンはあらゆるアフィリエイトプログラムに適用できます。

「いいね!」 11