Added blog and social cards tutorials (#7014)

* added tutorials page and blog tutorial

* proof reading, some language improvements

* split blog tutorial into parts

and reworked on the basis of comments, improved language, added missing
things

* + custom slugify function example

* +blog tutorial on engagement

* + section blog ToC

* + instructions for X/FB share buttons and started discussion system

* fix: module name `code` shadowed Python standard library module

* added What's next section

* +blog tutorial engagement part

* fix: updated Giscus code snippet

* trying multiple tutorials with headings for each group

* + basic social cards tutorial

* + custom social card tutorial

* + estimated time for custom card tutorial

* added tutorial sections to nav

* fixed typos, removed sponsor icon from level one heading

* removed "tutorial" from level one heading

* added headings to custom layout example

* fixed broken link

* fixes after run-through, added links to template repos

* added comment for @squidfunk

* clarified use of logos, some proof-reading

* removed question I left for @squidfunk

* clarified relationship between background color and image

* added override for the background image

* fixed wording and indentation

* changed example to be releases, not events

* being more specific where to add the last bit of code in the layout

---------

Co-authored-by: squidfunk <martin.donath@squidfunk.com>
This commit is contained in:
Alexander Voss 2024-05-28 13:21:00 +02:00 committed by GitHub
parent c8ee11ff2b
commit 50d7c54bdf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 1682 additions and 0 deletions

View File

@ -0,0 +1,375 @@
# Basic blogs
Blogs are a great way to engage with your audience. Software developers can use
a blog to announce new features, demonstrate their usage and provide background
information. You can demonstrate competence by commenting on the state of the
art or document your own work as best practice. Posts on current topics can help
draw in visitors for your main website and can keep your audience engaged. Of
course, you can blog about any topics close to your heart.
The [blog plugin] makes running a blog alongside your other content easy but you
can also configure it to run a stand-alone blog if posts are the only kind
of content you need.
After a brief overview of the basic concepts of a blog, this tutorial guides you
through the process of configuring the [blog plugin], setting up your blog,
creating posts, and defining post metadata.
[blog plugin]: ../../plugins/blog.md
__Time required:__ typically 20 minutes
## Key concepts
**Post, excerpt**: a blog consists of a number of self-contained _posts_ (often called
articles) and an index page that shows the posts in reverse chronological order, with
the most recent post at the top. The index page usually shows only a short _excerpt_ and a
link that the user can click to navigate to the full post.
**Metadata**: both the index page and the post itself list information such as
when you published the post, when you updated it, who the author is, and what the
expected reading time is.
**Slug**: since the blog posts are primarily arranged by time and not into a hierarchy,
their URLs do not reflect such a structure. Instead, each post's URL
contains a shortened description, the _slug_, which is usually derived from
the first heading in the post.
**Navigation**: the main navigation structure is the timeline, which you can
subdivide into _categories_. The main index page shows the more recent posts
while an _archive_ section allows access to older ones, organized by year.
In addition, posts can be _tagged_ and _tag index pages_ provide an additional
navigation structure based on content.
You can see all these elements on the [Material for MkDocs blog].
[Material for MkDocs blog]: https://squidfunk.github.io/mkdocs-material/blog/
## Setting up your blog
The blog plugin is part of Material for MkDocs but you need to configure it
in the `mkdocs.yml`.
!!! example "Set up a blog"
If you have not done so already, create a project for your blog,
then edit the `mkdocs.yml` file to make sure if has the following content:
```yaml
site_name: Blog Tutorial
site_description: an example blog set up following the tutorial
site_url: http://www.example.com
theme:
name: material
plugins:
- search
- blog
```
The blog plugin will create a directory structure for your blog posts if it
does not exist, so simply run `mkdocs serve` to get:
```
docs
├── blog
│   ├── index.md
│   └── posts
└── index.md
```
Now create your first blog post in `docs/blog/posts`. You can use any
naming convention and directory structure you like for your posts, as long as
they are inside `docs/blog/posts`.
Each post _must_ have a page header, which appears at the top of the Markdown
code between lines with three dashes. Within this header, you need to have at
least a `date` entry but you can add other data, as you will see below.
Following the header comes the page content. Note that it is important
to have a level one heading as the plugin uses it to produce the _slug_. Also,
by adding `<!-- more -->` to the page, you can define where the excerpt will end
that the index page shows.
!!! example "Write your first post"
Create a file `docs/blog/posts/myfirst.md` with the following contents:
```
---
date:
created: 2023-12-31
---
# Happy new years eve!
We hope you are all having fun and wish you all the best for the new year!
<!-- more -->
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.
```
Then, run `mkdocs serve` and point your web browser at
`http://localhost:8000/blog`.
The blog plugin automatically creates navigation elements for
the blog. The index page shows only the extract. When you select the
"Continue reading" link, you will get to the full blog post. Note how it
has a URL generated from the first-level heading.
!!! tip "Navigation"
We also have a [tutorial on navigation] that shows you how to change the
automatically created navigation and integrate the blog into your existing
navigation structure. It shows how to create secondary nagigation, produce
author pages, and control pagination.
[tutorial on navigation]: navigation.md
## Post metadata
In addition to the date, you can provide other metadata and give the plugin
instructions, such as to treat a post as a draft or to pin it.
### Drafts
You may want to produce a draft of a blog post and work with it locally but
exclude it from the build that you publish. Simply add a field to the page
header to indicate that a post is still in draft form.
!!! example "Create a draft"
Create a second blog post in `docs/blogs/posts/draft.md` with the following
contents:
```hl_lines="3"
---
date:
created: 2024-01-01
draft: true
---
# Happy new year!
Happy 2024 to everyone. Wishing you all the best!
<!-- more -->
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.
```
Now, note how the draft appears on the index page but with a label that
indicates that it is a draft. When you run `mkdocs build`, the draft will
_not_ appear in the output:
```
$ mkdocs build
$ ls site/blog
site/blog
├── 2023
│   └── 12
│   └── 31
│   └── happy-new-years-eve
│   └── index.html
...
```
The first blog post for 2024 is not there yet because it is still in draft
stage. Remember to remove the `draft` setting in the header when it is time
to publish it.
If you are using the [Insiders Edition], you can also create
a folder to keep your drafts in and use the [Meta plugin] to add the
`draft` header setting to all the posts in that folder. This has the advantage
that it is easier to see which posts are still in draft form. We will cover the
Meta plugin later on.
[Meta plugin]: ../../plugins/meta.md
### Edits
Sometimes, bloggers need to update a post. This might happen when you make
a mistake or when something changes that you need to reflect in the post. To
indicate you have edited a post, you can include an `updated` date in the page
header.
!!! example "Editing a post"
Make a change to your first blog post, then add an edit date to the header:
```hl_lines="3 4"
---
date:
created: 2023-12-31
updated: 2024-01-02
---
```
The Metadata section of the blog post itself will contain the edit date,
though the index page omits this detail by default.
### Reading time
To give the reader some idea of how long it might take them to read a post,
a read time is automatically calculated. If you want to override this, you can
do so in the page header by specifying the number of minutes you estimate
your readers will take the read the post.
!!! example "Overriding the reading time"
Add a reading time override to your first blog post:
```hl_lines="5"
---
date:
created: 2023-12-31
updated: 2024-01-02
readtime: 15
---
```
### Pinning
Sometimes, blog authors want to 'pin' a specific post so that it will always
appear at the top of the index page, no matter what else gets published. If you
are using the [Insiders Edition], you can achieve this by adding the `pin`
attribute in the page header:
!!! example "Pin a post <!-- md:sponsors -->"
Add the `pin` attribute to your first blog post:
```hl_lines="5"
---
date:
created: 2023-12-31
updated: 2024-01-02
readtime: 15
pin: true
---
```
Observe how this makes the post appear on top of the index page even though
its publication date is prior to other posts. A small pin icon shows that the
post has been pinned.
### Related links <!-- md:sponsors -->
When your blog is part of a wider site such as technical documentation, you
will want to provide links from blog posts into your other content. One way you
can do this is to have a related links section. In the [Insiders Edition], the
blog plugin can create one for you if you provide link targets in your page
header:
!!! example "Add a related links section <!-- md:sponsors -->"
Add the following to a blog post:
``` hl_lines="5-7"
---
date:
created: 2023-12-31
...
links:
- index.md
- blog/index.md
---
```
The related links appear underneath the Metadata section.
The nice thing here is that you do not need to provide a page title. The plugin
will deduce the link text by applying the same logic that MkDocs uses for the
main navigation. In fact, the syntax is the same as that of the `nav` section
in the `mkdocs.yml`, so you can override the title if you want and even define
subsections:
!!! example "Override the page titles"
Change the link section to override the page titles:
```hl_lines="6-9"
---
date:
created: 2023-12-31
...
links:
- Homepage: index.md
- Blog index: blog/index.md
- External links:
- Material documentation: https://squidfunk.github.io/mkdocs-material
---
```
The plugin renders related links in the left sidebar on screens that are wide
enough and at the bottom of the post on narrow screens. Change the size of your
browser window to see this in action.
## Meta plugin <!-- md:sponsors -->
The Meta plugin is available in the [Insiders Edition].
It helps simplify the management of metadata that is common to a group of
files in the same subdirectory. Instead of having to repeat the
same metadata in the page headers of a number of files, you can add a
`.meta.yml` file in the directory and the Meta plugin will merge its contents
into the headers of all the pages contained.
Settings from the page header take precedence, so you can always override
settings by adding them to a post's header.
For example, you may want to manage drafts by keeping them in a directory
together so that they are not only flagged as drafts but also easier to find.
(Otherwise, you would need to inspect the page headers or trace back from the
output to the files to figure out which posts are drafts.)
!!! example "Drafts using the Meta plugin <!-- md:sponsors -->"
You first need to activate the plugin in your `mkdocs.yaml`:
```yaml hl_lines="4"
plugins:
- search
- blog
- meta
```
Now create the folder for the drafts:
=== "MacOS/Linux"
```bash
$ mkdir docs/blog/posts/drafts
```
=== "Windows"
TODO
Now, within this folder, crate a file `.meta.yml` that contains:
```yaml
draft: true
```
Add another blog post and store it in `docs/blog/posts/drafts`. When you
look at it locally, you will see the label that identifies it as a draft,
while in the version built for publication it does not appear. To move a
post from draft status to published, simply move it outside `drafts/`.
[Insiders Edition]: ../../insiders/index.md
## What's next?
You should now have a working blog. However, as it accumulates content, you
may want to make sure that people can find posts they are interested in, so
you may want to add secondary navigation with tags and categories. You may
have more than one author and want to attribute posts to them as well as
generate author pages for them. We have a [tutorial on navigation, pagination,
and authors] that covers these topics.
[tutorial on navigation, pagination, and authors]: navigation.md
You may want to increase engagement with your blog by allowing people to
subscribe to an RSS feed or by setting up a comment system. The [engagement
and dissemination tutorial] walks you through setting these up.
[engagement and dissemination tutorial]: engage.md

View File

@ -0,0 +1,369 @@
# Engagement and dissemination
You can foster reader engagement and improve the dissemination of content
on your blog by providing an RSS feed that people can subscribe to and by
integrating a discussion system. To learn more about who is or is not reading
your posts, you may want to integrate an analytics system. You may also want
to post on social media when you public a new blog post. This tutorial gives
you a leg up on all of these topics.
__Time required:__ typically 30 minutes
## RSS feeds
An _RSS feed_ allows users to subscribe to a blog so that they get notified when
you publish new posts. RSS Feed readers are often used to access blogs that a
user follows. They usually support downloading the blog content for offline
consumption.
An easy way to create an RSS feed for your blog is to use the
[MkDocs RSS Plugin], which is well integrated with Material for MkDocs.
Since it is a third-party plugin, you need to install it before using it.
[MkDocs RSS Plugin]: https://guts.github.io/mkdocs-rss-plugin
!!! example "Add an RSS feed"
Install the RSS plugin into your project:
```
$ pip install mkdocs-rss-plugin
```
It is important that have the `site_name`, `site_description` and
`site_url` settings configured as [instructed in the basic blog tutorial].
The RSS plugin makes use of this information to construct the feed, so make
sure you have configured them.
[instructed in the basic blog tutorial]: basic.md#setting-up-your-blog
Now, configure the plugin in the `mkdocs.yml`. The options provided restrict
the pages that RSS entries are created for to the blog posts, which is
probably what you want. Also note the configuration of the date fields to
match the format that Material for MkDocs uses to accommodate both a
creation date and a date for updates.
```yaml hl_lines="9"
plugins:
- ...
- rss:
match_path: "blog/posts/.*"
date_from_meta:
as_creation: date.created
as_update: date.updated
```
Have a look at http://localhost:8000/feed_rss_created.xml to see the RSS
feed in all its XML glory. You can use a browser like Firefox or Chrome that
can display the raw RSS feed or use `curl` to get the feed and `xmllint` to
format it. (You may need to install these tools.)
```
curl -s http://localhost:8000/feed_rss_created.xml | xmllint --format -
```
You may also want to try your feed with a feed reader. There are various desktop
and mobile apps as well as online services. Of course, to use the latter you
will need to deploy your project somewhere that is accessible to them.
This minimal configuration should work well if you have not made any changes
to the default configuration of the blog plugin. For more information on adapting
the feed to your needs, see [the RSS plugin's documentation].
[the RSS plugin's documentation]: https://guts.github.io/mkdocs-rss-plugin/
## Social media buttons
Social media buttons can serve two purposes: to allow your readers to navigate
to your social media profiles or to share content you have published via their
own accounts.
### Profile links
Links to social media profiles a usually provided in the footer of pages and
Material for MkDocs makes this easy. All you need to do is to provide the
necessary links and define the icons to use.
!!! example "Adding social media profile links"
Add an `extra` section to your `mkdocs.yml` and, within it, a `social`
section to contain a list of link definitions. These consist of the logo
to use and the link to the profile.
```yaml
extra:
social:
- icon: fontawesome/brands/mastodon
name: squidfunk on Mastodon
link: https://fosstodon.org/@squidfunk
```
For the `icon`, you can choose any valid path to an icon bundled with the
theme. The `name` will be used as the title attribute for the icon and
including this improves accessibility.
For popular social media systems, the link needs to be absolute and
needs to include the scheme, most likely `https://`.
You can also use other schemes. For example, to cerate an icon that allows
people to create an email, add this:
```yaml
extra:
social:
- icon: /fontawesome/regular/envelope
name: send me an email
link: mailto:<email-address>
```
Finally, you can specify a URL within your site, such as to your contact
page. It is possible to specify only the path to the page:
```yaml
extra:
social:
- icon: /material/mailbox
name: contact us
link: /contact
```
### Share and like buttons
Adding buttons that let people share your content on social media is a bit
more involved, which is why there are companies offering components for this.
!!! tip "Data Protection"
"Share" and "Like" buttons that use integrations provided by social media
companies often leave copious data traces even when the user does not
interact with these buttons. If you choose to integate such feature on
your site please be aware of the data protection implications and your
duties as a provider to ensure that processing occurs only once the user
has granted consent.
This implementation of share buttons deliberately does not use third party code.
It supports sharing to Twitter/X and Facebook without causing a data flow to
these companies whenever someone views the pages. Only when someone clicks a
share button will there be interactions with those companies' servers.
!!! example "Add share buttons"
In order to add the share buttons, you can add a hook that appends buttons
for sharing the current page.
Create a directory `hooks` in your project root and configure it
in your `mkdocs.yml`:
```yaml
hooks:
- hooks/socialmedia.py
```
Add the file `hooks/socialmedia.py` with the following Python code:
```python
from textwrap import dedent
import urllib.parse
import re
x_intent = "https://twitter.com/intent/tweet"
fb_sharer = "https://www.facebook.com/sharer/sharer.php"
include = re.compile(r"blog/[1-9].*")
def on_page_markdown(markdown, **kwargs):
page = kwargs['page']
config = kwargs['config']
if not include.match(page.url):
return markdown
page_url = config.site_url+page.url
page_title = urllib.parse.quote(page.title+'\n')
return markdown + dedent(f"""
[Share on :simple-x:]({x_intent}?text={page_title}&url={page_url}){{ .md-button }}
[Share on :simple-facebook:]({fb_sharer}?u={page_url}){{ .md-button }}
""")
```
The hook first checks if the current page is a blog post and then appends
Markdown code for the share buttons. The buttons use icons, so you also need
to configure the following markdown extensions:
```yaml
markdown_extensions:
- attr_list
- pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
```
## Add a discussion system
Allowing your readers to comment on your posts is a great way of receiving
feedback, learning something, as well as giving readers the opportunity to
discuss the content and the topic it is about.
There are plenty of discussion system out there and you will need to consider
your audience when choosing one appropriate for your blog. Likewise, you will
also need to consider existing commitments to communication channels. If you
are a heavy user Slack, for example, you may have a string preference for this
system. Consider that when you add a communication channel, you will need to
be prepared to use it regularly and to moderate discussions.
### Giscus integration
In this tutorial, we will be using [Giscus] because it is free, open source,
and uses [GitHub Discussions] as a backend. Because a lot of users of Material
for MkDocs use GitHub, this seems like an obvious choice.
[Giscus]: https://giscus.app/
[GitHub Discussions]: https://docs.github.com/en/discussions
To add Giscuss to your blog you will need to go through a number of steps:
1. Create a GitHub repository if there is not already one
2. Turn on discussions and install the [Giscus app]
3. Configure the code needed to embed Giscus into your blog
4. Add the code to your MkDocs project
[Giscus app]: https://github.com/apps/giscus
You may want to create a test repository for this tutorial that you can
scrap later on. The instructions below assume that you are user "example"
and that you create a repository "giscus-test." The repository will need
to be public for people to be able to use the discussions.
In the instructions given below, you will need to replace at least the username
but also the repository name if you chose another name such as when you
want to work directly on an existing repository.
!!! example "Turn on discussions and install the Giscus app"
Once the repository is set up, go to its settings page and find
`Features` in the `General` section. Tick the checkbox for `Discussions`.
You will see that `Discussions` appears in the top navigation for the
repository. If you are using a live repository then you may want to add some
minimal content to the dicussions section at this point and come back to the
tutorial.
Next, you need to install the [Giscus app] by following the link in this
sentence, and choosing `Install`, then following the instructions to choose
where the Giscus app is to be installed:
1. Choose the account or organization for the repository you want to use.
2. Choose to install only on select repositories and select the one you
want to use. Note that you can choose more than one repository here.
3. Select `Install` at the end. You may need to authenticate to give
permission for this to happen.
4. You will end up on the `Applications` page in your settings, where you
can control the Gicsus app and uninstall it if so desired.
That is all the preparation you will need for the repository. Next, it is time
to generate a piece of code that embeds Giscuss in your site. The resulting code
snippet will look something like this:
```html
<script src="https://giscus.app/client.js"
data-repo="<username>/<repository>"
data-repo-id="..."
data-category="Announcements"
data-category-id="..."
data-mapping="title"
data-strict="1"
data-reactions-enabled="1"
data-emit-metadata="1"
data-input-position="top"
data-theme="preferred_color_scheme"
data-lang="en"
data-loading="lazy"
crossorigin="anonymous"
async>
</script>
```
!!! example "Configure the code needed to embed Giscus into your blog"
Go to the [Giscus homepage] and configure the embedding code. There are a
number of settings:
1. Choose the language
2. Enter the username / organization name and repository name
3. Choose how the discussions are to be mapped to the page on your blog.
Because for a blog post the title is the basis of the URL, it makes
sense to use the `Discussion title contains page <title>` option.
4. Under `Discussion Category` choose `Announcements` to limit the creation
of new discussions to Giscuss and people with maintainer or admin
permissions.
5. Under `Features`, select the following:
1. Enable reactions for the main post
2. Emit discussion metadata
3. Place the comment box above the comments
6. Under `Theme`, select `Preferred color scheme` so that Giscus matches
the color scheme selected by the user for your site.
[Giscus homepage]: https://giscus.app/
With these settings in place, you now need to integrate the code into your
site. There is a partial `partials/comments.html` that exists for this purpose
and is empty be default. It is included by the `content.html` partial, so will
be included for every page on your site. You may or may not want this. In this
tutorial, you will limit the Giscus integration to only blog posts but it is
easy enough to leave out the code that achieves this if you want to have Giscus
discussions active for every page.
!!! example "Add Giscus integration code"
First, you need to create an `overrides` directory that will contain the
templates and partials you want to override.
```
mkdir -p overrides/partials
```
You need to declare it in your `mkdocs.yaml`:
```yaml hl_lines="3"
theme:
name: material
custom_dir: overrides
```
Now add a file `overrides/partials/comments.html` and paste in the code
snippet you obtained from the Giscus homepage. Look at the result locally
and you will see that the integration is active on all pages of the site.
If you want to restrict it to your blog posts, you need to add a conditional
around the Giscus script that tests if comments should be included. A simple
way of doing this is to test for a metadata flag:
```html
{% if page.meta.comments %}
<script>...</script>
{% endif %}
```
The disadvantage is that you now need to manually turn on comments for each
blog post - unless you want to turn them off on some. To get the comments
section on all blog posts, use code like this:
```html
{% if page.file.src_uri.startswith('blog/posts') %}
<script>...</script>
{% endif %}
```
You should see now that the Giscus comments are added at the bottom of your
blog posts but not on other pages.
## What's next?
This is the end of the blog tutorial. We hope you have enjoyed it and manage to
set up your blog the way you like it. There are numerous other features and
options that we have not been able to cover here. The [blog plugin reference]
provides comprehensive documentation for the plugin. You may also want to
look at the [social plugin tutorial] to generate social cards for your blog
posts that get displayed when you post links to social media systems.
[blog plugin reference]: https://squidfunk.github.io/mkdocs-material/plugins/blog/
[social plugin tutorial]: ../social/basic.md

View File

@ -0,0 +1,525 @@
# Navigation, authors, and pagination
The Blog plugin provides blog-style navigation with a reverse-chronological
index page and an archive organized by year by default. This tutorial shows
how you can configure details of the default navigation, configure authors, and
add more navigation options using categories and the [Tags plugin].
[Tags plugin]: ../../plugins/tags.md
__Time required:__ typically 30 minutes
## Integrating navigation
So far, you have let the Blog plugin and MkDocs worry about navigation. For some
use cases, this might be enough and it is simply sufficient to not declare a
`nav` section in the `mkdocs.yml`.
However, you may want to integrate a blog with other content and a navigation
structure that you have defined in the `nav` section of the configuration.
In such cases, you need to provide a place where the Blog plugin should
attach the blog navigation to the rest of the navigation structure.
!!! example "Integrate with site navigation"
Add the following to your `mkdocs.yml` to see how the Blog plugin can
integrate the blog navigation with the overall navigation structure.
Note that the only thing you need to specify at this point is the
index page for the blog and its path must match the `blog_dir` setting,
which is `blog` by default:
```yaml hl_lines="5 6"
nav:
- Home: index.md
- Install: install.md
- Usage: usage.md
- Blog:
- blog/index.md
```
You will notice that "Blog" is duplicated in the navigation structure. To
avoid this, you can use the `navigation.indexes` feature to make the blog
index the seciton index page for the blog:
```yaml hl_lines="3 4"
theme:
name: material
features:
- navigation.indexes
```
!!! tip "Stand-alone blog"
If what you need is a stand-alone blog instead of one that is integrated with
a larger site, this can be done by using the `blog_dir` configuration option.
To see how this is done, see [setting up a blog].
The rest of the tutorial assumes that you are integrating the blog with
a wider site.
[Setting up a blog]: ../../setup/setting-up-a-blog.md#blog-only
!!! tip "Adding pages"
You can add additional pages to the blog section by putting them into
`docs/blog` (and adding them to the navigation). The blog archive will be
added to the navigation after these pages.
## Configuring the archive
By default, the blog archive lists posts by year only. If you want to add
listings by month, you can configure the date format for the archive.
!!! example "Organize posts by month"
Add the following to your `mkdocs.yml` to get a listing with the month
name (in the language selected in the theme options):
```yaml hl_lines="2"
- blog:
archive_date_format: MMMM yyyy
```
If you do not want the full month name, you can make the the date
configuration `MM/yyyy`, for example.
If you want to add the day, you can add a placeholder for them.
For example, to get an American-style output, make it `MM/dd/yyyy`.
For the plugin to sort the blog posts by the full date, you will
also need to set the `archive_url_date_format` to include the month
and day, so make it `MM/dd/yyyy` as well.
## Using categories
Categories are a way to make blog posts accessible by topic while retaining
the navigation structure based on chronology within each category listing.
Use them when there is a limited set of non-overlapping categories that
you can sort your posts into.
Categories appear in the main navigation, so are directly accessible from there.
This implies that there are relatively few categories as otherwise the
`categories` section in your main navigation will become too crowded.
!!! example "Add a category"
Add a category to your first blog post by adding it to the page header:
``` hl_lines="4 5""
---
date: 2023-12-31
updated: 2024-01-02
categories:
- Holidays
---
```
Now that the blog post has been categorised, `Holidays` appears under
`Categories` in the main navigation and the blog post appears in the
index page for this category.
!!! tip "Single or multiple categories?"
While it is traditionally the case that a blog post would belong to only
one category, Material for MkDocs actually allows you to assign more
than one. While this gives you a degree of freedom, you should
probably not use this too much, not least because you can use tags to
deal with multiple classifications. We will cover them in the next step.
Material allows you to control which categories blog authors can use. You
declare them in the `mkdocs.yml`. This way you can make sure everyone sticks
to agreed categories and that the plugin detects typos.
!!! example "Control your categories"
Add a `categories_allowed` entry to the configuration of the Blog plugin
with the entries "Holidays" and "News":
```yaml hl_lines="5-7"
plugins:
- search
- blog:
archive_date_format: MMMM yyyy
categories_allowed:
- Holidays
- News
```
Now, when you add a category to a blog post that does not match one of these
two, you should get a build error.
## Using tags
The [Tags plugin] provides another way to classify blog posts and to make
them accessible independently of the main navigation structure. Tags are useful
for making related content easily discoverable even if it is in different parts
of the navigation hierarchy.
[Tags plugin]: https://squidfunk.github.io/mkdocs-material/plugins/tags/
You may have a tutorial like this one as well as a more comprehensive setup guide
and reference documentation. Adding the same tag to all three shows that they
are related. As you will see, it is possible to navigate from a tagged page to
the tag index and, from there, to other pages that carry the same tag.
!!! example "Enable the plugin and add tags"
First, you need to add the plugin to your `mkdocs.yml`:
```yaml hl_lines="8"
plugins:
- search
- blog:
archive_date_format: MMMM yyyy
categories_allowed:
- Holidays
- News
- tags
```
Once this is done, you can add tags to posts in the page header:
``` hl_lines="9-12""
---
date:
created: 2023-12-31
updated: 2024-01-02
authors:
- material
categories:
- Holidays
tags:
- new year
- hogmanay
- festive season
---
```
You should see the tags that you defined at the top of the post. However, at the
moment that is it. While the blog plugin automatically creates an index page for
categories, the tags plugin does not do the same for tags. This is because the
tags plugin is not specific for blogs. You can use it for any site content, so
it is not obvious were the tag index should go.
You can configure a basic tag index using the public version of Material for
MkDocs. The Insider Edition supports this as well, of course, but also provides
an alternative index mechanism that allows for an arbitrary number of tag
indexes, scoped listings, shadow tags, nested tags, and much more.
!!! example "Adding a tags index"
=== "Basic tag index"
To configure a tag index using the public version, add a `tags_file` entry
to your configuration of the tags plugin and configure it in your `nav`
section. Remember to add a colon at the end of the existing `tags` entry.
```yaml hl_lines="8-9 17"
plugins:
- search
- blog:
archive_date_format: MMMM yyyy
categories_allowed:
- Holidays
- News
- tags:
tags_file: blog/tags.md
nav:
- Home: index.md
- Install: install.md
- Usage: usage.md
- Blog:
- blog/index.md
Tags: blog/tags.md
```
The tag index will be appended to the configured page, which you should
now create at the location specified.
Note that you can put the tag index page anywhere in your primary
navigation, so if you are using tags elsewhere instead of just in your
blog then you may want to have the tag index outside the blog section
of the navigation.
=== "Insider Edition"
To add a tag index, you add a placeholder in a Markdown file to tell
the plugin to insert an index at that point. This means that you
can add content before and after the index. Crucially, you can add
placeholders in multiple pages, each with a configuration of what
subset of tags should be displayed in the index.
The simplest index page looks like this. Create it under `docs/tags.md`.
```markdown
# Tag index
<!-- material/tags -->
```
Now, you may want to keep the tags for your blog separate from tags
you use in the rest of your page. You can achieve this by assigning
the tag index a scope. Put the following under `docs/blog/tags.md`:
```markdown
# Tag index for the blog
<!-- material/tags { scope: true } -->
```
You now have two index pages: one covers the whole site and one
covers only the blog. Add both to the navigation:
```yaml
nav:
- Home: index.md
- Tags: tags.md
- Blog:
- blog/index.md
- blog/tags.md
```
The tags plugin in the Insider Edition is an incredibly powerful tool
and we can only scratch the surface of what is possible with it. If you
want to explore more after you have worked for this part of the tutorial,
have a look at the [tags plugin reference].
[tags plugin reference]: ../../plugins/tags.md
## Defining authors
If your blog has more than one author then you may want to identify the author
for each blog post. The blog plugin allows you to create a file that contains
the author information and to then reference the authors of a particular post in
the page header.
!!! example "Create author info"
Create a file `docs/blog/.authors.yml` with this content:
```yaml
authors:
team:
name: Team
description: Creator
avatar: https://simpleicons.org/icons/materialformkdocs.svg
squidfunk:
name: Martin Donath
description: Creator
avatar: https://github.com/squidfunk.png
```
and then add a line to the header of the first post:
```hl_lines="5-6"
---
date:
created: 2023-12-31
updated: 2024-01-02
authors:
- team
---
```
Note that `authors` is a list, so you can specify multiple authors.
With the Insiders edition, you can create custom author index pages that
can highlight the contributions of an author as well as provide additional
information about them.
!!! example "Add author page <!-- md:sponsors -->"
First, you need to enable author profiles in the `mkdocs.yml`:
```yaml hl_lines="8"
plugins:
- search
- blog:
archive_date_format: MMMM yyyy
categories_allowed:
- Holidays
- News
authors_profiles: true
```
Check your blog to see that there is now an extra entry in the main
navigation next to `archive` and `categories` that lists the authors and
their contributions.
To customize the author page, you can create a page that overrides the one
generated by default. First, create the `author` directory that the profile
pages will live in:
```hl_lines="3"
docs
├── blog
│   ├── author
│   ├── index.md
│   └── posts
│   ├── draft.md
│   └── myfirst.md
└── index.md
```
Then create a page `docs/blog/author/team.md`:
```
# The Material Team
A small group of people dedicated to making writing documentation easy, if
not outright fun! Here are some of the things we have blogged about:
```
As you can see, the author index gets appended to the content you have
written in the Markdown file.
## Pagination
Once your blog starts growing, you may not want to pay attention to the number
of posts displayed per page. By default, the plugin displays up to 10 posts on
the index pages. You can change this number separately for the main index,
the archive index pages, and the category index pages.
!!! example "Changing pagination"
Add five more blog posts, then set the pagination setting to show five per
page only:
```yaml hl_lines="7"
- blog:
archive_date_format: MMMM yyyy
categories_allowed:
- Holidays
- News
authors_profiles: true
pagination_per_page: 5
```
You will see that the pagination setting for archive and category pages
are inherited from the setting you added. If you want to have different
settings for the different index pages, you can specify each setting
separately:
```yaml
- blog:
archive_date_format: MMMM yyyy
categories_allowed:
- Holidays
- News
authors_profiles: true
pagination_per_page: 5
archive_pagination_per_page: 10
categories_pagination_per_page: 10
```
## Blog table of contents
Another thing you may want to do once you have a large enough number of posts
is to turn on the function that produces a table of contents for the blog
index pages, giving your readers the opportunity to quickly scan the content
of each page for something that interests them without having to scroll
(assuming that the number of post per page is not too big).
!!! example "Turn on the table of contents feature"
To produce a table of contents for the blog index pages, add the following
to the configuration of the blog plugin:
```yaml hl_lines="2"
- blog:
blog_toc: true
archive_date_format: MMMM yyyy
# ...
```
## Custom slugs
If, for some reason, you are not happy with the way that Material for MkDocs
turns headings into slugs, you can create your own slugify function or you
can manually define a slug for a specific post.
!!! example "Slugify function"
To define your own slugify function, you need to write a Python function
that converts text into a slug given additional arguments from the
configuration. You also need to write a function that returns that
function.
Say you want to define two slugify functions that you can switch between.
The first one returns a slug similar to what the default slugify function
produces. The second one cuts the result of that up into words and returns
a slug based on a maximum of five of them:
```python
import re, functools, unicodedata
RE_HTML_TAGS = re.compile(r'</?[^>]*>', re.UNICODE)
RE_INVALID_SLUG_CHAR = re.compile(r'[^\w\- ]', re.UNICODE)
RE_WHITESPACE = re.compile(r'\s', re.UNICODE)
def _make_slug(text, sep, **kwargs):
slug = unicodedata.normalize('NFC', text)
slug = RE_HTML_TAGS.sub('', slug)
slug = RE_INVALID_SLUG_CHAR.sub('', slug)
slug = slug.strip().lower()
slug = RE_WHITESPACE.sub(sep, slug)
return slug
def _make_slug_short(text, sep, **kwargs):
words = _make_slug(text, sep, **kwargs).split(sep)
return sep.join(words[:5])
def slugify(**kwargs):
if 'short' in kwargs and kwargs['short']:
return functools.partial(_make_slug_short, **kwargs)
return functools.partial(_make_slug, **kwargs)
```
Save this code in `ext/slugs.py` and also add an (empty) `__init__.py`
file to indicate that the directory is a module. Now you can configure
your custom slugify code like this:
```yaml hl_lines="4-6"
plugins:
- blog:
# other entries omitted
post_slugify: !!python/object/apply:ext.slugs.slugify
kwds:
short: true
```
Change the heading of a blog post to be longer than five words and observe
how the slugify function shortens the URL. Change the `short` attribute to
`false` and you can turn this off again.
If you want to influence the slug only for a single blog post, you can define
it manually by specifying it in the header of the post. Note that this is meant
as a last resort option. Specifying a custom slug manually for every post would
be tedious.
!!! example "Manually define slug"
If, for example, you wanted the slug to be 'ny-eve' instead of the somewhat
lengthy 'happy-new-years-eve', you could add the following:
```hl_lines="7"
---
date:
created: 2023-12-31
updated: 2024-01-02
readtime: 15
pin: true
slug: ny-eve
---
```
The URL for this post should now be
`http://localhost:8000/blog/2023/01/31/ny-eve/`.
## What's next?
You may want to increase engagement with your blog by allowing people to
subscribe to an RSS feed, by providing links to your social media profiles, by
providing share and like buttons, or by setting up a comment system.
The [engagement and dissemination tutorial] walks you through setting these up.
[engagement and dissemination tutorial]: engage.md

56
docs/tutorials/index.md Normal file
View File

@ -0,0 +1,56 @@
# Tutorials
In addition to the basic getting started guides, we offer tutorials that aim to
show how you can use Material for MkDocs in different use cases. In contrast to
the getting started guides or the reference documentation, the tutorials show
the breadth of features available in Material for MkDocs but also within
the wider MkDocs ecosystem.
The tutorials guide you through worked examples, so by following them you should
gain not only an understanding of how to use Material for MkDocs, but also
a template for your own projects. For convenience, these templates are also
available as template repositories on GitHub.
The tutorials assume that you have installed either the [public version] or the
[Insiders edition] of Material for MkDocs and that you have worked through the
[creating your site] setup guide.
Note that where the features we use require the Insiders edition, we mark these
with the heart icon: <!-- md:sponsors --> If you are using the public version
then you can skip these steps. Sometimes there will be ways of achieving the
same goal that differ between the public version and the Insider edition. In
that case, we will show them in a tabbed view so you can see one or the other.
[public version]: ../getting-started.md
[Insiders edition]: ../insiders/getting-started.md
[creating your site]: ../creating-your-site.md
!!! note "Feedback wanted!"
The tutorials are a recent addition to our documentation and we are still
working out what shape they should have in the end. Please contact us if you
want to provide feedback. <!--- TODO: how? -->
Note, however, that suggestions should be specific and feasible. We want to
focus on creating more content at the moment, instead of developing a
specific styling or behaviour for the tutorials. If there are worthwhile
improvements that we can make through simple customization then we are happy
to consider those.
## Blogs
* [Basics](blogs/basic.md) (20 min) <br/>
covers the basics of setting up a blog, including post metadata.
* [Navigation, pagination, multiple authors](blogs/navigation.md) (30 min)<br/>
describes how to make it easier for your readers to find content.
* [Engagement and dissemination](blogs/engage.md) (30 min)<br/>
walks you through ways of increasing engagement with your content.
[:octicons-repo-template-24: Template Repository](https://github.com/mkdocs-material/create-blog)
## Social cards
* [Basics](social/basic.md) (20 min) <br/>
shows you how to configure Material for MkDocs to create social cards for
your content.
* [Custom cards](social/custom.md) (15 min)<br/>
shows you how to design your own custom social cards.
[:octicons-repo-template-24: Template Repository](https://github.com/mkdocs-material/create-social-cards)

View File

@ -0,0 +1,203 @@
# Basic social cards
Social cards are images that other systems such as social media can display as
a preview for content linked to. It is easy to get started with the social
plugin, true to the motto of Material with MkDocs: "batteries included."
## Basics
Before you start, there are just a couple of [dependencies to install]. These
are libraries for image processing that the plugin needs to produce the social
cards, as well as their Python bindings.
[dependencies to install]: https://squidfunk.github.io/mkdocs-material/plugins/requirements/image-processing/
With those prerequisites met, it is simply a matter of activating the plugin,
which will:
* produce the social cards as PNG images for each page in your site;
* create meta data in the headers of your site's pages that will provide
social media systems with key information and tell them how to find the
social card image.
!!! example "Add social cards"
Simply add the social plugin to your list of plugins:
```yaml hl_lines="3"
plugins:
- search
- social
- ...
```
Now, then you run `mkdocs build` and look at the `site` directory, you will
see that it contains subfolders under `assets/images/social` that reflect
the structure of your Markdown files. Each page has a corresponding PNG file
that contains the social card image.
Have a look at the generated HTML and you will see the metadata produced in
the `head` element, including one entry that points to the image.
## Background color
The social plugin has configuration options for changing aspects such as colors,
images, fonts, logos, the title, even the description. You can configure them
for all social cards in the `mkdocs.yml` and, in the Insiders Edition, they can
be overridden in the page header for individual pages.
!!! example "Change the background color"
To change the background color to an attention-grabbing hot pink,
you might add:
```yaml hl_lines="4-5"
plugins:
...
- social:
cards_layout_options:
background_color: "#ff1493"
```
## Logos
By default, the plugin uses the logo that you set for the whole site, either
through the `theme.logo` or the `theme.icon.logo` setting. The difference
between the two is that the `theme.icon.logo` version will directly embed the
logo's SVG code into the HTML, allowing it to inherit CSS color settings. When
you use `theme.logo`, the Material includes the logo as an image.
You can set your own logo specific for the social cards as well. The path used
is relative to your project root and needs to point to an SVG file or a pixel
image. It should be rectangular and have a transparent background.
!!! example "Set your own logo"
```yaml hl_lines="3-4"
plugins:
- social:
cards_layout_options:
logo: docs/assets/images/ourlogo.png
```
## Background images
In addition to adding your own logo, the most impactful way to personalize your
social cards is to add a background image instead of the default solid color
background. Make sure you choose one that will contrast well with the other
elements of the card.
Also, the background color gets rendered *on top of* the background image,
allowing you to use a transparent color to tint an image. To use just the image,
use the color value `transparent`.
!!! example "Add background image"
```yaml hl_lines="4 5"
plugins:
- social:
cards_layout_options:
background_image: layouts/background.png
background_color: transparent
```
The path to the background image is resolved from the root of your project,
so this is where you should make the `layouts` directory and place the
background image. The default site of the social cards included with the plugin
is 1200x630 pixels, so choose an image that size or one that scales well to it.
## Additional layouts and styles <!-- md:sponsors -->
The Insiders Edition provides additional layouts as well as the option to
configure different styles for different (kinds of) pages.
The Insiders Edition comes with a number of additional layouts for the social
cards. For example, the `default/variant` layout adds a page icon to the card.
You can use this to distinguish social cards visually, depending on what kind
of page you are sharing.
For example, imagine you have a set of pages that advertise events and you want
to include a calendar icon as a visual indication that a card advertises an
event. In the following, you will set up a directory for event pages and use
the meta plugin to assign them a calendar icon.
!!! example "Social cards for event pages"
First, create a directory in your `docs` directory to hold the event pages:
```
$ mkdir docs/events
```
Then, add a file `.meta.yml` inside this new directory with settings for
the page icon and a hot pink background color that will stand out on
social media. Note that you can override the background image by setting it
to `null` here since it is not visible anyway because of the opaque coloring.
```yaml
---
icon: material/calendar-plus
social:
cards_layout_options:
background_image: null
background_color: "#ff1493"
---
```
Now add a page within the `docs/events` directoy. It does not need to have
any special content, just a top level header.
To turn on the `default/variant` layout in `mkdocs.yml`, add the
`cards_layout` option and also add the meta plugin:
```yaml
plugins:
- meta
- social:
cards_layout: default/variant
```
After running `mkdocs build`, you can see that the social card at
`site/assets/images/social/events/index.png` features the page icon.
Note that the icon will also appear next to the navigation element for the
page. If that is not what you want then you will need to modify the social
card template to gets its icons from another source. You can learn how to
do this in the [custom social cards tutorial](custom.md).
## Per-page settings <!-- md:sponsors -->
With the Insiders Edition, you can customize the card layout for each
page by adding settings to the page header. You have effectively done this
in the previous exercise, but using the meta plugin to affect a whole set of
pages.
Say that in addition to regular events you also have the odd webinar and
for this you want to set a different icon and also set the description to
indicate that the event is part of the webinar series.
!!! example "Override card style in page header"
Add the following to the top of the page in `docs/events` or create a new
one:
```yaml
---
icon: material/web
social:
cards_layout_options:
description: Our Webinar Series
---
```
## What's next?
With the Insiders Edition, you can also define custom layouts if the
configuration options introduced above as not enough to meet your needs.
Continue to the [custom social cards tutorial](custom.md) if you want to
find out how to do this.
Social cards are particularly useful for blog posts. If you have a blog,
you need to do nothing more than to turn on both plugins to create social cards
to advertise your latest blog posts. If you do not have one yet but would like
to, why not check out the [blog tutorials](../index.md#blogs)?

View File

@ -0,0 +1,142 @@
# Custom cards
The Insiders Edition allows you to define custom layouts for your social cards
to suit your specific needs if the configuration options are not enough.
For example, you may want to define a social card to advertise a new release
of your product. It should have an icon indicating a launch announcement as
well as the version number of the release on the card.
## Setup
You can either design a custom layout from scratch or use an existing layout
as the basis that you add to or otherwise modify. In this tutorial, you will
use the default layout as the basis.
!!! example "Copy default layout to customize <!-- md:sponsors -->"
Copy the default social card layout from your installation of Material
for MkDocs to a new directory `layouts`. The instructions below assume you
are in your project root and have a virtual environment within this. The
path on your machine, of course, may differ.
```
$ mkdir layouts
$ cp venv/lib/python3.12/site-packages/material/plugins/social/templates/default/variant.yml \
layouts/release.yml
```
Before customizing the social cards, you need to tell the plugin where to
find them as well as tell MkDocs to watch for any changes. Add the following
to the plugin configuration in your `mkdocs.yml`:
``` yaml hl_lines="2-6"
plugins:
- social:
cards_layout_dir: layouts
watch:
- layouts
```
Have a look at the contents of `release.yml`. You will see that there are:
* a number of definitions of content pulled from the site,
* definitions of tags that end up in the `meta` elements in the page header
of each page,
* a specification that consists of a number of layers that the social plugin
applies on top of each other in the order in which they are defined.
## Define page metadata
In the following, you will add a version number to the social card. This
assumes you have a changelog page with information about each release.
Add the version number of the latest version to the page header (so it does
not need to be parsed out of the Markdown content):
!!! example "Defining the release data <!-- md:sponsors -->"
Create a page `docs/changelog.md` with the following content:
```yaml
---
icon: material/rocket-launch-outline
social:
cards_layout: release
cards_layout_options:
title: New release!
latest: 1.2.3
---
# Releases
```
## Extract page metadata
With the data defined in the page header, you can now add code to the layout
that pulls it out and makes it available to render later on. This is to separate
the data manipulation from the actual layout instructions and so make the
layout file easier to read.
!!! example "Adding data definitions"
Add the following at the top of the layout file:
```yaml hl_lines="2-9"
definitions:
- &latest >-
{%- if 'latest' in page.meta %}
{{ page.meta['latest']}}
{%- else -%}
No release version data defined!
{%- endif -%}
```
The code presented here checks whether the page header contains the necessary
entries and spits out a message to the social card if not. Unfortunately, there
is no straightforward way to raise an exception or log an error, so the messages
merely appear in the social card produced.
## Add release version layer
The next step is to use these data definitions in a new layer and add it to the
ones already present.
!!! example "Render release version"
Finally, add the following to end of the custom layout:
```yaml
- size: { width: 990, height: 50 }
offset: { x: 50, y: 360 }
typography:
content: *latest
align: start
color: *color
```
You should now see the social plugin use the custom layout on the changelog page
you set up.
## Adjust layout
Finally, the rocket icon used for the changelog page is not quite in the right
position. Find the please where the `page_icon` variable is used to create the
page icon layer and adjust the horizontal position to 600 instead of 800.
!!! tip "Debugging layout files"
Should you find that your layouts are causing your MkDocs build to fail,
there are a number of things you can do:
1. Run Mkdocs with the `--verbose` option to get more detailed reporting.
2. Comment out things you recently added or that you suspect are the cause
3. Install the `jinja2` command-line tool with `pip install Jinja2` and
run it over your layout file, for example: `jinja2 event.yml`.
## What's next?
If you do not have a blog yet, why not check out the
[blog tutorials](../index.md#blogs) and learn how to set one up? The social
plugin will help you draw attention to your posts on social media.
Check out the [other tutorials](../index.md) we have prepared for you.

View File

@ -174,6 +174,9 @@ markdown_extensions:
custom_checkbox: true custom_checkbox: true
- pymdownx.tilde - pymdownx.tilde
not_in_nav: |
/tutorials/**/*.md
# Page tree # Page tree
nav: nav:
- Home: index.md - Home: index.md
@ -188,6 +191,15 @@ nav:
- Philosophy: philosophy.md - Philosophy: philosophy.md
- Alternatives: alternatives.md - Alternatives: alternatives.md
- License: license.md - License: license.md
- Tutorials:
- tutorials/index.md
- "Blogs":
- tutorials/blogs/basic.md
- tutorials/blogs/navigation.md
- tutorials/blogs/engage.md
- "Social cards":
- tutorials/social/basic.md
- tutorials/social/custom.md
- Changelog: - Changelog:
- changelog/index.md - changelog/index.md
- How to upgrade: upgrade.md - How to upgrade: upgrade.md