Ditch Wordpress. Build Your Own CMS with Bash and Python!

Unless you absolutely love building websites, then the thought of building your next one can be discouraging.

There are very few good options out there.

Of course, you could follow the masses and build a WordPress website or utilize Wix.com. There is nothing wrong with that, and if you went that route, your website would function just fine without any issues.

But there’s always a catch.

No matter what sort of theme you pick, purchase, or utilize, all of them are a compromise. They never quite behave the way you want them to. It’s very hard to exact full control of your website when using one of these popular methods. That fact alone is enough to turn me off from utilizing WordPress ever again. But let’s look at some more important aspects.

By the time you add in four or five different plugins, your website load time is slow. Now let me explain what slow truly is. If a person who is trying to visit your website has to wait any amount of time, over a few milliseconds for your website to load, they may very well decide it’s not worth waiting for. People in today’s society are impatient and they have short attention spans.

Ideally, every single webpage on your website should be under 14 kb. That way when the first packets are sent to their browser, your page is fully loaded.

Well, there is really only one way to accomplish this. That is to build your website from pure HTML and CSS.

Before I built this website, I did not know any CSS. To be honest, learning CSS seemed like a daunting task. There was just so much of it. Of course, all the internet practitioners would encourage you to utilize Tailwind or some other framework. However, these frameworks are just as difficult to learn as the original vanilla CSS. So why wouldn’t you just go ahead and learn the original CSS and have full control over your site. That’s what I decided to do.

Now, if you utilize just HTML and CSS only, you are going to encounter two problems. First, If you change anything inside of your footer, then you must go to every single web page on your site and make that change manually again and again.

In order to solve this problem, you have to learn about PHP Includes. That way you can just simply change one piece of HTML code for your footer, and then that change will be cascaded across all of your website pages.

All right, so that’s the first problem solved. What about the second problem?

The second problem is this. How do you manage hundreds of webpages using only HTML and CSS? (and now a little php)

This requires some sort of content management system, also known as a CMS.

For those who can actually code their own website in HTML and CSS, there are many contact management system frameworks out there.

There is Ghost, 11ty, etc. These all require learning a new framework as well.

Something I really didn’t want to take the time to do.

I experimented with 11ty and saw how it functioned.

It became clear to me I could build the exact same thing using nothing more than Bash and Python.

So today I’m going to share with you exactly how this website is built and maintained.

How to Use BASH and Python to Build Your Own CMS

The basis of this system is truly built on markdown files. Every post starts as a markdown file. At the top of every markdown file is metadata. This metadata will be utilized by the bash scripts to create files and execute all sorts of other commands. The metadata at the beginning of each of my posts looks something like this.


           ---
           Title: 
           Author: Jonathan Adams
           Date: 
           Seo-Description: 
           Keywords: 
           ---
           

Once the post is written in markdown format, then two simple bash scripts are used to publish it on the website. Let’s have a look at the first one.

IMPORTANT NOTE --- Portions of this code will not display correctly on this WEB PAGE due to various factors. If you really want to see it; View this page using your developer tools in your browser. (Press F12)


           
            #!/bin/bash

            # Prompt the user for the filename
            read -p "Please enter the name of the markdown file you wish to post: " filename

            # Check if the file exists in the Markdown_Post_Files directory
            if [ -f "Markdown_Post_Files/$filename" ]; then
                echo "File found."
            else
                echo "File not found. Please check the filename and try again."
                exit 1
            fi

            # Extract metadata using grep and sed
            title=$(grep -oP '(?<=Title: ).*' "Markdown_Post_Files/$filename")
            author=$(grep -oP '(?<=Author: ).*' "Markdown_Post_Files/$filename")
            date=$(grep -oP '(?<=Date: ).*' "Markdown_Post_Files/$filename")
            seo_description=$(grep -oP '(?<=Seo-Description: ).*' "Markdown_Post_Files/$filename")
            keywords=$(grep -oP '(?<=Keywords: ).*' "Markdown_Post_Files/$filename")

            # Print the extracted metadata (for debugging purposes)
            echo "Title: $title"
            echo "Author: $author"
            echo "Date: $date"
            echo "SEO Description: $seo_description"
            echo "Keywords: $keywords"

            # Remove the .md extension from the filename
            html_filename="${filename%.md}.html"
            #php_filename="${filename%.md}.php"


            # Create a permalink from the title
            permalink=$(echo "$title" | tr '[:upper:]' '[:lower:]' | sed 's/ /-/g')

            # Prompt the user to accept the generated permalink or enter their own
            read -p "Do you accept this permalink: $permalink [Y/n] " confirm

            # Check the user's response and either use the generated permalink or prompt for a new one
            if [[ "$confirm" =~ ^[Yy]$ ]]; then
                echo "Using permalink: $permalink"
            else
                read -p "Please enter your own permalink: " custom_permalink
                permalink="$custom_permalink"
            fi

            # Add permalink full url to sitemap.txt file
            echo "https://jonathanadams.pro/blog-articles/"$permalink".php" >> public/sitemap.txt

            # Convert the Markdown file to HTML using Pandoc
            # (UNCOMMENT WHEN DONE)  
            pandoc -o "pandoc_html_files/$html_filename" --mathjax "Markdown_Post_Files/$filename"


            # Modify the 

