Skip to content

Commit

Permalink
Merge branch 'develop' into revalidate-archives
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasio committed Jul 11, 2023
2 parents e11dff8 + f5e4df9 commit 7967202
Show file tree
Hide file tree
Showing 51 changed files with 1,000 additions and 303 deletions.
7 changes: 7 additions & 0 deletions .changeset/bright-jokes-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@headstartwp/core": patch
---

Fix theme.json handling in `useBlockColors` and `useBlockTypography`.

Thanks @riccardodicurti @dhamibirendra for [the bug report](https://github.com/10up/headstartwp/issues/541).
5 changes: 0 additions & 5 deletions .changeset/few-donkeys-think.md

This file was deleted.

11 changes: 11 additions & 0 deletions .changeset/lovely-chicken-sparkle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@headstartwp/next": minor
"@headstartwp/headstartwp": patch
"@headstartwp/core": patch
---

Improves the Next.js preview cookie handling and fixes a bug where the locale was not properly being passed from WP when previewing.

First of all, it sets the preview cookie to expire within 5 minutes which aligns with the JWT token expiration.

Secondly, it will narrow the cookie to the post path being previewed so that `context.preview` is not true for other paths and thus avoiding bypassing getStaticProps until the cookies are cleared (either expires or the browser closes).
5 changes: 5 additions & 0 deletions .changeset/mighty-stingrays-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@headstartwp/core": minor
---

Introduces `SafeHtml` and `HtmlDecoder` components.
22 changes: 22 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"mode": "pre",
"tag": "next",
"initialVersions": {
"@headstartwp/core": "1.0.6",
"@10up/react-hooks": "1.2.3",
"@headstartwp/next": "1.0.6",
"@10up/next-redis-cache-provider": "0.1.5",
"@10up/headless-docs": "1.0.0",
"@10up/wp-multisite-i18n-nextjs": "0.2.0",
"@10up/wp-multisite-nextjs": "0.2.0",
"@10up/wp-nextjs": "0.2.0",
"@10up/wp-nextjs-ts": "0.2.1-next.2",
"@headstartwp/headstartwp": "1.0.8"
},
"changesets": [
"bright-jokes-learn",
"lovely-chicken-sparkle",
"mighty-stingrays-pay",
"two-cats-vanish"
]
}
5 changes: 0 additions & 5 deletions .changeset/sharp-pants-sin.md

This file was deleted.

5 changes: 5 additions & 0 deletions .changeset/two-cats-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@headstartwp/core": minor
---

