Cet article concerne de nombreux développeurs et créateurs de thèmes qui trouvent les aides standard offerts par Ghost (https://ghost.org/docs/themes/helpers/) insuffisants. Il est tout à fait normal de chercher des moyens d'étendre les capacités de nos thèmes qui utilisent le guidon fourni par Ghost. Avant de publier cet article et de trouver une solution pour mon thème, j'ai recherché l'internet entier et effectué une analyse du code source de Ghost moi-même.
J'ai découvert qu'il était possible d'étendre le code source de Ghost avec des aides supplémentaires. Je l'ai obtenu en ajoutant un nouveau répertoire dans Current / Core / Frontend / Apps. J'ai utilisé l'exemple d'une «application» existante appelée AMP, dont le code est très simple, pour commencer à créer une nouvelle aide disponible dans le thème. Dans ces applications existantes, la structure est simple car les aides sont enregistrées dans Lib / Helers. À la fin du processus, vous devez ajouter le nom de votre répertoire dans les applications à Current / Core / Shared / Config / Overrides.json dans la section JSON APPS.internal.
Un exemple de contenu du fichier index.js dans notre application serait:
const path = require('path'); module.exports = { activate: function activate(ghost) { ghost.helperService.registerDir(path.resolve(__dirname, './lib/helpers')); } };
Ensuite, dans le répertoire Lib de cette application, nous créons un dossier nommé aidants. À l'intérieur, nous créons un nouveau fichier, qui sera le nom de l'assistance à appeler dans un modèle de guidon. Par exemple, le nommez-le uppercase.js.
ci-dessous est un exemple d'un tel code d'un tel assistant, qui convertit simplement les lettres du texte donné dans l'argument d'assistance en majuscules:
const {SafeString, escapeExpression} = require('../../../../services/handlebars'); module.exports = function uppercase(text) { return `${text.toUpperCase()}`; };
N'oubliez pas d'ajouter le nom du répertoire d'application à Current / Core / Shared / Config / Overrides.json. Après avoir redémarré Ghost, tout devrait être prêt.
J'ai récemment développé cette méthode, et vous pouvez l'appliquer non seulement sur les fantômes auto-hébergés mais aussi sur les instances de fantômes offertes par les fournisseurs d'hébergement. Dans ce dernier cas, il nécessite une planification architecturale appropriée et l'achat d'un petit serveur qui agira comme un proxy pour votre instance fantôme finale.
L'architecture que nous utiliserons dans cette méthode:
Ninx Server ← Node.js middleware ← instance fantôme
Le navigateur de l'utilisateur envoie une demande au serveur Nginx, qui contient le middleware en amont. Toutes les demandes, quel que soit l'emplacement, seront proxies au middleware.
Le middleware est un serveur express exécutant dans node.js avec le Express-Http-Proxy ajouté (https://github.com/villadora/express-http-proxy), ce qui simplifie considérablement le travail. Nous configurons le proxy pour communiquer avec l'instance fantôme. La bibliothèque Express-HTTP-Proxy a une propriété USerresdecorator que nous pouvons utiliser pour "décorer la réponse du serveur proxed". Autrement dit, nous pouvons modifier la réponse de Ghost avant de l'envoyer au navigateur de l'utilisateur.
Notre userresdecorator sera asynchrone afin de ne pas bloquer le thread principal. Nous reviendrons sur le sujet du traitement asynchrone lors de la création d'aides. Pour l'instant, vous devez savoir que tout ce que le navigateur de l'utilisateur ne demande pas ne doit pas être décoré. Par conséquent, la première étape sera de vérifier l'en-tête de type contenu de la réponse de Ghost. Vous pouvez le faire comme suit, puis comparer s'il s'agit de texte / html pour décorer uniquement les documents HTML renvoyés à l'utilisateur:
// 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;
Dans cette déclaration conditionnelle, nous pouvons commencer à modifier HTMLContent, mais pourquoi en avons-nous besoin? Commençons par construire les bases de notre aide personnalisée dans le thème fantôme!
Dans cet article, je créerai une aide personnalisée dans le fichier index.hbs (page d'accueil) de mon thème. Dans un emplacement visible dans le modèle de guidon, j'ajoute un exemple d'assistance personnalisée, le nommant {{hello_world}}.
⚠️ Ensuite, je le place dans un endroit visible sur la page d'accueil - mais remarquez ce qui se passe lorsque je rafraîchis la page fantôme!
{{!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');Dans cette variable, nous avons la réponse de l'instance fantôme en tant que HTML complet de la page. Imaginez que cette réponse est la page d'accueil de votre instance fantôme. Le contenu HTML inclura également notre texte brut {{Hello_world}}, qui s'affiche en texte brut. Si notre aide personnalisée est dans ce formulaire, nous pouvons le compiler à l'aide de guichets.js (https://handlebarsjs.com/) dans notre middleware. N'oubliez pas d'installer la bibliothèque d'abord via un gestionnaire de packages, par exemple, npm: npm installer le guidon et l'ajouter à votre code: const de guidon = require ("guidon");.
// Compile response HTML with Handlebars, and return rendered template let htmlContent = proxyResData.toString('utf8'); const template = handlebars.compile(htmlContent); htmlContent = template({});Ouah! Nous avons maintenant compilé et rendu HTML à l'aide de guichets.js - mais nous n'avons pas encore fini. Nous devons encore enregistrer notre aide personnalisée {{Hello_world}}. Ajoutez le code suivant, de préférence après avoir initialisé les guidon.js:
// Returns 'Hello from middleware!' with the current timestamp handlebars.registerHelper('hello_world', function (options) { return `Hello from middleware! ${new Date().toISOString()}`; });Après avoir redémarré le serveur middleware et enregistré l'assistance ci-dessus, vous devriez voir l'assistance rendue dans le navigateur avec le texte renvoyé par notre aide et la date et l'heure actuelles.
À ce stade, vous pouvez étendre votre thème fantôme avec des aides personnalisées supplémentaires, que vous ajouterez au code du serveur middleware.
Sécurité
À un moment donné, vous voudrez peut-être retourner diverses choses avec vos aides. Par défaut, la bibliothèque protège contre les attaques XSS, mais lorsque vous utilisez la méthode de sécurité, cette protection cesse de fonctionner. Évitez de l'utiliser chaque fois que possible.
une autre chose! Imaginez qu'un utilisateur ajoute une telle aide dans la section des commentaires sous un message et ajoute du contenu malveillant dans le paramètre. Être conscient de la sécurité. Par exemple, si vous rendez complètement chaque HTML, vous pourriez être vulnérable aux attaques XSS. Il est recommandé de compiler et de rendre les guidon.js dans des zones spécifiques et fermées. Vous pouvez utiliser la bibliothèque Cheerio (https://cheerio.js.org/) pour analyser le guidon HTML et rendu si nécessaire. Voici un exemple de la façon dont vous pouvez vous sécuriser en modifiant le code de rendu précédent:
// Render handlebars only insidewith>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! // ... });N'oubliez pas d'ajouter l'initialisation de la bibliothèque au début de votre script: const asynchepers = require ('huisseau-async-helpers');. Si vous rencontrez des problèmes pour l'installer en raison de conflits de version entre le guidon-asynchronisation et le guidon, rétrogradent simplement à ^ 4.7.6. Malheureusement, la bibliothèque Async Helper n'a pas été maintenue depuis un certain temps, mais elle fonctionne toujours dans la pratique.
Communication et objets de la base de données
Si vous souhaitez faire des requêtes de base de données dans Ghost pour récupérer, par exemple, le message actuel, c'est possible et pas difficile. Vous pouvez utiliser une bibliothèque comme Knex (https://knexjs.org/), qui est un constructeur de requête SQL clair et rapide. N'oubliez pas que vous aurez besoin d'un guidon-async-helpers pour cela. Configurez correctement Knex pour se connecter à la base de données de Ghost.
Initialiser Knex comme la variable DB et essayer le code suivant:
// Return current post title from database hb.registerHelper('post_title', async function (options) { const uuid = options.hash.uuid; try { const { title } = await db("posts") .select("title") .where("uuid", uuid) .limit(1) .first(); return title; } catch (error) { return `Error: ${error.message}`; } });Ensuite, dans le modèle post.hbs du thème fantôme, ajoutez l'assistance suivante: \ {{post_title uuid = "{{uuid}}"}}. Dans cet exemple, {{UUID}} sera récupéré et passé en tant qu'assistance disponible dans Ghost, remplissant le champ UUID de notre aide et provoquant l'affichage du titre de poste par l'assistant personnalisé.
Vous pouvez également utiliser Axios pour faire des demandes HTTP à l'API de contenu fantôme, mais cela est nettement plus lent que la communication de base de données directe.
Performance
Je sais qu'une solution basée sur le middleware n'est peut-être pas la meilleure en termes de vitesse, mais j'utilise personnellement cette solution et je n'ai pas remarqué une baisse significative des temps de chargement de page. Le temps de réponse moyen pour une seule demande était inférieur à 100 ms (selon Express-Status-Monitor), et j'utilise une aide personnalisée qui récupère certaines valeurs de la base de données sur chaque page.
Vous pouvez, bien sûr, ajouter des mécanismes de mise en cache pour améliorer les performances du middleware ou utiliser des solutions alternatives au lieu de Express-Http-Proxy.
Implémentation de l'architecture
Utilisez Docker ou un autre mécanisme de contenerisation. Je l'ai utilisé dans mon projet, et cela fonctionne très bien. Ajoutez des images de base de fantômes et de base de données pour Ghost, Nginx et une image Node.js. Connectez-les à un réseau partagé (pilote: pont), configurez Nginx et le serveur Node.js en conséquence - tout est très simple!
Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.
Copyright© 2022 湘ICP备2022001581号-3