From acdabedabaa0d344068394073088563fa0b18f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcholas=20Andr=C3=A9?= Date: Tue, 14 Nov 2023 08:25:48 -0300 Subject: [PATCH 1/8] feat: first pass at matching category path --- .../strategies/PostsArchiveFetchStrategy.ts | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts b/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts index 84a0bee27..e030c4c2d 100644 --- a/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts +++ b/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts @@ -7,6 +7,7 @@ import { NotFoundError, addQueryArgs, getCustomTaxonomy, + removeSourceUrl, } from '../../utils'; import { endpoints, getPostAuthor, getPostTerms, removeFieldsFromPostRelatedData } from '../utils'; import { apiGet } from '../api'; @@ -180,6 +181,11 @@ export interface PostsArchiveParams extends EndpointParams { * Limit result set to items that are sticky. */ sticky?: boolean; + + /** + * Whether queriedObject.link should be checked against current path + */ + matchCurrentPath?: boolean; } /** @@ -199,6 +205,10 @@ export class PostsArchiveFetchStrategy< T extends PostEntity = PostEntity, P extends PostsArchiveParams = PostsArchiveParams, > extends AbstractFetchStrategy { + path: string = ''; + + locale: string = ''; + getDefaultEndpoint(): string { return endpoints.posts; } @@ -216,6 +226,12 @@ export class PostsArchiveFetchStrategy< * @param params */ getParamsFromURL(path: string, params: Partial

= {}): Partial

