Skip to content

Commit 693252c

Browse files
Swanand01Ta5rjustlevine
authored
fix: Add is404 flag for 404ed routes (#151)
* feat : add import/no-default-export eslint rule. * chore : updated files for no-default-exports. * chore : add changeset. * chore : reorder-import * temp : fix failing gh actions * fix : export default for codegen config and baseConfig * feat: add connectedNode field to template query * feat: add `is404` flag to parseQueryResult return values * chore: add changeset * chore: add is404 test * feat: expose `is404` to the frontend * chore: use named import in next config * feat: add 404 handling to current path middleware * refactor: remove custom header * refactor: update is404 parsing * fix: update tests * revert: current path middleware * feat: redirect to not-found * revert: connectedNode from query * revert: not-found.tsx * revert: passing is404 to `TeemplateRenderer` children * feat: add docs on handling 404 pages * chore: update changeset * chore: sort query a to z * chore: format * chore: cleanup * docs: working example * chore: format --------- Co-authored-by: Ta5r <srv.tanay@gmail.com> Co-authored-by: Tanay Srivastava <62954323+Ta5r@users.noreply.github.com> Co-authored-by: Dovid Levine <david@axepress.dev>
1 parent 3424d33 commit 693252c

File tree

7 files changed

+122
-0
lines changed

7 files changed

+122
-0
lines changed

.changeset/tame-beans-pay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@snapwp/query": patch
3+
---
4+
5+
dev: Expose `QueryEngine.getTemplateData().is404` for custom HTTP status code handling.

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ SnapWP provides several plugins, packages, and libraries that can be used indivi
5757
- [Overloading WordPress Behavior](docs/overloading-wp-behavior.md)
5858
- [NextJS Middleware](docs/middleware.md)
5959
- [Template Rendering System](docs/template-rendering.md)
60+
- [Handling HTTP Status Codes](docs/http-status-codes.md)
61+
- [Resolving CORS Issues](docs/cors.md)
6062

6163
## Development & Contributing
6264

docs/http-status-codes.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# HTTP Status Codes
2+
3+
NextJS's App Router does not support setting custom [HTTP Status Codes](https://github.com/vercel/next.js/discussions/53225). As a result, requests to a non-existing WordPress page will return a `STATUS 200` code when returning Block Theme's 404 page.
4+
5+
Although Vercel insists [this doesn't affect SEO](https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming#status-codes), you can choose to opt-out of using the [`TemplateRenderer`](./template-rendering.md#templaterenderer) and provide your own [Not Found page](https://nextjs.org/docs/app/api-reference/functions/not-found) - or even [`redirect()`](https://nextjs.org/docs/app/api-reference/functions/redirect) to a different WordPress - or non-WordPress - route.
6+
7+
## Example: Using `QueryEngine.getTemplateData().is404`
8+
9+
SnapWP's `QueryEngine.getTemplateData()` returns an `is404` boolean to detect routes that resolve to your Block Theme's 404 page. Here's how to use it with Next.js:
10+
11+
```tsx
12+
import { notFound } from 'next/navigation';
13+
import { TemplateRenderer } from '@snapwp/next';
14+
import { EditorBlocksRenderer } from '@snapwp/blocks';
15+
import { QueryEngine } from '@snapwp/query';
16+
17+
export default async function Page( {
18+
params,
19+
}: {
20+
params: { path?: string[] };
21+
} ) {
22+
const { path } = await params;
23+
const pathname = path?.join( '/' ) || '/';
24+
25+
const { is404 } = await QueryEngine.getTemplateData( pathname );
26+
27+
if ( is404 ) {
28+
notFound();
29+
}
30+
31+
return (
32+
<TemplateRenderer>
33+
{ ( editorBlocks ) => (
34+
<EditorBlocksRenderer editorBlocks={ editorBlocks } />
35+
) }
36+
</TemplateRenderer>
37+
);
38+
}
39+
```

packages/query/src/queries/get-current-template.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,5 +126,6 @@ query GetCurrentTemplate($uri: String!) {
126126
...CoreVideoFrag
127127
}
128128
}
129+
is404
129130
}
130131
}

