Tips
****

Here are some tips about Pelican that you might find useful.


Custom 404 Pages
================

When a browser requests a resource that the web server cannot find,
the web server usually displays a generic "File not found" (404) error
page that can be stark and unsightly. One way to provide an error page
that matches the theme of your site is to create a custom 404 page
(*not* an article), such as this Markdown-formatted example stored in
"content/pages/404.md":

   Title: Not Found
   Status: hidden
   Save_as: 404.html

   The requested item could not be located. Perhaps you might want to check
   the [Archives](/archives.html)?

The next step is to configure your web server to display this custom
page instead of its default 404 page. For Nginx, add the following to
your configuration file's "location" block:

   error_page 404 /404.html;

For Apache:

   ErrorDocument 404 /404.html

For Amazon S3, first navigate to the "Static Site Hosting" menu in the
bucket settings on your AWS console. From there:

   Error Document: 404.html


Publishing to GitHub Pages
==========================

If you use GitHub for your Pelican site you can publish your site to
GitHub Pages for free. Your site will be published to
"https://<username>.github.io" if it's a user or organization site or
to "https://<username>.github.io/<repository>" if it's a project site.
It's also possible to use a custom domain with GitHub Pages.

There are two ways to publish a site to GitHub Pages:

1. **Publishing from a branch:** run "pelican" locally and push the
   output directory to a special branch of your GitHub repo. GitHub
   will then publish the contents of this branch to your GitHub Pages
   site.

2. **Publishing with a custom GitHub Actions workflow:** just push the
   source files of your Pelican site to your GitHub repo's default
   branch and have a custom GitHub Actions workflow run "pelican" for
   you to generate the output directory and publish it to your GitHub
   Pages site.  This way you don't need to run "pelican" locally. You
   can even edit your site's source files using GitHub's web interface
   and any changes that you commit will be published.


Publishing a Project Site to GitHub Pages from a Branch
-------------------------------------------------------

To publish a Pelican site as a Project Page you need to *push* the
content of the "output" dir generated by Pelican to a repository's
"gh-pages" branch on GitHub.

The excellent ghp-import, which can be installed with "pip", makes
this process really easy.

For example, if the source of your Pelican site is contained in a
GitHub repository, and if you want to publish that Pelican site in the
form of Project Pages to this repository, you can then use the
following:

   $ pelican content -o output -s pelicanconf.py
   $ ghp-import output -b gh-pages
   $ git push origin gh-pages

