「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > ゴーストでカスタムハンドルバーヘルパーを作りましょう!

ゴーストでカスタムハンドルバーヘルパーを作りましょう!

2025-04-08に投稿
ブラウズ:505

Make Custom Handlebar Helpers in Ghost!

この記事は、Ghost(https://ghost.org/docs/themes/helpers/)が提供する標準的なヘルパーを見つける多くの開発者やテーマ作成者向けです。 Ghundが提供するハンドルバーを使用するテーマの機能を拡張する方法を探すのは完全に普通です。この記事を公開してテーマの解決策を見つける前に、インターネット全体を検索し、Ghostのソースコードの分析を自分で実施しました。

方法1(コアコードの変更)

私は、追加のヘルパーでGhostのソースコードを拡張することが可能であることを発見しました。 Current/Core/Frontend/Appsに新しいディレクトリを追加することでこれを達成しました。 AMPと呼ばれる既存の「アプリ」の例を使用しましたが、そのコードは非常にシンプルで、テーマで利用可能な新しいヘルパーの作成を開始しました。これらの既存のアプリでは、ヘルパーがLIB/ヘルパーに登録されているため、構造は簡単です。プロセスの最後に、アプリのディレクトリの名前をcurrent/core/shared/config/overrides.jsonに追加する必要があります。

アプリのindex.jsファイルの例の例は次のとおりです。

const path = require( 'path'); module.exports = { アクティブ化:function activate(ghost){ ghost.helperservice.registerdir(path.resolve(__ dirname、 './lib/helpers')); } };

次に、このアプリのLIBディレクトリで、ヘルパーという名前のフォルダーを作成します。内部では、新しいファイルを作成します。これは、ハンドルバーのテンプレートで呼び出されるヘルパーの名前です。たとえば、それをappercase.jsに名前を付けましょう。
const path = require('path');

module.exports = {
    activate: function activate(ghost) {
        ghost.helperService.registerDir(path.resolve(__dirname, './lib/helpers'));
    }
};
以下は、そのようなヘルパーのコードの例です。これは、ヘルパー引数の特定のテキストの文字を大文字に変換するだけです。

const {safestring、escapeexpression} = require( '../..//// services/handlebars'); module.exports = function repercase(text){ `$ {text.touppercase()}`;を返します。 };


アプリケーションディレクトリの名前をcurrent/core/shared/config/overrides.jsonに追加することを忘れないでください。ゴーストを再起動した後、すべての準備が整うはずです。

const {SafeString, escapeExpression} = require('../../../../services/handlebars');

module.exports = function uppercase(text) {
    return `${text.toUpperCase()}`;
};

私は最近この方法を開発しましたが、自己ホストのゴーストだけでなく、ホスティングプロバイダーが提供するゴーストインスタンスにも適用できます。後者の場合、最終的なゴーストインスタンスのプロキシとして機能する小さなサーバーの適切なアーキテクチャ計画と購入が必要です。

この方法で使用するアーキテクチャ:

nginxサーバー←node.jsミドルウェア←ゴーストインスタンス

ユーザーのブラウザは、ミドルウェアの上流を含むNginxサーバーにリクエストを送信します。場所に関係なく、すべてのリクエストはミドルウェアにプロキシ化されます。
ミドルウェアは、追加のExpress-http-proxy(https://github.com/villadora/express-http-proxy)ライブラリを使用してnode.jsで実行されているExpressサーバーです。これは、作業を大幅に簡素化します。 Ghostインスタンスと通信するプロキシを構成します。 Express-HTTP-Proxyライブラリには、「プロキシサーバーの応答を飾る」ために使用できるUSERRESRESDECORATORプロパティがあります。簡単に言えば、Ghostからの応答をユーザーのブラウザに送信する前に変更できます。

userresdecoratorは、メインスレッドをブロックしないように非同期になります。ヘルパーを作成するときに、非同期処理のトピックに戻ります。とりあえず、ユーザーのブラウザの要求がすべて装飾する必要があるわけではないことを知っておく必要があります。したがって、最初のステップは、ゴーストからの応答のコンテンツタイプのヘッダーを確認することです。これを次のように行い、それがテキスト/htmlであるかどうかを比較してユーザーに返されたHTMLドキュメントのみを飾ります:

//ここで、「プロキシレス」は「UserresDecorator」内のあなたのプロキシ応答です const contentType = proxyres.headers ['content-type'] || ''; if(!contentType.includes( 'text/html')){ //応答が「text/html」でない場合は元のコンテンツを返します proxyresdataを返します。 } let htmlcontent = proxyresdata.toString( 'utf8'); //「htmlcontent」で何かをして戻ります htmlcontentを返します。


この条件付きステートメントでは、htmlcontentの変更を開始できますが、なぜ必要なのですか?ゴーストテーマのカスタムヘルパーの基礎を構築することから始めましょう!

// Where 'proxyRes' is your proxy response inside 'userResDecorator'
const contentType = proxyRes.headers['content-type'] || '';
if (!contentType.includes('text/html')) {
    // Return original content if response is not 'text/html'
    return proxyResData;
}

let htmlContent = proxyResData.toString('utf8');
// Do something with 'htmlContent' and return
return htmlContent;
⚠️次に、ホームページの目に見える場所に配置しますが、ゴーストページを更新すると何が起こるかに注意してください!

{{!

更新後、{{hello_world}}ヘルパーがGhostのデフォルトヘルパーに存在しないため、Ghostからエラーメッセージが表示されます。私たちの論理が機能するためには、Ghostの組み込みハンドルバーによってヘルパーとして扱われないように、このヘルパーを逃れなければなりません。


正しい方法は、このヘルパーを\ {{hello_world}}として書くことです。このようにして、ゴーストはそれをプレーンテキストとして扱います。ゴーストホームページを更新した後、プレーンテキスト{{hello_world}}が表示されます。これが発生した場合、あなたは正しい軌道に乗っています。次に、ミドルウェアサーバーファイルに戻り、応答デコレータを使用します。

{{!



After refreshing, I get an error message from Ghost because the {{hello_world}} helper doesn’t exist in Ghost's default helpers. For our logic to work, we must escape this helper so that it’s not treated as a helper by Ghost’s built-in Handlebars.

The correct way is to write this helper as \{{hello_world}}. This way, Ghost treats it as plain text. After refreshing the Ghost homepage, you should see the plain text {{hello_world}}. If this happens, you are on the right track. Let’s now return to the middleware server file, where we will use the response decorator.

⚠️ Remember to escape custom helpers in your theme! Don’t forget to add the \ character.

let htmlContent = proxyResData.toString('utf8');
おお! HyndleBars.jsを使用してHTMLをコンパイルしてレンダリングしましたが、まだ完了していません。カスタムヘルパー{{hello_world}}を登録する必要があります。次のコードを追加します。できればハンドルバーを初期化した後:


//「ミドルウェアからこんにちは!」現在のタイムスタンプで handlebars.registerhelper( 'hello_world'、function(options){ ミドルウェアから `こんにちは! $ {new date()。toisostring()} `; });
// Compile response HTML with Handlebars, and return rendered template
let htmlContent = proxyResData.toString('utf8');
const template = handlebars.compile(htmlContent);
htmlContent = template({});
ミドルウェアサーバーを再起動して上記のヘルパーを登録した後、テキストがヘルパーと現在の日付と時刻を返したテキストで、ブラウザにレンダリングされたヘルパーが表示されるはずです。

この段階では、ゴーストテーマを追加のカスタムヘルパーで拡張できます。これをミドルウェアサーバーコードに追加します。

安全
const path = require('path');

module.exports = {
    activate: function activate(ghost) {
        ghost.helperService.registerDir(path.resolve(__dirname, './lib/helpers'));
    }
};
ある時点で、ヘルパーでさまざまなものを返したいと思うかもしれません。デフォルトでは、ライブラリはXSS攻撃から保護しますが、セーフストリング方法を使用すると、この保護が機能しなくなります。可能な場合はいつでも使用しないでください。

もう一つ!ユーザーが投稿の下のコメントセクションにそのようなヘルパーを追加し、パラメーターに悪意のあるコンテンツを追加することを想像してください。セキュリティに注意してください。たとえば、すべてのHTMLを完全にレンダリングすると、XSS攻撃に対して脆弱になる可能性があります。特定の閉じたエリアで、HandleBars.jsをコンパイルおよびレンダリングすることをお勧めします。 HTMLを解析し、必要に応じてハンドルバーをレンダリングするために、Cheerio(https://cheerio.js.org/)ライブラリを使用できます。以前のレンダリングコードを変更することで自分自身を保護する方法の例を次に示します。

//> with> with内部のみのハンドルバーをレンダリングします

このコードでは、カスタムヘルパーとハンドルバーは>
コンテナ内でのみレンダリングされます> 非同期処理

より複雑なデータを返す動的なヘルパーを作成する場合は、おそらくハンドルバーに非同期ヘルパーを時間の経過とともに実装する必要があります。これは、次のような場合に役立ちます


データベースから値を取得する(例:Ghostデータベース)
// Render handlebars only inside 
with>

In this code, our custom helpers and Handlebars are rendered only within a

container with>

Asynchronous Processing

If you intend to create dynamic helpers that return more complex data, you’ll probably need to implement asynchronous helpers in Handlebars over time. This is useful in cases like:

  • Fetching values from a database (e.g., Ghost database)
  • Sending API requests and processing their responses

You can use an extension called handlebars-async-helpers (https://www.npmjs.com/package/handlebars-async-helpers) for this purpose. It enables asynchronous operations in Handlebars.js, making potentially lengthy and dynamic tasks possible. Here’s a simple example of how you can implement asynchronous processing in your middleware:

// Register async helpers with Handlebars
const hb = asyncHelpers(handlebars);

hb.registerHelper('hello_world', async function (options) {
  // You can use await's here!
  // ...
});

//データベースから現在の投稿タイトルを返します hb.registerhelper( 'post_title'、async function(options){ const uuid = options.hash.uuid; 試す { const {title} = await db( "posts") .Select( "Title") .where( "uuid"、uuid) .limit(1) 。初め(); タイトルを返す; } catch(error){return `error:$ {error.message}`; } });

次に、ゴーストテーマのpost.hbsテンプレートで、次のヘルパーを追加します:\ {{post_title uuid = "{{uuid}}"}}。この例では、{{uuid}}がゴーストで利用可能なヘルパーとして取得され、渡され、ヘルパーのuuidフィールドを埋め、ポストタイトルをカスタムヘルパーによって表示します。

Axiosを使用してGhttpリクエストをGhttpリクエストにすることもできますが、これは直接データベース通信よりも大幅に遅いです。

パフォーマンス

ミドルウェアベースのソリューションは速度の面では最適ではないかもしれないことを知っていますが、私はこのソリューションを個人的に使用しており、ページの読み込み時間が大幅に低下することに気付いていません。単一のリクエストの平均応答時間は100ms未満でした(Express-Status-Monitorによる)。すべてのページのデータベースからいくつかの値を取得するカスタムヘルパーを使用します。
const path = require('path');

module.exports = {
    activate: function activate(ghost) {
        ghost.helperService.registerDir(path.resolve(__dirname, './lib/helpers'));
    }
};
もちろん、キャッシュメカニズムを追加してミドルウェアのパフォーマンスを改善したり、Express-HTTP-Proxyの代わりに代替ソリューションを使用したりできます。

アーキテクチャの実装

Dockerまたは別のコンテナ化メカニズムを使用します。私は自分のプロジェクトでそれを使用しました、そしてそれはうまく機能します。ゴースト、nginx、およびnode.js画像のゴースト画像とデータベース画像を追加します。それらを共有ネットワーク(ドライバー:ブリッジ)に接続し、それに応じてnginxとnode.jsサーバーを構成します - それはすべて非常に簡単です!

リリースステートメント この記事は、https://dev.to/piotrbednarski/make-custom handlebar-helpers-in-ghost-48nh?1に再現されています。
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3