How to Manage Common Resources Between Themes


When we redesigned all of the sites in the How to Ghost network, we wanted them to all use the same navigation bars, footer, and sidebar. The problem we were running into was if we made an update to the navbar, we would have to go through 5 different git repo's making the same commit over and over. Obviously this is inefficient and can cause problems, so we started using git submodules to house all the shared code so we would only have to update once.

Here is how you can setup and use git submodules to share code between your Ghost themes (this code assumes your themes are already using git):

All the code for our themes is located on GitHub if you would like examples of this in action

Initial Setup

  1. Create a new GitHub repo to house your shared code. Ours is called global-resources.
  2. Add some shared css, html, js, images, or whatever else to this repo and publish it.
  3. Now that the shared code is inside its own repo, head back over to your theme files

Add Submodule to Theme

  1. We need to add the new git repo to our theme as a submodule, so it can be updated independently and bring all the shared code in. To do that, run:

    git submodule add [link to github clone url of shared code]
    

    Ex.

    git submodule add git@github.com:howtoinstallghost/global-resources.git
    
  2. This will add all of the files of your submodule into its own folder inside your theme. For us it lives inside the global-resources folder.
  3. Since we just added the submodule, we need to commit this change to the theme:

    git add .
    git commit -m 'Adding global-resources as submodule'
    

Update Theme to Use Shared Code

  1. Since the shared code is now inside your submodule folder, you can remove the old files from your theme
  2. All the paths to that shared code have now changed. So, you will also need to go through your .hbs files to update the paths.

    Ex. you may need to change from this:

     <link rel="shortcut icon" href={{asset "icons/favicon.ico"}}>
    

    To something like this:

     <link rel="shortcut icon" href="/global-resources/icons/favicon.ico">
    

    We use sass to build our CSS file, so here is a good example of a file using both global and local assets

  3. Test to make sure your theme is linking to all the files correctly and functioning the way you want, and then commit your changes again.

First Update for Theme on Server

  1. Now we need to update the changes we made on the server running Ghost. Normally, if your theme is on GitHub, you just do a git pull, restart Ghost, and your done, but now, since all the code in the submodule is not local to your theme repo, we need to pull that in as well.
  2. Go ahead and cd to your theme directory on your server and do a git pull to pull in the new theme changes:

    cd /var/www/ghost/content/themes/yourtheme
    git pull
    
  3. Now, for the first time only, we need to initialize the submodule on the server:

    git submodule init
    git submodule update
    

    That will place all of the files into your global folder.

  4. Important Note: If you want to have partials files that live in your submodule, you will actually need to copy these from the submodule folder, into the partials folder so Ghost can render them as partials:

    cp global-resources/partials/* partials/.
    

    Now you are ready to restart Ghost and have your theme be using the new submodule you created

Updating Submodule

Now that your theme is using the submodule, if you want to make a change to this global code, the change needs to happen inside the submodule repo instead of your theme's repo.

Since the global code in your theme is not actually being stored there, any changes you make will be ignored. So, open up the files for the actual global submodule repo, make the changes there, and commit upto that repo.

Updating Theme with New Submodule Code

If you have updated your submodule, you now need to pull this new code into the Ghost theme on your server. Here are the commands to do that:

cd /var/www/ghost/content/themes/yourtheme
git pull
git submodule foreach git pull origin master
chown -R ghost:ghost ./*
cp global-resources/partials/* partials/.

git pull pulls in any new changes to your theme itself

git submodule foreach git pull origin master pulls in any new changes to the submodule

chown -R ghost:ghost ./* makes sure all new and updated files are owned by the ghost user. This may be different for you if you have a different user running Ghost (Ex. _www)

cp global-resources/partials/* partials/. is only needed if you have partials files inside your submodule that you want used by Ghost

Now you will have to restart Ghost.

Note: This will have to be done for each theme using the global resources after a submodule update. So, for us, if we make a change, we have to do this 5 times inside the theme folder for each site

Using Code Injection for Final Touches

One problem we ran into was that each of our sites has a different color scheme. We wanted the nav bar to highlight the site it was currenlty on and the footer to not show the current site in its 'other sites' section. So, how did we get around this? We used Ghost's code injection.

For the navigation bar and the site links in the footer, we gave each link its own HTML id. Then, in code injection, we added the styling for those specific links. So, we would make the current site have a color of white in the nav (instead of gray) and hide the current site in the 'other sites' on the footer. We would also change the colors of the nav bar and the sidebar to match the site it was on.

This was extremely useful and allowed us to add a ton more code to the submodule by keeping it generic and adding the final touches at the end through code injection.

Conclusion

While using submodules does seem a little tricky to get initially setup, it can save you so much time and headache if you are running multiple sites with similar code. I cannot tell you the number of times I would see a problem with the CSS, or a spelling error on something I had copied and pasted from one site to another and had to go to each repo updating it.

Hopefully this helped you out and saved you some time. We would love to know if this works for you, or if you have a different/better solution that you are using in the comments below.