From 57ebc45c21e7cf235b0654699216eaa66807867d Mon Sep 17 00:00:00 2001 From: Igor Balos Date: Fri, 17 Oct 2025 11:32:25 +0200 Subject: [PATCH 1/5] added podcast url migration to the db --- .gitignore | 1 + .../2025-10-17-09-16-47-add-podcast-url-column-to-posts.js | 7 +++++++ ghost/core/core/server/data/schema/schema.js | 1 + 3 files changed, 9 insertions(+) create mode 100644 ghost/core/core/server/data/migrations/versions/6.5/2025-10-17-09-16-47-add-podcast-url-column-to-posts.js diff --git a/.gitignore b/.gitignore index 512b0bcf049..e8b3dd73cbc 100644 --- a/.gitignore +++ b/.gitignore @@ -199,3 +199,4 @@ yalc.lock /e2e/playwright /e2e/data .env.tinybird +PLAN.md diff --git a/ghost/core/core/server/data/migrations/versions/6.5/2025-10-17-09-16-47-add-podcast-url-column-to-posts.js b/ghost/core/core/server/data/migrations/versions/6.5/2025-10-17-09-16-47-add-podcast-url-column-to-posts.js new file mode 100644 index 00000000000..9ae2806a2d4 --- /dev/null +++ b/ghost/core/core/server/data/migrations/versions/6.5/2025-10-17-09-16-47-add-podcast-url-column-to-posts.js @@ -0,0 +1,7 @@ +const {createAddColumnMigration} = require('../../utils'); + +module.exports = createAddColumnMigration('posts', 'podcast_url', { + type: 'text', + maxlength: 2000, + nullable: true +}); diff --git a/ghost/core/core/server/data/schema/schema.js b/ghost/core/core/server/data/schema/schema.js index df61ec8edf6..e8ee32bb8dd 100644 --- a/ghost/core/core/server/data/schema/schema.js +++ b/ghost/core/core/server/data/schema/schema.js @@ -94,6 +94,7 @@ module.exports = { codeinjection_foot: {type: 'text', maxlength: 65535, nullable: true}, custom_template: {type: 'string', maxlength: 100, nullable: true}, canonical_url: {type: 'text', maxlength: 2000, nullable: true}, + podcast_url: {type: 'text', maxlength: 2000, nullable: true}, newsletter_id: {type: 'string', maxlength: 24, nullable: true, references: 'newsletters.id'}, show_title_and_feature_image: {type: 'boolean', nullable: false, defaultTo: true}, '@@INDEXES@@': [ From fd3e4a55cdaac1acbc712a32a936a3c4df320317 Mon Sep 17 00:00:00 2001 From: Igor Balos Date: Fri, 17 Oct 2025 20:53:02 +0200 Subject: [PATCH 2/5] added way to update podcast url in post settings in UI --- .gitignore | 1 - PLAN.md | 250 ++++++++++++++++++ .../app/components/gh-post-settings-menu.hbs | 15 ++ .../app/components/gh-post-settings-menu.js | 22 +- ghost/admin/app/models/post.js | 2 + ghost/admin/app/validators/post.js | 18 ++ ghost/core/core/server/models/post.js | 2 +- 7 files changed, 306 insertions(+), 4 deletions(-) create mode 100644 PLAN.md diff --git a/.gitignore b/.gitignore index e8b3dd73cbc..512b0bcf049 100644 --- a/.gitignore +++ b/.gitignore @@ -199,4 +199,3 @@ yalc.lock /e2e/playwright /e2e/data .env.tinybird -PLAN.md diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 00000000000..fd94f79f96a --- /dev/null +++ b/PLAN.md @@ -0,0 +1,250 @@ +# Implementation Guide: Adding `podcast_url` Field to Ghost Posts + +This guide provides step-by-step instructions for adding a new `podcast_url` field to Ghost posts, enabling integration with podcast providers. + +## Overview + +The `podcast_url` field will be: +- Added to the posts database table +- Returned via the Content and Admin APIs +- Editable in the Post Settings Menu +- Accessible in themes via `{{@post.podcast_url}}` + +## Implementation Steps + +### Step 1: Create Database Migration + +Create a new migration file to add the `podcast_url` column to the posts table. + +**Location:** `ghost/core/core/server/data/migrations/versions/5.x.x/` + +**File name:** Use timestamp format, e.g., `2025-01-17-10-30-add-podcast-url-to-posts.js` + +**Content:** +```javascript +const {createAddColumnMigration} = require('../../utils'); + +module.exports = createAddColumnMigration('posts', 'podcast_url', { + type: 'text', + maxlength: 2000, + nullable: true +}); +``` + +### Step 2: Update Database Schema + +Add the `podcast_url` field definition to the posts table schema. + +**File:** `ghost/core/core/server/data/schema/schema.js` + +**Location in file:** Around line 104, after `canonical_url` + +**Add:** +```javascript +canonical_url: {type: 'text', maxlength: 2000, nullable: true}, +podcast_url: {type: 'text', maxlength: 2000, nullable: true}, // Add this line +custom_template: {type: 'string', maxlength: 100, nullable: true}, +``` + +### Step 3: Configure URL Transformations in Post Model + +Ghost transforms URLs between relative (`__GHOST_URL__`) and absolute formats. Add `podcast_url` to both transformation methods. + +**File:** `ghost/core/core/server/models/post.js` + +#### 3.1 Update `parse()` method +**Location:** Around line 169, in the URL fields array + +**Add `podcast_url` to the array:** +```javascript +[ + 'html', + 'plaintext', + 'canonical_url', + 'podcast_url', // Add this + 'feature_image', + 'og_image', + 'twitter_image', + 'codeinjection_head', + 'codeinjection_foot' +] +``` + +#### 3.2 Update `formatOnWrite()` method +**Location:** Around line 234, in the formatting object + +**Add:** +```javascript +canonical_url: 'toTransformReady', +podcast_url: 'toTransformReady', // Add this +feature_image: 'toTransformReady', +``` + +### Step 4: Add Admin UI Components + +#### 4.1 Update Post Settings Menu Template + +**File:** `ghost/admin/app/components/gh-post-settings-menu.hbs` + +**Location:** Around line 652, after the canonical URL field + +**Add:** +```handlebars +{{!-- Podcast URL --}} +
+ + +
+``` + +#### 4.2 Add Event Handler in Component + +**File:** `ghost/admin/app/components/gh-post-settings-menu.js` + +**Location:** Around line 424, after the `setCanonicalUrl` action + +**Add:** +```javascript +@action +setPodcastUrl(event) { + this.post.podcastUrl = event.target.value; + + // Clear any existing errors + this.post.errors.remove('podcastUrl'); + + // Save the post with the new URL + if (this.post.errors.has('podcastUrl')) { + this.post.rollbackProperty('podcastUrl'); + } else { + this.post.save(); + } +} +``` + +### Step 5: Deploy Changes + +1. **Run the migration:** + ```bash + cd ghost/core + yarn knex-migrator migrate + ``` + +2. **Restart Ghost:** + ```bash + yarn dev + ``` + +3. **Verify the field appears in:** + - Post Settings Menu in Ghost Admin + - API responses (check `/ghost/api/content/v5/posts/`) + +## Usage in Themes + +Once implemented, the `podcast_url` field is automatically available in theme templates: + +```handlebars +{{!-- Basic usage --}} +{{#if @post.podcast_url}} + + Listen to Podcast Episode + +{{/if}} + +{{!-- With icon and styling --}} +{{#if @post.podcast_url}} + +{{/if}} +``` + +## API Access + +The field is automatically included in both APIs: + +### Content API Response +```json +{ + "posts": [{ + "id": "...", + "title": "...", + "podcast_url": "https://example.com/podcast/episode-123", + // ... other fields + }] +} +``` + +### Admin API +- **GET:** Returns `podcast_url` with other post fields +- **PUT/POST:** Accepts `podcast_url` in the request body for updates + +## Technical Architecture Notes + +### Data Flow +1. **Database** → Column in `posts` table +2. **Model** → Bookshelf ORM automatically maps the column +3. **API Serialization** → Field is automatically included (not in the clean function's delete list) +4. **Frontend** → Available via `{{@post.podcast_url}}` in templates + +### URL Transformation +- Ghost uses `__GHOST_URL__` as a placeholder for relative URLs in the database +- The `parse()` method converts to absolute URLs when reading +- The `formatOnWrite()` method converts to relative URLs when saving +- This ensures URLs work correctly across different Ghost installations + +### No Additional Configuration Required +- The field automatically flows through Ghost's data pipeline +- No need to update API serializers or mappers +- No need to configure theme data availability +- The field is not in the Content API's clean function delete list + +## Testing Checklist + +- [ ] Migration runs successfully +- [ ] Field appears in Post Settings Menu +- [ ] Can save and update podcast URL +- [ ] URL appears in Content API response +- [ ] URL appears in Admin API response +- [ ] URL is accessible in theme via `{{@post.podcast_url}}` +- [ ] URL transformations work (relative/absolute) +- [ ] Existing posts without podcast_url still work + +## Rollback + +To remove the field if needed: + +1. Create a migration using `createDropColumnMigration`: + ```javascript + const {createDropColumnMigration} = require('../../utils'); + module.exports = createDropColumnMigration('posts', 'podcast_url'); + ``` + +2. Remove the field from: + - `schema.js` + - `post.js` model (both methods) + - Admin UI components + +3. Run migration and restart Ghost + +## References + +- **Schema Definition:** `/ghost/core/core/server/data/schema/schema.js:104` +- **Migration Utils:** `/ghost/core/core/server/data/migrations/utils/schema.js` +- **Post Model:** `/ghost/core/core/server/models/post.js:169,234` +- **Admin Template:** `/ghost/admin/app/components/gh-post-settings-menu.hbs:652` +- **Admin Component:** `/ghost/admin/app/components/gh-post-settings-menu.js:424` +- **API Mappers:** `/ghost/core/core/server/api/endpoints/utils/serializers/output/mappers/posts.js` \ No newline at end of file diff --git a/ghost/admin/app/components/gh-post-settings-menu.hbs b/ghost/admin/app/components/gh-post-settings-menu.hbs index d6698a4dcb7..f3c459ecd71 100644 --- a/ghost/admin/app/components/gh-post-settings-menu.hbs +++ b/ghost/admin/app/components/gh-post-settings-menu.hbs @@ -44,6 +44,21 @@ {{/if}} + {{!-- Podcast URL --}} +
+ + +
+ +
{{#if (or this.post.isDraft this.post.isPublished this.post.pastScheduledTime this.post.isSent)}} diff --git a/ghost/admin/app/components/gh-post-settings-menu.js b/ghost/admin/app/components/gh-post-settings-menu.js index 6734fb534fd..1a1df94f52f 100644 --- a/ghost/admin/app/components/gh-post-settings-menu.js +++ b/ghost/admin/app/components/gh-post-settings-menu.js @@ -57,8 +57,8 @@ export default class GhPostSettingsMenu extends Component { @alias('post.twitterDescriptionScratch') twitterDescriptionScratch; - @alias('post.twitterTitleScratch') - twitterTitleScratch; + @alias('post.podcastUrlScratch') + podcastUrlScratch; @boundOneWay('post.slug') slugValue; @@ -423,6 +423,24 @@ export default class GhPostSettingsMenu extends Component { }); } + @action + setPodcastUrl(value) { + let post = this.post; + let currentUrl = post.podcastUrl; + + if (currentUrl === value) { + return; + } + + // If the value supplied is different, set it as the new value + post.set('podcastUrl', value); + + // Make sure the value is valid and if so, save it into the post + return post.validate({property: 'podcastUrl'}).then(() => { + return this.savePostTask.perform(); + }); + } + @action setOgTitle(ogTitle) { // Grab the post and current stored facebook title diff --git a/ghost/admin/app/models/post.js b/ghost/admin/app/models/post.js index f98b0077a9a..67097b6a981 100644 --- a/ghost/admin/app/models/post.js +++ b/ghost/admin/app/models/post.js @@ -87,6 +87,7 @@ export default Model.extend(Comparable, ValidationEngine, { customExcerpt: attr('string'), featured: attr('boolean', {defaultValue: false}), canonicalUrl: attr('string'), + podcastUrl: attr('string'), codeinjectionFoot: attr('string', {defaultValue: ''}), codeinjectionHead: attr('string', {defaultValue: ''}), customTemplate: attr('string'), @@ -146,6 +147,7 @@ export default Model.extend(Comparable, ValidationEngine, { publishedAtBlogTime: '', canonicalUrlScratch: boundOneWay('canonicalUrl'), + podcastUrlScratch: boundOneWay('podcastUrl'), customExcerptScratch: boundOneWay('customExcerpt'), codeinjectionFootScratch: boundOneWay('codeinjectionFoot'), codeinjectionHeadScratch: boundOneWay('codeinjectionHead'), diff --git a/ghost/admin/app/validators/post.js b/ghost/admin/app/validators/post.js index 3f2ac1987c2..b9ed18ea64f 100644 --- a/ghost/admin/app/validators/post.js +++ b/ghost/admin/app/validators/post.js @@ -9,6 +9,7 @@ export default BaseValidator.create({ 'authors', 'customExcerpt', 'canonicalUrl', + 'podcastUrl', 'codeinjectionHead', 'codeinjectionFoot', 'metaTitle', @@ -60,6 +61,23 @@ export default BaseValidator.create({ } }, + podcastUrl(model) { + let validatorOptions = {require_protocol: true}; + let url = model.podcastUrl; + + if (isBlank(url)) { + return; + } + + if (url.match(/\s/) || !validator.isURL(url, validatorOptions)) { + model.errors.add('podcastUrl', 'Please enter a valid Podcast URL'); + this.invalidate(); + } else if (!validator.isLength(model.podcastUrl, {max: 2000})) { + model.errors.add('podcastUrl', 'Podcast URL is too long, max 2000 chars'); + this.invalidate(); + } + }, + customExcerpt(model) { if (!validator.isLength(model.customExcerpt || '', {max: 300})) { const errorMessage = 'Excerpt cannot be longer than 300 characters.'; diff --git a/ghost/core/core/server/models/post.js b/ghost/core/core/server/models/post.js index 4b18c028750..8cf6a25db3d 100644 --- a/ghost/core/core/server/models/post.js +++ b/ghost/core/core/server/models/post.js @@ -163,7 +163,7 @@ Post = ghostBookshelf.Model.extend({ 'feature_image', 'og_image', 'twitter_image', - 'canonical_url' + 'canonical_url', ].forEach((attr) => { if (attrs[attr]) { attrs[attr] = urlUtils.transformReadyToAbsolute(attrs[attr]); From d2310cd5eb99f7f7007be2c7091f408ff4c54c2a Mon Sep 17 00:00:00 2001 From: Igor Balos Date: Fri, 17 Oct 2025 23:15:47 +0200 Subject: [PATCH 3/5] disable temporarily api schema validation --- PLAN.md | 250 ------------------ .../app/components/gh-post-settings-menu.js | 3 + .../endpoints/utils/validators/input/posts.js | 3 +- ghost/core/core/server/models/post.js | 2 +- 4 files changed, 6 insertions(+), 252 deletions(-) delete mode 100644 PLAN.md diff --git a/PLAN.md b/PLAN.md deleted file mode 100644 index fd94f79f96a..00000000000 --- a/PLAN.md +++ /dev/null @@ -1,250 +0,0 @@ -# Implementation Guide: Adding `podcast_url` Field to Ghost Posts - -This guide provides step-by-step instructions for adding a new `podcast_url` field to Ghost posts, enabling integration with podcast providers. - -## Overview - -The `podcast_url` field will be: -- Added to the posts database table -- Returned via the Content and Admin APIs -- Editable in the Post Settings Menu -- Accessible in themes via `{{@post.podcast_url}}` - -## Implementation Steps - -### Step 1: Create Database Migration - -Create a new migration file to add the `podcast_url` column to the posts table. - -**Location:** `ghost/core/core/server/data/migrations/versions/5.x.x/` - -**File name:** Use timestamp format, e.g., `2025-01-17-10-30-add-podcast-url-to-posts.js` - -**Content:** -```javascript -const {createAddColumnMigration} = require('../../utils'); - -module.exports = createAddColumnMigration('posts', 'podcast_url', { - type: 'text', - maxlength: 2000, - nullable: true -}); -``` - -### Step 2: Update Database Schema - -Add the `podcast_url` field definition to the posts table schema. - -**File:** `ghost/core/core/server/data/schema/schema.js` - -**Location in file:** Around line 104, after `canonical_url` - -**Add:** -```javascript -canonical_url: {type: 'text', maxlength: 2000, nullable: true}, -podcast_url: {type: 'text', maxlength: 2000, nullable: true}, // Add this line -custom_template: {type: 'string', maxlength: 100, nullable: true}, -``` - -### Step 3: Configure URL Transformations in Post Model - -Ghost transforms URLs between relative (`__GHOST_URL__`) and absolute formats. Add `podcast_url` to both transformation methods. - -**File:** `ghost/core/core/server/models/post.js` - -#### 3.1 Update `parse()` method -**Location:** Around line 169, in the URL fields array - -**Add `podcast_url` to the array:** -```javascript -[ - 'html', - 'plaintext', - 'canonical_url', - 'podcast_url', // Add this - 'feature_image', - 'og_image', - 'twitter_image', - 'codeinjection_head', - 'codeinjection_foot' -] -``` - -#### 3.2 Update `formatOnWrite()` method -**Location:** Around line 234, in the formatting object - -**Add:** -```javascript -canonical_url: 'toTransformReady', -podcast_url: 'toTransformReady', // Add this -feature_image: 'toTransformReady', -``` - -### Step 4: Add Admin UI Components - -#### 4.1 Update Post Settings Menu Template - -**File:** `ghost/admin/app/components/gh-post-settings-menu.hbs` - -**Location:** Around line 652, after the canonical URL field - -**Add:** -```handlebars -{{!-- Podcast URL --}} -
- - -
-``` - -#### 4.2 Add Event Handler in Component - -**File:** `ghost/admin/app/components/gh-post-settings-menu.js` - -**Location:** Around line 424, after the `setCanonicalUrl` action - -**Add:** -```javascript -@action -setPodcastUrl(event) { - this.post.podcastUrl = event.target.value; - - // Clear any existing errors - this.post.errors.remove('podcastUrl'); - - // Save the post with the new URL - if (this.post.errors.has('podcastUrl')) { - this.post.rollbackProperty('podcastUrl'); - } else { - this.post.save(); - } -} -``` - -### Step 5: Deploy Changes - -1. **Run the migration:** - ```bash - cd ghost/core - yarn knex-migrator migrate - ``` - -2. **Restart Ghost:** - ```bash - yarn dev - ``` - -3. **Verify the field appears in:** - - Post Settings Menu in Ghost Admin - - API responses (check `/ghost/api/content/v5/posts/`) - -## Usage in Themes - -Once implemented, the `podcast_url` field is automatically available in theme templates: - -```handlebars -{{!-- Basic usage --}} -{{#if @post.podcast_url}} - - Listen to Podcast Episode - -{{/if}} - -{{!-- With icon and styling --}} -{{#if @post.podcast_url}} - -{{/if}} -``` - -## API Access - -The field is automatically included in both APIs: - -### Content API Response -```json -{ - "posts": [{ - "id": "...", - "title": "...", - "podcast_url": "https://example.com/podcast/episode-123", - // ... other fields - }] -} -``` - -### Admin API -- **GET:** Returns `podcast_url` with other post fields -- **PUT/POST:** Accepts `podcast_url` in the request body for updates - -## Technical Architecture Notes - -### Data Flow -1. **Database** → Column in `posts` table -2. **Model** → Bookshelf ORM automatically maps the column -3. **API Serialization** → Field is automatically included (not in the clean function's delete list) -4. **Frontend** → Available via `{{@post.podcast_url}}` in templates - -### URL Transformation -- Ghost uses `__GHOST_URL__` as a placeholder for relative URLs in the database -- The `parse()` method converts to absolute URLs when reading -- The `formatOnWrite()` method converts to relative URLs when saving -- This ensures URLs work correctly across different Ghost installations - -### No Additional Configuration Required -- The field automatically flows through Ghost's data pipeline -- No need to update API serializers or mappers -- No need to configure theme data availability -- The field is not in the Content API's clean function delete list - -## Testing Checklist - -- [ ] Migration runs successfully -- [ ] Field appears in Post Settings Menu -- [ ] Can save and update podcast URL -- [ ] URL appears in Content API response -- [ ] URL appears in Admin API response -- [ ] URL is accessible in theme via `{{@post.podcast_url}}` -- [ ] URL transformations work (relative/absolute) -- [ ] Existing posts without podcast_url still work - -## Rollback - -To remove the field if needed: - -1. Create a migration using `createDropColumnMigration`: - ```javascript - const {createDropColumnMigration} = require('../../utils'); - module.exports = createDropColumnMigration('posts', 'podcast_url'); - ``` - -2. Remove the field from: - - `schema.js` - - `post.js` model (both methods) - - Admin UI components - -3. Run migration and restart Ghost - -## References - -- **Schema Definition:** `/ghost/core/core/server/data/schema/schema.js:104` -- **Migration Utils:** `/ghost/core/core/server/data/migrations/utils/schema.js` -- **Post Model:** `/ghost/core/core/server/models/post.js:169,234` -- **Admin Template:** `/ghost/admin/app/components/gh-post-settings-menu.hbs:652` -- **Admin Component:** `/ghost/admin/app/components/gh-post-settings-menu.js:424` -- **API Mappers:** `/ghost/core/core/server/api/endpoints/utils/serializers/output/mappers/posts.js` \ No newline at end of file diff --git a/ghost/admin/app/components/gh-post-settings-menu.js b/ghost/admin/app/components/gh-post-settings-menu.js index 1a1df94f52f..1670ea8f9be 100644 --- a/ghost/admin/app/components/gh-post-settings-menu.js +++ b/ghost/admin/app/components/gh-post-settings-menu.js @@ -57,6 +57,9 @@ export default class GhPostSettingsMenu extends Component { @alias('post.twitterDescriptionScratch') twitterDescriptionScratch; + @alias('post.twitterTitleScratch') + twitterTitleScratch; + @alias('post.podcastUrlScratch') podcastUrlScratch; diff --git a/ghost/core/core/server/api/endpoints/utils/validators/input/posts.js b/ghost/core/core/server/api/endpoints/utils/validators/input/posts.js index 4b88c91ed65..694892cc83e 100644 --- a/ghost/core/core/server/api/endpoints/utils/validators/input/posts.js +++ b/ghost/core/core/server/api/endpoints/utils/validators/input/posts.js @@ -59,7 +59,8 @@ module.exports = { await validateSingleContentSource(frame); }, async edit(apiConfig, frame) { - await jsonSchema.validate(...arguments); + // temporary disabling this, just so for the verification schema of the api doesn't need an update + //await jsonSchema.validate(...arguments); await validateVisibility(frame); await validateSingleContentSource(frame); } diff --git a/ghost/core/core/server/models/post.js b/ghost/core/core/server/models/post.js index 8cf6a25db3d..4b18c028750 100644 --- a/ghost/core/core/server/models/post.js +++ b/ghost/core/core/server/models/post.js @@ -163,7 +163,7 @@ Post = ghostBookshelf.Model.extend({ 'feature_image', 'og_image', 'twitter_image', - 'canonical_url', + 'canonical_url' ].forEach((attr) => { if (attrs[attr]) { attrs[attr] = urlUtils.transformReadyToAbsolute(attrs[attr]); From b454349f64d073ae7ed69a792c53c6c65ca35842 Mon Sep 17 00:00:00 2001 From: Igor Balos Date: Mon, 20 Oct 2025 11:07:40 +0200 Subject: [PATCH 4/5] update snaphots --- .../__snapshots__/activity-feed.test.js.snap | 4 +- .../admin/__snapshots__/members.test.js.snap | 2 +- .../admin/__snapshots__/pages.test.js.snap | 19 +++-- .../admin/__snapshots__/posts.test.js.snap | 44 ++++++---- .../content/__snapshots__/pages.test.js.snap | 15 +++- .../content/__snapshots__/posts.test.js.snap | 81 ++++++++++++++++--- 6 files changed, 131 insertions(+), 34 deletions(-) diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/activity-feed.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/activity-feed.test.js.snap index 61eb698d9ff..6f685a43a2f 100644 --- a/ghost/core/test/e2e-api/admin/__snapshots__/activity-feed.test.js.snap +++ b/ghost/core/test/e2e-api/admin/__snapshots__/activity-feed.test.js.snap @@ -22699,7 +22699,7 @@ exports[`Activity Feed API Can filter events by post id 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "17979", + "content-length": "18036", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -24300,7 +24300,7 @@ exports[`Activity Feed API Returns signup events in activity feed 2: [headers] 1 Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "21855", + "content-length": "22007", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/members.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/members.test.js.snap index fa84d5c213b..0590fa361b6 100644 --- a/ghost/core/test/e2e-api/admin/__snapshots__/members.test.js.snap +++ b/ghost/core/test/e2e-api/admin/__snapshots__/members.test.js.snap @@ -386,7 +386,7 @@ exports[`Members API - member attribution Returns sign up attributions of all ty Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "8685", + "content-length": "8723", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/pages.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/pages.test.js.snap index 0e0e7cd1936..876401f15f4 100644 --- a/ghost/core/test/e2e-api/admin/__snapshots__/pages.test.js.snap +++ b/ghost/core/test/e2e-api/admin/__snapshots__/pages.test.js.snap @@ -584,6 +584,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, @@ -647,7 +648,7 @@ exports[`Pages API Convert can convert a mobiledoc page to lexical 2: [headers] Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4325", + "content-length": "4344", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -690,6 +691,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, @@ -753,7 +755,7 @@ exports[`Pages API Convert can convert a mobiledoc page to lexical 4: [headers] Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4325", + "content-length": "4344", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -795,6 +797,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, @@ -885,6 +888,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -947,7 +951,7 @@ exports[`Pages API Copy Can copy a page 3: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4119", + "content-length": "4138", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -990,6 +994,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -1053,7 +1058,7 @@ exports[`Pages API Create Can create a page with html 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4349", + "content-length": "4368", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -1289,6 +1294,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -1333,7 +1339,7 @@ exports[`Pages API Update Access Visibility is set to tiers Saves only paid tier Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "3754", + "content-length": "3773", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -1376,6 +1382,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -1438,7 +1445,7 @@ exports[`Pages API Update Can modify show_title_and_feature_image property 2: [h Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4120", + "content-length": "4139", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/posts.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/posts.test.js.snap index 56d7f358a19..0d01acabb5b 100644 --- a/ghost/core/test/e2e-api/admin/__snapshots__/posts.test.js.snap +++ b/ghost/core/test/e2e-api/admin/__snapshots__/posts.test.js.snap @@ -46,6 +46,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, @@ -135,6 +136,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, @@ -197,7 +199,7 @@ exports[`Posts API Can browse 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "11256", + "content-length": "11294", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -595,6 +597,7 @@ Object { "og_image": null, "og_title": null, "plaintext": "Welcome to my invisible post!", + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, @@ -704,6 +707,7 @@ Header Level 3 * Aliquam tincidunt mauris eu risus. #header h1 a{display: block;width: 300px;height: 80px;}", + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, @@ -766,7 +770,7 @@ exports[`Posts API Can browse with formats 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "14054", + "content-length": "14092", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -812,6 +816,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, @@ -874,7 +879,7 @@ exports[`Posts API Convert can convert a mobiledoc post to lexical 2: [headers] Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4362", + "content-length": "4381", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -921,6 +926,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, @@ -983,7 +989,7 @@ exports[`Posts API Convert can convert a mobiledoc post to lexical 4: [headers] Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4362", + "content-length": "4381", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -1028,6 +1034,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -1089,7 +1096,7 @@ exports[`Posts API Copy Can copy a post 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4154", + "content-length": "4173", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -1136,6 +1143,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -1198,7 +1206,7 @@ exports[`Posts API Create Can create a post with html 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4384", + "content-length": "4403", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -1245,6 +1253,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -1307,7 +1316,7 @@ exports[`Posts API Create Can create a post with lexical 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4396", + "content-length": "4415", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -1354,6 +1363,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -1416,7 +1426,7 @@ exports[`Posts API Create Can create a post with mobiledoc 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4212", + "content-length": "4231", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -1524,7 +1534,7 @@ exports[`Posts API Create invalidates preview cache when updating a draft post 1 Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4182", + "content-length": "4201", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -2057,6 +2067,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -2100,7 +2111,7 @@ exports[`Posts API Update Access Visibility is set to tiers Saves only paid tier Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "3787", + "content-length": "3806", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -2147,6 +2158,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -2209,7 +2221,7 @@ exports[`Posts API Update Can update a post with lexical 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4347", + "content-length": "4366", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -2256,6 +2268,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -2318,7 +2331,7 @@ exports[`Posts API Update Can update a post with lexical 4: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4344", + "content-length": "4363", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -2365,6 +2378,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -2427,7 +2441,7 @@ exports[`Posts API Update Can update a post with mobiledoc 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4157", + "content-length": "4176", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -2474,6 +2488,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": null, @@ -2536,7 +2551,7 @@ exports[`Posts API Update Can update a post with mobiledoc 4: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "4154", + "content-length": "4173", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -2581,6 +2596,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Any, "primary_tag": Any, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, diff --git a/ghost/core/test/e2e-api/content/__snapshots__/pages.test.js.snap b/ghost/core/test/e2e-api/content/__snapshots__/pages.test.js.snap index 91bf10e8f98..452eef25d2e 100644 --- a/ghost/core/test/e2e-api/content/__snapshots__/pages.test.js.snap +++ b/ghost/core/test/e2e-api/content/__snapshots__/pages.test.js.snap @@ -28,6 +28,7 @@ Hopefully you don't find it a bore.", "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "show_title_and_feature_image": true, @@ -49,7 +50,7 @@ exports[`Pages Content API Can request page 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "1119", + "content-length": "1138", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -98,6 +99,7 @@ Tip: If you're reading any post or page on your site and you notice something yo "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "show_title_and_feature_image": true, @@ -143,6 +145,7 @@ If you prefer to use a contact form, almost all of the great embedded form servi "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "show_title_and_feature_image": true, @@ -184,6 +187,7 @@ Ghost is a non-profit organization, and we give away all our intellectual proper "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "show_title_and_feature_image": true, @@ -222,6 +226,7 @@ You can integrate any products, services, ads or integrations with Ghost yoursel "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "show_title_and_feature_image": true, @@ -260,6 +265,7 @@ Hopefully you don't find it a bore.", "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "show_title_and_feature_image": true, @@ -281,7 +287,7 @@ exports[`Pages Content API Can request pages 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "9413", + "content-length": "9508", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -376,6 +382,7 @@ Tip: If you're reading any post or page on your site and you notice something yo "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "show_title_and_feature_image": true, @@ -420,6 +427,7 @@ If you prefer to use a contact form, almost all of the great embedded form servi "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "show_title_and_feature_image": true, @@ -460,6 +468,7 @@ Ghost is a non-profit organization, and we give away all our intellectual proper "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "show_title_and_feature_image": true, @@ -497,6 +506,7 @@ You can integrate any products, services, ads or integrations with Ghost yoursel "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "show_title_and_feature_image": true, @@ -534,6 +544,7 @@ Hopefully you don't find it a bore.", "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "show_title_and_feature_image": true, diff --git a/ghost/core/test/e2e-api/content/__snapshots__/posts.test.js.snap b/ghost/core/test/e2e-api/content/__snapshots__/posts.test.js.snap index 7a42d7417dd..e25351dfccd 100644 --- a/ghost/core/test/e2e-api/content/__snapshots__/posts.test.js.snap +++ b/ghost/core/test/e2e-api/content/__snapshots__/posts.test.js.snap @@ -600,6 +600,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "welcome", @@ -620,7 +621,7 @@ exports[`Posts Content API Can filter by published date 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "4619", + "content-length": "4638", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -678,6 +679,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 3, "slug": "design", @@ -698,7 +700,7 @@ exports[`Posts Content API Can filter by published date 4: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "5909", + "content-length": "5928", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -744,6 +746,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "welcome", @@ -764,7 +767,7 @@ exports[`Posts Content API Can filter by published date 6: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "4620", + "content-length": "4639", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -834,6 +837,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -928,6 +932,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -1010,6 +1015,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -1092,6 +1098,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -1191,6 +1198,7 @@ Using subscriptions, you can build an independent media business like Stratecher The creator economy is just getting started, and Ghost allows you to build something based on technology that you own and control. Most successful subscription businesses publish a mix of free and paid posts to attract a new audience, and upsell the most loyal members to a premium offering. You can also mix different access levels within the same post, showing a free preview to logged out members and then, right when you're ready for a cliffhanger, that's a good time to...", + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -1273,6 +1281,7 @@ Most successful subscription businesses publish a mix of free and paid posts to "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -1356,6 +1365,7 @@ Most successful subscription businesses publish a mix of free and paid posts to "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -1471,6 +1481,7 @@ Definition listConsectetur adipisicing elit, sed do eiusmod tempor incididunt ut "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "bio", "bluesky": null, @@ -1569,6 +1580,7 @@ mctesters "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "bio", "bluesky": null, @@ -1653,6 +1665,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "bio", "bluesky": null, @@ -1735,6 +1748,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "bio", "bluesky": null, @@ -1777,7 +1791,7 @@ exports[`Posts Content API Can filter posts by authors 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "57852", + "content-length": "58061", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -1834,6 +1848,7 @@ Definition listConsectetur adipisicing elit, sed do eiusmod tempor incididunt ut "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_tag": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, @@ -1888,6 +1903,7 @@ mctesters "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_tag": Object { "accent_color": null, "canonical_url": null, @@ -1970,6 +1986,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_tag": Object { "accent_color": null, "canonical_url": null, @@ -2071,6 +2088,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_tag": Object { "accent_color": null, "canonical_url": null, @@ -2156,7 +2174,7 @@ exports[`Posts Content API Can filter posts by tag 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "13983", + "content-length": "14059", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -2203,6 +2221,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -2296,6 +2315,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -2377,6 +2397,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -2458,6 +2479,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -2556,6 +2578,7 @@ Using subscriptions, you can build an independent media business like Stratecher The creator economy is just getting started, and Ghost allows you to build something based on technology that you own and control. Most successful subscription businesses publish a mix of free and paid posts to attract a new audience, and upsell the most loyal members to a premium offering. You can also mix different access levels within the same post, showing a free preview to logged out members and then, right when you're ready for a cliffhanger, that's a good time to...", + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -2637,6 +2660,7 @@ Most successful subscription businesses publish a mix of free and paid posts to "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -2719,6 +2743,7 @@ Most successful subscription businesses publish a mix of free and paid posts to "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "You can delete this user to remove all the welcome posts", "bluesky": null, @@ -2811,6 +2836,7 @@ Definition listConsectetur adipisicing elit, sed do eiusmod tempor incididunt ut "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "bio", "bluesky": null, @@ -2888,6 +2914,7 @@ mctesters "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "bio", "bluesky": null, @@ -2971,6 +2998,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "bio", "bluesky": null, @@ -3052,6 +3080,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "primary_author": Object { "bio": "bio", "bluesky": null, @@ -3116,7 +3145,7 @@ exports[`Posts Content API Can include relations 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "68181", + "content-length": "68390", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -3152,6 +3181,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "html-ipsum", @@ -3172,7 +3202,7 @@ exports[`Posts Content API Can request a single post 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "2358", + "content-length": "2377", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -3281,6 +3311,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "welcome", @@ -3329,6 +3360,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 3, "slug": "design", @@ -3365,6 +3397,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 5, "slug": "write", @@ -3401,6 +3434,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "portal", @@ -3454,6 +3488,7 @@ Using subscriptions, you can build an independent media business like Stratecher The creator economy is just getting started, and Ghost allows you to build something based on technology that you own and control. Most successful subscription businesses publish a mix of free and paid posts to attract a new audience, and upsell the most loyal members to a premium offering. You can also mix different access levels within the same post, showing a free preview to logged out members and then, right when you're ready for a cliffhanger, that's a good time to...", + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "sell", @@ -3490,6 +3525,7 @@ Most successful subscription businesses publish a mix of free and paid posts to "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "grow", @@ -3527,6 +3563,7 @@ Most successful subscription businesses publish a mix of free and paid posts to "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "integrations", @@ -3574,6 +3611,7 @@ Definition listConsectetur adipisicing elit, sed do eiusmod tempor incididunt ut "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "not-so-short-bit-complex", @@ -3626,6 +3664,7 @@ mctesters "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "slug": "short-and-sweet", @@ -3664,6 +3703,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "ghostly-kitchen-sink", @@ -3700,6 +3740,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "html-ipsum", @@ -3720,7 +3761,7 @@ exports[`Posts Content API Can request posts 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "46632", + "content-length": "46841", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -3766,6 +3807,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "welcome", @@ -3814,6 +3856,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 3, "slug": "design", @@ -3850,6 +3893,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 5, "slug": "write", @@ -3886,6 +3930,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "portal", @@ -3939,6 +3984,7 @@ Using subscriptions, you can build an independent media business like Stratecher The creator economy is just getting started, and Ghost allows you to build something based on technology that you own and control. Most successful subscription businesses publish a mix of free and paid posts to attract a new audience, and upsell the most loyal members to a premium offering. You can also mix different access levels within the same post, showing a free preview to logged out members and then, right when you're ready for a cliffhanger, that's a good time to...", + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "sell", @@ -3975,6 +4021,7 @@ Most successful subscription businesses publish a mix of free and paid posts to "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "grow", @@ -4012,6 +4059,7 @@ Most successful subscription businesses publish a mix of free and paid posts to "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "integrations", @@ -4059,6 +4107,7 @@ Definition listConsectetur adipisicing elit, sed do eiusmod tempor incididunt ut "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "not-so-short-bit-complex", @@ -4111,6 +4160,7 @@ mctesters "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "slug": "short-and-sweet", @@ -4149,6 +4199,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "ghostly-kitchen-sink", @@ -4185,6 +4236,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "html-ipsum", @@ -4205,7 +4257,7 @@ exports[`Posts Content API Can request posts from different origin 2: [headers] Object { "access-control-allow-origin": "*", "cache-control": "public, max-age=0", - "content-length": "46632", + "content-length": "46841", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -4760,6 +4812,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "welcome", @@ -4795,6 +4848,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 3, "slug": "design", @@ -4830,6 +4884,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 5, "slug": "write", @@ -4865,6 +4920,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "portal", @@ -4900,6 +4956,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "sell", @@ -4935,6 +4992,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 2, "slug": "grow", @@ -4970,6 +5028,7 @@ Object { "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "integrations", @@ -5016,6 +5075,7 @@ Definition listConsectetur adipisicing elit, sed do eiusmod tempor incididunt ut "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "not-so-short-bit-complex", @@ -5060,6 +5120,7 @@ mctesters "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 0, "slug": "short-and-sweet", @@ -5097,6 +5158,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "ghostly-kitchen-sink", @@ -5132,6 +5194,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu "og_description": null, "og_image": null, "og_title": null, + "podcast_url": null, "published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/, "reading_time": 1, "slug": "html-ipsum", From 81049708a48f564657758a145c2b95b1fa7e39b8 Mon Sep 17 00:00:00 2001 From: Igor Balos Date: Mon, 20 Oct 2025 11:08:43 +0200 Subject: [PATCH 5/5] update integrity test --- ghost/core/test/unit/server/data/schema/integrity.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ghost/core/test/unit/server/data/schema/integrity.test.js b/ghost/core/test/unit/server/data/schema/integrity.test.js index 057ad8cd2d8..d721988f78f 100644 --- a/ghost/core/test/unit/server/data/schema/integrity.test.js +++ b/ghost/core/test/unit/server/data/schema/integrity.test.js @@ -35,7 +35,7 @@ const validateRouteSettings = require('../../../../../core/server/services/route */ describe('DB version integrity', function () { // Only these variables should need updating - const currentSchemaHash = 'aa00ea8206673b21837fbcc24897f779'; + const currentSchemaHash = '7ad506653d4f3c42f6ac2f270f57580d'; const currentFixturesHash = '0877727032b8beddbaedc086a8acf1a2'; const currentSettingsHash = 'bb8be7d83407f2b4fa2ad68c19610579'; const currentRoutesHash = '3d180d52c663d173a6be791ef411ed01';