Disqus on Ghost

Updated 6 Mar 2021 - Scroll to bottom for the update

More adventures into self-hosting Ghost. I have Disqus up and running again, all the comments are still there. Since Disqus was based on URL, and the URL didn't change, everything just started working once the Disqus universal code was added. I did run into the same problem as I did with the security.txt file (which is the reason I'm documenting this).

The section of code I need to add this to is post.hbs in /var/www/ghost/versions/1.23.1/content/themes/casper/ (1.23.1 is the version number, and will change). So, like the location for security.txt, this will change every time Ghost is updated.

Another short script, that you can either run on a cron job, every update, etc. fixes this. I reused the same first few lines to enumerate and move into the version directories. Then I test to see if the word "disqus" is in post.hbs, if it is, we've already fixed this file, skip it. If not, backup post.hbs, and then the real magic happens.

sed 'N;/{{content}}\n.*<\/div>$/ r /home/ubuntu/disqus_universal.txt' $dir/post.hbs.bak > $dir/post.hbs: Sed finds "{{content}}" and the </div> in the following line in post.hbs.bak and, directly after that, adds the content of the file "disqus_universal.txt", directing the output into post.hbs.

disqus_universal.txt contains, of course, the universal embed code.


for f in /var/www/ghost/versions/*; do
    if [ -d ${f} ]; then
		# echo $f
		# echo $dir
		if grep -q disqus $dir/post.hbs; then
			echo "Disqus already set in $dir"
			echo "Provisioning Disqus in $dir/post.hbs"
            mv $dir/post.hbs $dir/post.hbs.bak
            sed 'N;/{{content}}\n.*<\/div>$/ r /home/ubuntu/disqus_universal.txt' $dir/post.hbs.bak > $dir/post.hbs

Update 7/28/2018: Around v1.25.0 Ghost made a change to post.hbs

Previous code:

            <section class="post-full-content">

New Code:

            <section class="post-full-content">
                <div class="post-content">

Placing the Disqus universal code directly after the content tag would now place it within the "post-content" div, causing issues (it doesn't exactly not render, but it might as well, it almost appears 1 pixel wide). So we now have to place it after the </div> and before the </section>. Therefore, we modify our sed command. Per this comment:

sed normally works on one line at a time. If you want to work on several lines in the same command, you have to add them to the pattern buffer with the N command:".

I've replaced the original sed command with the new multiline version. We still look for the {{content}} tag, but now add a line break (\n) followed by matching anything (.*) to account for spaces/tabs leading up to the </div> tag, which comes at the end of the line ($).

This appears to work correctly, but I won't be absolutly sure until I try it on the next update.

Update 3/6/2021: At some point ghost made further changes to post.hbs

Updated again 3/15/2021: Of course they move to Ghost 4 right after I post this and change the text in post.hbs. I've updated the script below for v4.

I've been EXTREAMLY lazy about this. The last update was in version 1.x of Ghost, which is now on 3.42.0. It's been three years. Ghost has added a section specifically for comments to post.hbs, and my previous bash script hasn't really worked correctly in all this time. I've finally replaced it with a proper python script.

Here's the new comment section

<section class="post-full-comments">
    If you want to embed comments, this is a good place to do it!

Here's my working python script

from glob import glob
import re
import shutil

paths = []
files = []
test_string = ( "    {{!--\n"
                "    <section class=\"article-comments gh-canvas\">\n"
                "        If you want to embed comments, this is a good place to paste your code!\n"
                "    </section>\n"
                "    --}}")

paths = glob("/var/www/ghost/versions/*/")

for path in paths:
        files.append((glob(path + 'content/themes/casper' + '/**/post.hbs', recursive=True))[0])

for file in files:
        with open(file, "r") as f:
                file_text = f.read()
                if 'disqus' in file_text:
                        print("Disqus already set in "+file)
                if not 'disqus' in file_text:
                        results = re.findall(test_string, file_text, re.MULTILINE)
                        if len(results) > 0:
                                print("Provisioing Disqus in "+file)
                                shutil.copy(file, file+'.bak')
                                with open("/home/ubuntu/disqus_universal.txt", "r") as disqus_universal:
                                        disqus_universal_text = disqus_universal.read()
                                        content_new = re.sub(test_string, disqus_universal_text, file_text, re.MULTILINE)
                                        with open(file, "w") as outfile:
                        if len(results) <= 0:
                                print("Error occured in file: "+file)
                                print("Disqus not found AND comments section not found")

The disqus_universal.txt file has changed only slightly, adding the <section> tags that are being found/replaced by the python script.

<section class="article-comments gh-canvas">
<div id="disqus_thread"></div>
    var disqus_config = function () {
        this.page.url = "{{url absolute="true"}}";
        this.page.identifier = "ghost-{{comment_id}}"
    (function() {
    var d = document, s = d.createElement('script');
    s.src = 'https://<YOURDISQUSSITE>.disqus.com/embed.js';
    s.setAttribute('data-timestamp', +new Date());
    (d.head || d.body).appendChild(s);
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>