The "ghp-import output" command updates the local "gh-pages" branch
with the content of the "output" directory (creating the branch if it
doesn't already exist). The "git push origin gh-pages" command updates
the remote "gh-pages" branch, effectively publishing the Pelican site.

Note:

  The "github" target of the Makefile (and the "gh_pages" task of
  "tasks.py") created by the "pelican-quickstart" command publishes
  the Pelican site as Project Pages, as described above.


Publishing a User Site to GitHub Pages from a Branch
----------------------------------------------------

To publish a Pelican site in the form of User Pages, you need to
*push* the content of the "output" dir generated by Pelican to the
"main" branch of your "<username>.github.io" repository on GitHub.

Again, you can take advantage of "ghp-import":

   $ pelican content -o output -s pelicanconf.py
   $ ghp-import output -b gh-pages
   $ git push git@github.com:elemoine/elemoine.github.io.git gh-pages:main

The "git push" command pushes the local "gh-pages" branch (freshly
updated by the "ghp-import" command) to the "elemoine.github.io"
repository's "main" branch on GitHub.

Note:

  To publish your Pelican site as User Pages, feel free to adjust the
  "github" target of the Makefile.

Another option for publishing to User Pages is to generate the output
files in the root directory of the project.

For example, your main project folder is "<username>.github.io" and
you can create the Pelican project in a subdirectory called "Pelican".
Then from inside the "Pelican" folder you can run:

   $ pelican content -o .. -s pelicanconf.py

Now you can push the whole project "<username>.github.io" to the main
branch of your GitHub repository:

   $ git push origin main

(assuming origin is set to your remote repository).


Publishing to GitHub Pages Using a Custom GitHub Actions Workflow
-----------------------------------------------------------------

Pelican-powered sites can be published to GitHub Pages via a custom
workflow. To use it:

1. Enable GitHub Pages in your repo: go to **Settings → Pages** and
   choose **GitHub Actions** for the **Source** setting.

2. Commit a ".github/workflows/pelican.yml" file to your repo with
   these contents:

      name: Deploy to GitHub Pages
      on:
        push:
          branches: ["main"]
        workflow_dispatch:
      jobs:
        deploy:
          uses: "getpelican/pelican/.github/workflows/github_pages.yml@main"
          permissions:
            contents: "read"
            pages: "write"
            id-token: "write"
          with:
            settings: "publishconf.py"

   You may want to replace the "@main" with the ID of a specific
   commit in this repo in order to pin the version of the reusable
   workflow that you're using: "uses:
   getpelican/pelican/.github/workflows/github_pages.yml@<COMMIT_ID>".
   If you do this you might want to get Dependabot to send you
   automated pull requests to update that commit ID whenever new
   versions of this workflow are published, like so:

      # .github/dependabot.yml
      version: 2
      updates:
        - package-ecosystem: "github-actions"
          directory: "/"
          schedule:
            interval: "monthly"

   See GitHub's docs about using Dependabot to keep your actions up to
   date.

3. Go to the **Actions** tab in your repo
   ("https://github.com/<username>/<repository>/actions") and you
   should see a **Deploy to GitHub Pages** action running.

4. Once the action completes you should see your Pelican site deployed
   at your repo's GitHub Pages URL: "https://<username>.github.io" for
   a user or organization site or
   "https://<username>.github.io/<repository>>" for a project site.

Notes:

* You don't need to set "SITEURL" or "FEED_DOMAIN" in your Pelican
  settings: the workflow will set them correctly for you

* You don't need to commit your "--output" / "OUTPUT_PATH" directory
  ("output/") to git: the workflow will run "pelican" to build the
  output directory for you on GitHub Actions

See GitHub's docs about reusable workflows for more information.

A number of optional inputs can be added to the "with:" block when
calling the workflow, for example:

   with:
     settings: "publishconf.py"
     requirements: "pelican[markdown] typogrify"
     theme: "https://github.com/seanh/sidecar.git"
     python: "3.12"

Here's the complete list of workflow inputs:

+--------------------+------------+----------------------------------------------+----------+-----------------+
| Name               | Required   | Description                                  | Type     | Default         |
|====================|============|==============================================|==========|=================|
| "settings"         | Yes        | The path to your Pelican settings file       | string   |                 |
|                    |            | ("pelican"'s "--settings" option), for       |          |                 |
|                    |            | example: ""publishconf.py""                  |          |                 |
+--------------------+------------+----------------------------------------------+----------+-----------------+
| "requirements"     | No         | The Python requirements to install, for      | string   | ""pelican""     |
|                    |            | example to enable markdown and typogrify     |          |                 |
|                    |            | use: ""pelican[markdown] typogrify"" or if   |          |                 |
|                    |            | you have a requirements file: ""-r           |          |                 |
|                    |            | requirements.txt""                           |          |                 |
+--------------------+------------+----------------------------------------------+----------+-----------------+
| "output-path"      | No         | Where to output the generated files          | string   | ""output/""     |
|                    |            | ("pelican"'s "--output" option)              |          |                 |
+--------------------+------------+----------------------------------------------+----------+-----------------+
| "theme"            | No         | The GitHub repo URL of a custom theme to     | string   | """"            |
|                    |            | use, for example:                            |          |                 |
|                    |            | ""https://github.com/seanh/sidecar.git""     |          |                 |
+--------------------+------------+----------------------------------------------+----------+-----------------+
| "python"           | No         | The version of Python to use to build the    | string   | ""3.12""        |
|                    |            | site, for example: ""3.12"" (to use the most |          |                 |
|                    |            | recent version of Python 3.12, this is       |          |                 |
|                    |            | faster) or ""3.12.1"" (to use an exact       |          |                 |
|                    |            | version, slower)                             |          |                 |
+--------------------+------------+----------------------------------------------+----------+-----------------+
| "siteurl"          | No         | The base URL of your web site (Pelican's     | string   | The URL of your |
|                    |            | "SITEURL" setting). If not passed this will  |          | GitHub Pages    |
|                    |            | default to the URL of your GitHub Pages      |          | site.           |
|                    |            | site, which is correct in most cases.        |          |                 |
+--------------------+------------+----------------------------------------------+----------+-----------------+
| "feed_domain"      | No         | The domain to be prepended to feed URLs      | string   | The URL of your |
|                    |            | (Pelican's "FEED_DOMAIN" setting). If not    |          | GitHub Pages    |
|                    |            | passed this will default to the URL of your  |          | site.           |
|                    |            | GitHub Pages site, which is correct in most  |          |                 |
|                    |            | cases.                                       |          |                 |
+--------------------+------------+----------------------------------------------+----------+-----------------+
| "deploy"           | No         | This is used to determine whether you will   | bool     | "true"          |
|                    |            | deploy the site or not to GitHub Pages. This |          |                 |
|                    |            | is most useful if you want to test a change  |          |                 |
|                    |            | to your website in a pull request before     |          |                 |
|                    |            | deploying those change.                      |          |                 |
+--------------------+------------+----------------------------------------------+----------+-----------------+


Testing Your Build in a GitHub Pull Request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you want to test your build in a pull request before deploying to
GitHub, your workflow might look something like this:

   name: Build and Deploy Site
   on:
     push:
       branches: ["main"]
     pull_request:
       branches: ["main"]
     workflow_dispatch:
       inputs:
         deploy:
           required: false
           default: true
           description: "Whether to deploy the site. If checked, then build the site and deploy it. If not checked, then just test that the site builds successfully but don't deploy anything."
           type: boolean
   jobs:
     deploy:
       uses: "getpelican/pelican/.github/workflows/github_pages.yml@main"
       permissions:
         id-token: write
         contents: read
         pages: write
       with:
         settings: "publishconf.py"
         requirements: "-r requirements.txt"
         deploy: ${{ (github.event_name == 'workflow_dispatch' && inputs.deploy == true) || (github.event_name == 'push' && github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch) }}

The "on" section of the workflow defines the events that will trigger
the workflow. In this example, the workflow will run on pushes to the
main branch, pull requests to the main branch, and manual runs of the
workflow.

"workflow_dispatch" defines the deploy boolean to be true by default.
This means that if you run the workflow manually, it will deploy the
site.

The "deploy" input for the job is using a set of standard GitHub
workflow variables to control when "deploy" will either be true or
false (you can customize this to your needs).

In this example, the "deploy" will be true if the event is a push to
the main branch (or merging into main from a PR) or a manual run of
the workflow. If the event is a pull request, the "deploy" will be
false and it will only build an artifact for the site.


"Insecure content" warnings from browsers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If your site uses "https://" and is broken because the browser is
blocking network requests (for example for CSS files) due to "insecure
content" this may be because GitHub Pages is generating "http://" URLs
for your site.

To fix this go into your site repo's settings and enable the **Enforce
HTTPS** setting: go to **Settings → Pages** and check **Enforce
HTTPS**. Then re-run the workflow to re-deploy your site.
Alternatively, you can use the workflow's "siteurl" and "feed_domain"
settings.


Custom 404 Pages
----------------

GitHub Pages will display the custom 404 page described above, as
noted in the relevant GitHub docs.


Update your site on each commit
-------------------------------

To automatically update your Pelican site on each commit, you can
create a post-commit hook. For example, you can add the following to
".git/hooks/post-commit":

   pelican content -o output -s pelicanconf.py && ghp-import output && git push origin gh-pages


Copy static files to the root of your site
------------------------------------------

To use a custom domain with GitHub Pages, you need to put the domain
of your site (e.g., "blog.example.com") inside a "CNAME" file at the
root of your site. To do this, create the "content/extra/" directory
and add a "CNAME" file to it. Then use the "STATIC_PATHS" setting to
tell Pelican to copy this file to your output directory. For example:

   STATIC_PATHS = ['images', 'extra/CNAME']
   EXTRA_PATH_METADATA = {'extra/CNAME': {'path': 'CNAME'},}

Note: use forward slashes, "/", even on Windows.

You can also use the "EXTRA_PATH_METADATA" mechanism to place a
"favicon.ico" or "robots.txt" at the root of any site.


How to add YouTube or Vimeo Videos
==================================

The easiest way is to paste the embed code of the video from these
sites directly into your source content.

Alternatively, you can also use Pelican plugins like "liquid_tags",
"pelican_youtube", or "pelican_vimeo" to embed videos in your content.

Moreover, markup languages like reST and Markdown have plugins that
let you embed videos in the markup. You can use reST video directive
for reST or mdx_video plugin for Markdown.


Develop Locally Using SSL
=========================

Here's how you can set up your local pelican server to support SSL.

First, create a self-signed certificate and key using "openssl" (this
creates "cert.pem" and "key.pem"):

   $ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

And use this command to launch the server (the server starts within
your "output" directory):

   python -m pelican.server 8443 --key=../key.pem --cert=../cert.pem

If you are using "develop-server.sh",  add this to the top:

   CERT="$BASEDIR/cert.pem"
   KEY="$BASEDIR/key.pem"

and modify the "pelican.server" line as follows:

   $PY -m pelican.server $port --ssl --cert="$CERT" --key="$KEY" &