tags in the HTML file using sed sed -i 's/

/

/g' "pandoc_html_files/$html_filename" # Modify the

  • tags in the HTML file using sed sed -i 's/
  • Obviously, there is a lot occurring in this Bash script. But as you take the time to go through it, you will see it’s really not all that complicated.

    The first step is to simply take the metadata and store it in variables to use in later commands. Next, you will see Pandoc utilized in order to convert the markdown format to HTML.

    You will also notice the script changing a bunch of file names. Nothing too complicated.

    Now where this Bash script really gets interesting is when it gets to the HERE document. This shell scripting technique allows you to utilize a different programming language inside of your shell script. It is denoted by EOF. I would encourage you to read up more on the HERE document. It is very powerful, and you can utilize more than simply just Python.

    Now you may be wondering if all I was doing is simply reading and writing to a file, why on Earth did I utilize Python and not the actual Bash script?

    Well the short answer is regular expressions. Due to the HTML code including so many special characters that are recognized as regular expressions in shell scripting; I was unable to complete this part of the code utilizing Bash. Therefore, I had to drag out the Python and put it in there.

    Now this Bash script only takes care of converting a markdown file into a blog post article and placing it in the correct folders. It still has done nothing in regards to actually publishing this file to your hosting server. But don’t worry, we have a shell script for that.

    Since my website is hosted on Hostinger, I can simply push these files into a GitHub repository and have a webhook on Hostinger grab the files whenever new items are sent to the repository.

    Would you like to see it? Of course you would!

    
               
                #!/bin/bash
    
                # Prompt the user for the git comment
                read -p "Please enter the comment you wish to have placed in the commit message: " comment
    
    
                git add .
                echo "Added all files to the local git folder"
    
                git commit -m "$comment"
    
                echo "Added the following message to the commit: $comment"
    
                git push -u origin master
    
                echo "Pushed a copy of the master branch to github"
    
                git subtree split --prefix public -b hostinger-deploy
    
                echo "Created subtree split"
    
                git push origin hostinger-deploy:hostinger --force
    
                echo "Pushed to hostinger branch"
    
                git branch -D hostinger-deploy
    
                echo "Deleted subtree split"
                echo "Done"
                echo "Visit site https://jonathanadams.pro"
    
    
               

    Having this Bash script at your disposal is very nice. It allows me to completely maintain my website on my local computer. I can make sure it looks exactly the way I want, making last many changes in the code as needed. Then when I’m certain it is perfect, I can simply publish it by running this Bash script. What’s even better is it actually produces a live copy in my GitHub repository. Even if my computer fails, my website is backed up.

    What Have We Learned Here Today?

    It is clear building websites is not part of data science. However, cleaning data certainly is. One of the most interesting parts of this little project is the fact you can utilize HERE documents inside of your shell scripts.

    Now you are no longer simply chained to Python when it comes time to clean your data. You can utilize sed, grep, awk, and then any other command inside the Python libraries you deem fit.

    This is very powerful, and you may find it very helpful for your needs in the future.

    Well, it looks like this post is almost done. I guess I better get ready to run these two scripts.

    Jonathan Adams

    September 17th, 2025