diff --git a/.changeset/config.json b/.changeset/config.json index cbf5d706a..13199afe7 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -7,18 +7,9 @@ "access": "restricted", "baseBranch": "trunk", "updateInternalDependencies": "patch", - "privatePackages": { "version": true, "tag": false }, - "ignore": [ - "@10up/wp-nextjs", - "@10up/wp-nextjs-app", - "@10up/wp-nextjs-epio", - "@10up/wp-polylang-nextjs-app", - "@10up/wp-multisite-nextjs-app", - "@10up/wp-multisite-nextjs", - "@10up/wp-multisite-i18n-nextjs", - "@headstartwp/vite-react-test", - "@10up/wp-nextjs-universal-blocks", - "@headstartwp/component-library", - "tenup-theme" - ] -} \ No newline at end of file + "privatePackages": { + "version": true, + "tag": false + }, + "ignore": [] +} diff --git a/.changeset/core-primitive-param-types.md b/.changeset/core-primitive-param-types.md new file mode 100644 index 000000000..d4573a9ce --- /dev/null +++ b/.changeset/core-primitive-param-types.md @@ -0,0 +1,15 @@ +--- +'@headstartwp/core': minor +--- + +Fix boxed object types in `PostParams`. + +`SinglePostFetchStrategy`'s `id` and `revision` params were typed as `Number` +and `Boolean` (the boxed object types) rather than `number` and `boolean`. +Passing primitives already worked, so this is a type-level fix for nearly all +consumers — but anyone who explicitly annotated a variable as `Number` will need +to switch to `number`. + +Note that `params.id` of `0` is now correctly falsy in the strategy's internal +truthiness guards; `0` was never a valid post ID, so this should not change +runtime behavior in practice. diff --git a/.changeset/deprecate-linaria-support.md b/.changeset/deprecate-linaria-support.md new file mode 100644 index 000000000..262c75f8e --- /dev/null +++ b/.changeset/deprecate-linaria-support.md @@ -0,0 +1,7 @@ +--- +'@headstartwp/next': minor +--- + +Deprecate the built-in linaria/wyw-in-js webpack integration in `withHeadstartWPConfig`. + +The loader still runs when `@linaria/webpack-loader` or `@wyw-in-js/webpack-loader` is installed, but it now logs a deprecation warning and will be removed in the next major version. HeadstartWP no longer prescribes a styling solution — the example projects use plain CSS, and any styling approach (CSS Modules, Tailwind, CSS-in-JS) works. If you want to keep using linaria, configure the loader yourself via `nextConfig.webpack`. diff --git a/.changeset/fix-cross-domain-redirect-skip.md b/.changeset/fix-cross-domain-redirect-skip.md deleted file mode 100644 index 84eca3685..000000000 --- a/.changeset/fix-cross-domain-redirect-skip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@headstartwp/core": patch ---- - -Fix: shouldSkipRedirect incorrectly skipping cross-domain redirects when pathnames match. Fixes #941 diff --git a/.changeset/fix-gutenberg-dollar-sign.md b/.changeset/fix-gutenberg-dollar-sign.md deleted file mode 100644 index d5e069e73..000000000 --- a/.changeset/fix-gutenberg-dollar-sign.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@headstartwp/headstartwp": patch ---- - -Fix Gutenberg block attribute rendering when JSON attribute values contain dollar signs (for example, `$50 million`), preventing incorrect replacement escaping. - diff --git a/.changeset/fix-undefined-context-key.md b/.changeset/fix-undefined-context-key.md deleted file mode 100644 index f8bc49475..000000000 --- a/.changeset/fix-undefined-context-key.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@headstartwp/headstartwp": patch ---- - -Fix: Add null coalescing check for context parameter in extend_post_content to prevent PHP 8+ "Undefined array key" warning. Fixes #940 diff --git a/.changeset/replace-example-projects-with-prds.md b/.changeset/replace-example-projects-with-prds.md new file mode 100644 index 000000000..e54c4a53b --- /dev/null +++ b/.changeset/replace-example-projects-with-prds.md @@ -0,0 +1,18 @@ +--- +'@headstartwp/core': minor +'@headstartwp/next': minor +--- + +Replace the example and starter projects with LLM-ready PRDs. + +The `projects/` and `test-projects/` workspaces have been removed from the repository. Each one is now +documented as a product requirements document in [`prds/`](https://github.com/10up/headstartwp/tree/develop/prds), +written so an LLM coding agent can stand up an equivalent project against the package versions you are +installing. Start with `prds/00-foundation.md` plus the PRD that matches your use case (most new projects +want `prds/app-router-starter.md`). + +**Heads up:** `npx create-next-app -e https://github.com/10up/headstartwp/tree/trunk/projects/wp-nextjs-app` +no longer works once this ships to `trunk`. The Quick Setup docs now describe the PRD workflow instead. The +last commit containing the legacy projects is `1c5d2be` if you need to reference their code. + +No package APIs changed in this release. diff --git a/.changeset/wordpress-7-1-1-and-php-82.md b/.changeset/wordpress-7-1-1-and-php-82.md new file mode 100644 index 000000000..9a043e345 --- /dev/null +++ b/.changeset/wordpress-7-1-1-and-php-82.md @@ -0,0 +1,14 @@ +--- +'@headstartwp/headstartwp': minor +--- + +Raise the PHP floor to 8.2 and pin the test environment to WordPress 7.1.1. + +`composer.json` now requires `php >=8.2` (was `>=8`), and the plugin header +declares `Requires PHP: 8.2` so WordPress blocks activation on older PHP rather +than fataling. PHPUnit runs against PHP 8.2 and 8.4. + +`.wp-env.json` pins `core` to `WordPress/WordPress#7.1.1`. It previously +tracked whatever the latest WordPress release happened to be, which meant core +changes could break CI on unrelated PRs. **After pulling this branch, run +`wp-env destroy` once** so your local container picks up the pinned version. diff --git a/.changeset/wordpress-7-baseline.md b/.changeset/wordpress-7-baseline.md new file mode 100644 index 000000000..4c0c5b0d9 --- /dev/null +++ b/.changeset/wordpress-7-baseline.md @@ -0,0 +1,16 @@ +--- +'@headstartwp/block-primitives': major +--- + +Target the WordPress 7 package generation. + +`@wordpress/*` peer dependencies move to the WP 7 line (`block-editor@^15.13.2`, +`data@^10.40.1`, `components@^32.2.1`, `blob@^4.40.1`). Consumers on the WP 6.5 +generation will need to upgrade alongside this release. + +The `@types/wordpress__block-editor` and `@types/wordpress__block-library` +dependencies are removed — the WP 7 packages ship their own types, and the +DefinitelyTyped packages pulled a conflicting older `@wordpress/components` into +the tree. `DropdownProps` is now derived from the public `Dropdown` component +rather than a deep `build-types/` import, which `@wordpress/components@32` no +longer exposes through its `exports` map. diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 098c36bf1..000000000 --- a/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -dist -node_modules -vendor -./examples/**/** -projects/docs/public \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 16fd3ad25..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,40 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - extends: ['@10up/eslint-config/react', '@10up/eslint-config/jest'], - plugins: ['@typescript-eslint'], - rules: { - 'jsdoc/require-returns-type': 0, - 'jsdoc/require-returns': 0, - 'jsdoc/require-param': [ - 'warn', - { - checkDestructured: false, - }, - ], - 'jsdoc/check-tag-names': [ - 'warn', - { - definedTags: ['category'], - }, - ], - 'jsdoc/check-param-names': [ - 'warn', - { - checkDestructured: false, - }, - ], - 'react/function-component-definition': 0, - 'react/require-default-props': 0, - 'jest/expect-expect': [ - 'warn', - { - assertFunctionNames: ['expect', 'expectTypeOf'], - }, - ], - 'no-redeclare': 'off', - '@typescript-eslint/no-redeclare': 'error', - }, - settings: { - 'import/resolver': 'typescript', - }, -}; diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 8c235fae5..908ca6bd7 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -5,20 +5,21 @@ permissions: on: [pull_request] +concurrency: + group: build-test-${{ github.ref }} + cancel-in-progress: true + jobs: build-test: + name: build-test (${{ matrix.os }}) runs-on: ${{ matrix.os }} strategy: - # This ensures only one combination runs at a time to avoid rate limiting - max-parallel: 1 + # One leg failing should not cancel the other - we want both results. + fail-fast: false matrix: + # Node 24 only: workspace packages declare engines.node >=24.0.0 + # and the repo runs with engineStrict, so older majors cannot install. os: [ubuntu-latest, windows-latest] - node-version: [18, 20, 22] - exclude: - - os: windows-latest - node-version: 18 - - os: windows-latest - node-version: 20 steps: - name: Configure Git line endings @@ -28,25 +29,19 @@ jobs: git config --global core.eol lf - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - name: Setup Node ${{ matrix.node-version }} - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 24 + cache: npm + + - name: Ensure npm satisfies devEngines (>=11.6.0) + run: npm i -g npm@11 - - name: Setup npm cache - uses: actions/cache@v4 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - name: Install dependencies - run: npm install - - name: Build Projects (Windows) - if: matrix.os == 'windows-latest' - run: npm run build:wpnextjs:app && npm run build:wpnextjs - - name: Build Projects - if: matrix.os != 'windows-latest' - run: npm run build \ No newline at end of file + run: npm ci + + - name: Build Packages + run: npm run build diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 3e5ccf5f4..b4e0b623d 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 cache: npm - name: Install dependencies run: npm install diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml deleted file mode 100644 index 64c53638b..000000000 --- a/.github/workflows/eslint.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: eslint - -permissions: - contents: read - -on: [pull_request] - -jobs: - eslint: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [20.x] - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup Node ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - - name: Setup npm cache - uses: actions/cache@v4 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - - name: Install dependencies - run: npm install && npm run build:packages - - name: Run eslint - run: npm run lint \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..16dad606d --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,34 @@ +name: lint + +permissions: + contents: read + +on: [pull_request] + +concurrency: + group: lint-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: lint + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + + - name: Ensure npm satisfies devEngines (>=11.6.0) + run: npm i -g npm@11 + + - name: Install dependencies + run: npm ci && npm run build:packages + + - name: Run oxlint (vp lint) + run: npm run lint diff --git a/.github/workflows/nextjs_bundle_analysis-app-router.yml b/.github/workflows/nextjs_bundle_analysis-app-router.yml deleted file mode 100644 index 8348a33c9..000000000 --- a/.github/workflows/nextjs_bundle_analysis-app-router.yml +++ /dev/null @@ -1,117 +0,0 @@ -name: '(App Router) Next.js Bundle Analysis' - -permissions: - contents: read - pull-requests: write - -on: - pull_request: - push: - branches: - - develop # change this if your default branch is named differently - workflow_dispatch: - -defaults: - run: - # change this if your nextjs app does not live at the root of the repo - working-directory: ./projects/wp-nextjs-app - -jobs: - analyze: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set up node - uses: actions/setup-node@v3 - with: - node-version: '20.x' - - - name: Install dependencies - run: (cd ../../ && npm ci) - - - name: Restore next build - uses: actions/cache@v4 - id: restore-build-cache - env: - cache-name: cache-next-build - with: - # if you use a custom build directory, replace all instances of `.next` in this file with your build directory - # ex: if your app builds to `dist`, replace `.next` with `dist` - path: .next/cache - # change this if you prefer a more strict cache - key: ${{ runner.os }}-build-${{ env.cache-name }} - - - name: Build next.js app - # change this if your site requires a custom build command - run: (cd ../../ && npm run build -- --filter=@10up/wp-nextjs-app) - - # Here's the first place where next-bundle-analysis' own script is used - # This step pulls the raw bundle stats for the current bundle - - name: Analyze bundle - run: npx -p nextjs-bundle-analysis report - - - name: Upload bundle - uses: actions/upload-artifact@v4 - with: - name: bundle - path: ./projects/wp-nextjs-app/.next/analyze/__bundle_analysis.json - - - name: Download base branch bundle stats - uses: dawidd6/action-download-artifact@v6 - if: success() && github.event.number - with: - workflow: nextjs_bundle_analysis.yml - branch: ${{ github.event.pull_request.base.ref }} - path: ./projects/wp-nextjs-app/.next/analyze/base - - # And here's the second place - this runs after we have both the current and - # base branch bundle stats, and will compare them to determine what changed. - # There are two configurable arguments that come from package.json: - # - # - budget: optional, set a budget (bytes) against which size changes are measured - # it's set to 350kb here by default, as informed by the following piece: - # https://infrequently.org/2021/03/the-performance-inequality-gap/ - # - # - red-status-percentage: sets the percent size increase where you get a red - # status indicator, defaults to 20% - # - # Either of these arguments can be changed or removed by editing the `nextBundleAnalysis` - # entry in your package.json file. - - name: Compare with base branch bundle - if: success() && github.event.number - run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare - - - name: Get comment body - id: get-comment-body - if: success() && github.event.number - run: | - body=$(cat .next/analyze/__bundle_analysis_comment.txt) - body="${body//'%'/'%25'}" - body="${body//$'\n'/'%0A'}" - body="${body//$'\r'/'%0D'}" - echo ::set-output name=body::$body - - - name: Find Comment - uses: peter-evans/find-comment@v1 - if: success() && github.event.number - id: fc - with: - issue-number: ${{ github.event.number }} - body-includes: '' - - - name: Create Comment - uses: peter-evans/create-or-update-comment@v1.4.4 - if: success() && github.event.number && steps.fc.outputs.comment-id == 0 - with: - issue-number: ${{ github.event.number }} - body: ${{ steps.get-comment-body.outputs.body }} - - - name: Update Comment - uses: peter-evans/create-or-update-comment@v1.4.4 - if: success() && github.event.number && steps.fc.outputs.comment-id != 0 - with: - issue-number: ${{ github.event.number }} - body: ${{ steps.get-comment-body.outputs.body }} - comment-id: ${{ steps.fc.outputs.comment-id }} - edit-mode: replace diff --git a/.github/workflows/nextjs_bundle_analysis.yml b/.github/workflows/nextjs_bundle_analysis.yml deleted file mode 100644 index 2f29399b0..000000000 --- a/.github/workflows/nextjs_bundle_analysis.yml +++ /dev/null @@ -1,119 +0,0 @@ -name: '(Pages Router) Next.js Bundle Analysis' - -permissions: - contents: read - actions: read - pull-requests: write - issues: write - -on: - pull_request: - push: - branches: - - develop # change this if your default branch is named differently - workflow_dispatch: - -defaults: - run: - # change this if your nextjs app does not live at the root of the repo - working-directory: ./ - -jobs: - analyze: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set up node - uses: actions/setup-node@v3 - with: - node-version: '20.x' - - - name: Install dependencies - uses: bahmutov/npm-install@v1 - - - name: Restore next build - uses: actions/cache@v4 - id: restore-build-cache - env: - cache-name: cache-next-build - with: - # if you use a custom build directory, replace all instances of `.next` in this file with your build directory - # ex: if your app builds to `dist`, replace `.next` with `dist` - path: ./projects/wp-nextjs/.next/cache - # change this if you prefer a more strict cache - key: ${{ runner.os }}-build-${{ env.cache-name }} - - - name: Build next.js app - # change this if your site requires a custom build command - run: npm run build -- --filter=@10up/wp-nextjs - - # Here's the first place where next-bundle-analysis' own script is used - # This step pulls the raw bundle stats for the current bundle - - name: Analyze bundle - run: npx -p nextjs-bundle-analysis report - - - name: Upload bundle - uses: actions/upload-artifact@v4 - with: - name: bundle - path: ./projects/wp-nextjs/.next/analyze/__bundle_analysis.json - - - name: Download base branch bundle stats - uses: dawidd6/action-download-artifact@v6 - if: success() && github.event.number - with: - workflow: nextjs_bundle_analysis.yml - branch: ${{ github.event.pull_request.base.ref }} - path: ./projects/wp-nextjs/.next/analyze/base - - # And here's the second place - this runs after we have both the current and - # base branch bundle stats, and will compare them to determine what changed. - # There are two configurable arguments that come from package.json: - # - # - budget: optional, set a budget (bytes) against which size changes are measured - # it's set to 350kb here by default, as informed by the following piece: - # https://infrequently.org/2021/03/the-performance-inequality-gap/ - # - # - red-status-percentage: sets the percent size increase where you get a red - # status indicator, defaults to 20% - # - # Either of these arguments can be changed or removed by editing the `nextBundleAnalysis` - # entry in your package.json file. - - name: Compare with base branch bundle - if: success() && github.event.number - run: ls -laR ./projects/wp-nextjs/.next/analyze/base && npx -p nextjs-bundle-analysis compare - - - name: Get comment body - id: get-comment-body - if: success() && github.event.number - run: | - body=$(cat ./projects/wp-nextjs/.next/analyze/__bundle_analysis_comment.txt) - body="${body//'%'/'%25'}" - body="${body//$'\n'/'%0A'}" - body="${body//$'\r'/'%0D'}" - echo ::set-output name=body::$body - - - name: Find Comment - uses: peter-evans/find-comment@v1 - if: success() && github.event.number - id: fc - with: - issue-number: ${{ github.event.number }} - body-includes: '' - - - name: Create Comment - uses: peter-evans/create-or-update-comment@v1.4.4 - if: success() && github.event.number && steps.fc.outputs.comment-id == 0 - with: - issue-number: ${{ github.event.number }} - body: ${{ steps.get-comment-body.outputs.body }} - - - name: Update Comment - uses: peter-evans/create-or-update-comment@v1.4.4 - if: success() && github.event.number && steps.fc.outputs.comment-id != 0 - with: - issue-number: ${{ github.event.number }} - body: ${{ steps.get-comment-body.outputs.body }} - comment-id: ${{ steps.fc.outputs.comment-id }} - edit-mode: replace diff --git a/.github/workflows/npm-release-next-version.yml b/.github/workflows/npm-release-next-version.yml index 61e3d9ed9..a60828327 100644 --- a/.github/workflows/npm-release-next-version.yml +++ b/.github/workflows/npm-release-next-version.yml @@ -17,12 +17,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 24.x - name: Install Dependencies run: npm ci @@ -46,7 +46,7 @@ jobs: needs: [packages] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Publish to the publishing repository id: push_directory uses: cpina/github-action-push-to-another-repository@main @@ -60,7 +60,7 @@ jobs: commit-message: See ORIGIN_COMMIT from $GITHUB_REF target-branch: next - name: Checkout the publishing repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: 10up/headstartwp-plugin path: 'repo' diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 5b238b282..7a4757aa8 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -5,23 +5,42 @@ permissions: on: pull_request +concurrency: + group: phpunit-${{ github.ref }} + cancel-in-progress: true + jobs: phpunit: - name: phpunit + name: phpunit (${{ matrix.php-version }}) runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - php-version: ['7.4', '8.0', '8.2'] + # 8.2 is the supported floor; 8.4 catches forward-compat breakage. + php-version: ['8.2', '8.4'] steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Set PHP version - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-version }} - - name: npm install - run: npm install - - name: composer install - run: cd ./wp/headless-wp && composer install --ignore-platform-reqs - - name: Run tests - run: npm run test:php -w=wp/headless-wp \ No newline at end of file + - name: Checkout + uses: actions/checkout@v4 + + - name: Set PHP version + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + + - name: Ensure npm satisfies devEngines (>=11.6.0) + run: npm i -g npm@11 + + - name: npm ci + run: npm ci + + - name: composer install + run: cd ./wp/headless-wp && composer install --ignore-platform-reqs + + - name: Run tests + run: npm run test:php -w=wp/headless-wp diff --git a/.github/workflows/release-latest-version.yml b/.github/workflows/release-latest-version.yml index c5aa9c9af..01500bce7 100644 --- a/.github/workflows/release-latest-version.yml +++ b/.github/workflows/release-latest-version.yml @@ -22,12 +22,12 @@ jobs: hasChangesets: ${{ steps.changesets.outputs.hasChangesets }} steps: - name: Checkout Repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 24.x - name: Install Dependencies run: npm ci @@ -52,7 +52,7 @@ jobs: if: needs.packages.outputs.hasChangesets == 'false' && github.ref == 'refs/heads/trunk' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Publish to the publishing repository id: push_directory uses: cpina/github-action-push-to-another-repository@main @@ -66,7 +66,7 @@ jobs: commit-message: See ORIGIN_COMMIT from $GITHUB_REF target-branch: trunk - name: Checkout the publishing repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: 10up/headstartwp-plugin path: 'repo' diff --git a/.github/workflows/release-v1.yml b/.github/workflows/release-v1.yml new file mode 100644 index 000000000..9836422bf --- /dev/null +++ b/.github/workflows/release-v1.yml @@ -0,0 +1,51 @@ +name: Release @v1 (maintenance) + +# Publishes bug and security fixes for the 1.x line (Next.js 15) after 2.x +# owns `latest`. Cut `release/1.x` from trunk once 1.x is published, then land +# fixes there with changesets as usual. + +permissions: + contents: write + pull-requests: write + +on: + push: + branches: + - release/1.x + workflow_dispatch: + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + packages: + name: Release 1.x + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/release/1.x' + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + + - name: Ensure npm satisfies devEngines (>=11.6.0) + run: npm i -g npm@11 + + - name: Install Dependencies + run: npm ci + + - name: Create Release Pull Request or Publish to npm + uses: changesets/action@v1 + with: + # --tag v1 keeps `latest` pointing at 2.x. Without it, the first 1.x + # patch published after 2.0.0 would move `latest` back to 1.x. + publish: npm run publish -- --tag v1 + version: npm run version + commit: 'chore: version packages (1.x)' + title: 'chore: version packages (1.x)' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index e7f7460cd..6f0423c15 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -5,31 +5,30 @@ permissions: on: [pull_request] +concurrency: + group: unit-tests-${{ github.ref }} + cancel-in-progress: true + jobs: unit-tests: + name: unit-tests runs-on: ubuntu-latest - strategy: - matrix: - node-version: [16.x, 18.x, 20.x] - steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - name: Setup Node ${{ matrix.node-version }} - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 24 + cache: npm + + - name: Ensure npm satisfies devEngines (>=11.6.0) + run: npm i -g npm@11 - - name: Setup npm cache - uses: actions/cache@v4 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - name: Install dependencies - run: npm install + run: npm ci + - name: Run unit tests - run: npm run test \ No newline at end of file + run: npm run test diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile index 8c00642d5..218444ed6 100644 --- a/.gitpod.Dockerfile +++ b/.gitpod.Dockerfile @@ -1,5 +1,5 @@ FROM gitpod/workspace-full:latest -RUN bash -c ". .nvm/nvm.sh && nvm install 20 && nvm use 20 && nvm alias default 20" +RUN bash -c ". .nvm/nvm.sh && nvm install 24 && nvm use 24 && nvm alias default 24" RUN echo "nvm use default &>/dev/null" >> ~/.bashrc.d/51-nvm-fix \ No newline at end of file diff --git a/.husky/.gitignore b/.husky/.gitignore deleted file mode 100644 index c9cdc63b0..000000000 --- a/.husky/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_ \ No newline at end of file diff --git a/.husky/commit-msg b/.husky/commit-msg deleted file mode 100755 index 0bd658f49..000000000 --- a/.husky/commit-msg +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -npx --no-install commitlint --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 36af21989..000000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -npx lint-staged diff --git a/.lintstagedrc.json b/.lintstagedrc.json deleted file mode 100644 index 7a9d31767..000000000 --- a/.lintstagedrc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "*.[tj]s": [ - "eslint" - ], - "*.[tj]sx": [ - "eslint" - ] -} \ No newline at end of file diff --git a/.nvmrc b/.nvmrc index 2edeafb09..a45fd52cc 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20 \ No newline at end of file +24 diff --git a/.vite-hooks/commit-msg b/.vite-hooks/commit-msg new file mode 100755 index 000000000..5f7557125 --- /dev/null +++ b/.vite-hooks/commit-msg @@ -0,0 +1 @@ +vp exec commitlint --edit "$1" diff --git a/.vite-hooks/pre-commit b/.vite-hooks/pre-commit new file mode 100755 index 000000000..85fb65b4f --- /dev/null +++ b/.vite-hooks/pre-commit @@ -0,0 +1 @@ +vp staged diff --git a/.vscode/settings.json b/.vscode/settings.json index 6ee516c29..2b623ccf9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,18 +6,6 @@ "[php]": { "editor.defaultFormatter": "valeryanm.vscode-phpsab" }, - "[javascript]": { - "editor.defaultFormatter": "dbaeumer.vscode-eslint" - }, - "[typescript]": { - "editor.defaultFormatter": "dbaeumer.vscode-eslint" - }, - "[javascriptreact]": { - "editor.defaultFormatter": "dbaeumer.vscode-eslint" - }, - "[typescriptreact]": { - "editor.defaultFormatter": "dbaeumer.vscode-eslint" - }, "editor.formatOnSave": true, "biome.enabled": false -} \ No newline at end of file +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64039c452..af6b6df20 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,12 +36,33 @@ The `develop` branch is the development branch which means it contains the next ## Get the project running -First and foremost, run `npm install` from the root. Then run `npm run dev` or `npm run dev:multisite`. +First and foremost, run `npm install` from the root. -The `npm run dev` command will spin up a single WordPress instance that by default will run at http://localhost:8888 and a the starter Next.js project. +- `npm run build` builds every package under `packages/`. +- `npm run dev` watches and rebuilds all packages and starts the local WordPress instance (via `wp-env`) + at http://localhost:8888. +- `npm run test` runs the package unit tests. -The `npm run dev:multisite` command will spin up a single WordPress instance that by default will run at http://localhost:8888 and the multisite next.js project. +`npm install` also installs the Git hooks through Vite+ (`vp config`, run by the root `prepare` script). +The hooks live in `.vite-hooks/`: `pre-commit` runs `vp staged` (the `staged` block in `vite.config.ts`) +and `commit-msg` runs commitlint. To skip them for one commit use `VP_GIT_HOOKS=0 git commit ...`; to turn +them off in your clone run `npx vp hooks disable` (and `npx vp hooks enable` to turn them back on). +### Testing changes against a real front end + +As of 1.8.0 this repository no longer contains example or starter Next.js projects. Their knowledge now +lives in [`prds/`](./prds/README.md) as PRDs an LLM can use to stand up an equivalent project. + +To exercise a package change end to end: + +1. Generate a throwaway project **outside this repo** from the relevant PRD (for example + `prds/app-router-starter.md`), pointing it at `http://localhost:8888`. +2. Point its HeadstartWP dependencies at your local build, e.g. + `npm install ../headstartwp/packages/core ../headstartwp/packages/next`. +3. Keep `npm run dev` running here so the packages rebuild as you edit. + +If your change alters how projects should be wired (new config options, route handlers, conventions), +update the affected PRDs in the same pull request. ## Troubleshooting diff --git a/README.md b/README.md index bae6a45e6..fe7cd20e1 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,13 @@ [![Support Level](https://img.shields.io/badge/support-active-green.svg)](#support-level) [![eslint](https://github.com/10up/headstartwp/actions/workflows/eslint.yml/badge.svg)](https://github.com/10up/headstartwp/actions/workflows/eslint.yml) [![PHPCS check](https://github.com/10up/headstartwp/actions/workflows/phpcs.yml/badge.svg)](https://github.com/10up/headstartwp/actions/workflows/phpcs.yml) [![unit tests](https://github.com/10up/headstartwp/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/10up/headstartwp/actions/workflows/unit-tests.yml) [![Core Package MIT License](https://img.shields.io/badge/core%20package-MIT-green)](https://github.com/10up/headstartwp/blob/develop/packages/core/LICENSE.md) [![Hooks Package MIT License](https://img.shields.io/badge/hooks%20package-MIT-green)](https://github.com/10up/headstartwp/blob/develop/packages/hooks/LICENSE.md) [![Next Package MIT License](https://img.shields.io/badge/next%20package-MIT-green)](https://github.com/10up/headstartwp/blob/develop/packages/next/LICENSE.md) -[![wp-multisite-i18n-nextjs Project GPLv2 License](https://img.shields.io/badge/wp--multisite--i18n--nextjs%20project-GPLv2-orange)](https://github.com/10up/headstartwp/blob/develop/projects/wp-multisite-i18n-nextjs/LICENSE.md) [![wp-multisite-nextjs Project GPLv2 License](https://img.shields.io/badge/wp--multisite--nextjs%20project-GPLv2-orange)](https://github.com/10up/headstartwp/blob/develop/projects/wp-multisite-nextjs/LICENSE.md) [![wp-nextjs Project GPLv2 License](https://img.shields.io/badge/wp--nextjs%20package-GPLv2-orange)](https://github.com/10up/headstartwp/blob/develop/projects/wp-nextjs/LICENSE.md) [![HeadstartWP Plugin GPLv2 License](https://img.shields.io/badge/Headless%20WordPress%20plugin-GPLv2-orange)](https://github.com/10up/headstartwp/blob/develop/wp/tenup-headless-wp/LICENSE.md) ## Documentation -See our [Getting Started](https://headstartwp.10up.com/docs/learn/getting-started/quick-setup/) guide. +See our [Getting Started](https://headstartwp.fueled.com/docs/learn/getting-started/quick-setup/) guide. -Visit [headstartwp.10up.com/docs](https://headstartwp.10up.com/docs) for the full documentation. +Visit [headstartwp.fueled.com/docs](https://headstartwp.fueled.com/docs) for the full documentation. ### Running docs site locally @@ -36,8 +35,12 @@ A complete listing of all notable changes to 10up's Headless Framework are docum Visit the [CONTRIBUTING](/CONTRIBUTING.md) page for initial contribution and engineering guidance. -This repository is a monorepo, under the `packages` there are all the tools that are published to npm. The `projects` directory is a collection of test projects linked to the tools in `packages` and is used for testing purposes. +This repository is a monorepo. The `packages` directory contains every tool published to npm, and `wp` contains the HeadstartWP WordPress plugin and local development tooling. + +## Starting a new project + +HeadstartWP no longer ships starter or example projects. Instead, [`prds/`](./prds/README.md) contains product requirement documents describing each former example project (App Router starter, multisite, Polylang, ElasticPress search, universal blocks, Pages Router references, and a Vite SPA). Point your LLM coding agent at [`prds/00-foundation.md`](./prds/00-foundation.md) plus the PRD that matches what you're building, and describe what's specific to your project. ## Like what you see? -10up +[![Work with the 10up WordPress Practice at Fueled](https://github.com/10up/.github/blob/trunk/profile/10up-github-banner.jpg)](http://10up.com/contact/) diff --git a/docs/documentation/01-Getting Started/quick-setup.md b/docs/documentation/01-Getting Started/quick-setup.md index 97bb45189..14026adfe 100644 --- a/docs/documentation/01-Getting Started/quick-setup.md +++ b/docs/documentation/01-Getting Started/quick-setup.md @@ -10,52 +10,65 @@ If you're new to Next.js App Router, we recommend reviewing [Next.js App Router ## System Requirements -- Node.js 18 or later -- NPM >= 7 -- WordPress >= 5.9 (prior versions might work but haven't been tested) -- Next.js 15+ (HeadstartWP only supports App Router with Next.js 15+) +- Node.js 24 or later +- npm 11 or later +- WordPress with the [HeadstartWP plugin](/learn/getting-started/installing-wordpress-plugin) installed +- Next.js 15 and React 18 (HeadstartWP 1.x) ## Installation -The easiest way to get started with HeadstartWP and App Router is by using `create-next-app` with the official App Router starter project. - -```bash -npx create-next-app --use-npm -e https://github.com/10up/headstartwp/tree/trunk/projects/wp-nextjs-app +HeadstartWP does not ship a starter project. Instead, the repository contains [PRDs](https://github.com/10up/headstartwp/blob/develop/prds/README.md) +(product requirement documents) written for LLM coding agents such as Claude, Cursor or Copilot. Each PRD +describes a complete project — its routes, configuration, and acceptance criteria — and the agent +generates it for you against the package versions you're installing. + +1. Create an empty directory for your project. +2. Give your agent [`00-foundation.md`](https://github.com/10up/headstartwp/blob/develop/prds/00-foundation.md) and the PRD that fits what you're building. + Most new projects should use the [App Router starter PRD](https://github.com/10up/headstartwp/blob/develop/prds/app-router-starter.md). +3. Describe what's specific to your project. For example: + +```text +Read prds/00-foundation.md and prds/app-router-starter.md from +https://github.com/10up/headstartwp/tree/develop/prds and stand up a new HeadstartWP project in this +directory. My WordPress backend is https://cms.example.com. We use Tailwind. Verify each acceptance +criterion before you finish and tell me which ones you could not verify. ``` -Then run `npm run dev` and open http://localhost:3000 in your browser. +4. Run `npm run dev` and open http://localhost:3000. + +Other PRDs cover [multisite](https://github.com/10up/headstartwp/blob/develop/prds/app-router-multisite.md), [Polylang](https://github.com/10up/headstartwp/blob/develop/prds/app-router-polylang.md), +[ElasticPress search](https://github.com/10up/headstartwp/blob/develop/prds/app-router-elasticpress-search.md), +[universal blocks](https://github.com/10up/headstartwp/blob/develop/prds/universal-blocks.md), and legacy Pages Router setups. + +If you'd rather wire things up by hand, see [Setting up manually](/learn/getting-started/setting-up-manually). ### Project Structure -The starter project follows Next.js App Router conventions: +A project generated from the App Router starter PRD follows Next.js App Router conventions: ``` src/ ├── app/ -│ ├── layout.tsx # Root layout -│ ├── page.tsx # Home page -│ ├── not-found.tsx # 404 page -│ ├── (single)/ # Route group for posts/pages -│ │ └── [...path]/ -│ │ └── page.tsx # Dynamic catch-all route -│ ├── blog/ -│ │ └── page.tsx # Blog archive -│ ├── category/ -│ │ └── [slug]/ -│ │ └── page.tsx # Category archive -│ └── globals.css +│ ├── layout.tsx # Root layout (settings, menu, block styles) +│ ├── page.tsx # Home page +│ ├── not-found.tsx # 404 page +│ ├── (single)/[...path]/ # Posts and pages by permalink +│ ├── blog/[[...path]]/ # Blog archive + single posts +│ ├── category/[...path]/ # Category archive +│ ├── tag/[...path]/ # Tag archive +│ ├── author/[...path]/ # Author archive +│ ├── search/[[...path]]/ # Search results +│ └── api/ # preview + revalidate route handlers ├── components/ -│ ├── Blocks.tsx # Gutenberg blocks renderer -│ └── ... -└── middleware.ts # middleware +│ └── Blocks.tsx # Gutenberg blocks renderer +└── middleware.ts ``` ### Environment Variables -By default, the starter project will point to `js1.10up.com`. Either change the -`NEXT_PUBLIC_HEADLESS_WP_URL` variable or create a `.env.local` file to override the default env variables. +Set `NEXT_PUBLIC_HEADLESS_WP_URL` to your WordPress URL (in `.env`, or `.env.local` for local overrides). -If you're developing locally and using HTTPS with WordPress and you don't have valid certs, you will need to add `NODE_TLS_REJECT_UNAUTHORIZED=0` as an env variable +If you're developing locally and using HTTPS with WordPress and you don't have valid certs, you will need to add `NODE_TLS_REJECT_UNAUTHORIZED=0` as an env variable in `.env.local`: ``` NEXT_PUBLIC_HEADLESS_WP_URL=https://wordpress.test diff --git a/docs/documentation/06-WordPress Integration/multisite.md b/docs/documentation/06-WordPress Integration/multisite.md index 275683ae1..7f5760c4b 100644 --- a/docs/documentation/06-WordPress Integration/multisite.md +++ b/docs/documentation/06-WordPress Integration/multisite.md @@ -11,7 +11,7 @@ The `sites` option allows specifying as many sites you want to connect to your a This feature does not require that all sites belong to the same multisite, you're free to connect the Next.js app to a completely separate WordPress instance, as long as that instance implements what your Next.js app needs. -Take a look at the [App Router multisite demo project](https://github.com/10up/headstartwp/tree/develop/projects/wp-multisite-nextjs-app) to familiarize yourself with the set-up. +Take a look at the [App Router multisite PRD](https://github.com/10up/headstartwp/blob/develop/prds/app-router-multisite.md) to familiarize yourself with the set-up. ## Usage @@ -182,7 +182,7 @@ With this configuration, you can create site-specific routes like: This provides a powerful way of powering complex multi-tenant apps that shares a codebase but render completely different pages and layouts. -## Demo Project +## Reference PRD -Take a look at the [App Router multisite demo project](https://github.com/10up/headstartwp/tree/develop/projects/wp-multisite-nextjs-app) to see a complete implementation of multisite with App Router. +The [App Router multisite PRD](https://github.com/10up/headstartwp/blob/develop/prds/app-router-multisite.md) describes a complete multisite implementation with the App Router. Give it (with [`00-foundation.md`](https://github.com/10up/headstartwp/blob/develop/prds/00-foundation.md)) to an LLM coding agent to stand up a multisite project. diff --git a/docs/documentation/06-WordPress Integration/polylang.md b/docs/documentation/06-WordPress Integration/polylang.md index 89bd53abd..205d7539f 100644 --- a/docs/documentation/06-WordPress Integration/polylang.md +++ b/docs/documentation/06-WordPress Integration/polylang.md @@ -110,14 +110,16 @@ src/app/ └── page.tsx # Pages and single posts ``` -### Demo Project +### Reference PRD -For a complete example of Polylang integration with HeadstartWP, check out our [demo project](https://github.com/10up/headstartwp/tree/develop/projects/wp-polylang-nextjs-app). The demo includes: +The [App Router + Polylang PRD](https://github.com/10up/headstartwp/blob/develop/prds/app-router-polylang.md) describes a complete Polylang integration with HeadstartWP, including: -- Full App Router setup with language routing -- Language switcher component implementation -- WordPress configuration examples -- Proper handling of translations and locale detection +- Full App Router setup with `[lang]` routing +- Per-language front pages and menus +- A language switcher requirement +- WordPress configuration prerequisites and common pitfalls + +Give it (with [`00-foundation.md`](https://github.com/10up/headstartwp/blob/develop/prds/00-foundation.md)) to an LLM coding agent to stand up a multilingual project. ## How it Works diff --git a/docs/documentation/06-WordPress Integration/revalidate.md b/docs/documentation/06-WordPress Integration/revalidate.md index 9fe6c7d10..0d2363007 100644 --- a/docs/documentation/06-WordPress Integration/revalidate.md +++ b/docs/documentation/06-WordPress Integration/revalidate.md @@ -218,7 +218,7 @@ module.exports = withHeadstartWPConfig(nextConfig); ``` :::info -The HeadstartWP [scaffold](https://github.com/10up/headstartwp/tree/develop/projects/wp-nextjs-app) already includes the code above +Projects generated from the [App Router starter PRD](https://github.com/10up/headstartwp/blob/develop/prds/app-router-starter.md) include the code above ::: The code above checks for `NEXT_REDIS_URL` and `VIP_REDIS_PRIMARY` (which is specific for WordPress VIP hosting), however there are several other env variables you can use to configure your redis connection. diff --git a/docs/documentation/08-Guides/typescript.md b/docs/documentation/08-Guides/typescript.md index bd0537993..57bbb877f 100644 --- a/docs/documentation/08-Guides/typescript.md +++ b/docs/documentation/08-Guides/typescript.md @@ -4,7 +4,7 @@ sidebar_label: TypeScript # TypeScript -HeadstartWP offers first-class support for TypeScript. In this guide we document how to leverage TypeScript with HeadstartWP and the Next.js App Router. We also recommend reviewing the official Next.js [docs for TypeScript](https://nextjs.org/docs/app/building-your-application/configuring/typescript) as well as using the default [HeadstartWP App Router project](https://github.com/10up/headstartwp/tree/develop/projects/wp-nextjs-app) as a reference for building with TypeScript. +HeadstartWP offers first-class support for TypeScript. In this guide we document how to leverage TypeScript with HeadstartWP and the Next.js App Router. We also recommend reviewing the official Next.js [docs for TypeScript](https://nextjs.org/docs/app/building-your-application/configuring/typescript) as well as the [App Router starter PRD](https://github.com/10up/headstartwp/blob/develop/prds/app-router-starter.md), which describes a TypeScript-first project layout. ## Server Components and Data Fetching diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 9896e10ed..bdc3e3757 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -6,11 +6,13 @@ import { themes as prismThemes } from 'prism-react-renderer'; /** @type {import('@docusaurus/types').Config} */ const config = { - title: 'HeadstartWP Docs - Next.js Framework for WordPress', + title: 'HeadstartWP Docs - Next.js Framework for Headless WordPress', tagline: '', - url: 'https://headstartwp.10up.com', + url: 'https://headstartwp.fueled.com', baseUrl: '/docs', - onBrokenLinks: 'throw', + // Links into the generated /api section are unavoidably broken when + // SKIP_TYPEDOC skips generation — downgrade so local builds still pass. + onBrokenLinks: process.env.SKIP_TYPEDOC ? 'warn' : 'throw', onBrokenMarkdownLinks: 'warn', favicon: 'img/favicon.ico', organizationName: '10up', // Usually your GitHub org/user name. @@ -32,9 +34,19 @@ const config = { ({ docs: false, blog: false, - googleTagManager: { - containerId: 'GTM-TKCGKK2', - }, + // Same Google tag as the main site (Site Kit on + // headstartwp.fueled.com) — one GA4 property covers the full + // site→docs journey. Replaces the legacy 10up GTM container. + // Production-only: in dev the gtag script never loads, so the + // plugin's route-change handler would throw on every navigation. + ...(process.env.NODE_ENV === 'production' + ? { + gtag: { + trackingID: 'GT-WRDG786', + anonymizeIP: true, + }, + } + : {}), theme: { customCss: './src/css/custom.css', }, @@ -43,21 +55,29 @@ const config = { ], plugins: [ - [ - 'docusaurus-plugin-typedoc', - { - name: 'HeadstartWP', - out: './docs', - entryPoints: ['../packages/core', '../packages/next'], - entryPointStrategy: 'packages', - packageOptions: { - entryPoints: ['src/docs-entry-point.ts'], - }, - categorizeByGroup: false, - excludeInternal: true, - readme: 'none', - }, - ], + // SKIP_TYPEDOC=1 skips API-reference generation for faster local + // theme/content work (it needs the monorepo packages installed and + // built). CI always runs it. Local builds still get working search, + // minus API-reference entries (see the search plugin config below). + ...(process.env.SKIP_TYPEDOC + ? [] + : [ + [ + 'docusaurus-plugin-typedoc', + { + name: 'HeadstartWP', + out: './docs', + entryPoints: ['../packages/core', '../packages/next'], + entryPointStrategy: 'packages', + packageOptions: { + entryPoints: ['src/docs-entry-point.ts'], + }, + categorizeByGroup: false, + excludeInternal: true, + readme: 'none', + }, + ], + ]), [ '@docusaurus/plugin-content-docs', { @@ -97,8 +117,11 @@ const config = { '@easyops-cn/docusaurus-search-local', { indexDocs: true, - docsRouteBasePath: ['learn', 'api'], - docsDir: ['documentation', 'docs'], + // Search must only reference contexts that emit an index: with + // SKIP_TYPEDOC there is no /api content, and a missing context + // index leaves the search loader hanging forever. + docsRouteBasePath: process.env.SKIP_TYPEDOC ? ['learn'] : ['learn', 'api'], + docsDir: process.env.SKIP_TYPEDOC ? ['documentation'] : ['documentation', 'docs'], hashed: true, }, ], @@ -121,7 +144,7 @@ const config = { type: 'doc', docId: 'index', position: 'right', - label: 'Docs', + label: 'Developer Guide', }, { type: 'doc', @@ -135,6 +158,12 @@ const config = { position: 'left', dropdownActiveClassDisabled: true, }, + { + href: 'https://headstartwp.fueled.com/', + label: 'About HeadstartWP', + position: 'right', + className: 'navbar-site-cta', + }, ], }, announcementBar: { @@ -149,24 +178,53 @@ const config = { style: 'light', links: [ { - title: 'Docs', + title: 'Docs & Community', items: [ { - label: 'Documentation', + label: 'Developer Guide', to: '/learn', }, { label: 'API Reference', to: '/api', }, + { + label: 'GitHub Discussions', + href: 'https://github.com/10up/headstartwp/discussions/', + }, ], }, { - title: 'Community', + title: 'HeadstartWP', items: [ { - label: 'GitHub Discussions', - href: 'https://github.com/10up/headstartwp/discussions/', + label: 'Main site', + href: 'https://headstartwp.fueled.com/', + }, + { + label: 'News & Updates', + href: 'https://headstartwp.fueled.com/news/', + }, + { + label: 'Privacy Policy', + href: 'https://headstartwp.fueled.com/privacy-policy/', + }, + ], + }, + { + title: 'Fueled (formerly 10up)', + items: [ + { + label: 'WordPress', + href: 'https://fueled.com/wordpress/?utm_source=referral&utm_medium=Website%20Referral&utm_campaign=headstartwp.fueled.com&utm_content=docs-footer', + }, + { + label: 'Hire us', + href: 'https://fueled.com/contact/?utm_source=referral&utm_medium=Website%20Referral&utm_campaign=headstartwp.fueled.com&utm_content=docs-footer-hire', + }, + { + label: 'Careers', + href: 'https://fueled.com/careers/?utm_source=referral&utm_medium=Website%20Referral&utm_campaign=headstartwp.fueled.com&utm_content=docs-footer-careers', }, ], }, diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index f0a1b18a9..347ee3135 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -4,7 +4,7 @@ * work well for content-centric websites. */ -@import url("https://fonts.googleapis.com/css2?family=Cabin:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Condensed:wght@600;700&family=IBM+Plex+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap"); @font-face { font-family: "Virgil"; diff --git a/docs/src/css/global-footer.css b/docs/src/css/global-footer.css index fe2f081b8..9712db87e 100644 --- a/docs/src/css/global-footer.css +++ b/docs/src/css/global-footer.css @@ -3,97 +3,108 @@ border-top: 2px solid var(--ifm-color-secondary-lightest); } -.footer-about { - background-color: var(--ifm-color-secondary-lightest); - padding: 3rem var(--ifm-spacing-horizontal); -} - -.footer-about-inner { - margin: 0 auto; - max-width: var(--wide-width); +/* --- Bottom band: mirrors the headstartwp.fueled.com site footer --- */ + +.footer-fueled { + background-color: #323F60; + color: #fff; + font-size: 0.8rem; + font-weight: 300; + padding: 3.5rem var(--ifm-spacing-horizontal); text-align: center; } -.cta-careers { - vertical-align: top; +.footer-fueled a { + color: #fff; + text-decoration: underline; } -.license { - margin-top: 20px; +.footer-fueled a:hover { + color: #ddd; } -.license p { +.footer-fueled p { margin: 0; } -.license .copyright { - margin-right: 4px; +.footer-fueled .footer-links { + list-style: none; + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 4px 18px; + margin: 6px 0 0; + padding: 0; } -@media (min-width: 900px) { - .cta-careers { - display: inline-block; - vertical-align: top; - text-align: left; - width: 48%; - } - - .license { - display: inline-block; - margin-left: 2%; - text-align: right; - width: 48%; - margin-top: 0; - } +.footer-fueled .footer-links li { + opacity: 0.75; } -.cta-careers .button { - margin-top: .5em; - background-color: var(--ifm-color-primary); - text-decoration: none; +.footer-fueled .footer-links li:hover { + opacity: 1; } -.cta-careers .button:hover { - background-color: var(--ifm-color-primary-dark); +.footer-fueled .footer-links a { + color: inherit; } - -.footer-10up { - padding: 3rem var(--ifm-spacing-horizontal); +.footer-fueled .logo img { + width: 170px; + height: auto; + display: block; + margin: 30px auto; } -.footer-10up .wrap { - margin: 0 auto; - max-width: var(--wide-width); - text-align: center; +.footer-fueled .social ul { + list-style: none; + display: flex; + justify-content: center; + gap: 5px; + margin: 0; + padding: 0; } -.footer-10up .social-media svg { - width: 25px; - margin-right: 15px; +.footer-fueled .social svg { + width: 24px; + display: block; } -.footer-10up .social-media path { - fill: var(--ifm-color-gray-600); +.footer-fueled .social path { + fill: #fff; } -.footer-10up .social-media svg:hover path { - fill: var(--ifm-color-black); +.footer-fueled .social a:hover path { + fill: #ddd; } -.footer-10up p { - margin: 20px 0; +.footer-fueled .sr-only { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(1px, 1px, 1px, 1px); } @media (min-width: 900px) { - .footer-10up .wrap { - display: flex; - text-align: left; + .footer-fueled .wrap { + display: grid; + grid-template-columns: 1fr 170px 1fr; align-items: center; - justify-content: space-between; + max-width: var(--wide-width); + margin: 0 auto; + text-align: left; + } + + .footer-fueled .footer-links { + justify-content: flex-start; + } + + .footer-fueled .logo img { + margin: 0 auto; } - .footer-10up p { - margin: 0; + .footer-fueled .social ul { + justify-content: flex-end; } -} \ No newline at end of file +} diff --git a/docs/src/css/global-header.css b/docs/src/css/global-header.css index 24019fc91..5be752860 100644 --- a/docs/src/css/global-header.css +++ b/docs/src/css/global-header.css @@ -8,4 +8,18 @@ html:not(.docs-wrapper) .navbar { box-shadow: none; -} \ No newline at end of file +} +/* CTA back to the main site (mirrors the site header's Get Started chip). */ +.navbar-site-cta { + background: #1C1F37; + color: #fff !important; + border-radius: 2px; + padding: 8px 16px; + margin-left: 8px; + font-weight: 600; + text-decoration: none; +} + +.navbar-site-cta:hover { + background: var(--ifm-color-primary); +} diff --git a/docs/src/css/variables.css b/docs/src/css/variables.css index 0c35aaafa..36dc3d32f 100644 --- a/docs/src/css/variables.css +++ b/docs/src/css/variables.css @@ -8,23 +8,26 @@ --g2-color-slate: #40464d; --g2-color-black: #1e1e1e; + /* HeadstartWP site palette (headstartwp.fueled.com): teal links on + navy ink, light-blue accents. */ --ifm-footer-link-color: var(--ifm-color-black); - --ifm-color-primary: #df2b26; - --ifm-color-primary-dark: #B5130E; - --ifm-color-primary-darker: #213dd3; - --ifm-color-primary-darkest: #8A0400; - --ifm-color-primary-light: #FE4641; - --ifm-color-primary-lighter: #FF6662; - --ifm-color-primary-lightest: #FF918E; + --ifm-color-primary: #33647E; + --ifm-color-primary-dark: #2B5468; + --ifm-color-primary-darker: #284E61; + --ifm-color-primary-darkest: #1C1F37; + --ifm-color-primary-light: #3B7492; + --ifm-color-primary-lighter: #3F7C9C; + --ifm-color-primary-lightest: #4BA0C4; --ifm-footer-background-color: #fff; --ifm-link-decoration: underline; --ifm-link-hover-color: var(--ifm-color-primary-dark); --ifm-code-font-size: 1rem; --ifm-container-width-xl: 130ch; --ifm-container-width: 90ch; - --ifm-font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", - Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; - --ifm-heading-font-family: var(--ifm-font-family-base); + --ifm-font-family-base: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, + "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji"; + --ifm-heading-font-family: "IBM Plex Sans Condensed", var(--ifm-font-family-base); --ifm-h1-font-size: 2.625rem; --ifm-h2-font-size: 2rem; --ifm-heading-font-weight: var(--ifm-font-weight-semibold); @@ -32,9 +35,6 @@ --ifm-leading-desktop: 1.5; --ifm-menu-color-background-active: white; --ifm-navbar-height: 4.375rem; - --c-10up-secondary: #E3FAF8; - --c-10up-secondary-dark: #7ED5D4; - --wide-width: min(calc(100vw - 2.5rem), calc(var(--ifm-container-width-xl) + 300px)); --docusaurus-highlighted-code-line-bg: #e0e0e0; diff --git a/docs/src/pages/index.js b/docs/src/pages/index.js index 96c306cf8..7b3c0c5af 100644 --- a/docs/src/pages/index.js +++ b/docs/src/pages/index.js @@ -18,7 +18,7 @@ export default function Home() {

HeadstartWP

-

Next.js Framework for WordPress

+

Next.js Framework for Headless WordPress

@@ -31,7 +31,7 @@ export default function Home() { height={237} /> -

Documentation

+

Developer Guide

If you are unsure how to do something with the framework, this is where you should start. diff --git a/docs/src/pages/index.module.css b/docs/src/pages/index.module.css index 16cf451f8..854907858 100644 --- a/docs/src/pages/index.module.css +++ b/docs/src/pages/index.module.css @@ -7,11 +7,61 @@ padding: 6rem 0; text-align: center; position: relative; - background-color: var(--c-10up-secondary); + /* No overflow:hidden here - the search dropdown must be able to + extend past the hero. The lattice stays contained because the + ::after box is inset:0 with border-radius:inherit. */ + /* Mirrors the main site's hero: soft lavender wash with the purple + radial from the top right, and the lattice graphic ghosted on the + right (CSS background keeps it inert - no click capture, no + gradient-id collisions). */ + background: + radial-gradient(153.4% 328.78% at 88.61% -33.98%, rgba(163, 107, 163, 0.24) 0%, rgba(163, 107, 163, 0) 53.12%), + #faf8fb; border-radius: 2rem; margin-inline: 1rem; } +.heroBanner::after { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + background: url("../../static/img/hero-lattice.svg") no-repeat right -8rem center; + background-size: auto 200%; + opacity: 0.5; + pointer-events: none; +} + +.heroBanner > * { + position: relative; + z-index: 1; +} + +/* The oversized lattice reads great wide, but scales down busy — step the + crop and strength down with the viewport. */ +@media (max-width: 1200px) { + .heroBanner::after { + background-position: right -5rem center; + background-size: auto 160%; + opacity: 0.4; + } +} + +@media (max-width: 996px) { + .heroBanner::after { + background-position: right -4rem center; + background-size: auto 130%; + opacity: 0.25; + } +} + +@media (max-width: 600px) { + .heroBanner::after { + background-size: auto 110%; + opacity: 0.18; + } +} + .heroBanner p { font-size: 1.25rem; } diff --git a/docs/src/pages/philosophy.md b/docs/src/pages/philosophy.md index c06fd74c6..026656b86 100644 --- a/docs/src/pages/philosophy.md +++ b/docs/src/pages/philosophy.md @@ -1,16 +1,16 @@ # Framework Principles -These are the guiding principles for 10up's Headless Framework. +These are the guiding principles for HeadstartWP, Fueled's framework for headless WordPress. ## Solid Foundation -We aren't trying to reinvent the wheel nor do we want to spend a massive amount of resources building a new foundation for our framework. Therefore we decided to pick an existing and solid foundation to power 10up's Headless Framework: [Next.js](https://nextjs.org/). +We aren't trying to reinvent the wheel nor do we want to spend a massive amount of resources building a new foundation for our framework. Therefore we decided to pick an existing and solid foundation to power HeadstartWP: [Next.js](https://nextjs.org/). Next.js is by far the most used Full-Stack React Framework and we believe using Next.js will give us a solid foundation for our framework and let us focus on what matters: solving headless WordPress sites. ## Reduce the complexity of building headless sites -The 10up headless framework aims at making creating headless sites as easy as creating traditional WordPress sites. We want to reduce the complexity that developers need to face when building headless WordPress sites from scratch. +HeadstartWP aims at making creating headless sites as easy as creating traditional WordPress sites. We want to reduce the complexity that developers need to face when building headless WordPress sites from scratch. We aim to let engineers focus on the important aspects of the site instead of spending time figuring out how to "wire up" the Next.js application with WordPress. @@ -20,7 +20,7 @@ We want to boost creativity and let engineers explore new ways of building and s ## Low cost of maintenance -The 10up headless framework is a thin layer built on top of a solid foundation. It focuses on interacting with WordPress. At the end of the day, it's a Next.js application. +HeadstartWP is a thin layer built on top of a solid foundation. It focuses on interacting with WordPress. At the end of the day, it's a Next.js application. This means the maintenance cost is low as the lowest-level and most complex parts are provided by Next.js which is maintained by Vercel and have been driving a lot of innovations alongside partners like Google. @@ -30,7 +30,7 @@ We also aim at maintaining a simple stack. ### REST API over WPGraphQL -The 10up's Headless Framework at the moment does not work with WPGraphQL. +HeadstartWP at the moment does not work with WPGraphQL. GraphQL is great and when used on the right project adds tons of value in the long run. However, for most headless sites, there isn’t much value added by GraphQL. The additional complexity and engineering time required by adopting GraphQL/WPGraphQL isn’t worth the cost most of the time (caching, persisted queries, cache-bursting, etc). diff --git a/docs/src/theme/Footer/index.js b/docs/src/theme/Footer/index.js index 03619e62c..d317c84c9 100644 --- a/docs/src/theme/Footer/index.js +++ b/docs/src/theme/Footer/index.js @@ -4,90 +4,91 @@ import React from 'react'; import Footer from '@theme-original/Footer'; import useBaseUrl from '@docusaurus/useBaseUrl'; +/** + * Bottom band mirrors the footer on headstartwp.fueled.com: greyish-blue + * ground, "Finely crafted by Fueled (formerly 10up)" with a links row, + * centered white Fueled lockup, GitHub + LinkedIn on the right. + */ export default function FooterWrapper(props) { + const year = new Date().getFullYear(); + return ( <>