{ + const config = getSiteBySourceUrl(this.baseURL); + + // this is required for post path mapping + this.locale = config.integrations?.polylang?.enable && params.lang ? params.lang : ''; + this.path = path; + const matchers = [...postsMatchers]; if (typeof params.taxonomy === 'string') { @@ -306,6 +322,62 @@ export class PostsArchiveFetchStrategy< return super.buildEndpointURL(endpointParams as P); } + prepareResponse(response: FetchResponse, params: Partial

): FetchResponse { + const queriedObject = this.getQueriedObject(response, params); + + const currentPath = decodeURIComponent(this.path).replace(/\/?$/, '/'); + let queriedObjectPath = ''; + let type = ''; + if (queriedObject?.term?.link) { + // if term is set then it should match the url + queriedObjectPath = decodeURIComponent( + removeSourceUrl({ + link: queriedObject.term.link, + backendUrl: this.baseURL, + }), + )?.replace(/\/?$/, '/'); + type = queriedObject.term.taxonomy; + } + + if (queriedObject?.author?.link) { + // if author is set then it should match the url + queriedObjectPath = decodeURIComponent( + removeSourceUrl({ + link: queriedObject.author.link, + backendUrl: this.baseURL, + }), + )?.replace(/\/?$/, '/'); + } + + if (queriedObjectPath && type) { + const taxonomyObj = getCustomTaxonomy(type, this.baseURL); + + if ( + queriedObjectPath !== currentPath && + // using rewrite as prefix + queriedObjectPath !== `/${this.locale}${currentPath}` && + queriedObjectPath !== `/${taxonomyObj?.rewrite}${currentPath}}` && + // using rest param as prefix + queriedObjectPath !== `/${this.locale}/${taxonomyObj?.rewrite}${currentPath}` && + queriedObjectPath !== `/${taxonomyObj?.restParam}/${currentPath}` && + queriedObjectPath !== `/${this.locale}/${taxonomyObj?.restParam}${currentPath}` && + // using slug as prefix + queriedObjectPath !== `/${taxonomyObj?.slug}${currentPath}` && + queriedObjectPath !== `/${this.locale}/${taxonomyObj?.slug}${currentPath}` + ) { + throw new NotFoundError( + `Posts were found but did not match current path: "${this.path}""`, + ); + } + } + + return { + ...response, + queriedObject, + result: response.result as unknown as T[], + }; + } + /** * Before fetching posts, we need handle taxonomy and authors. * From b62328b4929e70735898f35b6e1b2dff5629d4e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcholas=20Andr=C3=A9?= Date: Tue, 14 Nov 2023 13:20:56 -0300 Subject: [PATCH 2/8] fix: config injection --- .../strategies/PostsArchiveFetchStrategy.ts | 27 ++-- packages/core/src/types.ts | 24 +++ packages/next/package.json | 1 - .../ModifySourcePlugin/ModifySourcePlugin.ts | 139 ++++++++++++++++++ .../plugins/ModifySourcePlugin/index.ts | 2 + .../plugins/ModifySourcePlugin/loader.ts | 65 ++++++++ .../operations/AbstractOperation.ts | 15 ++ .../operations/ConcatOperation.ts | 27 ++++ .../operations/Operation.ts | 120 +++++++++++++++ .../operations/ReplaceOperation.ts | 28 ++++ .../ModifySourcePlugin/operations/index.ts | 4 + .../next/src/config/withHeadlessConfig.ts | 9 +- 12 files changed, 441 insertions(+), 20 deletions(-) create mode 100644 packages/next/src/config/plugins/ModifySourcePlugin/ModifySourcePlugin.ts create mode 100644 packages/next/src/config/plugins/ModifySourcePlugin/index.ts create mode 100644 packages/next/src/config/plugins/ModifySourcePlugin/loader.ts create mode 100644 packages/next/src/config/plugins/ModifySourcePlugin/operations/AbstractOperation.ts create mode 100644 packages/next/src/config/plugins/ModifySourcePlugin/operations/ConcatOperation.ts create mode 100644 packages/next/src/config/plugins/ModifySourcePlugin/operations/Operation.ts create mode 100644 packages/next/src/config/plugins/ModifySourcePlugin/operations/ReplaceOperation.ts create mode 100644 packages/next/src/config/plugins/ModifySourcePlugin/operations/index.ts diff --git a/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts b/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts index e030c4c2d..cfed7143c 100644 --- a/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts +++ b/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts @@ -183,9 +183,11 @@ export interface PostsArchiveParams extends EndpointParams { sticky?: boolean; /** - * Whether queriedObject.link should be checked against current path + * Overrides the value set in {@link CustomTaxonomy#matchArchivePath} + * + * @default false */ - matchCurrentPath?: boolean; + matchArchivePath?: boolean; } /** @@ -327,7 +329,8 @@ export class PostsArchiveFetchStrategy< const currentPath = decodeURIComponent(this.path).replace(/\/?$/, '/'); let queriedObjectPath = ''; - let type = ''; + let taxonomySlug = ''; + if (queriedObject?.term?.link) { // if term is set then it should match the url queriedObjectPath = decodeURIComponent( @@ -336,23 +339,15 @@ export class PostsArchiveFetchStrategy< backendUrl: this.baseURL, }), )?.replace(/\/?$/, '/'); - type = queriedObject.term.taxonomy; - } - - if (queriedObject?.author?.link) { - // if author is set then it should match the url - queriedObjectPath = decodeURIComponent( - removeSourceUrl({ - link: queriedObject.author.link, - backendUrl: this.baseURL, - }), - )?.replace(/\/?$/, '/'); + taxonomySlug = queriedObject.term.taxonomy; } - if (queriedObjectPath && type) { - const taxonomyObj = getCustomTaxonomy(type, this.baseURL); + if (queriedObjectPath && taxonomySlug) { + const taxonomyObj = getCustomTaxonomy(taxonomySlug, this.baseURL); + const shouldMatchArchivePath = taxonomyObj?.matchArchivePath || params.matchCurrentPath; if ( + shouldMatchArchivePath && queriedObjectPath !== currentPath && // using rewrite as prefix queriedObjectPath !== `/${this.locale}${currentPath}` && diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index c5be9d8cb..97b2eed14 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -3,6 +3,19 @@ export type CustomPostType = { endpoint: string; single?: string; archive?: string; + + /** + * Whether this custom post type should match the archive path + * + * If set to true, then when querying a post type archive page such as `/[post-type]/[post-name]` the + * `post.link` property should match the current path. This will avoid matching nested posts/pages that doesn't exist for instance: + * `/[post-type]/fake-parent-page/[post-name]` will not match if this option is set to true even though `post-name` exists. + * + * It is strongly recommended to set this option to true, otherwise hierarchical post types (such as pages) will not work properly. + * + * @default true + */ + matchSinglePath?: boolean; }; export type CustomPostTypes = Array; @@ -14,6 +27,17 @@ export type CustomTaxonomy = { endpoint: string; rewrite?: string; restParam?: string; + + /** + * Whether this custom taxonomy should match the archive path + * + * If set to true, then when querying a taxonomy archive page such as `/[taxonmy-slug]/[term-slug]` the + * `term.link` property should match the current path. This will avoid matching nested categories that doesn't exist for instance: + * `/[taxonmy-slug]/fake-parent-term/[term-slug]` will not match if this option is set to true even though `term-slug` exists. + * + * @default false + */ + matchArchivePath?: boolean; }; export type CustomTaxonomies = Array; diff --git a/packages/next/package.json b/packages/next/package.json index a885f0d28..d2ff3058f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -50,7 +50,6 @@ "dependencies": { "deepmerge": "^4.3.1", "@headstartwp/core": "^1.1.2", - "modify-source-webpack-plugin": "^4.1.0", "loader-utils": "^3.2.0", "schema-utils": "^4.0.0" }, diff --git a/packages/next/src/config/plugins/ModifySourcePlugin/ModifySourcePlugin.ts b/packages/next/src/config/plugins/ModifySourcePlugin/ModifySourcePlugin.ts new file mode 100644 index 000000000..5d5f65694 --- /dev/null +++ b/packages/next/src/config/plugins/ModifySourcePlugin/ModifySourcePlugin.ts @@ -0,0 +1,139 @@ +import type { Compiler, NormalModule, Compilation } from 'webpack'; + +import { AbstractOperation, Operation } from './operations'; + +const { validate } = require('schema-utils'); + +export interface Rule { + test: RegExp | ((module: NormalModule, compilation: Compilation) => boolean); + operations?: AbstractOperation[]; +} + +export type Options = { + debug?: boolean; + rules: Rule[]; + constants?: Record; +}; + +const validationSchema = { + type: 'object', + additionalProperties: false, + properties: { + rules: { + type: 'array', + items: { + type: 'object', + additionalProperties: false, + properties: { + test: { + anyOf: [{ instanceof: 'Function' }, { instanceof: 'RegExp' }], + }, + operations: { + type: 'array', + items: { + type: 'object', + }, + }, + }, + }, + }, + constants: { + type: 'object', + }, + debug: { + type: 'boolean', + }, + }, +}; + +const PLUGIN_NAME = 'ModifySourcePlugin'; + +export class ModifySourcePlugin { + constructor(protected readonly options: Options) { + validate(validationSchema, options, { + name: PLUGIN_NAME, + }); + } + + public apply(compiler: Compiler): void { + const { rules, debug, constants = {} } = this.options; + + compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => { + const modifiedModules: (string | number)[] = []; + + const tapCallback = (_: any, normalModule: NormalModule) => { + const userRequest = normalModule.userRequest || ''; + + const startIndex = + userRequest.lastIndexOf('!') === -1 ? 0 : userRequest.lastIndexOf('!') + 1; + + const moduleRequest = userRequest.substring(startIndex).replace(/\\/g, '/'); + + if (modifiedModules.includes(moduleRequest)) { + return; + } + + rules.forEach((ruleOptions) => { + const { test } = ruleOptions; + const isMatched = (() => { + if (typeof test === 'function' && test(normalModule, compilation)) { + return true; + } + + return test instanceof RegExp && test.test(moduleRequest); + })(); + + if (isMatched) { + type NormalModuleLoader = { + loader: string; + options: any; + ident?: string; + type?: string; + }; + + const serializableOperations = ruleOptions.operations?.map((op) => + Operation.makeSerializable(op), + ); + + let loader; + + try { + loader = require.resolve('./loader.js'); + } catch (e) { + loader = require.resolve('../build/loader.js'); + } + + (normalModule.loaders as NormalModuleLoader[]).push({ + loader, + options: { + moduleRequest, + operations: serializableOperations, + constants, + }, + }); + + modifiedModules.push(moduleRequest); + + if (debug) { + // eslint-disable-next-line no-console + console.log(`\n[${PLUGIN_NAME}] Use loader for "${moduleRequest}".`); + } + } + }); + }; + + const NormalModule = compiler.webpack?.NormalModule; + const isNormalModuleAvailable = + Boolean(NormalModule) && Boolean(NormalModule.getCompilationHooks); + + if (isNormalModuleAvailable) { + NormalModule.getCompilationHooks(compilation).beforeLoaders.tap( + PLUGIN_NAME, + tapCallback, + ); + } else { + compilation.hooks.normalModuleLoader.tap(PLUGIN_NAME, tapCallback); + } + }); + } +} diff --git a/packages/next/src/config/plugins/ModifySourcePlugin/index.ts b/packages/next/src/config/plugins/ModifySourcePlugin/index.ts new file mode 100644 index 000000000..7787b76c9 --- /dev/null +++ b/packages/next/src/config/plugins/ModifySourcePlugin/index.ts @@ -0,0 +1,2 @@ +export * from './ModifySourcePlugin'; +export * from './operations'; diff --git a/packages/next/src/config/plugins/ModifySourcePlugin/loader.ts b/packages/next/src/config/plugins/ModifySourcePlugin/loader.ts new file mode 100644 index 000000000..8729b656b --- /dev/null +++ b/packages/next/src/config/plugins/ModifySourcePlugin/loader.ts @@ -0,0 +1,65 @@ +import path from 'path'; + +import { Operation, SerializableOperation } from './operations'; + +const { validate } = require('schema-utils'); + +const schema = { + type: 'object', + properties: { + operations: { + type: 'array', + items: { + type: 'object', + }, + }, + moduleRequest: { + type: 'string', + }, + constants: { + type: 'object', + }, + }, + additionalProperties: false, +}; + +interface LoaderOptions { + operations: SerializableOperation[]; + moduleRequest: string; + constants: Record; +} + +interface modifyModuleSourceLoader { + getOptions?: () => LoaderOptions; +} + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export default function modifyModuleSourceLoader( + this: modifyModuleSourceLoader, + source: string, +): string { + const options: LoaderOptions = this.getOptions + ? this.getOptions() + : require('loader-utils-webpack-v4').getOptions(this); // eslint-disable-line global-require + + validate(schema, options, { + name: 'ModifySourcePlugin webpack loader', + }); + + const cleanPath = options.moduleRequest.split('?')[0]; + const fileName = path.basename(cleanPath); + + if (source.includes('__setHeadstartWPConfig')) { + return source; + } + + return options.operations.reduce((sourceText, serializableOp) => { + const operation = Operation.fillConstants(Operation.fromSerializable(serializableOp), { + ...options.constants, + FILE_PATH: cleanPath, + FILE_NAME: fileName, + }); + + return Operation.apply(sourceText, operation); + }, source); +} diff --git a/packages/next/src/config/plugins/ModifySourcePlugin/operations/AbstractOperation.ts b/packages/next/src/config/plugins/ModifySourcePlugin/operations/AbstractOperation.ts new file mode 100644 index 000000000..9cb4bd99c --- /dev/null +++ b/packages/next/src/config/plugins/ModifySourcePlugin/operations/AbstractOperation.ts @@ -0,0 +1,15 @@ +export type SerializableProperties = { + [K in keyof T as T[K] extends string ? K : never]: T[K] extends string ? T[K] : never; +}; + +export type SerializableOperation = { + operationName: string; +} & { + [K in keyof T as T[K] extends string ? K : never]: T[K] extends string ? T[K] : never; +}; + +export abstract class AbstractOperation { + public abstract getSerializableProperties(): string[]; + + public abstract getTextProperties(): string[]; +} diff --git a/packages/next/src/config/plugins/ModifySourcePlugin/operations/ConcatOperation.ts b/packages/next/src/config/plugins/ModifySourcePlugin/operations/ConcatOperation.ts new file mode 100644 index 000000000..77a5b3a81 --- /dev/null +++ b/packages/next/src/config/plugins/ModifySourcePlugin/operations/ConcatOperation.ts @@ -0,0 +1,27 @@ +import { AbstractOperation } from './AbstractOperation'; + +export enum ConcatOperationType { + 'start' = 'start', + 'end' = 'end', +} + +export class ConcatOperation extends AbstractOperation { + constructor( + public readonly type: keyof typeof ConcatOperationType, + public readonly value: string, + ) { + super(); + } + + public getSerializableProperties(): (keyof this & string)[] { + return ['type', 'value']; + } + + public getTextProperties(): (keyof this & string)[] { + return ['value']; + } + + public static getAllowedTypes(): ConcatOperationType[] { + return [ConcatOperationType.start, ConcatOperationType.end]; + } +} diff --git a/packages/next/src/config/plugins/ModifySourcePlugin/operations/Operation.ts b/packages/next/src/config/plugins/ModifySourcePlugin/operations/Operation.ts new file mode 100644 index 000000000..d488b93fb --- /dev/null +++ b/packages/next/src/config/plugins/ModifySourcePlugin/operations/Operation.ts @@ -0,0 +1,120 @@ +import { + AbstractOperation, + SerializableOperation, + SerializableProperties, +} from './AbstractOperation'; +import { ConcatOperation } from './ConcatOperation'; +import { ReplaceOperation } from './ReplaceOperation'; + +function isSerializableOfOperation( + serializable: SerializableOperation, + operation: { new (...args: any[]): T }, +): serializable is SerializableOperation { + return serializable.operationName === operation.name; +} + +function throwUnknownOperationType(op: AbstractOperation, opType: string): void { + const allowedTypes = + op instanceof ConcatOperation + ? ConcatOperation.getAllowedTypes() + : ReplaceOperation.getAllowedTypes(); + + throw new Error( + `Incorrect operation type '${opType}' for ${ + op.constructor.name + }. Allowed types: '${allowedTypes.join("', '")}'.`, + ); +} + +export class Operation { + public static makeSerializable(op: T): SerializableOperation { + const propertyValues = op.getSerializableProperties().reduce((acc, val) => { + return { + ...acc, + [val]: op[val as keyof T], + }; + }, {} as SerializableProperties); + + return { + operationName: op.constructor.name, + ...propertyValues, + }; + } + + public static fromSerializable(serializable: SerializableOperation): AbstractOperation { + if (isSerializableOfOperation(serializable, ConcatOperation)) { + const { type, value } = serializable; + + return new ConcatOperation(type, value); + } + + if (isSerializableOfOperation(serializable, ReplaceOperation)) { + const { type, searchValue, replaceValue } = serializable; + + return new ReplaceOperation(type, searchValue, replaceValue); + } + + throw new Error(`Incorrect serializable provided: ${JSON.stringify(serializable)}`); + } + + public static fillConstants< + T extends AbstractOperation, + TConstants extends Record, + >(operation: T, constants: TConstants): T { + const filledTextProps = operation.getTextProperties().reduce((acc, propName) => { + let propValue = operation[propName as keyof T] as string; + + Object.keys(constants).forEach((constant) => { + propValue = propValue.replace( + new RegExp(`\\$${constant}`, 'g'), + String(constants[constant]), + ); + }); + + return { + ...acc, + [propName]: propValue, + }; + }, {}); + + const mergedObject = { + ...Operation.makeSerializable(operation), + ...filledTextProps, + }; + + return Operation.fromSerializable(mergedObject) as T; + } + + public static apply(src: string, operation: AbstractOperation): string { + if (operation instanceof ConcatOperation) { + switch (operation.type) { + case 'start': + return operation.value + src; + + case 'end': + return src + operation.value; + + default: + throwUnknownOperationType(operation, operation.type); + } + } + + if (operation instanceof ReplaceOperation) { + switch (operation.type) { + case 'once': + return src.replace(operation.searchValue, operation.replaceValue); + + case 'all': + return src.replace( + new RegExp(operation.searchValue, 'g'), + operation.replaceValue, + ); + + default: + throwUnknownOperationType(operation, operation.type); + } + } + + throw new Error(`Unknown operation instance: ${operation.constructor.name}`); + } +} diff --git a/packages/next/src/config/plugins/ModifySourcePlugin/operations/ReplaceOperation.ts b/packages/next/src/config/plugins/ModifySourcePlugin/operations/ReplaceOperation.ts new file mode 100644 index 000000000..38a56a793 --- /dev/null +++ b/packages/next/src/config/plugins/ModifySourcePlugin/operations/ReplaceOperation.ts @@ -0,0 +1,28 @@ +import { AbstractOperation } from './AbstractOperation'; + +export enum ReplaceOperationType { + 'once' = 'once', + 'all' = 'all', +} + +export class ReplaceOperation extends AbstractOperation { + constructor( + public readonly type: keyof typeof ReplaceOperationType, + public readonly searchValue: string, + public readonly replaceValue: string, + ) { + super(); + } + + public getSerializableProperties(): (keyof this & string)[] { + return ['type', 'searchValue', 'replaceValue']; + } + + public getTextProperties(): (keyof this & string)[] { + return ['searchValue', 'replaceValue']; + } + + public static getAllowedTypes(): ReplaceOperationType[] { + return [ReplaceOperationType.all, ReplaceOperationType.once]; + } +} diff --git a/packages/next/src/config/plugins/ModifySourcePlugin/operations/index.ts b/packages/next/src/config/plugins/ModifySourcePlugin/operations/index.ts new file mode 100644 index 000000000..d5848b6d5 --- /dev/null +++ b/packages/next/src/config/plugins/ModifySourcePlugin/operations/index.ts @@ -0,0 +1,4 @@ +export * from './AbstractOperation'; +export * from './ConcatOperation'; +export * from './ReplaceOperation'; +export * from './Operation'; diff --git a/packages/next/src/config/withHeadlessConfig.ts b/packages/next/src/config/withHeadlessConfig.ts index 0b08d7a5a..4aa554961 100644 --- a/packages/next/src/config/withHeadlessConfig.ts +++ b/packages/next/src/config/withHeadlessConfig.ts @@ -1,8 +1,8 @@ import { ConfigError, HeadlessConfig } from '@headstartwp/core'; import { NextConfig } from 'next'; -import { ModifySourcePlugin, ConcatOperation } from 'modify-source-webpack-plugin'; import path from 'path'; import fs from 'fs'; +import { ModifySourcePlugin, ConcatOperation } from './plugins/ModifySourcePlugin'; const LINARIA_EXTENSION = '.linaria.module.css'; @@ -153,9 +153,12 @@ export function withHeadlessConfig( }, webpack: (config, options) => { + const headlessConfigPath = `${process.cwd()}/headless.config.js`; + const importSetHeadlessConfig = ` - import { setHeadstartWPConfig } from '@headstartwp/core/utils'; - setHeadstartWPConfig(${JSON.stringify(headlessConfig)}); + import { setHeadstartWPConfig as __setHeadstartWPConfig } from '@headstartwp/core/utils'; + import headlessConfig from '${headlessConfigPath}'; + __setHeadstartWPConfig(headlessConfig); `; // clear webpack cache whenever headless.config.js changes or one of the env files From b9835f9d12f498b22c13261817682a55d3816fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcholas=20Andr=C3=A9?= Date: Tue, 14 Nov 2023 13:22:55 -0300 Subject: [PATCH 3/8] Revert "feat: first pass at matching category path" This reverts commit acdabedabaa0d344068394073088563fa0b18f46. --- .../strategies/PostsArchiveFetchStrategy.ts | 67 ------------------- 1 file changed, 67 deletions(-) diff --git a/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts b/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts index cfed7143c..84a0bee27 100644 --- a/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts +++ b/packages/core/src/data/strategies/PostsArchiveFetchStrategy.ts @@ -7,7 +7,6 @@ import { NotFoundError, addQueryArgs, getCustomTaxonomy, - removeSourceUrl, } from '../../utils'; import { endpoints, getPostAuthor, getPostTerms, removeFieldsFromPostRelatedData } from '../utils'; import { apiGet } from '../api'; @@ -181,13 +180,6 @@ export interface PostsArchiveParams extends EndpointParams { * Limit result set to items that are sticky. */ sticky?: boolean; - - /** - * Overrides the value set in {@link CustomTaxonomy#matchArchivePath} - * - * @default false - */ - matchArchivePath?: boolean; } /** @@ -207,10 +199,6 @@ export class PostsArchiveFetchStrategy< T extends PostEntity = PostEntity, P extends PostsArchiveParams = PostsArchiveParams, > extends AbstractFetchStrategy { - path: string = ''; - - locale: string = ''; - getDefaultEndpoint(): string { return endpoints.posts; } @@ -228,12 +216,6 @@ export class PostsArchiveFetchStrategy< * @param params */ getParamsFromURL(path: string, params: Partial

= {}): Partial

{ - const config = getSiteBySourceUrl(this.baseURL); - - // this is required for post path mapping - this.locale = config.integrations?.polylang?.enable && params.lang ? params.lang : ''; - this.path = path; - const matchers = [...postsMatchers]; if (typeof params.taxonomy === 'string') { @@ -324,55 +306,6 @@ export class PostsArchiveFetchStrategy< return super.buildEndpointURL(endpointParams as P); } - prepareResponse(response: FetchResponse, params: Partial

): FetchResponse { - const queriedObject = this.getQueriedObject(response, params); - - const currentPath = decodeURIComponent(this.path).replace(/\/?$/, '/'); - let queriedObjectPath = ''; - let taxonomySlug = ''; - - if (queriedObject?.term?.link) { - // if term is set then it should match the url - queriedObjectPath = decodeURIComponent( - removeSourceUrl({ - link: queriedObject.term.link, - backendUrl: this.baseURL, - }), - )?.replace(/\/?$/, '/'); - taxonomySlug = queriedObject.term.taxonomy; - } - - if (queriedObjectPath && taxonomySlug) { - const taxonomyObj = getCustomTaxonomy(taxonomySlug, this.baseURL); - const shouldMatchArchivePath = taxonomyObj?.matchArchivePath || params.matchCurrentPath; - - if ( - shouldMatchArchivePath && - queriedObjectPath !== currentPath && - // using rewrite as prefix - queriedObjectPath !== `/${this.locale}${currentPath}` && - queriedObjectPath !== `/${taxonomyObj?.rewrite}${currentPath}}` && - // using rest param as prefix - queriedObjectPath !== `/${this.locale}/${taxonomyObj?.rewrite}${currentPath}` && - queriedObjectPath !== `/${taxonomyObj?.restParam}/${currentPath}` && - queriedObjectPath !== `/${this.locale}/${taxonomyObj?.restParam}${currentPath}` && - // using slug as prefix - queriedObjectPath !== `/${taxonomyObj?.slug}${currentPath}` && - queriedObjectPath !== `/${this.locale}/${taxonomyObj?.slug}${currentPath}` - ) { - throw new NotFoundError( - `Posts were found but did not match current path: "${this.path}""`, - ); - } - } - - return { - ...response, - queriedObject, - result: response.result as unknown as T[], - }; - } - /** * Before fetching posts, we need handle taxonomy and authors. * From c51faf35263f79004a4452c48ea26779b3fe3344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcholas=20Andr=C3=A9?= Date: Tue, 14 Nov 2023 13:23:57 -0300 Subject: [PATCH 4/8] revert: types --- packages/core/src/types.ts | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 97b2eed14..c5be9d8cb 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -3,19 +3,6 @@ export type CustomPostType = { endpoint: string; single?: string; archive?: string; - - /** - * Whether this custom post type should match the archive path - * - * If set to true, then when querying a post type archive page such as `/[post-type]/[post-name]` the - * `post.link` property should match the current path. This will avoid matching nested posts/pages that doesn't exist for instance: - * `/[post-type]/fake-parent-page/[post-name]` will not match if this option is set to true even though `post-name` exists. - * - * It is strongly recommended to set this option to true, otherwise hierarchical post types (such as pages) will not work properly. - * - * @default true - */ - matchSinglePath?: boolean; }; export type CustomPostTypes = Array; @@ -27,17 +14,6 @@ export type CustomTaxonomy = { endpoint: string; rewrite?: string; restParam?: string; - - /** - * Whether this custom taxonomy should match the archive path - * - * If set to true, then when querying a taxonomy archive page such as `/[taxonmy-slug]/[term-slug]` the - * `term.link` property should match the current path. This will avoid matching nested categories that doesn't exist for instance: - * `/[taxonmy-slug]/fake-parent-term/[term-slug]` will not match if this option is set to true even though `term-slug` exists. - * - * @default false - */ - matchArchivePath?: boolean; }; export type CustomTaxonomies = Array; From 7ea62f869cb80d9254c81773013a744575cb1013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcholas=20Andr=C3=A9?= Date: Tue, 14 Nov 2023 13:25:13 -0300 Subject: [PATCH 5/8] chore: update package-lock --- package-lock.json | 66 +++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index ef0f8436b..68e522798 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3381,6 +3381,7 @@ }, "node_modules/@jridgewell/source-map": { "version": "0.3.3", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -4862,6 +4863,7 @@ }, "node_modules/@types/eslint": { "version": "8.37.0", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -4871,6 +4873,7 @@ }, "node_modules/@types/eslint-scope": { "version": "3.7.4", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -4880,6 +4883,7 @@ }, "node_modules/@types/estree": { "version": "1.0.1", + "dev": true, "license": "MIT", "peer": true }, @@ -5025,6 +5029,7 @@ }, "node_modules/@types/node": { "version": "12.20.55", + "dev": true, "license": "MIT" }, "node_modules/@types/node-fetch": { @@ -5430,6 +5435,7 @@ }, "node_modules/@webassemblyjs/ast": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -5439,16 +5445,19 @@ }, "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true }, @@ -5515,6 +5524,7 @@ }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -5525,11 +5535,13 @@ }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -5541,6 +5553,7 @@ }, "node_modules/@webassemblyjs/ieee754": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -5549,6 +5562,7 @@ }, "node_modules/@webassemblyjs/leb128": { "version": "1.11.5", + "dev": true, "license": "Apache-2.0", "peer": true, "dependencies": { @@ -5557,11 +5571,13 @@ }, "node_modules/@webassemblyjs/utf8": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -5577,6 +5593,7 @@ }, "node_modules/@webassemblyjs/wasm-gen": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -5589,6 +5606,7 @@ }, "node_modules/@webassemblyjs/wasm-opt": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -5600,6 +5618,7 @@ }, "node_modules/@webassemblyjs/wasm-parser": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -5651,6 +5670,7 @@ }, "node_modules/@webassemblyjs/wast-printer": { "version": "1.11.5", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -5914,6 +5934,7 @@ }, "node_modules/acorn": { "version": "8.8.2", + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -5933,6 +5954,7 @@ }, "node_modules/acorn-import-assertions": { "version": "1.8.0", + "dev": true, "license": "MIT", "peer": true, "peerDependencies": { @@ -8929,6 +8951,7 @@ }, "node_modules/es-module-lexer": { "version": "1.2.1", + "dev": true, "license": "MIT", "peer": true }, @@ -9500,6 +9523,7 @@ }, "node_modules/eslint-scope": { "version": "5.1.1", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -9511,6 +9535,7 @@ }, "node_modules/eslint-scope/node_modules/estraverse": { "version": "4.3.0", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -10966,6 +10991,7 @@ }, "node_modules/glob-to-regexp": { "version": "0.4.1", + "dev": true, "license": "BSD-2-Clause", "peer": true }, @@ -14661,6 +14687,7 @@ }, "node_modules/loader-runner": { "version": "4.3.0", + "dev": true, "license": "MIT", "peer": true, "engines": { @@ -14674,19 +14701,6 @@ "node": ">= 12.13.0" } }, - "node_modules/loader-utils-webpack-v4": { - "name": "loader-utils", - "version": "2.0.4", - "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, "node_modules/locate-path": { "version": "6.0.0", "license": "MIT", @@ -15111,6 +15125,7 @@ }, "node_modules/merge-stream": { "version": "2.0.0", + "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -15340,17 +15355,6 @@ "node": ">=10" } }, - "node_modules/modify-source-webpack-plugin": { - "version": "4.1.0", - "license": "MIT", - "dependencies": { - "loader-utils-webpack-v4": "npm:loader-utils@^2.0.4", - "schema-utils": "^4.0.0" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" - } - }, "node_modules/move-concurrently": { "version": "1.0.1", "license": "ISC", @@ -18073,6 +18077,7 @@ }, "node_modules/serialize-javascript": { "version": "6.0.1", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" @@ -19396,6 +19401,7 @@ }, "node_modules/terser": { "version": "5.17.1", + "dev": true, "license": "BSD-2-Clause", "peer": true, "dependencies": { @@ -19413,6 +19419,7 @@ }, "node_modules/terser-webpack-plugin": { "version": "5.3.7", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -19446,6 +19453,7 @@ }, "node_modules/terser-webpack-plugin/node_modules/has-flag": { "version": "4.0.0", + "dev": true, "license": "MIT", "peer": true, "engines": { @@ -19454,6 +19462,7 @@ }, "node_modules/terser-webpack-plugin/node_modules/jest-worker": { "version": "27.5.1", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -19467,6 +19476,7 @@ }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.1.2", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -19484,6 +19494,7 @@ }, "node_modules/terser-webpack-plugin/node_modules/supports-color": { "version": "8.1.1", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -19498,11 +19509,13 @@ }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", + "dev": true, "license": "MIT", "peer": true }, "node_modules/terser/node_modules/source-map-support": { "version": "0.5.21", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -20513,6 +20526,7 @@ }, "node_modules/watchpack": { "version": "2.4.0", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -20817,6 +20831,7 @@ }, "node_modules/webpack": { "version": "5.81.0", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -20977,6 +20992,7 @@ }, "node_modules/webpack-sources": { "version": "3.2.3", + "dev": true, "license": "MIT", "peer": true, "engines": { @@ -20985,6 +21001,7 @@ }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.1.2", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -21758,7 +21775,6 @@ "@headstartwp/core": "^1.1.2", "deepmerge": "^4.3.1", "loader-utils": "^3.2.0", - "modify-source-webpack-plugin": "^4.1.0", "schema-utils": "^4.0.0" }, "devDependencies": { From 15fe6fcd20013cf81e362a3fc4a36e170638c5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcholas=20Andr=C3=A9?= Date: Tue, 14 Nov 2023 13:26:04 -0300 Subject: [PATCH 6/8] chore: changelog --- .changeset/fair-yaks-smash.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fair-yaks-smash.md diff --git a/.changeset/fair-yaks-smash.md b/.changeset/fair-yaks-smash.md new file mode 100644 index 000000000..9e26032d3 --- /dev/null +++ b/.changeset/fair-yaks-smash.md @@ -0,0 +1,5 @@ +--- +"@headstartwp/next": patch +--- + +Fix loading of the headless.config.js file to prevent injecting it twice. From 43bd2477eb0936bcbb5dd7d70f3fe1bddc91786b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcholas=20Andr=C3=A9?= Date: Tue, 14 Nov 2023 13:31:31 -0300 Subject: [PATCH 7/8] feat: support headstartwp.config.js as well --- packages/next/src/config/withHeadlessConfig.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/next/src/config/withHeadlessConfig.ts b/packages/next/src/config/withHeadlessConfig.ts index 4aa554961..44a84a667 100644 --- a/packages/next/src/config/withHeadlessConfig.ts +++ b/packages/next/src/config/withHeadlessConfig.ts @@ -154,11 +154,16 @@ export function withHeadlessConfig( webpack: (config, options) => { const headlessConfigPath = `${process.cwd()}/headless.config.js`; + const headstartWpConfigPath = `${process.cwd()}/headstartwp.config.js`; + + const configPath = fs.existsSync(headstartWpConfigPath) + ? headstartWpConfigPath + : headlessConfigPath; const importSetHeadlessConfig = ` import { setHeadstartWPConfig as __setHeadstartWPConfig } from '@headstartwp/core/utils'; - import headlessConfig from '${headlessConfigPath}'; - __setHeadstartWPConfig(headlessConfig); + import __headlessConfig from '${configPath}'; + __setHeadstartWPConfig(__headlessConfig); `; // clear webpack cache whenever headless.config.js changes or one of the env files From 7e35e10cefbbf37fd621a7bc197535aabef77632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcholas=20Andr=C3=A9?= Date: Tue, 14 Nov 2023 13:35:38 -0300 Subject: [PATCH 8/8] fix: eslint error/drop support to webpack v4 --- .../next/src/config/plugins/ModifySourcePlugin/loader.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/next/src/config/plugins/ModifySourcePlugin/loader.ts b/packages/next/src/config/plugins/ModifySourcePlugin/loader.ts index 8729b656b..db9e40cf3 100644 --- a/packages/next/src/config/plugins/ModifySourcePlugin/loader.ts +++ b/packages/next/src/config/plugins/ModifySourcePlugin/loader.ts @@ -30,7 +30,7 @@ interface LoaderOptions { } interface modifyModuleSourceLoader { - getOptions?: () => LoaderOptions; + getOptions: () => LoaderOptions; } // eslint-disable-next-line @typescript-eslint/no-redeclare @@ -38,9 +38,7 @@ export default function modifyModuleSourceLoader( this: modifyModuleSourceLoader, source: string, ): string { - const options: LoaderOptions = this.getOptions - ? this.getOptions() - : require('loader-utils-webpack-v4').getOptions(this); // eslint-disable-line global-require + const options: LoaderOptions = this.getOptions(); validate(schema, options, { name: 'ModifySourcePlugin webpack loader',