packages/query/src/query-engine/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ export class QueryEngine {
168168
scripts: EnqueuedScriptProps[] | undefined;
169169
scriptModules: ScriptModuleProps[] | undefined;
170170
bodyClasses: string[] | undefined;
171+
is404: boolean;
171172
} > => {
172173
if ( ! QueryEngine.isClientInitialized ) {
173174
QueryEngine.initialize();

packages/query/src/utils/parse-template.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export function parseQueryResult(
2929
scripts: EnqueuedScriptProps[] | undefined;
3030
scriptModules: ScriptModuleProps[] | undefined;
3131
bodyClasses: string[] | undefined;
32+
is404: boolean;
3233
} {
3334
if ( queryData.errors?.length ) {
3435
queryData.errors?.forEach( ( error ) => {
@@ -51,13 +52,15 @@ export function parseQueryResult(
5152
}
5253

5354
const templateByUri = queryData.data?.templateByUri;
55+
const is404 = templateByUri?.is404 ?? false;
5456

5557
return {
5658
stylesheets: parseEnqueuedStylesheets( wordpressUrl, templateByUri ),
5759
editorBlocks: parseEditorBlocks( templateByUri ),
5860
scripts: parseEnqueuedScripts( templateByUri, wordpressUrl ),
5961
scriptModules: parseScriptModules( templateByUri, wordpressUrl ),
6062
bodyClasses: parseBodyClasses( templateByUri ),
63+
is404,
6164
};
6265
}
6366

packages/query/src/utils/tests/parse-template.test.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ describe( 'parseQueryResult', () => {
8585
{ src: 'https://cdn.com/script.js', handle: 'cdn-script' },
8686
],
8787
bodyClasses: [ 'class1', 'class2' ],
88+
is404: false,
8889
} );
8990
} );
9091

@@ -106,4 +107,74 @@ describe( 'parseQueryResult', () => {
106107
{ message: 'Critical error occurred' }
107108
);
108109
} );
110+
111+
it( 'should return is404 true if `templateByUri.is404` is true', () => {
112+
const queryData: ApolloQueryResult< GetCurrentTemplateQuery > = {
113+
data: {
114+
templateByUri: {
115+
bodyClasses: [ 'class1', 'class2' ],
116+
enqueuedScripts: {
117+
nodes: [
118+
{
119+
id: '122',
120+
src: '/script.js',
121+
handle: 'test-script',
122+
},
123+
{
124+
id: '123',
125+
src: 'https://cdn.com/script.js',
126+
handle: 'cdn-script',
127+
},
128+
],
129+
},
130+
enqueuedStylesheets: {
131+
nodes: [
132+
{
133+
src: '/style.css',
134+
handle: 'test-style',
135+
before: [ 'before-content' ],
136+
after: [ 'after-content' ],
137+
},
138+
],
139+
},
140+
editorBlocks: [
141+
{
142+
type: 'core/paragraph',
143+
renderedHtml: '<p>Text</p>',
144+
},
145+
],
146+
is404: true,
147+
},
148+
},
149+
errors: [],
150+
loading: false,
151+
networkStatus: 7,
152+
};
153+
154+
const result = parseQueryResult( queryData, wordpressUrl, uri );
155+
156+
expect( result ).toEqual( {
157+
stylesheets: [
158+
{
159+
src: 'https://test.com/style.css',
160+
handle: 'test-style',
161+
before: 'before-content',
162+
after: 'after-content',
163+
},
164+
],
165+
editorBlocks: [
166+
{
167+
type: 'core/paragraph',
168+
renderedHtml: '<p>Text</p>',
169+
},
170+
],
171+
scriptModules: undefined,
172+
scripts: [
173+
{ src: 'https://test.com/script.js', handle: 'test-script' },
174+
{ src: 'https://cdn.com/script.js', handle: 'cdn-script' },
175+
],
176+
bodyClasses: [ 'class1', 'class2' ],
177+
is404: true,
178+
} );
179+
} );
109180
} );

0 commit comments

Comments
 (0)