https://github.com/timthepost/lume-basic-seo
A basic SEO plugin for Lume to help avoid common content pitfalls.
https://github.com/timthepost/lume-basic-seo
Last synced: about 2 months ago
JSON representation
A basic SEO plugin for Lume to help avoid common content pitfalls.
- Host: GitHub
- URL: https://github.com/timthepost/lume-basic-seo
- Owner: timthepost
- License: mit
- Created: 2025-02-16T18:39:55.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2025-02-16T20:10:08.000Z (2 months ago)
- Last Synced: 2025-02-16T20:24:43.186Z (2 months ago)
- Language: TypeScript
- Size: 5.86 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-lume - Basic SEO
README
# Basic Automated SEO Checks for Lume Sites!
A basic SEO plugin for Lume to help avoid common content pitfalls through
automated checks as part of the site build process.Currently beta, kind of messy, but extremely useful.
## One Plugin: Many Checks.
The plugin checks for the following common mistakes that can result in a penalty
when it comes to how your site is indexed. Currently, checks are:- Make sure titles are under 80 characters, this helps their chances of being
indexed.
- Make sure URLs are under 70% (default) of title length, for the same reason.
- Make sure only one `` element exists in a page.
- Make sure heading elements are used in semantic order (`` - `
`).
- Make sure titles and URLs contain a relatively low percentage of
[common words][1].
- Make sure images have `alt=""` and `title=""` attributes. This helps
accessibility, and boosts image search strategies.
- Configurable content length warnings.
- Lots more coming soon (see below).This plugin is meant to run in conjunction with the [Check URLs][2] and
[Metas][3] plugins for a comprehensive approach to managing SEO factors. It is
not meant to be a self-contained solution.The idea is to catch mistakes that get introduced during the non-automated parts
of content creation. If you aren't already automating the creation and setup of
new pages, see Lume's [archetypes](https://lume.land/docs/core/archetypes/); you
might be surprised how many fewer mistakes happen when all frontmatter is
automated, for instance.## Installation:
The easiest way is to import from JSDelivr (in `plugins.ts`):
```ts
import seo from "https://cdn.jsdelivr.net/gh/timthepost/[email protected]/mod.ts";
```And, a little lower:
```ts
.use(seo({ output: "_seo-report.json" }))
```If you intend to customize the plugin, just clone this repo and install the
plugin locally and import it from the file system, or use submodules.## Configuration:
All options are optional and have built-in defaults, which are provided in the
following table:| Option | Type | Since Version | Description | Default |
| --------------------------------- | ------------------ | ------------- | -------------------------------------------------------------------------------------- | ---------------------- |
| `warnTitleLength` | boolean | 1.0.0 | Warn if titles are too long | true |
| `warnUrlLength` | boolean | 1.0.0 | Warn if URLs are too long | true |
| `warnDuplicateHeadings` | boolean | 1.0.0 | Warn if more than one `` tag appears | true |
| `warnHeadingOrder` | boolean | 1.0.0 | Warn if `` - `
` elements are used out of order | true |
| `warnImageAltAttribute` | boolean | 1.0.0 | Warn if images lack an `alt` attribute. | true |
| `warnImageTitleAttribute` | boolean | 1.0.0 | Warn if images lack a `title` attribute. | true |
| `warnUrlCommonWords` | boolean | 1.0.0 | Warn on URLs with a high percentage of common words. | true |
| `warnTitleCommonWords` | boolean | 1.0.0 | Warn on Titles with a high percentage of common words. | true |
| `warnContentLength` | boolean | 1.0.1 | (Unreleased) Warn if content is too short or long. | true |
| `warnMetasDescriptionLength` | boolean | 1.0.1 | (Unreleased) If `metas:` is set, analyze the meta description length. | true |
| `warnMetasDescriptionCommonWords` | boolean | 1.0.1 | (Unreleased) If `metas:` is set, analyze the meta description for common word density. | true |
| `thresholdLength` | number | 1.0.0 | How long is too long for a title? (chars) | 80 |
| `thresholdMetaDescriptionLength` | number | 1.0.1 | (Unreleased) How long can a meta description be? (chars) | 150 |
| `thresholdLengthPercentage` | number | 1.0.0 | What percentage of `thresholdLength` applies to URLs? | .7 |
| `thresholdCommonWordsPercent` | number | 1.0.0 | What % of common words is okay? | 40 |
| `thresholdLengthForCWCheck` | number | 1.0.0 | Minimum length required for any common word check (chars) | 35 |
| `thresholdContentMinimum` | number | 1.0.1 | (Unreleased) The minimum length (chars) page content should be | 15000 |
| `thresholdContentMaximum` | number | 1.0.1 | (Unreleased) The maximum length (chars) page content should be | 75000 |
| `userCommonWordSet` | Set | 1.0.0 | A custom set of common words for the plugin to use. | English |
| `removeReportFile` | boolean | 1.0.1 | (Unreleased) If reporting to a file, unlink it if report is empty. | true |
| `extensions` | string[] | 1.0.0 | What extensions should the plugin process? | `["md", "mdx"]` |
| `ignore` | string[] | 1.0.0 | List of URLs to skip | `["404.html"]` |
| `output` | string or function | 1.0.0 | File name to save, or function that accepts `Map>` | null (standard output) |**Please note: (Unreleased) features are still subject to breaking changes
without notice.**## Frontmatter Control:
It's handy to be able to control certain behaviors on a per-page basis, right in
the frontmatter. To do this, you just add a `seo:` section below the existing
frontmatter that you have. Where you have something like this:```yml
title: My Title
url: /my_url/
tags:
- tag1
- tag2
```You will have this:
```yml
title: My Title
url: /my_url/
tags:
- tag1
- tag2
seo:
setting: value
```The following settings are available in frontmatter:
| Setting | Expects | Since Version | Description |
| ------------- | ------- | ------------- | -------------------------------------------------------------------------------------------- |
| ignore: | boolean | 1.0.0 | set to `true` to skip the entire page while processing. No checks run at all. |
| skip_content: | boolean | 1.0.1 | (Unreleased) Don't run content length checks (doesn't interfere with other checks). |
| skip_metas: | boolean | 1.0.1 | (Unreleased) Don't run checks on `metas:` for the page (doesn't interfere with other checks) |Please, before you use ignore, consider reading just a _little_ further `:)`
_**It is expected that the default settings will be very noisy.**_ I suggest
looking at the warnings, addressing them as best you can while remembering that
it's humans that we must really optimize for, and then dial settings back until
you're happy with the output.Don't make your content _less_ readable by reacting to these warnings. Not every
title can be re-worded with fewer common words and still have the same meaning.
It's always a subjective balance.Treat the warnings like lint: fix what makes sense, ignore or squelch what does
not. But, at least _think about_ each one before you turn them down / off.## Background
This plugin was written by [Tim Post][4] after sharing an initial ad-hoc script
that accomplished a few of the tasks that this plugin handles.It quickly became clear that there's a need for a consolidated plugin to do this
kind of stuff, so the script was polished up, features added, and published as a
(mostly) proper plugin.Most of the checks are based on lessons Tim learned while working on quality and
growth initiatives at Stack Overflow & Stack Exchange. These tweaks helped the
site outrank the bad actors who were just republishing the database dumps with
ads and outscoring the real site itself in indexes.More behind the rationale of the checks is discussed in
[the announcement blog post][5].## Internationalization
There's two parts of this plugin that are hard-coded English:
- The list of common words in the function that evaluates them, and,
- The warnings / logging phrases.For the first, there's an option `userCommonWordSet` where you can pass your own
set of words similar to what's in the plugin. Just make sure they really are
common in the topic / setting.For the logging / warnings, there's no clear / clean way for
internationalization in plugins that I know of. What I suggest is forking the
plugin, then renaming it to `lume-basic-seo-XX`, where `XX` is the two-letter
language code. Send me a link and I'll link to it here.It's probably easiest to just pass the custom common word set.
## Support & Requesting Features
Use GH issues, or find me in Lume's Discord server (issues almost guarantees a
faster response). I'm disabled and don't have a ton of productive free time, but
I'm happy to help. If you add a check that you think would be beneficial for
everyone, consider sending me a PR to include it, just make sure you remember to
update the options and option defaults.## Next-up Ideas For Checks / Features
**Make sure to check out the [changelog](/changelog); it contains information on
unreleased features and fixes slated for the next release (currently `1.0.1`).**- _**Tests**_. Still wrapping my head around how to do that headlessly with
Lume.- Analyze site tags dynamically to find the most-used tags, and optionally make
them the beginning of titles. This can be a very powerful edge for programming
and technology related sites. _How to iterate over an object_ is not nearly as
good as _[JavaScript]: How to iterate over an object_, as an example.- Use the `Intl.Segmenter` API to accept lengths in either words or characters
anywhere they can be specified to control a check. Probably a nomenclature
like `80c` or `15w` or (for sentences) `5s` (as a starting idea).- Submit new pages to indexes and keep track of when they last updated. This
could be by leaving a list to process in `_seo-report.json` and having a Lume
script run `fetch()`, or perhaps a CLI tool. Controlled via frontmatter, e.g.
`seo.auto_submit` or something.- Use proper Lume events to re-run checks on site change. This almost works now,
but all checks need to be wrapped in a function and it has to be registered
properly to be smooth.- Query Google Search Console indexed status per url with a Lume script? Perhaps
even present some kind of seo report page in the CMS based on the report file?## Credits
This plugin borrows some design ideas and even a little code from the
[Check URLs][2] plugin, as it manages a similar type of lifting. Plus, I really
liked how it lets you configure output.[1]: https://en.wikipedia.org/wiki/Most_common_words_in_English
[2]: https://lume.land/plugins/check_urls/
[3]: https://lume.land/plugins/metas/
[4]: https://timthepost.deno.dev
[5]: https://timthepost.deno.dev/posts/lume-seo-plugin-brewing/