"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > ¡Haga ayudantes de manillar personalizados en Ghost!

¡Haga ayudantes de manillar personalizados en Ghost!

Publicado el 2025-04-08
Navegar:785

Make Custom Handlebar Helpers in Ghost!

Este artículo es para muchos desarrolladores y creadores de temas que encuentran los ayudantes estándar ofrecidos por Ghost (https://ghost.org/docs/themes/helpers/) insuficiente. Es completamente normal buscar formas de extender las capacidades de nuestros temas que usan el manillar proporcionado por Ghost. Antes de publicar este artículo y encontrar una solución para mi tema, busqué en toda Internet y realicé un análisis del código fuente de Ghost.

Método 1 (modificación del código central)

descubrí que es posible extender el código fuente de Ghost con ayudantes adicionales. Lo logré agregando un nuevo directorio en actual/core/frontend/aplicaciones. Utilicé el ejemplo de una "aplicación" existente llamada AMP, cuyo código es muy simple, para comenzar a crear un nuevo ayudante disponible en el tema. En estas aplicaciones existentes, la estructura es sencilla porque los ayudantes están registrados en lib/ayudantes. Al final del proceso, debe agregar el nombre de su directorio en las aplicaciones a la sección actual/core/compartir/config/overrés.json en la sección JSON INTERNAL.

un contenido de ejemplo del archivo index.js en nuestra aplicación sería:

const path = require('path');

module.exports = {
    activate: function activate(ghost) {
        ghost.helperService.registerDir(path.resolve(__dirname, './lib/helpers'));
    }
};

A continuación, en el directorio lib de esta aplicación, creamos una carpeta llamada ayudantes. En el interior, creamos un nuevo archivo, que será el nombre del ayudante que se llamará en una plantilla de manillares. Por ejemplo, lo nombremos UpperCase.js.

a continuación se muestra un ejemplo del código de dicho ayudante, que simplemente convierte las letras del texto dado en el argumento auxiliar a uppercase:

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

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

no olvide agregar el nombre del directorio de aplicaciones a actual/core/compartir/config/overRides.json. Después de reiniciar Ghost, todo debería estar listo.

Método 2 (sin modificar el código central)

desarrollé recientemente este método, y puede aplicarlo no solo en el fantasma autohospedado sino también en las instancias fantasmas ofrecidas por los proveedores de alojamiento. En el último caso, requiere una planificación arquitectónica apropiada y la compra de un pequeño servidor que actúe como un proxy para su instancia fantasma final.

La arquitectura que usaremos en este método:
Nginx Server ← Node.js Middleware ← Instancia fantasma

El navegador del usuario envía una solicitud al servidor NGINX, que contiene el flujo aguas arriba del middleware. Todas las solicitudes, independientemente de la ubicación, se representarán en el middleware.

El middleware es un servidor Express que se ejecuta en Node.js con la biblioteca Express-Http-Proxy agregada (https://github.com/villadora/express-http-proxy), que simplifica significativamente el trabajo. Configuramos el proxy para comunicarnos con la instancia fantasma. La biblioteca Express-HTTP-Proxy tiene una propiedad UserResDecorator que podemos usar para "decorar la respuesta del servidor proxy". En pocas palabras, podemos modificar la respuesta de Ghost antes de enviarla al navegador del usuario.

Nuestro UserResDecorator será asíncrono para no bloquear el hilo principal. Volveremos al tema del procesamiento asincrónico al crear ayudantes. Por ahora, debe saber que no todo lo que las solicitudes del navegador del usuario deben decorarse. Por lo tanto, el primer paso será verificar el encabezado de tipo de contenido de la respuesta de Ghost. Puede hacer esto de la siguiente manera y luego comparar si es texto/html para decorar solo los documentos HTML devueltos al usuario:

// 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;

En esta declaración condicional, podemos comenzar a modificar htmlcontent, pero ¿por qué la necesitamos? ¡Comencemos construyendo las bases para nuestro ayudante personalizado en el tema fantasma!

En este artículo, crearé un ayudante personalizado en el archivo index.hbs (página de inicio) de mi tema. En una ubicación visible en la plantilla de manillares, agrego un ejemplo de ayudante personalizado, nombrándolo {{hello_world}}.

⚠️ entonces, lo coloco en un lugar visible en la página de inicio, pero observe lo que sucede cuando actualizo la página Ghost!

{{!



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');

En esta variable, tenemos la respuesta de la instancia fantasma como el HTML completo de la página. Imagine que esta respuesta es la página de inicio de su instancia de fantasma. El contenido HTML también incluirá nuestro texto sin formato {{hello_world}}, que se muestra como texto sin formato. Si nuestro ayudante personalizado está en este formulario, podemos compilarlo usando HandleBars.js (https://handlebarsjs.com/) en nuestro middleware. Recuerde instalar la biblioteca primero a través de un administrador de paquetes, por ejemplo, NPM: NPM Instale Hanebars y agrégala a su código: Const HaneSebars = request ("Handlebars");.

// Compile response HTML with Handlebars, and return rendered template
let htmlContent = proxyResData.toString('utf8');
const template = handlebars.compile(htmlContent);
htmlContent = template({});

¡Guau! Ahora hemos compilado y renderizado HTML usando manillars.js, pero aún no hemos terminado. Todavía necesitamos registrar nuestro ayudante personalizado {{hello_world}}. Agregue el siguiente código, preferiblemente después de inicializar el manillar.js:

// Returns 'Hello from middleware!' with the current timestamp
handlebars.registerHelper('hello_world', function (options) {
   return `Hello from middleware! ${new Date().toISOString()}`;
});

Después de reiniciar el servidor de middleware y registrar el ayudante anterior, debe ver el ayudante renderizado en el navegador con el texto devuelto por nuestro ayudante y la fecha y hora actuales.

En esta etapa, puede extender su tema fantasma con ayudantes personalizados adicionales, que agregará al código del servidor de middleware.

Seguridad

En algún momento, es posible que desee devolver varias cosas con sus ayudantes. Por defecto, la biblioteca protege contra los ataques XSS, pero cuando usa el método SafeString, esta protección deja de funcionar. Evite usarlo siempre que sea posible.

¡otra cosa! Imagine un usuario agrega un ayudante en la sección de comentarios en una publicación y agrega contenido malicioso en el parámetro. Tenga en cuenta la seguridad. Por ejemplo, si representa cada HTML por completo, podría ser vulnerable a los ataques XSS. Se recomienda compilar y renderizar el manillar.js en áreas específicas y cerradas. Puede usar la biblioteca Cheerio (https://cheerio.js.org/) para analizar HTML y hacer manillares cuando sea necesario. Aquí hay un ejemplo de cómo puede asegurarse modificando el código de representación anterior:

// 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!
  // ...
});

Recuerde agregar la inicialización de la biblioteca al inicio de su script: const asynchelpers = request ('manebars-async-helpers');. Si se encuentra con los problemas de instalarlo debido a los conflictos de versión entre Handlebars-Async-Helpers y Manillars, simplemente degrade el manillar a ^4.7.6. Desafortunadamente, la Biblioteca Async Helper no se ha mantenido por un tiempo, pero todavía funciona en la práctica.

Comunicación de bases de datos y objetos

Si desea hacer consultas de base de datos en Ghost para obtener, por ejemplo, la publicación actual, es posible y no difícil. Puede usar una biblioteca como Knex (https://knexjs.org/), que es un creador de consultas SQL claro y rápido. Recuerde que necesitará manubrantes-async-Helpers para esto. Configure Knex correctamente para conectarse a la base de datos de Ghost.

Inicializar a Knex como la variable DB e intente el siguiente código:

// 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}`; }
});

Entonces, en la plantilla post.hbs del tema fantasma, agregue el siguiente ayudante: \ {{post_title uuid = "{{uuid}}"}}. En este ejemplo, {{UUID}} se recuperará y pasará como un ayudante disponible en Ghost, llenando el campo UUID de nuestro ayudante y haciendo que el título de la publicación sea mostrado por el ayudante personalizado.

también puede usar AXIOS para realizar solicitudes HTTP a la API de contenido fantasma, pero esto es significativamente más lento que la comunicación de la base de datos directa.

Actuación

Sé que una solución basada en el middleware podría no ser la mejor en términos de velocidad, pero personalmente uso esta solución y no he notado una caída significativa en los tiempos de carga de la página. El tiempo de respuesta promedio para una sola solicitud fue menos de 100 ms (según Express-Status-Monitor), y uso un ayudante personalizado que recupera algunos valores de la base de datos en cada página.

puede, por supuesto, agregar mecanismos de almacenamiento en caché para mejorar el rendimiento del middleware o usar soluciones alternativas en lugar de express-http-prooxy.

Implementación de la arquitectura

use Docker u otro mecanismo de contenedores. Lo he usado en mi proyecto, y funciona muy bien. Agregue imágenes de fantasma y base de datos para la imagen Ghost, Nginx y una imagen node.js. Conéctelos a una red compartida (controlador: puente), configure Nginx y el servidor node.js en consecuencia, ¡todo es muy simple!

Declaración de liberación Este artículo se reproduce en: https://dev.to/piotrbednarski/make-custom-handlebar-helpers-in-ghost-48nh?1 Si hay alguna infracción, comuníquese con [email protected] para eliminarlo.
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3