#473 - Allow setting the SEO title name

This commit is contained in:
Elio Struyf
2023-02-04 10:08:25 +01:00
parent db38b9da68
commit 4a50cf70a0
10 changed files with 39 additions and 19 deletions
+1
View File
@@ -8,6 +8,7 @@
### 🎨 Enhancements
- [#473](https://github.com/estruyf/vscode-front-matter/issues/473): Allow setting the SEO title name with the `frontMatter.taxonomy.seoTitleField` setting
- [#474](https://github.com/estruyf/vscode-front-matter/issues/474): Allow to define the file prefix on content types
- [#484](https://github.com/estruyf/vscode-front-matter/issues/484): Support for overriding scripts per environment type
- [#494](https://github.com/estruyf/vscode-front-matter/issues/494): Support for external image URLs in previews
+6
View File
@@ -1492,6 +1492,12 @@
"markdownDescription": "Specifies the optimal slug length for SEO (set to `-1` to turn it off). [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.taxonomy.seoSlugLength)",
"scope": "Taxonomy"
},
"frontMatter.taxonomy.seoTitleField": {
"type": "string",
"default": "title",
"markdownDescription": "Specifies the name of the SEO title field for your page. Default is 'title'. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.taxonomy.seotitlefield)",
"scope": "Taxonomy"
},
"frontMatter.taxonomy.seoTitleLength": {
"type": "number",
"default": 60,
+8 -5
View File
@@ -4,6 +4,7 @@ import {
NOTIFICATION_TYPE,
SETTING_SEO_DESCRIPTION_FIELD,
SETTING_SEO_DESCRIPTION_LENGTH,
SETTING_SEO_TITLE_FIELD,
SETTING_SEO_TITLE_LENGTH
} from './../constants';
import * as vscode from 'vscode';
@@ -59,15 +60,17 @@ export class StatusListener {
// Retrieve the SEO config properties
const titleLength = (Settings.get(SETTING_SEO_TITLE_LENGTH) as number) || -1;
const descLength = (Settings.get(SETTING_SEO_DESCRIPTION_LENGTH) as number) || -1;
const fieldName =
const titleField =
(Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title;
const descriptionField =
(Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string) || DefaultFields.Description;
if (article.data.title && titleLength > -1) {
SeoHelper.checkLength(editor, collection, article, 'title', titleLength);
if (article.data[titleField] && titleLength > -1) {
SeoHelper.checkLength(editor, collection, article, titleField, titleLength);
}
if (article.data[fieldName] && descLength > -1) {
SeoHelper.checkLength(editor, collection, article, fieldName, descLength);
if (article.data[descriptionField] && descLength > -1) {
SeoHelper.checkLength(editor, collection, article, descriptionField, descLength);
}
// Check the required fields
+1
View File
@@ -2,5 +2,6 @@ export const DefaultFields = {
PublishingDate: `date`,
LastModified: `lastmod`,
Description: `description`,
Title: `title`,
Slug: `slug`
};
+1
View File
@@ -27,6 +27,7 @@ export const SETTING_REMOVE_QUOTES = 'taxonomy.noPropertyValueQuotes';
export const SETTING_FRONTMATTER_TYPE = 'taxonomy.frontMatterType';
export const SETTING_SEO_TITLE_FIELD = 'taxonomy.seoTitleField';
export const SETTING_SEO_TITLE_LENGTH = 'taxonomy.seoTitleLength';
export const SETTING_SEO_SLUG_LENGTH = 'taxonomy.seoSlugLength';
export const SETTING_SEO_DESCRIPTION_LENGTH = 'taxonomy.seoDescriptionLength';
+3 -1
View File
@@ -29,7 +29,8 @@ import {
SETTING_TAXONOMY_CUSTOM,
SETTING_TAXONOMY_FIELD_GROUPS,
SETTING_TAXONOMY_TAGS,
SETTING_GIT_ENABLED
SETTING_GIT_ENABLED,
SETTING_SEO_TITLE_FIELD
} from '../constants';
import { GitListener } from '../listeners/general';
import {
@@ -55,6 +56,7 @@ export class PanelSettings {
slug: (Settings.get(SETTING_SEO_SLUG_LENGTH) as number) || -1,
description: (Settings.get(SETTING_SEO_DESCRIPTION_LENGTH) as number) || -1,
content: (Settings.get(SETTING_SEO_CONTENT_MIN_LENGTH) as number) || -1,
titleField: (Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title,
descriptionField:
(Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string) || DefaultFields.Description
},
+1
View File
@@ -136,6 +136,7 @@ export interface SEO {
slug: number;
description: number;
content: number;
titleField: string;
descriptionField: string;
}
@@ -182,7 +182,7 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
);
} else if (field.type === 'string') {
let limit = -1;
if (field.name === 'title') {
if (field.name === settings.seo.titleField) {
limit = settings?.seo.title;
} else if (field.name === settings.seo.descriptionField) {
limit = settings?.seo.description;
+9 -7
View File
@@ -1,4 +1,5 @@
import * as React from 'react';
import { useEffect } from 'react';
import { SEO } from '../../models/PanelSettings';
import { TagType } from '../TagType';
import { ArticleDetails } from './ArticleDetails';
@@ -32,10 +33,10 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
}, 10);
}).current;
const { descriptionField } = seo;
const { descriptionField, titleField } = seo;
// Workaround for lit components not updating render
React.useEffect(() => {
useEffect(() => {
setTimeout(() => {
let height = 0;
@@ -47,7 +48,7 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
tableRef.current.style.height = `${height}px`;
}
}, 10);
}, [title, data[descriptionField], data?.articleDetails?.wordCount]);
}, [title, data[titleField], data[descriptionField], data?.articleDetails?.wordCount]);
const renderContent = () => {
if (!isOpen) {
@@ -66,14 +67,15 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
<VsTableHeaderCell className={`table__cell`}>Valid</VsTableHeaderCell>
</VsTableHeader>
<VsTableBody slot="body">
{title && seo.title > 0 && (
{data[titleField] && seo.title > 0 && (
<SeoFieldInfo
title={`title`}
value={title.length}
title={titleField}
value={data[titleField].length}
recommendation={`${seo.title} chars`}
isValid={title.length <= seo.title}
isValid={data[titleField].length <= seo.title}
/>
)}
{slug && seo.slug > 0 && (
<SeoFieldInfo
title={`slug`}
+8 -5
View File
@@ -8,7 +8,8 @@ import {
DefaultFields,
DEFAULT_CONTENT_TYPE_NAME,
ExtensionState,
SETTING_SEO_DESCRIPTION_FIELD
SETTING_SEO_DESCRIPTION_FIELD,
SETTING_SEO_TITLE_FIELD
} from '../constants';
import { Page } from '../dashboardWebView/models';
import {
@@ -155,10 +156,12 @@ export class PagesParser {
folderTitle: string
): Promise<Page | undefined> {
const article = await ArticleHelper.getFrontMatterByPath(filePath);
const articleTitle = article?.data.title || fileName;
if (article?.data) {
const wsFolder = Folders.getWorkspaceFolder();
const titleField = (Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title;
const descriptionField =
(Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string) || DefaultFields.Description;
@@ -175,7 +178,7 @@ export class PagesParser {
const staticFolder = Folders.getStaticFolderRelativePath();
let escapedTitle = articleTitle;
let escapedTitle = article?.data[titleField] || fileName;
if (escapedTitle && typeof escapedTitle !== 'string') {
escapedTitle = '<invalid title>';
}
@@ -205,10 +208,10 @@ export class PagesParser {
fmBody: article?.content || '',
// Make sure these are always set
title: escapedTitle,
description: escapedDescription,
slug: article?.data.slug,
date: article?.data[dateField] || '',
draft: article?.data.draft,
description: escapedDescription
draft: article?.data.draft
};
const contentType = ArticleHelper.getContentType(article.data);