From 2670864c4f48e6f687ddf6781da0ef3acdcd4b23 Mon Sep 17 00:00:00 2001 From: efuller Date: Fri, 16 Aug 2024 16:09:59 -0400 Subject: [PATCH 01/11] Install SWR --- package-lock.json | 20 +++++++++++++++++++- package.json | 3 ++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0ea43d07..3e2f7f3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,8 @@ "dompurify": "^3.1.6", "prop-types": "^15.8.1", "react": "18.3.1", - "react-dom": "18.3.1" + "react-dom": "18.3.1", + "swr": "^2.2.5" }, "devDependencies": { "@alleyinteractive/build-tool": "^0.1.4", @@ -12158,6 +12159,11 @@ "webpack": ">=4.0.0 <6.0.0" } }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, "node_modules/clipboard": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", @@ -25031,6 +25037,18 @@ "node": ">= 10" } }, + "node_modules/swr": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz", + "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==", + "dependencies": { + "client-only": "^0.0.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", diff --git a/package.json b/package.json index 5f954ee5..35874df3 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,8 @@ "dompurify": "^3.1.6", "prop-types": "^15.8.1", "react": "18.3.1", - "react-dom": "18.3.1" + "react-dom": "18.3.1", + "swr": "^2.2.5" }, "devDependencies": { "@alleyinteractive/build-tool": "^0.1.4", From 623f2099abacf7eac031531414a0b790c97bc3c7 Mon Sep 17 00:00:00 2001 From: efuller Date: Fri, 16 Aug 2024 16:10:30 -0400 Subject: [PATCH 02/11] Initial query block post SWR fetcher function --- services/queryBlockPostFetcher/index.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 services/queryBlockPostFetcher/index.ts diff --git a/services/queryBlockPostFetcher/index.ts b/services/queryBlockPostFetcher/index.ts new file mode 100644 index 00000000..5882bb80 --- /dev/null +++ b/services/queryBlockPostFetcher/index.ts @@ -0,0 +1,20 @@ +import apiFetch from '@wordpress/api-fetch'; + +type FetcherProps = [string | undefined, number]; + +const queryBlockPostFetcher = ([url, currentPostId]: FetcherProps) => apiFetch({ path: url }) + .then((response) => { + let revisedResponse; + // If the response is an array, filter out the current post. + if (Array.isArray(response)) { + revisedResponse = response.filter((item) => item !== currentPostId); + } else if (response.id === currentPostId) { + // Response is an object, if id is the current post, nullify it. + revisedResponse = null; + } else { + revisedResponse = response; + } + return revisedResponse; + }); + +export default queryBlockPostFetcher; From 16a8575c864c308f8bc7237181d4411ea53531b1 Mon Sep 17 00:00:00 2001 From: efuller Date: Fri, 16 Aug 2024 16:11:01 -0400 Subject: [PATCH 03/11] Build posts API path query args --- services/buildPostsApiPath/index.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 services/buildPostsApiPath/index.ts diff --git a/services/buildPostsApiPath/index.ts b/services/buildPostsApiPath/index.ts new file mode 100644 index 00000000..5abcff4f --- /dev/null +++ b/services/buildPostsApiPath/index.ts @@ -0,0 +1,23 @@ +import { addQueryArgs } from '@wordpress/url'; + +interface PathProps { + search: string, + offset: number, + postType: string, + status: 'publish', + perPage: 20, + orderBy: string, + currentPostId: number +} + +export default function buildPostsApiPath(pathProps: PathProps) { + return addQueryArgs('/wp-curate/v1/posts', { + search: pathProps.search, + offset: pathProps.offset, + post_type: pathProps.postType, + status: pathProps.status, + per_page: pathProps.perPage, + orderby: pathProps.orderBy, + current_post_id: pathProps.currentPostId, + }); +} From b49a488ea637e6c2cd5789e7f7cbc1d814659339 Mon Sep 17 00:00:00 2001 From: efuller Date: Fri, 16 Aug 2024 16:23:26 -0400 Subject: [PATCH 04/11] Sure up types and formatting --- services/queryBlockPostFetcher/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/queryBlockPostFetcher/index.ts b/services/queryBlockPostFetcher/index.ts index 5882bb80..edcd9e08 100644 --- a/services/queryBlockPostFetcher/index.ts +++ b/services/queryBlockPostFetcher/index.ts @@ -2,7 +2,11 @@ import apiFetch from '@wordpress/api-fetch'; type FetcherProps = [string | undefined, number]; -const queryBlockPostFetcher = ([url, currentPostId]: FetcherProps) => apiFetch({ path: url }) +type PostResponse = number[] | { id: number }; + +const queryBlockPostFetcher = ( + [url, currentPostId]: FetcherProps, +) => apiFetch({ path: url }) .then((response) => { let revisedResponse; // If the response is an array, filter out the current post. From f9fcd64083ce85ce42a8e81c50db740e7d40ac19 Mon Sep 17 00:00:00 2001 From: efuller Date: Fri, 16 Aug 2024 16:23:54 -0400 Subject: [PATCH 05/11] Initial pass at using SWR for posts API call --- blocks/query/edit.tsx | 81 ++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 51 deletions(-) diff --git a/blocks/query/edit.tsx b/blocks/query/edit.tsx index 977cdd41..54b5f860 100644 --- a/blocks/query/edit.tsx +++ b/blocks/query/edit.tsx @@ -1,4 +1,5 @@ /* eslint-disable camelcase */ +import useSWR from 'swr'; import { PostPicker, TermSelector, Checkboxes } from '@alleyinteractive/block-editor-tools'; import classnames from 'classnames'; import { useDebounce } from '@uidotdev/usehooks'; @@ -21,7 +22,6 @@ import { useState, } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; -import { addQueryArgs } from '@wordpress/url'; import { Template } from '@wordpress/blocks'; import type { @@ -32,11 +32,10 @@ import type { Types, } from './types'; -import { - mainDedupe, -} from '../../services/deduplicate'; - +import { mainDedupe } from '../../services/deduplicate'; +import buildPostsApiPath from '../../services/buildPostsApiPath'; import buildTermQueryArgs from '../../services/buildTermQueryArgs'; +import queryBlockPostFetcher from '../../services/queryBlockPostFetcher'; import './index.scss'; @@ -134,9 +133,25 @@ export default function Edit({ ); const manualPostIds = manualPosts.map((post) => (post ?? null)).join(','); - const currentPostId = useSelect((select: any) => select('core/editor').getCurrentPostId(), []); + const currentPostId = Number(useSelect((select: any) => select('core/editor').getCurrentPostId(), [])); const postTypeString = postTypes.join(','); + // Construct the API path using your query args + const path = Object.keys(availableTaxonomies).length > 0 + ? `${buildPostsApiPath({ + search: debouncedSearchTerm, + offset, + postType: postTypeString, + status: 'publish', + perPage: 20, + orderBy: orderby, + currentPostId, + })}&${termQueryArgs}` + : undefined; + + // Use SWR to fetch data + const { data, error } = useSWR([path, currentPostId], queryBlockPostFetcher); + // Fetch available taxonomies. useEffect(() => { const fetchTaxonomies = async () => { @@ -158,57 +173,19 @@ export default function Edit({ }, []); // Fetch "backfill" posts when categories, tags, or search term change. + // Handle the fetched data useEffect(() => { - if (Object.keys(availableTaxonomies).length <= 0) { - return; + if (data && !error) { + setAttributes({ backfillPosts: data }); } - const fetchPosts = async () => { - let path = addQueryArgs( - '/wp-curate/v1/posts', - { - search: debouncedSearchTerm, - offset, - post_type: postTypeString, - status: 'publish', - per_page: 20, - orderby, - current_post_id: Number.isInteger(currentPostId) ? currentPostId : 0, - }, - ); - path += `&${termQueryArgs}`; - - apiFetch({ path }).then((response:any) => { - let revisedResponse; - // If the response is an array, filter out the current post. - if (Array.isArray(response)) { - revisedResponse = response.filter((item) => item !== currentPostId); - } else if (response.id === currentPostId) { - // Response is an object, if id is the current post, nullify it. - revisedResponse = null; - } else { - revisedResponse = response; - } - if (revisedResponse !== null) { - setAttributes({ backfillPosts: revisedResponse as Array }); - } - }); - }; - fetchPosts(); - }, [ - availableTaxonomies, - currentPostId, - debouncedSearchTerm, - offset, - orderby, - postTypeString, - setAttributes, - termQueryArgs, - ]); + }, [data, error, setAttributes]); // Update the query when the backfillPosts change. // The query is passed via context to the core/post-template block. useEffect(() => { - mainDedupe(); + if (data && !error) { + mainDedupe(); + } }, [ manualPostIds, backfillPosts, @@ -218,6 +195,8 @@ export default function Edit({ isPostDeduplicating, deduplication, uniquePinnedPosts, + data, + error, ]); const setManualPost = (id: number, index: number) => { From 2f18495af64ee757cc245333436325074a18c5b4 Mon Sep 17 00:00:00 2001 From: efuller Date: Mon, 19 Aug 2024 11:28:23 -0400 Subject: [PATCH 06/11] Swap out useSWR hook with useSWRImmutable This essentially turns of default automatic revalidations --- blocks/query/edit.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/blocks/query/edit.tsx b/blocks/query/edit.tsx index 54b5f860..c2f49fa3 100644 --- a/blocks/query/edit.tsx +++ b/blocks/query/edit.tsx @@ -1,5 +1,5 @@ /* eslint-disable camelcase */ -import useSWR from 'swr'; +import useSWRImmutable from 'swr/immutable'; import { PostPicker, TermSelector, Checkboxes } from '@alleyinteractive/block-editor-tools'; import classnames from 'classnames'; import { useDebounce } from '@uidotdev/usehooks'; @@ -150,7 +150,10 @@ export default function Edit({ : undefined; // Use SWR to fetch data - const { data, error } = useSWR([path, currentPostId], queryBlockPostFetcher); + const { data, error } = useSWRImmutable( + [path, currentPostId], + queryBlockPostFetcher, + ); // Fetch available taxonomies. useEffect(() => { From a1657976fff5b928840069afc1d58137bd63a555 Mon Sep 17 00:00:00 2001 From: efuller Date: Mon, 19 Aug 2024 11:42:26 -0400 Subject: [PATCH 07/11] Cleanup comments --- blocks/query/edit.tsx | 4 ++-- services/buildPostsApiPath/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/blocks/query/edit.tsx b/blocks/query/edit.tsx index c2f49fa3..aa384aa4 100644 --- a/blocks/query/edit.tsx +++ b/blocks/query/edit.tsx @@ -136,7 +136,7 @@ export default function Edit({ const currentPostId = Number(useSelect((select: any) => select('core/editor').getCurrentPostId(), [])); const postTypeString = postTypes.join(','); - // Construct the API path using your query args + // Construct the API path using query args. const path = Object.keys(availableTaxonomies).length > 0 ? `${buildPostsApiPath({ search: debouncedSearchTerm, @@ -149,7 +149,7 @@ export default function Edit({ })}&${termQueryArgs}` : undefined; - // Use SWR to fetch data + // Use SWR to fetch data. const { data, error } = useSWRImmutable( [path, currentPostId], queryBlockPostFetcher, diff --git a/services/buildPostsApiPath/index.ts b/services/buildPostsApiPath/index.ts index 5abcff4f..56d70ad7 100644 --- a/services/buildPostsApiPath/index.ts +++ b/services/buildPostsApiPath/index.ts @@ -1,6 +1,6 @@ import { addQueryArgs } from '@wordpress/url'; -interface PathProps { +interface PostsApiPathProps { search: string, offset: number, postType: string, @@ -10,7 +10,7 @@ interface PathProps { currentPostId: number } -export default function buildPostsApiPath(pathProps: PathProps) { +export default function buildPostsApiPath(pathProps: PostsApiPathProps) { return addQueryArgs('/wp-curate/v1/posts', { search: pathProps.search, offset: pathProps.offset, From de0f467bbb54f00c7a8f9fddbe5f6544ebdc6526 Mon Sep 17 00:00:00 2001 From: efuller Date: Mon, 19 Aug 2024 15:38:13 -0400 Subject: [PATCH 08/11] Update comments --- blocks/query/edit.tsx | 3 +-- services/queryBlockPostFetcher/index.ts | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/blocks/query/edit.tsx b/blocks/query/edit.tsx index aa384aa4..4c20e302 100644 --- a/blocks/query/edit.tsx +++ b/blocks/query/edit.tsx @@ -175,8 +175,7 @@ export default function Edit({ fetchTypes(); }, []); - // Fetch "backfill" posts when categories, tags, or search term change. - // Handle the fetched data + // Handle the fetched data. useEffect(() => { if (data && !error) { setAttributes({ backfillPosts: data }); diff --git a/services/queryBlockPostFetcher/index.ts b/services/queryBlockPostFetcher/index.ts index edcd9e08..509edbb3 100644 --- a/services/queryBlockPostFetcher/index.ts +++ b/services/queryBlockPostFetcher/index.ts @@ -1,9 +1,13 @@ import apiFetch from '@wordpress/api-fetch'; type FetcherProps = [string | undefined, number]; - type PostResponse = number[] | { id: number }; +/** + * Fetches the post data from the API. + * @param url The API url. + * @param currentPostId The current post ID. + */ const queryBlockPostFetcher = ( [url, currentPostId]: FetcherProps, ) => apiFetch({ path: url }) From 0553a9cee3ddc93128e32d08bd1784e277e8b7f4 Mon Sep 17 00:00:00 2001 From: efuller Date: Mon, 19 Aug 2024 16:00:37 -0400 Subject: [PATCH 09/11] Bump phpstan to 1024M --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d7d57e55..eaedb351 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,7 @@ "phpcbf": "phpcbf .", "phpcs": "phpcs .", "phpunit": "phpunit", - "phpstan": "phpstan --memory-limit=512M", + "phpstan": "phpstan --memory-limit=1024M", "test": [ "@phpcs", "@phpstan", From c314ce08c3b13b80d5511854f60dbc6e80244857 Mon Sep 17 00:00:00 2001 From: efuller Date: Wed, 21 Aug 2024 11:43:01 -0400 Subject: [PATCH 10/11] Install collision as a dev dep --- composer.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 1f388350..1ddd1f04 100644 --- a/composer.json +++ b/composer.json @@ -24,13 +24,12 @@ "php": "^8.1", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "alleyinteractive/traverse-reshape": "^2.0", - "alleyinteractive/wp-type-extensions": "^2.0", - "nunomaduro/collision": "^7.10" + "alleyinteractive/wp-type-extensions": "^2.0" }, "require-dev": { "alleyinteractive/alley-coding-standards": "^2.0", "mantle-framework/testkit": "^1.1", - "nunomaduro/collision": "^6.0", + "nunomaduro/collision": "^7.10", "szepeviktor/phpstan-wordpress": "^1.1" }, "config": { From 32e1e4c3a35ae3c76b1a9290acd11f14f0e218d7 Mon Sep 17 00:00:00 2001 From: efuller Date: Wed, 21 Aug 2024 11:56:40 -0400 Subject: [PATCH 11/11] Bump version. --- CHANGELOG.md | 4 ++++ wp-curate.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b582c51c..fe96b12b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `WP Curate` will be documented in this file. +## 2.2.2 - 2024-08-21 + +- Enhancement: Introduce `SWR` for caching API requests in the Query block. + ## 2.2.1 - 2024-08-15 - Bug Fix: Handle cases where a pinned post has been deleted or unpublished. diff --git a/wp-curate.php b/wp-curate.php index 57b32414..3afc4502 100644 --- a/wp-curate.php +++ b/wp-curate.php @@ -3,7 +3,7 @@ * Plugin Name: WP Curate * Plugin URI: https://github.com/alleyinteractive/wp-curate * Description: Plugin to curate homepages and other landing pages - * Version: 2.2.1 + * Version: 2.2.2 * Author: Alley Interactive * Author URI: https://github.com/alleyinteractive/wp-curate * Requires at least: 6.4