Introduces the `decodeHtmlSpecialChars` function.
6 changes: 3 additions & 3 deletions docs/documentation/01-Getting Started/headless-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ module.exports = {
archive: '/books',
},
],
cstomTaxonomies: [
customTaxonomies: [
{
slug: 'genre',
endpoint: '/wp-json/wp/v2/genre',
Expand All @@ -100,13 +100,13 @@ After adding a custom taxonomy to the config, you will be able to filter posts b
```js
usePost({ postType: ['book'], genre: 'action' });
usePosts({ postType:'book', genre: 'action' perPage: 10 });
useTerms({ taxonomy: 'genre' } );
useTerms({ taxonomy: 'genre' });
```

Additionally, if you have an archive route such as `/blog` or `/books` filtering for all registered taxonomies works out of the box. For instance, take the headless config above the following page route:

```js title=src/pages/books/[[...path]].js
import { usePosts} from '@headstartwp/next';
import { usePosts } from '@headstartwp/next';
const BooksPage = () => {
const { data, error, loading } = usePosts({postType: 'book'});

Expand Down
2 changes: 1 addition & 1 deletion docs/documentation/01-Getting Started/quick-tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The great thing about this is that you don’t need multiple Next.js routes to h

### Basic Data Fetching

Now let’s look at how data fetching for this route works. To make things easier to understand, let’s disregard `getStaticPaths` and `getStaticProps`functions.
Now let’s look at how data fetching for this route works. To make things easier to understand, let’s disregard `getStaticPaths` and `getStaticProps` functions.

```js title="src/params.js"
/**
Expand Down
2 changes: 1 addition & 1 deletion docs/documentation/01-Getting Started/wordpress-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Make sure to set up the path for installing this as a WordPress Plugin:

## Manual install

[Download the plugin's zip file](https://github.com/10up/tenup-headless-wp-plugin/archive/refs/heads/trunk.zip), manually move it to `wp-content/plugins` and activate the plugin.
[Download the plugin's zip file](https://github.com/10up/headstartwp-plugin/archive/refs/heads/trunk.zip), manually move it to `wp-content/plugins` and activate the plugin.

## Enter the front-end site URL.

Expand Down
6 changes: 3 additions & 3 deletions docs/documentation/02 - Data Fetching/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The following example uses the `useFetchPost` to manually fetch a page with the
import { useFetchPost } from '@headstartwp/core/react';

const Page = () => {
const { data: { post }, loading } = useFetchPost({ slug: 'about', post_type: 'page' } );
const { data: { post }, loading } = useFetchPost({ slug: 'about', post_type: 'page' });

if (loading) {
return 'Loading...';
Expand All @@ -43,7 +43,7 @@ const Page = () => {
You could omit the `slug` param by specifying the current path of the page and it will parse the path and extract matched params following the WordPress pretty permalinks convention.

```js
usePost({ post_type: 'page' }, {}, '/about' );
usePost({ post_type: 'page' }, {}, '/about');
```

By using the Next.js bindings and following the path catch-all route convention, the URL extraction is automatic.
Expand All @@ -54,7 +54,7 @@ import { usePost } from '@headstartwp/next';
const Page = () => {
// slug is automatically injected from the next.js router
// if you pass a slug it will override what's coming from the URL
const { loading, error, data } = usePost( { post_type: 'page' });
const { loading, error, data } = usePost({ post_type: 'page' });

if (loading) {
return 'Loading...';
Expand Down
66 changes: 66 additions & 0 deletions docs/documentation/03- Utilities/sanitization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
slug: /utilities/sanitization
sidebar_label: Escaping & Sanitization
---

# Escaping & Sanitization
As you're probably aware, React won't render raw HTML by default. If you want to do so you must use [dangerouslySetInnerHTML](https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html).

This page describes some of the utility functions and components provided by the framework to help with escaping & sanitization when rendering raw markup.

## wpKsesPost

This function sanitizes HTML content with requirements similar to [wp_kses_post](https://developer.wordpress.org/reference/functions/wp_kses_post/). If you are rendering arbitrary HTML markup you should probably run the markup through this function first.

```jsx
import { wpKsesPost } from '@headstartwp/core';

const markup = { __html: wpKsesPost('<p>some raw html</p>') };
return <div dangerouslySetInnerHTML={markup} />;
```

## stripTags

This function simply strips any html tags from a string. This can be useful in contexts where you don't want any HTML to be rendered.

```jsx
import { stripTags } from '@headstartwp/core';

return <h1>{stripTags('this is a title <span>without a span</span>')}</h1>;
```

## BlocksRenderer

When using [BlocksRenderer](/learn/gutenberg/rendering-blocks) your markup already goes through `wpKsesPost` so there's nothing else you need to worry about.

## HtmlDecoder

Sometimes you might just want to decode some HTML entities without actually rendering any HTML tags. For this purpose you can use the `HtmlDecoder` component.

```jsx
import { HtmlDecoder } from '@headstartwp/core/react';

<h1>
<HtmlDecoder html="Hello world! &#8211; foo bar &#8211;"/>
</h1>
```

## SafeHtml

The `SafeHtml` component provides an easy way to safely render HTML markup. It runs the markup through `wpKsesPost` just like `BlocksRenderer`.

```jsx
import { SafeHtml } from '@headstartwp/core/react';

<SafeHtml html="<div><p>hello world</p> div content</div>">
```

## decodeHtmlSpeciaChars

This function will decode a pre-defined set of html special chars.

```js
import { decodeHtmlSpeciaChars } from '@headstartwp/core';

decodeHtmlSpeciaChars('Hello world! &#8211; foo bar &#8211');
```
67 changes: 44 additions & 23 deletions docs/documentation/06-WordPress Integration/previews.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ The preview feature requires the 10up's headless WordPress plugin installed. The

For previews to work, make sure the frontend URL is entered in WP settings as per instructions in [Installing WordPress Plugin](/learn/getting-started/installing-wordpress-plugin).

The logic for generating the JWT token and redirecting to the preview endpoint can be seen [here](https://github.com/10up/headstartwp/blob/develop/wp/tenup-headless-wp/includes/classes/Preview/preview.php).

The logic for generating the JWT token and redirecting to the preview endpoint can be seen [here](https://github.com/10up/headstartwp/blob/develop/wp/headless-wp/includes/classes/Preview/preview.php).
```php
$token = PreviewToken::generate(
[
Expand Down Expand Up @@ -41,8 +40,6 @@ Below is a summary of the preview workflow.
- The token is sent alongside the post_type, post_id and a boolean indicating whether the post being previewed is a revision or not.
- The token is verified against the parameters and the token is used to fetch the post's draft/revision content.



## Usage

The Next.js project **must** expose a `api/preview` endpoint that uses the [previewHandler](/api/modules/headstartwp_next/#previewhandler).
Expand Down Expand Up @@ -86,38 +83,62 @@ export default async function handler(req, res) {

`name` would now be available in the context object of `getServerSideProps` and `getStaticProps` (`ctx.previewData`);

#### `onRedirect`
#### `getRedirectPath`

The `onRedirect` option allows you to customize the redirected URL that should handle the preview request. This can be useful if you have implemented a non-standard URL structure. For instance, if the permalink for your posts are `/%category%/%postname%/` you could create a `src/pages/[category]/[...path.js]` route to handle single post. However once you do that the `previewHandler` doesn't know how to redirect to that URL and as such you will have to provide your own redirect handling.
:::info
This option was added in `@headstartwp/[email protected]`.
:::info

:::caution
When handling redirects yourself, make sure to always append `-preview=true` to the end of the redirected URL.
:::caution
The `getRedirectPath` option allows you to customize the redirected URL that should handle the preview request. This can be useful if you have implemented a non-standard URL structure. For instance, if the permalink for your posts are `/%category%/%postname%/` you could create a `/src/pages/[category]/[...path.js]` route to handle single post. However, once you do that the `previewHandler` doesn't know how to redirect to that URL and as such you will have to provide your own redirect handling.

The framework will also use this value to restrict the preview cookie to the post being previewed to avoid bypassing `getStaticProps` until the cookie expires or the browser is closed. See the [Next.js docs](https://nextjs.org/docs/pages/building-your-application/configuring/preview-mode#specify-the-preview-mode-duration) for more info.

```ts
import { getPostTerms } from '@headstartwp/core';
import { previewHandler } from '@headstartwp/next';

export default async function handler(req, res) {
return previewHandler(req, res, {
// add categorySlug and post slug to preview data
preparePreviewData(req, res, post, previewData) {
const terms = getPostTerms(post);
if (Array.isArray(terms?.category) && terms.category.length > 0) {
const [category] = terms.category;
getRedirectPath(defaultRedirectPath, post) {
const { type, id, slug } = post;

if (type === 'post') {
const terms = getPostTerms(post);

if (Array.isArray(terms?.category) && terms.category.length > 0) {
const [category] = terms.category;

return { ...previewData, categorySlug: category.slug, slug: post.slug };
return `/${categorySlug}/${id}/${slug || id}`;
}
}
return { ...previewData };

return defaultRedirectPath
},
onRedirect(req, res, previewData, defaultRedirect) {
const { postType, id, slug, categorySlug } = previewData;
});
}
```

if (postType === 'post' && typeof categorySlug === 'string') {
return res.redirect(`/${categorySlug}/${id}/${slug || id}-preview=true`);
}
#### `onRedirect`

:::caution
Instead of implementing `onRedirect` we recommend implementing `getRedirectPath` instead as that will only enable the preview cookie for
the post being previewed.
:::caution

return defaultRedirect(req, res, previewData);
The `onRedirect` gives you full access to the `req` and `res` objects. If you do need implement this function we recommend also implementing `getRedirectPath`.

:::caution
When handling redirects yourself, make sure to always append `-preview=true` to the end of the redirected URL.
:::caution

```ts
import { getPostTerms } from '@headstartwp/core';
import { previewHandler } from '@headstartwp/next';

export default async function handler(req, res) {
return previewHandler(req, res, {
onRedirect(req, res, previewData) {
return res.redirect('/custom-path-preview-true');
},
});
}
Expand All @@ -127,7 +148,7 @@ export default async function handler(req, res) {

**After a while, the preview URL stops working**

The JWT token expires after 5 min by default, after this period, open another preview window from WordPress to preview the post.
The JWT token expires after 5 min by default, after this period, open another preview window from WordPress to preview the post. The Next.js preview cookie also last for only 5 minutes.

**I'm unable to preview a custom post type**

Expand Down
6 changes: 3 additions & 3 deletions docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const config = {
sidebarPath: require.resolve('./sidebars.js'),
showLastUpdateTime: true,
showLastUpdateAuthor: true,
editUrl: 'https://github.com/10up/headstartwp/tree/trunk/site',
editUrl: 'https://github.com/10up/headstartwp/tree/trunk/docs',
sidebarCollapsed: false,
},
],
Expand All @@ -75,7 +75,7 @@ const config = {
sidebarPath: require.resolve('./sidebars.js'),
showLastUpdateTime: true,
showLastUpdateAuthor: true,
editUrl: 'https://github.com/10up/headstartwp/tree/trunk/site',
editUrl: 'https://github.com/10up/headstartwp/tree/trunk/docs',
sidebarCollapsed: false,
},
], */
Expand All @@ -87,7 +87,7 @@ const config = {
sidebarPath: require.resolve('./sidebars.js'),
showLastUpdateTime: true,
showLastUpdateAuthor: true,
editUrl: 'https://github.com/10up/headstartwp/tree/trunk/site',
editUrl: 'https://github.com/10up/headstartwp/tree/trunk/docs',
sidebarCollapsed: false,
},
],
Expand Down
Loading

0 comments on commit 7967202

Please sign in to comment.