WordPress is great for getting things up and running, but it's big and bloated and far from a finely honed solution to our specific problem.
The biggest one is that even when writing a custom theme with caching plugins enabled, WordPress will always love to hammer the database. It's easy to scale up servers, but it isn't cheap.
Enter Pelican, a Python-based static site generator. It will take Markdown source files of articles and pages and turn them into a fully static directory of HTML, CSS, JavaScript, and images. That way you'll at most need to set proper cache-control per-file and dick around an .htaccess file.
Pelican requires Python 3.9 or newer, but this was developed on 3.13.5.
It's recommended you use pyenv + pyenv-virtualenv (or similar) to manage versions. On macOS, for instance, this can be accomplished with the following (in addition to updating your .bash_profile).
$ brew update
$ brew install pyenv
$ brew install pyenv-virtualenv
$ pyenv install 3.13.5
$ pyenv virtualenv 3.13.5 blog
$ echo "blog" > .python-versionThat way the blog virtualenv will automatically activate whenever you navigate to the repo.
After that, then you can install the packages.
$ pip install -r requirements.txtThere are also front-end dependencies for the admin interface, for which you'll need Yarn.
$ yarn installWe do something a little different from Pelican's suggested usage in that we manually organize our content files.
Within the /content/ directory, you'll find a hierarchy that should be fairly logical. The highest folders are years, and those contain months, and those contain individual Markdown files.
├── content
│ ├── {{YEAR}}
│ │ ├── {{MONTH}}
│ │ │ ├── {{YEAR}}-{{MONTH}}-{{DAY}}-{{SLUG}}.html
│ │ │ └── ...
│ │ └── ...
│ └── ...
│ ├── images
│ └── pages
└── ...
This is so that when you crack open this repo in Sublime or ls it in your shell, they are at least ordered in some reasonable way.
This includes naming individual posts in the {{YEAR}}-{{MONTH}}-{{DAY}}-{{SLUG}}.html pattern.
Title: Some Sort of Review
Date: 2017-01-02T03:04:05+00:00
Modified: 2017-02-03T04:05:06+00:00
Category: Reviews
Subcategories: Movies
Tags: Movie Title, Movie Director, Lead Actor
Slug: some-sort-of-review
Authors: Firstname Lastname
Summary: Read all about it!
Featured: http://i.imgur.com/bF1gdy6.jpgA lot of the metadata should be self-explanatory. Title, Date, etc.
Author should be whatever the key value is in the AUTHORS dictionary in pelicanconf.py. This means that whenever there is a new author, a new item should be added to AUTHORS.
Featured is the main header image for the post, similar to the Featured Image in WordPress. It should be the absolute URL to the image.
Pelican supports only a single Category out of the box, so we have a custom attribute with Subcategories, which works a lot more like Tags in that it supports a comma-separated list of other categories. For that reason, here is the preferred structure.
NewsReviewsPreviewsFeaturesOpinion
MoviesVideo GamesTelevisionTechnology- Or whatever
Subcategories are completely optional, but you should upgrade the Subcategories value to the Category if there is nothing in Category you would use for your post.
Reviews require some special metadata to help populate structured data. This helps web crawlers find the information they need.
All reviews require the following.
- The first item in
Tagsshould be the product title Rating- a one-out-of-ten numerical value indicating the review scoreRelease- formatted date string for when the reviewed product was releasedWebsite- URL of product website (can be the Wikipedia page)
Genre- the film's genre; don't shorten names (i.e., "science fiction" instead of "sci-fi")Director- comma-separated if there are multiple directorsCast- just the leads or any substantially impactful supporting castDuration- use the ISO 8601 duration format (e.g.,PT1H30M)
Genre- using whatever Wikipedia lists is usually a safe betDeveloper- comma-separated if there are multiple studios involvedPublisher- make sure it's publishing arm if it's also a development studioDirector- we'll also take the lead designerPlayers- the player count the game allowsPlatforms- all available platforms at the time of review
Season- numerical season of the show being reviewedGenre- almost always choose to usesitcomovercomedyShowrunner- just for the season being reviewedCast- keep it to the regular castPlatforms- restrict it to the platforms it premiered on likeNetflixorHBO
We use the liquid_tags plugin.
When embedding images, you can use full-image as a class name to create a responsive image.
Go ahead and generate the content.
$ pelican content
$ ./node_modules/.bin/webpack --config webpack.config.jsAnd then launch a server.
$ pelican --listenSince this is all based on Markdown files being committed to this repository, new writers need to first acquire a GitHub account.
Then, that user needs to be added to the Working Mirror organization.
Finally, there's a big ol' AUTHORS dict in pelicanconf.py that contains all the required information for when we generate pages. It should follow this structure.
AUTHORS = {
'Lando Calrissian': {
'email': '[email protected]',
'bio': 'You can totally trust me.',
'twitter': 'lando',
'facebook': 'lando',
'instagram': 'lando',
'website': 'http://landocalrissian.com/',
},
}