|
| 1 | +# Basic blogs |
| 2 | + |
| 3 | +Blogs are a great way to engage with your audience. Software developers can use |
| 4 | +a blog to announce new features, demonstrate their usage and provide background |
| 5 | +information. You can demonstrate competence by commenting on the state of the |
| 6 | +art or document your own work as best practice. Posts on current topics can help |
| 7 | +draw in visitors for your main website and can keep your audience engaged. Of |
| 8 | +course, you can blog about any topics close to your heart. |
| 9 | + |
| 10 | +The [blog plugin] makes running a blog alongside your other content easy but you |
| 11 | +can also configure it to run a stand-alone blog if posts are the only kind |
| 12 | +of content you need. |
| 13 | + |
| 14 | +After a brief overview of the basic concepts of a blog, this tutorial guides you |
| 15 | +through the process of configuring the [blog plugin], setting up your blog, |
| 16 | +creating posts, and defining post metadata. |
| 17 | + |
| 18 | +[blog plugin]: ../../plugins/blog.md |
| 19 | + |
| 20 | +__Time required:__ typically 20 minutes |
| 21 | + |
| 22 | +## Key concepts |
| 23 | + |
| 24 | +**Post, excerpt**: a blog consists of a number of self-contained _posts_ (often called |
| 25 | +articles) and an index page that shows the posts in reverse chronological order, with |
| 26 | +the most recent post at the top. The index page usually shows only a short _excerpt_ and a |
| 27 | +link that the user can click to navigate to the full post. |
| 28 | + |
| 29 | +**Metadata**: both the index page and the post itself list information such as |
| 30 | +when you published the post, when you updated it, who the author is, and what the |
| 31 | +expected reading time is. |
| 32 | + |
| 33 | +**Slug**: since the blog posts are primarily arranged by time and not into a hierarchy, |
| 34 | +their URLs do not reflect such a structure. Instead, each post's URL |
| 35 | +contains a shortened description, the _slug_, which is usually derived from |
| 36 | +the first heading in the post. |
| 37 | + |
| 38 | +**Navigation**: the main navigation structure is the timeline, which you can |
| 39 | +subdivide into _categories_. The main index page shows the more recent posts |
| 40 | +while an _archive_ section allows access to older ones, organized by year. |
| 41 | +In addition, posts can be _tagged_ and _tag index pages_ provide an additional |
| 42 | +navigation structure based on content. |
| 43 | + |
| 44 | +You can see all these elements on the [Material for MkDocs blog]. |
| 45 | + |
| 46 | +[Material for MkDocs blog]: https://squidfunk.github.io/mkdocs-material/blog/ |
| 47 | + |
| 48 | +## Setting up your blog |
| 49 | + |
| 50 | +The blog plugin is part of Material for MkDocs but you need to configure it |
| 51 | +in the `mkdocs.yml`. |
| 52 | + |
| 53 | +!!! example "Set up a blog" |
| 54 | + |
| 55 | + If you have not done so already, create a project for your blog, |
| 56 | + then edit the `mkdocs.yml` file to make sure if has the following content: |
| 57 | + |
| 58 | + ```yaml |
| 59 | + site_name: Blog Tutorial |
| 60 | + site_description: an example blog set up following the tutorial |
| 61 | + site_url: http://www.example.com |
| 62 | + |
| 63 | + theme: |
| 64 | + name: material |
| 65 | + |
| 66 | + plugins: |
| 67 | + - search |
| 68 | + - blog |
| 69 | + ``` |
| 70 | + |
| 71 | + The blog plugin will create a directory structure for your blog posts if it |
| 72 | + does not exist, so simply run `mkdocs serve` to get: |
| 73 | + |
| 74 | + ``` |
| 75 | + docs |
| 76 | + ├── blog |
| 77 | + │ ├── index.md |
| 78 | + │ └── posts |
| 79 | + └── index.md |
| 80 | + ``` |
| 81 | + |
| 82 | +Now create your first blog post in `docs/blog/posts`. You can use any |
| 83 | +naming convention and directory structure you like for your posts, as long as |
| 84 | +they are inside `docs/blog/posts`. |
| 85 | + |
| 86 | +Each post _must_ have a page header, which appears at the top of the Markdown |
| 87 | +code between lines with three dashes. Within this header, you need to have at |
| 88 | +least a `date` entry but you can add other data, as you will see below. |
| 89 | +Following the header comes the page content. Note that it is important |
| 90 | +to have a level one heading as the plugin uses it to produce the _slug_. Also, |
| 91 | +by adding `<!-- more -->` to the page, you can define where the excerpt will end |
| 92 | +that the index page shows. |
| 93 | + |
| 94 | +!!! example "Write your first post" |
| 95 | + |
| 96 | + Create a file `docs/blog/posts/myfirst.md` with the following contents: |
| 97 | + |
| 98 | + ``` |
| 99 | + --- |
| 100 | + date: |
| 101 | + created: 2023-12-31 |
| 102 | + --- |
| 103 | + |
| 104 | + # Happy new years eve! |
| 105 | + |
| 106 | + We hope you are all having fun and wish you all the best for the new year! |
| 107 | + <!-- more --> |
| 108 | + |
| 109 | + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod |
| 110 | + tempor incididunt ut labore et dolore magna aliqua. |
| 111 | + ``` |
| 112 | + |
| 113 | + Then, run `mkdocs serve` and point your web browser at |
| 114 | + `http://localhost:8000/blog`. |
| 115 | + |
| 116 | + The blog plugin automatically creates navigation elements for |
| 117 | + the blog. The index page shows only the extract. When you select the |
| 118 | + "Continue reading" link, you will get to the full blog post. Note how it |
| 119 | + has a URL generated from the first-level heading. |
| 120 | + |
| 121 | +!!! tip "Navigation" |
| 122 | + |
| 123 | + We also have a [tutorial on navigation] that shows you how to change the |
| 124 | + automatically created navigation and integrate the blog into your existing |
| 125 | + navigation structure. It shows how to create secondary nagigation, produce |
| 126 | + author pages, and control pagination. |
| 127 | + |
| 128 | +[tutorial on navigation]: navigation.md |
| 129 | + |
| 130 | +## Post metadata |
| 131 | + |
| 132 | +In addition to the date, you can provide other metadata and give the plugin |
| 133 | +instructions, such as to treat a post as a draft or to pin it. |
| 134 | + |
| 135 | +### Drafts |
| 136 | + |
| 137 | +You may want to produce a draft of a blog post and work with it locally but |
| 138 | +exclude it from the build that you publish. Simply add a field to the page |
| 139 | +header to indicate that a post is still in draft form. |
| 140 | + |
| 141 | +!!! example "Create a draft" |
| 142 | + |
| 143 | + Create a second blog post in `docs/blogs/posts/draft.md` with the following |
| 144 | + contents: |
| 145 | + |
| 146 | + ```hl_lines="3" |
| 147 | + --- |
| 148 | + date: |
| 149 | + created: 2024-01-01 |
| 150 | + draft: true |
| 151 | + --- |
| 152 | + |
| 153 | + # Happy new year! |
| 154 | + |
| 155 | + Happy 2024 to everyone. Wishing you all the best! |
| 156 | + <!-- more --> |
| 157 | + |
| 158 | + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod |
| 159 | + tempor incididunt ut labore et dolore magna aliqua. |
| 160 | + ``` |
| 161 | + |
| 162 | + Now, note how the draft appears on the index page but with a label that |
| 163 | + indicates that it is a draft. When you run `mkdocs build`, the draft will |
| 164 | + _not_ appear in the output: |
| 165 | + |
| 166 | + ``` |
| 167 | + $ mkdocs build |
| 168 | + $ ls site/blog |
| 169 | + site/blog |
| 170 | + ├── 2023 |
| 171 | + │ └── 12 |
| 172 | + │ └── 31 |
| 173 | + │ └── happy-new-years-eve |
| 174 | + │ └── index.html |
| 175 | + ... |
| 176 | + ``` |
| 177 | + |
| 178 | + The first blog post for 2024 is not there yet because it is still in draft |
| 179 | + stage. Remember to remove the `draft` setting in the header when it is time |
| 180 | + to publish it. |
| 181 | + |
| 182 | +If you are using the [Insiders Edition], you can also create |
| 183 | +a folder to keep your drafts in and use the [Meta plugin] to add the |
| 184 | +`draft` header setting to all the posts in that folder. This has the advantage |
| 185 | +that it is easier to see which posts are still in draft form. We will cover the |
| 186 | +Meta plugin later on. |
| 187 | + |
| 188 | +[Meta plugin]: ../../plugins/meta.md |
| 189 | + |
| 190 | +### Edits |
| 191 | + |
| 192 | +Sometimes, bloggers need to update a post. This might happen when you make |
| 193 | +a mistake or when something changes that you need to reflect in the post. To |
| 194 | +indicate you have edited a post, you can include an `updated` date in the page |
| 195 | +header. |
| 196 | + |
| 197 | +!!! example "Editing a post" |
| 198 | + |
| 199 | + Make a change to your first blog post, then add an edit date to the header: |
| 200 | + |
| 201 | + ```hl_lines="3 4" |
| 202 | + --- |
| 203 | + date: |
| 204 | + created: 2023-12-31 |
| 205 | + updated: 2024-01-02 |
| 206 | + --- |
| 207 | + ``` |
| 208 | + |
| 209 | +The Metadata section of the blog post itself will contain the edit date, |
| 210 | +though the index page omits this detail by default. |
| 211 | + |
| 212 | +### Reading time |
| 213 | + |
| 214 | +To give the reader some idea of how long it might take them to read a post, |
| 215 | +a read time is automatically calculated. If you want to override this, you can |
| 216 | +do so in the page header by specifying the number of minutes you estimate |
| 217 | +your readers will take the read the post. |
| 218 | + |
| 219 | +!!! example "Overriding the reading time" |
| 220 | + |
| 221 | + Add a reading time override to your first blog post: |
| 222 | + |
| 223 | + ```hl_lines="5" |
| 224 | + --- |
| 225 | + date: |
| 226 | + created: 2023-12-31 |
| 227 | + updated: 2024-01-02 |
| 228 | + readtime: 15 |
| 229 | + --- |
| 230 | + ``` |
| 231 | + |
| 232 | +### Pinning |
| 233 | + |
| 234 | +Sometimes, blog authors want to 'pin' a specific post so that it will always |
| 235 | +appear at the top of the index page, no matter what else gets published. If you |
| 236 | +are using the [Insiders Edition], you can achieve this by adding the `pin` |
| 237 | +attribute in the page header: |
| 238 | + |
| 239 | +!!! example "Pin a post <!-- md:sponsors -->" |
| 240 | + |
| 241 | + Add the `pin` attribute to your first blog post: |
| 242 | + |
| 243 | + ```hl_lines="5" |
| 244 | + --- |
| 245 | + date: |
| 246 | + created: 2023-12-31 |
| 247 | + updated: 2024-01-02 |
| 248 | + readtime: 15 |
| 249 | + pin: true |
| 250 | + --- |
| 251 | + ``` |
| 252 | + |
| 253 | + Observe how this makes the post appear on top of the index page even though |
| 254 | + its publication date is prior to other posts. A small pin icon shows that the |
| 255 | + post has been pinned. |
| 256 | + |
| 257 | +### Related links <!-- md:sponsors --> |
| 258 | + |
| 259 | +When your blog is part of a wider site such as technical documentation, you |
| 260 | +will want to provide links from blog posts into your other content. One way you |
| 261 | +can do this is to have a related links section. In the [Insiders Edition], the |
| 262 | +blog plugin can create one for you if you provide link targets in your page |
| 263 | +header: |
| 264 | + |
| 265 | +!!! example "Add a related links section <!-- md:sponsors -->" |
| 266 | + |
| 267 | + Add the following to a blog post: |
| 268 | + |
| 269 | + ``` hl_lines="5-7" |
| 270 | + --- |
| 271 | + date: |
| 272 | + created: 2023-12-31 |
| 273 | + ... |
| 274 | + links: |
| 275 | + - index.md |
| 276 | + - blog/index.md |
| 277 | + --- |
| 278 | + ``` |
| 279 | + |
| 280 | + The related links appear underneath the Metadata section. |
| 281 | + |
| 282 | +The nice thing here is that you do not need to provide a page title. The plugin |
| 283 | +will deduce the link text by applying the same logic that MkDocs uses for the |
| 284 | +main navigation. In fact, the syntax is the same as that of the `nav` section |
| 285 | +in the `mkdocs.yml`, so you can override the title if you want and even define |
| 286 | +subsections: |
| 287 | + |
| 288 | +!!! example "Override the page titles" |
| 289 | + |
| 290 | + Change the link section to override the page titles: |
| 291 | + |
| 292 | + ```hl_lines="6-9" |
| 293 | + --- |
| 294 | + date: |
| 295 | + created: 2023-12-31 |
| 296 | + ... |
| 297 | + links: |
| 298 | + - Homepage: index.md |
| 299 | + - Blog index: blog/index.md |
| 300 | + - External links: |
| 301 | + - Material documentation: https://squidfunk.github.io/mkdocs-material |
| 302 | + --- |
| 303 | + ``` |
| 304 | + |
| 305 | +The plugin renders related links in the left sidebar on screens that are wide |
| 306 | +enough and at the bottom of the post on narrow screens. Change the size of your |
| 307 | +browser window to see this in action. |
| 308 | + |
| 309 | +## Meta plugin <!-- md:sponsors --> |
| 310 | + |
| 311 | +The Meta plugin is available in the [Insiders Edition]. |
| 312 | +It helps simplify the management of metadata that is common to a group of |
| 313 | +files in the same subdirectory. Instead of having to repeat the |
| 314 | +same metadata in the page headers of a number of files, you can add a |
| 315 | +`.meta.yml` file in the directory and the Meta plugin will merge its contents |
| 316 | +into the headers of all the pages contained. |
| 317 | +Settings from the page header take precedence, so you can always override |
| 318 | +settings by adding them to a post's header. |
| 319 | + |
| 320 | +For example, you may want to manage drafts by keeping them in a directory |
| 321 | +together so that they are not only flagged as drafts but also easier to find. |
| 322 | +(Otherwise, you would need to inspect the page headers or trace back from the |
| 323 | +output to the files to figure out which posts are drafts.) |
| 324 | + |
| 325 | +!!! example "Drafts using the Meta plugin <!-- md:sponsors -->" |
| 326 | + |
| 327 | + You first need to activate the plugin in your `mkdocs.yaml`: |
| 328 | + |
| 329 | + ```yaml hl_lines="4" |
| 330 | + plugins: |
| 331 | + - search |
| 332 | + - blog |
| 333 | + - meta |
| 334 | + ``` |
| 335 | + |
| 336 | + Now create the folder for the drafts: |
| 337 | + |
| 338 | + === "MacOS/Linux" |
| 339 | + |
| 340 | + ```bash |
| 341 | + $ mkdir docs/blog/posts/drafts |
| 342 | + ``` |
| 343 | + |
| 344 | + === "Windows" |
| 345 | + TODO |
| 346 | + |
| 347 | + Now, within this folder, crate a file `.meta.yml` that contains: |
| 348 | + |
| 349 | + ```yaml |
| 350 | + draft: true |
| 351 | + ``` |
| 352 | + |
| 353 | + Add another blog post and store it in `docs/blog/posts/drafts`. When you |
| 354 | + look at it locally, you will see the label that identifies it as a draft, |
| 355 | + while in the version built for publication it does not appear. To move a |
| 356 | + post from draft status to published, simply move it outside `drafts/`. |
| 357 | + |
| 358 | +[Insiders Edition]: ../../insiders/index.md |
| 359 | + |
| 360 | +## What's next? |
| 361 | + |
| 362 | +You should now have a working blog. However, as it accumulates content, you |
| 363 | +may want to make sure that people can find posts they are interested in, so |
| 364 | +you may want to add secondary navigation with tags and categories. You may |
| 365 | +have more than one author and want to attribute posts to them as well as |
| 366 | +generate author pages for them. We have a [tutorial on navigation, pagination, |
| 367 | +and authors] that covers these topics. |
| 368 | + |
| 369 | +[tutorial on navigation, pagination, and authors]: navigation.md |
| 370 | + |
| 371 | +You may want to increase engagement with your blog by allowing people to |
| 372 | +subscribe to an RSS feed or by setting up a comment system. The [engagement |
| 373 | +and dissemination tutorial] walks you through setting these up. |
| 374 | + |
| 375 | +[engagement and dissemination tutorial]: engage.md |
0 commit comments