From 34d267deccaad811b7a188425221b1f4533cf12a Mon Sep 17 00:00:00 2001
From: Steve Larson <9larsons@gmail.com>
Date: Mon, 18 Nov 2024 11:45:03 -0600
Subject: [PATCH 1/2] Reverted custom fonts flag (#21645)
ref https://ghost.slack.com/archives/C025584CA/p1731950126867179
- moved custom fonts functionality back to a labs flag
- reverted gscan version to 4.45 which doesn't include the custom fonts
checks/warnings
---
.../settings/advanced/labs/AlphaFeatures.tsx | 4 +
.../site/designAndBranding/GlobalSettings.tsx | 91 ++++++++++---------
.../site/designAndBranding/ThemeSettings.tsx | 10 +-
.../test/acceptance/site/design.test.ts | 3 +
.../core/core/frontend/helpers/body_class.js | 42 +++++----
.../core/core/frontend/helpers/ghost_head.js | 40 ++++----
ghost/core/core/shared/labs.js | 3 +-
ghost/core/package.json | 2 +-
.../admin/__snapshots__/config.test.js.snap | 1 +
.../__snapshots__/ghost_head.test.js.snap | 12 +--
.../unit/frontend/helpers/body_class.test.js | 18 +++-
.../unit/frontend/helpers/ghost_head.test.js | 10 ++
yarn.lock | 8 +-
13 files changed, 143 insertions(+), 101 deletions(-)
diff --git a/apps/admin-x-settings/src/components/settings/advanced/labs/AlphaFeatures.tsx b/apps/admin-x-settings/src/components/settings/advanced/labs/AlphaFeatures.tsx
index e640d587b5..7e38884a47 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/labs/AlphaFeatures.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/labs/AlphaFeatures.tsx
@@ -63,6 +63,10 @@ const features = [{
title: 'Staff 2FA',
description: 'Enables email verification for staff logins',
flag: 'staff2fa'
+}, {
+ title: 'Custom Fonts',
+ description: 'Enables new custom font settings',
+ flag: 'customFonts'
}];
const AlphaFeatures: React.FC = () => {
diff --git a/apps/admin-x-settings/src/components/settings/site/designAndBranding/GlobalSettings.tsx b/apps/admin-x-settings/src/components/settings/site/designAndBranding/GlobalSettings.tsx
index ff6da175bd..1b62a06389 100644
--- a/apps/admin-x-settings/src/components/settings/site/designAndBranding/GlobalSettings.tsx
+++ b/apps/admin-x-settings/src/components/settings/site/designAndBranding/GlobalSettings.tsx
@@ -1,3 +1,4 @@
+import BehindFeatureFlag from '../../../BehindFeatureFlag';
import React, {useState} from 'react';
import UnsplashSelector from '../../../selectors/UnsplashSelector';
import clsx from 'clsx';
@@ -318,50 +319,52 @@ const GlobalSettings: React.FC<{ values: GlobalSettingValues, updateSetting: (ke
}
-
+
+
+
>
);
};
diff --git a/apps/admin-x-settings/src/components/settings/site/designAndBranding/ThemeSettings.tsx b/apps/admin-x-settings/src/components/settings/site/designAndBranding/ThemeSettings.tsx
index 96181906d2..dddd00f4e8 100644
--- a/apps/admin-x-settings/src/components/settings/site/designAndBranding/ThemeSettings.tsx
+++ b/apps/admin-x-settings/src/components/settings/site/designAndBranding/ThemeSettings.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import ThemeSetting from './ThemeSetting';
+import useFeatureFlag from '../../../../hooks/useFeatureFlag';
import {CustomThemeSetting} from '@tryghost/admin-x-framework/api/customThemeSettings';
import {Form} from '@tryghost/admin-x-design-system';
import {Theme, useBrowseThemes} from '@tryghost/admin-x-framework/api/themes';
@@ -43,6 +44,7 @@ const ThemeSettings: React.FC = ({sections, updateSetting})
const {data: themesData} = useBrowseThemes();
const activeTheme = themesData?.themes.find((theme: Theme) => theme.active);
const activeThemeName = activeTheme?.package.name?.toLowerCase() || '';
+ const hasCustomFonts = useFeatureFlag('customFonts');
return (
<>
@@ -65,9 +67,11 @@ const ThemeSettings: React.FC = ({sections, updateSetting})
// hides typography related theme settings from official themes
// should be removed once we remove the settings from the themes in 6.0
- const hidingSettings = themeSettingsMap[activeThemeName];
- if (hidingSettings && hidingSettings.includes(setting.key)) {
- spaceClass += ' hidden';
+ if (hasCustomFonts) {
+ const hidingSettings = themeSettingsMap[activeThemeName];
+ if (hidingSettings && hidingSettings.includes(setting.key)) {
+ spaceClass += ' hidden';
+ }
}
previousType = setting.type;
diff --git a/apps/admin-x-settings/test/acceptance/site/design.test.ts b/apps/admin-x-settings/test/acceptance/site/design.test.ts
index b590b2e5ce..0159600300 100644
--- a/apps/admin-x-settings/test/acceptance/site/design.test.ts
+++ b/apps/admin-x-settings/test/acceptance/site/design.test.ts
@@ -3,6 +3,7 @@ import {
mockApi,
mockSitePreview,
responseFixtures,
+ toggleLabsFlag,
updatedSettingsResponse
} from '@tryghost/admin-x-framework/test/acceptance';
import {expect, test} from '@playwright/test';
@@ -305,6 +306,7 @@ test.describe('Design settings', async () => {
});
test('Custom fonts', async ({page}) => {
+ toggleLabsFlag('customFonts', true);
await mockApi({page, requests: {
...globalDataRequests,
browseCustomThemeSettings: {method: 'GET', path: '/custom_theme_settings/', response: {
@@ -350,6 +352,7 @@ test.describe('Design settings', async () => {
});
test('Custom fonts setting back to default', async ({page}) => {
+ toggleLabsFlag('customFonts', true);
await mockApi({page, requests: {
...globalDataRequests,
browseSettings: {...globalDataRequests.browseSettings, response: updatedSettingsResponse([
diff --git a/ghost/core/core/frontend/helpers/body_class.js b/ghost/core/core/frontend/helpers/body_class.js
index a734a49b62..e1d5bbca69 100644
--- a/ghost/core/core/frontend/helpers/body_class.js
+++ b/ghost/core/core/frontend/helpers/body_class.js
@@ -2,7 +2,7 @@
// Usage: `{{body_class}}`
//
// Output classes for the body element
-const {settingsCache} = require('../services/proxy');
+const {labs, settingsCache} = require('../services/proxy');
const {generateCustomFontBodyClass, isValidCustomFont, isValidCustomHeadingFont} = require('@tryghost/custom-fonts');
const {SafeString} = require('../services/handlebars');
@@ -45,28 +45,30 @@ module.exports = function body_class(options) { // eslint-disable-line camelcase
classes.push('paged');
}
- // Check if if the request is for a site preview, in which case we **always** use the custom font values
- // from the passed in data, even when they're empty strings or settings cache has values.
- const isSitePreview = options.data?.site?._preview ?? false;
- // Taking the fonts straight from the passed in data, as they can't be used from the
- // settings cache for the theme preview until the settings are saved. Once saved,
- // we need to use the settings cache to provide the correct CSS injection.
- const headingFont = isSitePreview ? options.data?.site?.heading_font : settingsCache.get('heading_font');
- const bodyFont = isSitePreview ? options.data?.site?.body_font : settingsCache.get('body_font');
+ if (labs.isSet('customFonts')) {
+ // Check if if the request is for a site preview, in which case we **always** use the custom font values
+ // from the passed in data, even when they're empty strings or settings cache has values.
+ const isSitePreview = options.data.site._preview;
+ // Taking the fonts straight from the passed in data, as they can't be used from the
+ // settings cache for the theme preview until the settings are saved. Once saved,
+ // we need to use the settings cache to provide the correct CSS injection.
+ const headingFont = isSitePreview ? options.data.site.heading_font : settingsCache.get('heading_font');
+ const bodyFont = isSitePreview ? options.data.site.body_font : settingsCache.get('body_font');
- if ((typeof headingFont === 'string' && isValidCustomHeadingFont(headingFont)) ||
- (typeof bodyFont === 'string' && isValidCustomFont(bodyFont))) {
- /** @type FontSelection */
- const fontSelection = {};
+ if ((typeof headingFont === 'string' && isValidCustomHeadingFont(headingFont)) ||
+ (typeof bodyFont === 'string' && isValidCustomFont(bodyFont))) {
+ /** @type FontSelection */
+ const fontSelection = {};
- if (headingFont) {
- fontSelection.heading = headingFont;
+ if (headingFont) {
+ fontSelection.heading = headingFont;
+ }
+ if (bodyFont) {
+ fontSelection.body = bodyFont;
+ }
+ const customBodyClasses = generateCustomFontBodyClass(fontSelection);
+ classes.push(new SafeString(customBodyClasses));
}
- if (bodyFont) {
- fontSelection.body = bodyFont;
- }
- const customBodyClasses = generateCustomFontBodyClass(fontSelection);
- classes.push(new SafeString(customBodyClasses));
}
classes = classes.join(' ').trim();
diff --git a/ghost/core/core/frontend/helpers/ghost_head.js b/ghost/core/core/frontend/helpers/ghost_head.js
index 113df61aae..3d2a004c5a 100644
--- a/ghost/core/core/frontend/helpers/ghost_head.js
+++ b/ghost/core/core/frontend/helpers/ghost_head.js
@@ -353,27 +353,29 @@ module.exports = async function ghost_head(options) { // eslint-disable-line cam
head.push(getTinybirdTrackerScript(dataRoot));
}
- // Check if if the request is for a site preview, in which case we **always** use the custom font values
- // from the passed in data, even when they're empty strings or settings cache has values.
- const isSitePreview = options.data?.site?._preview ?? false;
- // Taking the fonts straight from the passed in data, as they can't be used from the
- // settings cache for the theme preview until the settings are saved. Once saved,
- // we need to use the settings cache to provide the correct CSS injection.
- const headingFont = isSitePreview ? options.data?.site?.heading_font : settingsCache.get('heading_font');
- const bodyFont = isSitePreview ? options.data?.site?.body_font : settingsCache.get('body_font');
- if ((typeof headingFont === 'string' && isValidCustomHeadingFont(headingFont)) ||
- (typeof bodyFont === 'string' && isValidCustomFont(bodyFont))) {
- /** @type FontSelection */
- const fontSelection = {};
+ if (labs.isSet('customFonts')) {
+ // Check if if the request is for a site preview, in which case we **always** use the custom font values
+ // from the passed in data, even when they're empty strings or settings cache has values.
+ const isSitePreview = options.data.site._preview;
+ // Taking the fonts straight from the passed in data, as they can't be used from the
+ // settings cache for the theme preview until the settings are saved. Once saved,
+ // we need to use the settings cache to provide the correct CSS injection.
+ const headingFont = isSitePreview ? options.data.site.heading_font : settingsCache.get('heading_font');
+ const bodyFont = isSitePreview ? options.data.site.body_font : settingsCache.get('body_font');
+ if ((typeof headingFont === 'string' && isValidCustomHeadingFont(headingFont)) ||
+ (typeof bodyFont === 'string' && isValidCustomFont(bodyFont))) {
+ /** @type FontSelection */
+ const fontSelection = {};
- if (headingFont) {
- fontSelection.heading = headingFont;
+ if (headingFont) {
+ fontSelection.heading = headingFont;
+ }
+ if (bodyFont) {
+ fontSelection.body = bodyFont;
+ }
+ const customCSS = generateCustomFontCss(fontSelection);
+ head.push(new SafeString(customCSS));
}
- if (bodyFont) {
- fontSelection.body = bodyFont;
- }
- const customCSS = generateCustomFontCss(fontSelection);
- head.push(new SafeString(customCSS));
}
}
diff --git a/ghost/core/core/shared/labs.js b/ghost/core/core/shared/labs.js
index 4d2c76fab3..461c11e6db 100644
--- a/ghost/core/core/shared/labs.js
+++ b/ghost/core/core/shared/labs.js
@@ -46,7 +46,8 @@ const ALPHA_FEATURES = [
'adminXDemo',
'contentVisibility',
'commentImprovements',
- 'staff2fa'
+ 'staff2fa',
+ 'customFonts'
];
module.exports.GA_KEYS = [...GA_FEATURES];
diff --git a/ghost/core/package.json b/ghost/core/package.json
index f1a80b65dc..fbc8483982 100644
--- a/ghost/core/package.json
+++ b/ghost/core/package.json
@@ -192,7 +192,7 @@
"ghost-storage-base": "1.0.0",
"glob": "8.1.0",
"got": "11.8.6",
- "gscan": "4.46.0",
+ "gscan": "4.45.0",
"human-number": "2.0.4",
"image-size": "1.1.1",
"intl": "1.2.5",
diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/config.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/config.test.js.snap
index 3d86cbea3c..0f4e57852c 100644
--- a/ghost/core/test/e2e-api/admin/__snapshots__/config.test.js.snap
+++ b/ghost/core/test/e2e-api/admin/__snapshots__/config.test.js.snap
@@ -20,6 +20,7 @@ Object {
"collectionsCard": true,
"commentImprovements": true,
"contentVisibility": true,
+ "customFonts": true,
"editorExcerpt": true,
"emailCustomization": true,
"i18n": true,
diff --git a/ghost/core/test/unit/frontend/helpers/__snapshots__/ghost_head.test.js.snap b/ghost/core/test/unit/frontend/helpers/__snapshots__/ghost_head.test.js.snap
index c2ee2114bd..f686b3fa2f 100644
--- a/ghost/core/test/unit/frontend/helpers/__snapshots__/ghost_head.test.js.snap
+++ b/ghost/core/test/unit/frontend/helpers/__snapshots__/ghost_head.test.js.snap
@@ -1032,7 +1032,7 @@ Object {
-
+
",
}
@@ -1106,7 +1106,7 @@ Object {
-
+
",
}
@@ -1180,7 +1180,7 @@ Object {
-
+
",
}
@@ -1254,7 +1254,7 @@ Object {
-
+
",
}
@@ -1403,7 +1403,7 @@ Object {
-
+
",
@@ -1553,7 +1553,7 @@ Object {
-
+
",
diff --git a/ghost/core/test/unit/frontend/helpers/body_class.test.js b/ghost/core/test/unit/frontend/helpers/body_class.test.js
index dec854c436..c39ac4ab2c 100644
--- a/ghost/core/test/unit/frontend/helpers/body_class.test.js
+++ b/ghost/core/test/unit/frontend/helpers/body_class.test.js
@@ -7,7 +7,7 @@ const body_class = require('../../../../core/frontend/helpers/body_class');
// Stubs
const proxy = require('../../../../core/frontend/services/proxy');
-const {settingsCache} = proxy;
+const {settingsCache, labs} = proxy;
describe('{{body_class}} helper', function () {
let options = {};
@@ -30,8 +30,7 @@ describe('{{body_class}} helper', function () {
root: {
context: [],
settings: {active_theme: 'casper'}
- },
- site: {}
+ }
}
};
});
@@ -164,6 +163,7 @@ describe('{{body_class}} helper', function () {
describe('custom fonts', function () {
let settingsCacheStub;
+ let labsStub;
function callBodyClassWithContext(context, self) {
options.data.root.context = context;
@@ -174,6 +174,7 @@ describe('{{body_class}} helper', function () {
}
beforeEach(function () {
+ labsStub = sinon.stub(labs, 'isSet').withArgs('customFonts').returns(true);
settingsCacheStub = sinon.stub(settingsCache, 'get');
options = {
data: {
@@ -215,6 +216,17 @@ describe('{{body_class}} helper', function () {
rendered.string.should.equal('post-template tag-foo tag-bar gh-font-heading-space-grotesk gh-font-body-noto-sans');
});
+ it('does not include custom font classes when custom fonts are not enabled', function () {
+ labsStub.withArgs('customFonts').returns(false);
+
+ const rendered = callBodyClassWithContext(
+ ['post'],
+ {relativeUrl: '/my-awesome-post/', post: {tags: [{slug: 'foo'}, {slug: 'bar'}]}}
+ );
+
+ rendered.string.should.equal('post-template tag-foo tag-bar');
+ });
+
it('includes custom font classes for home page when set in options data object', function () {
options.data.site.heading_font = 'Space Grotesk';
options.data.site.body_font = '';
diff --git a/ghost/core/test/unit/frontend/helpers/ghost_head.test.js b/ghost/core/test/unit/frontend/helpers/ghost_head.test.js
index e6c10fef25..839e24f9bc 100644
--- a/ghost/core/test/unit/frontend/helpers/ghost_head.test.js
+++ b/ghost/core/test/unit/frontend/helpers/ghost_head.test.js
@@ -1128,6 +1128,8 @@ describe('{{ghost_head}} helper', function () {
describe('custom fonts', function () {
it('includes custom font when set in options data object and preview is set', async function () {
+ sinon.stub(labs, 'isSet').withArgs('customFonts').returns(true);
+
const renderObject = {
post: posts[1]
};
@@ -1152,6 +1154,7 @@ describe('{{ghost_head}} helper', function () {
});
it('includes custom font when set in settings cache and no preview', async function () {
+ sinon.stub(labs, 'isSet').withArgs('customFonts').returns(true);
settingsCache.get.withArgs('heading_font').returns('Playfair Display');
settingsCache.get.withArgs('body_font').returns('Lora');
@@ -1171,6 +1174,8 @@ describe('{{ghost_head}} helper', function () {
});
it('does not include custom font when not set', async function () {
+ sinon.stub(labs, 'isSet').withArgs('customFonts').returns(true);
+
settingsCache.get.withArgs('heading_font').returns(null);
settingsCache.get.withArgs('body_font').returns('');
@@ -1190,6 +1195,8 @@ describe('{{ghost_head}} helper', function () {
});
it('does not include custom font when invalid', async function () {
+ sinon.stub(labs, 'isSet').withArgs('customFonts').returns(true);
+
settingsCache.get.withArgs('heading_font').returns(null);
settingsCache.get.withArgs('body_font').returns('Wendy Sans');
@@ -1216,6 +1223,7 @@ describe('{{ghost_head}} helper', function () {
});
it('does not inject custom fonts when preview is set and default font was selected (empty string)', async function () {
+ sinon.stub(labs, 'isSet').withArgs('customFonts').returns(true);
// The site has fonts set up, but we override them with Theme default fonts (empty string)
settingsCache.get.withArgs('heading_font').returns('Playfair Display');
settingsCache.get.withArgs('body_font').returns('Lora');
@@ -1240,6 +1248,8 @@ describe('{{ghost_head}} helper', function () {
});
it('can handle preview being set and custom font keys missing', async function () {
+ sinon.stub(labs, 'isSet').withArgs('customFonts').returns(true);
+
// The site has fonts set up, but we override them with Theme default fonts (empty string)
settingsCache.get.withArgs('heading_font').returns('Playfair Display');
settingsCache.get.withArgs('body_font').returns('Lora');
diff --git a/yarn.lock b/yarn.lock
index a2dbc8ff89..60c65bd26d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -18792,10 +18792,10 @@ growly@^1.3.0:
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==
-gscan@4.46.0:
- version "4.46.0"
- resolved "https://registry.yarnpkg.com/gscan/-/gscan-4.46.0.tgz#682e5388061e35518e0906ca1285734347cbbe60"
- integrity sha512-SHsvld0EbVW7X9aHqL6P2CG31yjvrX1IxrVePZTm4yKxH7jjD1QmSmL1Ol3sFAh5MRqtGBuj9mGfDC1nJI0e7w==
+gscan@4.45.0:
+ version "4.45.0"
+ resolved "https://registry.yarnpkg.com/gscan/-/gscan-4.45.0.tgz#8f033793b80ac65b64d666aac0891287c1e74909"
+ integrity sha512-d7yu7eGJSv7Xrd8lcBr7Bq76xeKe/LYkrRsRgE8vPRlmHxLPx7AlFb585vbS1Q64cQGwQhlAGusIeKesrfOa6w==
dependencies:
"@sentry/node" "^7.73.0"
"@tryghost/config" "^0.2.18"
From d41ccdde8dd9f1f4851f85dcc9caed306f7cf67e Mon Sep 17 00:00:00 2001
From: Ghost CI <41898282+github-actions[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 18:14:42 +0000
Subject: [PATCH 2/2] v5.101.2
---
ghost/admin/package.json | 2 +-
ghost/core/package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ghost/admin/package.json b/ghost/admin/package.json
index 379575b3bc..eae466200a 100644
--- a/ghost/admin/package.json
+++ b/ghost/admin/package.json
@@ -1,6 +1,6 @@
{
"name": "ghost-admin",
- "version": "5.101.1",
+ "version": "5.101.2",
"description": "Ember.js admin client for Ghost",
"author": "Ghost Foundation",
"homepage": "http://ghost.org",
diff --git a/ghost/core/package.json b/ghost/core/package.json
index fbc8483982..690d79fe14 100644
--- a/ghost/core/package.json
+++ b/ghost/core/package.json
@@ -1,6 +1,6 @@
{
"name": "ghost",
- "version": "5.101.1",
+ "version": "5.101.2",
"description": "The professional publishing platform",
"author": "Ghost Foundation",
"homepage": "https://ghost.org",