Search code examples
javascriptnode.jsghost-blog

How can we execute a javascript code before sending it to the user in nodejs?


im running a blog using the Ghost platform. Ghost is built on Nodejs but I don't know much about it. I have built the following code the grab the first image of every post and set it as og:image. The problem is it loads only after the website arrives in the user's machine. Is it possible to execute this from the server and then send it to the user?

    $(document).ready(function() {
        var siteURL = location.host;

         if(
                $('.post-template').length > 0 || 
                $('.page-template').length > 0
            ) {

                var featured_image = $('.post-content img[alt="featured-image"]').first().attr('src');


                // check if the featured image exists
                if(featured_image && featured_image.length > 0) {
                    var featured_image_fe = featured_image;
                    // create container for the image
                    if(featured_image_fe.substr(0,7) != 'http://'){
                        featured_image_fe = siteURL + featured_image_fe;
                    }

                    $('meta[property="og:image"]').attr('content', featured_image_fe);
                } else {
                    var featured_image = $('.post-content img').first().attr('src');

                    if(featured_image && featured_image.length > 0) {

                        var featured_image_nfe = featured_image;
                        if((featured_image_nfe.substr(0,7) != 'http://') && (featured_image_nfe.substr(0,8) != 'https://')){
                            featured_image_nfe = 'http://' + siteURL + featured_image_nfe;
                        }

                        $('meta[property="og:image"]').attr('content', featured_image_nfe);
                    } else {
                        $('meta[property="og:image"]').attr('content', 'http://media.techhamlet.com/wp-content/uploads/2014/06/techhamlet.jpg');
                    }


                }
            }
    }

Solution

  • Yes, this is definitely possible. I have figured out a quick hack to get og:image support working in Ghost. This is definitely a non-optimal solution, but it requires the fewest code changes. You'll need to install cheerio and modify two files.

    core/server/controllers/frontend.js

    We need to update the formatResponse function starting on line 76.

    var cheerio = require('cheerio');
    
    function formatResponse(post) {
        var $ = cheerio.load(post.html);
        var firstImage = $('img').first();
        if(firstImage) {
            post.meta_image = firstImage.attr('src');
        }
    
        // Delete email from author for frontend output
        // TODO: do this on API level if no context is available
        if (post.author) {
            delete post.author.email;
        }
        return {post: post};
    }
    

    What we're doing it running the post HTML through cheerio. Grabbing the first image, and stuffing the src into a new variable (meta_image) off of the post object. This will make that variable available to the handlebars templating system.

    content/themes//default.hbs

    Here I just updated the {{! Page Meta }} section like so:

        {{! Page Meta }}
        <title>{{meta_title}}</title>
        <meta name="description" content="{{meta_description}}" />
    {{#if this.post.meta_image}}
        <meta property="og:image" content="{{this.post.meta_image}}" />
    {{/if}}
        <meta name="HandheldFriendly" content="True" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    

    We just check to see if this.post.meta_image exists, and if it does create the meta tag.

    more "proper" solution

    What you should really do to add this feature is add an additional field to the post object for the og:image. Then you would either populate that with a separate field from the admin, or you could parse the html whenever you save your post and put the value into the appropriate field. This way, the logic for populating the og:image is only run once when the page is saved versus every time the page is displayed.