From 5c737630336048f103168fd787320f4d163aa639 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Fri, 1 Mar 2024 14:39:24 -0600 Subject: [PATCH 01/21] WIP: issue-142 From a461992ba77ce9bf02488acfafbaa52040160ff4 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Fri, 1 Mar 2024 14:41:32 -0600 Subject: [PATCH 02/21] setting up editor controls --- blocks/query/block.json | 4 ++++ blocks/query/edit.tsx | 14 ++++++++++++++ blocks/query/index.php | 1 + blocks/query/types.ts | 1 + package-lock.json | 8 ++++---- package.json | 2 +- src/main.php | 1 + 7 files changed, 26 insertions(+), 5 deletions(-) diff --git a/blocks/query/block.json b/blocks/query/block.json index 5a0f498b..b00b2d93 100644 --- a/blocks/query/block.json +++ b/blocks/query/block.json @@ -94,6 +94,10 @@ "OR" ], "type": "string" + }, + "trending": { + "default": false, + "type": "boolean" } } } diff --git a/blocks/query/edit.tsx b/blocks/query/edit.tsx index 31a5bc4e..80e1cb1e 100644 --- a/blocks/query/edit.tsx +++ b/blocks/query/edit.tsx @@ -11,6 +11,7 @@ import { RangeControl, SelectControl, TextControl, + ToggleControl, } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; import { @@ -44,6 +45,7 @@ interface Window { wpCurateQueryBlock: { allowedPostTypes: Array; allowedTaxonomies: Array; + useParsely: string, }; } @@ -69,6 +71,7 @@ export default function Edit({ terms = {}, termRelations = {}, taxRelation = 'AND', + trending = false, }, setAttributes, }: EditProps) { @@ -76,6 +79,7 @@ export default function Edit({ wpCurateQueryBlock: { allowedPostTypes = [], allowedTaxonomies = [], + useParsely = 'false', } = {}, } = (window as any as Window); @@ -161,6 +165,7 @@ export default function Edit({ type: postTypeString, status: 'publish', per_page: 20, + trending, }, ); path += `&${termQueryArgs}`; @@ -181,6 +186,7 @@ export default function Edit({ offset, postTypeString, availableTaxonomies, + trending, setAttributes, ]); @@ -384,6 +390,14 @@ export default function Edit({ onChange={(next) => setAttributes({ searchTerm: next })} value={searchTerm} /> + { useParsely === 'true' ? ( + setAttributes({ trending: next })} + /> + ) : null } diff --git a/blocks/query/index.php b/blocks/query/index.php index 4eac746a..07a5d4e4 100644 --- a/blocks/query/index.php +++ b/blocks/query/index.php @@ -45,6 +45,7 @@ function wp_curate_query_block_init(): void { [ 'allowedPostTypes' => $allowed_post_types, 'allowedTaxonomies' => $allowed_taxonomies, + 'useParsely' => apply_filters( 'wp_curate_use_parsely', false ) ? 'true' : 'false', ] ); } diff --git a/blocks/query/types.ts b/blocks/query/types.ts index d1d1a49c..f1b59503 100644 --- a/blocks/query/types.ts +++ b/blocks/query/types.ts @@ -19,6 +19,7 @@ interface EditProps { [key: string]: string; }; taxRelation?: string; + trending?: boolean; }; setAttributes: (attributes: any) => void; } diff --git a/package-lock.json b/package-lock.json index 58402c61..05d3c718 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { - "@alleyinteractive/block-editor-tools": "^0.6.3", + "@alleyinteractive/block-editor-tools": "^0.6.4", "@types/jest": "^29.5.12", "@types/wordpress__block-editor": "^11.5.0", "@uidotdev/usehooks": "^2.4.1", @@ -61,9 +61,9 @@ } }, "node_modules/@alleyinteractive/block-editor-tools": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@alleyinteractive/block-editor-tools/-/block-editor-tools-0.6.3.tgz", - "integrity": "sha512-N6TWQEk4M08U1RLQUlyvCnTXZfvKMMlWWXtOLdw/W2PNSQYtJqimYE1V2uJaLo7klxt3HDiif9gB49/0AjQROw==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@alleyinteractive/block-editor-tools/-/block-editor-tools-0.6.4.tgz", + "integrity": "sha512-R+Sw5sDPHUQLPAmI4x+hFoX0H3p3wLueRy+gVnmd1Rq1PsL2o45Hv1tdQcmsuvnXA5gBey/6Hatm0FIHVi3nzA==", "engines": { "node": ">=16.0.0 <21.0.0", "npm": ">=8.0.0" diff --git a/package.json b/package.json index 1b539864..dac217a7 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "test": "jest --passWithNoTests" }, "dependencies": { - "@alleyinteractive/block-editor-tools": "^0.6.3", + "@alleyinteractive/block-editor-tools": "^0.6.4", "@types/jest": "^29.5.12", "@types/wordpress__block-editor": "^11.5.0", "@uidotdev/usehooks": "^2.4.1", diff --git a/src/main.php b/src/main.php index cc0a45fa..0459def0 100644 --- a/src/main.php +++ b/src/main.php @@ -38,6 +38,7 @@ function main(): void { stop_queries_var: $stop_queries_var, block_type_registry: WP_Block_Type_Registry::get_instance(), ); + $features[] = new Features\Parsely_Support(); $features[] = new Features\Rest_Api(); From d537250a2fae492b7a9425a8bb1e3e7867e8fd68 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Fri, 1 Mar 2024 14:57:36 -0600 Subject: [PATCH 03/21] adding endpoint --- blocks/query/edit.tsx | 2 +- src/features/class-parsely-support.php | 30 ++++++++++++ src/features/class-rest-api.php | 64 ++++++++++++++++++++------ 3 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 src/features/class-parsely-support.php diff --git a/blocks/query/edit.tsx b/blocks/query/edit.tsx index 80e1cb1e..ee680e7c 100644 --- a/blocks/query/edit.tsx +++ b/blocks/query/edit.tsx @@ -158,7 +158,7 @@ export default function Edit({ } const fetchPosts = async () => { let path = addQueryArgs( - '/wp/v2/posts', + '/wp-curate/v1/posts', { search: debouncedSearchTerm, offset, diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php new file mode 100644 index 00000000..680ec36b --- /dev/null +++ b/src/features/class-parsely-support.php @@ -0,0 +1,30 @@ +|string> $query_args The existing query args. - * @param WP_REST_Request $request The REST request. - * @return array|string> + * @return void */ - // @phpstan-ignore-next-line - public function add_type_param( $query_args, $request ): array { // phpcs:ignore Squiz.Commenting.FunctionComment.WrongStyle - $type = $request->get_param( 'type' ); - - if ( ! empty( $type ) && is_string( $type ) ) { - $types = explode( ',', $type ); - $types = array_filter( $types, 'post_type_exists' ); - $query_args['post_type'] = $types; + public function register_endpoints(): void { + register_rest_route( + 'wp-curate/v1', + '/posts/', + [ + 'methods' => 'GET', + 'callback' => [ $this, 'get_posts' ], + 'permission_callback' => function () { + return true; + return current_user_can( 'edit_posts' ); + }, + ] + ); + } + + /** + * Gets the posts. + * + * @param WP_REST_Request $request The request object. + * @return array + */ + public function get_posts( WP_REST_Request $request ): array { + $search_term = $request->get_param( 'search' ) ?? ''; + $offset = $request->get_param( 'offset' ) ?? 0; + $postTypeString = $request->get_param( 'post_type' ) ?? 'post'; + $per_page = $request->get_param( 'per_page' ) ?? 20; + $trending = $request->get_param( 'trending' ) ?? false; + + $post_types = explode( ',', $postTypeString ); + $allowed_post_types = apply_filters( 'wp_curate_allowed_post_types', [ 'post' ] ); + + $post_types = array_filter( $post_types, function ( $post_type ) use ( $allowed_post_types ) { + return in_array( $post_type, $allowed_post_types, true ); + } ); + + $args = [ + 'post_type' => $post_types, + 'posts_per_page' => $per_page, + 'offset' => $offset, + ]; + if ( ! empty( $search_term ) ) { + $args['s'] = $search_term; } - return $query_args; + $query = new \WP_Query( $args ); + + $posts = []; + + return $query->posts; } } From 6def2e99fac0e3d99c587cf83fc9061b66d73e94 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Fri, 1 Mar 2024 15:52:58 -0600 Subject: [PATCH 04/21] new endpoint working --- blocks/query/edit.tsx | 5 +---- src/features/class-rest-api.php | 40 +++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/blocks/query/edit.tsx b/blocks/query/edit.tsx index ee680e7c..96eff1ac 100644 --- a/blocks/query/edit.tsx +++ b/blocks/query/edit.tsx @@ -173,10 +173,7 @@ export default function Edit({ apiFetch({ path, }).then((response) => { - const postIds: number[] = (response as WP_REST_API_Posts).map( - (post: WP_REST_API_Post) => post.id, - ); - setAttributes({ backfillPosts: postIds }); + setAttributes({ backfillPosts: response as Array }); }); }; fetchPosts(); diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index 3a6a8402..0242fe16 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -58,6 +58,31 @@ public function get_posts( WP_REST_Request $request ): array { $postTypeString = $request->get_param( 'post_type' ) ?? 'post'; $per_page = $request->get_param( 'per_page' ) ?? 20; $trending = $request->get_param( 'trending' ) ?? false; + $tax_relation = $request->get_param( 'tax_relation' ) ?? 'OR'; + + $allowed_taxonomies = apply_filters( 'wp_curate_allowed_taxonomies', [ 'category', 'post_tag' ] ); + $taxonomies = array_map( 'get_taxonomy', $allowed_taxonomies ); + $tax_query = []; + foreach ( $taxonomies as $taxonomy ) { + $tax_param = $request->get_param( $taxonomy->rest_base ); + $terms = $tax_param['terms'] ?? []; + $operator = $tax_param['operator'] ?? 'OR'; + if ( empty( $terms ) ) { + continue; + } + $terms = explode( ',', $terms ); + $terms = array_map( 'intval', $terms ); + $terms = array_filter( $terms, 'term_exists' ); + $tax_query[] = [ + 'taxonomy' => $taxonomy->name, + 'field' => 'term_id', + 'terms' => $terms, + 'operator' => 'AND' === $operator ? 'AND' : 'IN', + ]; + } + if ( ! empty( $tax_query ) && 1 < count( $tax_query ) ) { + $tax_query['relation'] = $tax_relation; + } $post_types = explode( ',', $postTypeString ); $allowed_post_types = apply_filters( 'wp_curate_allowed_post_types', [ 'post' ] ); @@ -67,18 +92,19 @@ public function get_posts( WP_REST_Request $request ): array { } ); $args = [ - 'post_type' => $post_types, - 'posts_per_page' => $per_page, - 'offset' => $offset, + 'post_type' => $post_types, + 'posts_per_page' => $per_page, + 'offset' => $offset, + 'ignore_sticky_posts' => true, ]; if ( ! empty( $search_term ) ) { $args['s'] = $search_term; } + if ( ! empty( $tax_query ) ) { + $args['tax_query'] = $tax_query; + } $query = new \WP_Query( $args ); - - $posts = []; - - return $query->posts; + return wp_list_pluck( $query->posts, 'ID' ); } } From 880dca9190592760eab6dd7dc399aff2698988ec Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Fri, 1 Mar 2024 17:33:01 -0600 Subject: [PATCH 05/21] phpcs --- src/features/class-parsely-support.php | 65 ++++++++++++++++++++++++-- src/features/class-rest-api.php | 50 +++++++++++--------- 2 files changed, 89 insertions(+), 26 deletions(-) diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index 680ec36b..675091b6 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -13,18 +13,73 @@ * Add support for Parsely, if the plugin in installed. */ final class Parsely_Support implements Feature { + /** + * Store the parsely object. + * + * @var \Parsely\Parsely + */ + private $parsely; + /** * Set up. */ public function __construct() {} - /** + /** * Boot the feature. */ public function boot(): void { - if ( ! class_exists( 'Parsely\Parsely' ) ) { - return; - } - add_filter( 'wp_curate_use_parsely', '__return_true' ); + if ( ! class_exists( 'Parsely\Parsely' ) ) { + return; + } + $this->parsely = new \Parsely\Parsely(); + if ( ! $this->parsely->api_secret_is_set() ) { + return; + } + add_filter( 'wp_curate_use_parsely', '__return_true' ); + add_filter( 'wp_curate_trending_posts_query', [ $this, 'add_parsely_trending_posts_query' ], 10, 2 ); + } + + /** + * Gets the trending posts from Parsely. + * + * @param array $posts The posts, which should be an empty array. + * @param array $args The WP_Query args. + * @return array Array of post IDs. + */ + public function add_parsely_trending_posts_query( $posts, $args ) { + // TODO: Add failover if we're not on production. + $api = new \Parsely\RemoteAPI\Analytics_Posts_API( $this->parsely ); + $parsely_args = [ + 'limit' => $args['posts_per_page'], + 'sort' => 'views', + 'period_start' => '1d', + 'period_end' => 'now', + ]; + $cache_key = 'parsely_trending_posts_' . md5( wp_json_encode( $parsely_args ) ); + $ids = wp_cache_get( $cache_key ); + if ( false === $ids ) { + $posts = $api->get_posts_analytics( $parsely_args ); + $ids = array_map( + function ( $post ) { + // Check if the metadata contains post_id, if not, use the URL to get the post ID. + $metadata = json_decode( $post['metadata'] ?? '', true ); + if ( ! empty( $post['metadata'] ) && isset( $metadata['post_id'] ) ) { + $post_id = intval( $metadata['post_id'] ); + } else { + if ( function_exists( 'wpcom_vip_url_to_postid' ) ) { + $post_id = wpcom_vip_url_to_postid( $post['url'] ); + } else { + $post_id = url_to_postid( $post['url'] ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.url_to_postid_url_to_postid + } + } + return $post_id; + }, + $posts + ); + wp_cache_set( $cache_key, $ids, '', 10 * MINUTE_IN_SECONDS ); + } + + return( $ids ); } } diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index 0242fe16..50177168 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -39,7 +39,6 @@ public function register_endpoints(): void { 'methods' => 'GET', 'callback' => [ $this, 'get_posts' ], 'permission_callback' => function () { - return true; return current_user_can( 'edit_posts' ); }, ] @@ -53,26 +52,26 @@ public function register_endpoints(): void { * @return array */ public function get_posts( WP_REST_Request $request ): array { - $search_term = $request->get_param( 'search' ) ?? ''; - $offset = $request->get_param( 'offset' ) ?? 0; - $postTypeString = $request->get_param( 'post_type' ) ?? 'post'; - $per_page = $request->get_param( 'per_page' ) ?? 20; - $trending = $request->get_param( 'trending' ) ?? false; - $tax_relation = $request->get_param( 'tax_relation' ) ?? 'OR'; + $search_term = $request->get_param( 'search' ) ?? ''; + $offset = $request->get_param( 'offset' ) ?? 0; + $post_type_string = $request->get_param( 'post_type' ) ?? 'post'; + $per_page = $request->get_param( 'per_page' ) ?? 20; + $trending = 'true' === $request->get_param( 'trending' ) ? true : false; + $tax_relation = $request->get_param( 'tax_relation' ) ?? 'OR'; $allowed_taxonomies = apply_filters( 'wp_curate_allowed_taxonomies', [ 'category', 'post_tag' ] ); - $taxonomies = array_map( 'get_taxonomy', $allowed_taxonomies ); - $tax_query = []; + $taxonomies = array_map( 'get_taxonomy', $allowed_taxonomies ); + $tax_query = []; foreach ( $taxonomies as $taxonomy ) { $tax_param = $request->get_param( $taxonomy->rest_base ); - $terms = $tax_param['terms'] ?? []; - $operator = $tax_param['operator'] ?? 'OR'; + $terms = $tax_param['terms'] ?? []; + $operator = $tax_param['operator'] ?? 'OR'; if ( empty( $terms ) ) { continue; } - $terms = explode( ',', $terms ); - $terms = array_map( 'intval', $terms ); - $terms = array_filter( $terms, 'term_exists' ); + $terms = explode( ',', $terms ); + $terms = array_map( 'intval', $terms ); + $terms = array_filter( $terms, 'term_exists' ); $tax_query[] = [ 'taxonomy' => $taxonomy->name, 'field' => 'term_id', @@ -84,12 +83,15 @@ public function get_posts( WP_REST_Request $request ): array { $tax_query['relation'] = $tax_relation; } - $post_types = explode( ',', $postTypeString ); + $post_types = explode( ',', $post_type_string ); $allowed_post_types = apply_filters( 'wp_curate_allowed_post_types', [ 'post' ] ); - $post_types = array_filter( $post_types, function ( $post_type ) use ( $allowed_post_types ) { - return in_array( $post_type, $allowed_post_types, true ); - } ); + $post_types = array_filter( + $post_types, + function ( $post_type ) use ( $allowed_post_types ) { + return in_array( $post_type, $allowed_post_types, true ); + } + ); $args = [ 'post_type' => $post_types, @@ -101,10 +103,16 @@ public function get_posts( WP_REST_Request $request ): array { $args['s'] = $search_term; } if ( ! empty( $tax_query ) ) { - $args['tax_query'] = $tax_query; + $args['tax_query'] = $tax_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query } - $query = new \WP_Query( $args ); - return wp_list_pluck( $query->posts, 'ID' ); + if ( $trending ) { + $posts = apply_filters( 'wp_curate_trending_posts_query', [], $args ); + } + if ( empty( $posts ) ) { + $query = new \WP_Query( $args ); + $posts = wp_list_pluck( $query->posts, 'ID' ); + } + return $posts; } } From ddb7cfbc4a5c41a44a04c3723d81a38b0f6f402b Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Mon, 4 Mar 2024 19:53:03 -0600 Subject: [PATCH 06/21] adding trending-post-queries --- src/class-trending-post-queries.php | 52 ++++++++++++++++++++++ src/features/class-parsely-support.php | 18 ++++---- src/features/class-query-block-context.php | 41 +++++++++-------- src/features/class-rest-api.php | 4 +- 4 files changed, 85 insertions(+), 30 deletions(-) create mode 100644 src/class-trending-post-queries.php diff --git a/src/class-trending-post-queries.php b/src/class-trending-post-queries.php new file mode 100644 index 00000000..64e0f266 --- /dev/null +++ b/src/class-trending-post-queries.php @@ -0,0 +1,52 @@ + $args The arguments to be used in the query. + * @return Post_Query + */ + public function query( array $args ): Post_Query { + $parsely = new Parsely_Support(); + $trending = $parsely->get_trending_posts( $args ); + if ( ! empty( $trending ) ) { + return new WP_Query_Envelope( + new \WP_Query( + [ + 'post__in' => $trending, + 'post_type' => 'any', + 'ignore_sticky_posts' => true, + 'orderby' => 'post__in', + ] + ) + ); + } + + return $this->origin->query( $args ); + } +} diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index 675091b6..dad4aa74 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -13,13 +13,6 @@ * Add support for Parsely, if the plugin in installed. */ final class Parsely_Support implements Feature { - /** - * Store the parsely object. - * - * @var \Parsely\Parsely - */ - private $parsely; - /** * Set up. */ @@ -32,8 +25,8 @@ public function boot(): void { if ( ! class_exists( 'Parsely\Parsely' ) ) { return; } - $this->parsely = new \Parsely\Parsely(); - if ( ! $this->parsely->api_secret_is_set() ) { + $parsely = new \Parsely\Parsely(); + if ( ! $parsely->api_secret_is_set() ) { return; } add_filter( 'wp_curate_use_parsely', '__return_true' ); @@ -48,8 +41,12 @@ public function boot(): void { * @return array Array of post IDs. */ public function add_parsely_trending_posts_query( $posts, $args ) { + $trending_posts = $this->get_trending_posts( $args ); + return $trending_posts; + } + + public function get_trending_posts( $args ) { // TODO: Add failover if we're not on production. - $api = new \Parsely\RemoteAPI\Analytics_Posts_API( $this->parsely ); $parsely_args = [ 'limit' => $args['posts_per_page'], 'sort' => 'views', @@ -59,6 +56,7 @@ public function add_parsely_trending_posts_query( $posts, $args ) { $cache_key = 'parsely_trending_posts_' . md5( wp_json_encode( $parsely_args ) ); $ids = wp_cache_get( $cache_key ); if ( false === $ids ) { + $api = new \Parsely\RemoteAPI\Analytics_Posts_API( $GLOBALS['parsely'] ); $posts = $api->get_posts_analytics( $parsely_args ); $ids = array_map( function ( $post ) { diff --git a/src/features/class-query-block-context.php b/src/features/class-query-block-context.php index 37873be8..c1d56186 100644 --- a/src/features/class-query-block-context.php +++ b/src/features/class-query-block-context.php @@ -11,6 +11,7 @@ use Alley\WP\Blocks\Parsed_Block; use Alley\WP\Post_IDs\Used_Post_IDs; use Alley\WP\Post_Queries\Exclude_Queries; +use Alley\WP\WP_Curate\Trending_Post_Queries; use Alley\WP\Post_Queries\Variable_Post_Queries; use Alley\WP\Types\Feature; use Alley\WP\Types\Post_Queries; @@ -73,31 +74,33 @@ public function filter_query_context( $context, $parsed_block, $parent_block ): origin: new Must_Include_Curated_Posts( qv: $this->stop_queries_var, origin: new Plugin_Curated_Posts( - queries: new Variable_Post_Queries( - input: function () use ( $parsed_block ) { - $main_query = $this->main_query->query_object(); + queries: new Trending_Post_Queries( + origin: new Variable_Post_Queries( + input: function () use ( $parsed_block ) { + $main_query = $this->main_query->query_object(); - if ( isset( $parsed_block['attrs']['deduplication'] ) && 'never' === $parsed_block['attrs']['deduplication'] ) { - return false; - } + if ( isset( $parsed_block['attrs']['deduplication'] ) && 'never' === $parsed_block['attrs']['deduplication'] ) { + return false; + } - if ( true === $main_query->is_singular() || true === $main_query->is_posts_page ) { - $post_level_deduplication = get_post_meta( $main_query->get_queried_object_id(), 'wp_curate_deduplication', true ); + if ( true === $main_query->is_singular() || true === $main_query->is_posts_page ) { + $post_level_deduplication = get_post_meta( $main_query->get_queried_object_id(), 'wp_curate_deduplication', true ); - if ( true === (bool) $post_level_deduplication ) { - return true; + if ( true === (bool) $post_level_deduplication ) { + return true; + } } - } - return false; - }, - test: new Comparison( [ 'compared' => true ] ), - is_true: new Exclude_Queries( - $this->history, - $this->default_per_page, - $this->post_queries, + return false; + }, + test: new Comparison( [ 'compared' => true ] ), + is_true: new Exclude_Queries( + $this->history, + $this->default_per_page, + $this->post_queries, + ), + is_false: $this->post_queries, ), - is_false: $this->post_queries, ), ), ), diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index 50177168..76a0d30f 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -39,6 +39,7 @@ public function register_endpoints(): void { 'methods' => 'GET', 'callback' => [ $this, 'get_posts' ], 'permission_callback' => function () { + return true; return current_user_can( 'edit_posts' ); }, ] @@ -98,6 +99,7 @@ function ( $post_type ) use ( $allowed_post_types ) { 'posts_per_page' => $per_page, 'offset' => $offset, 'ignore_sticky_posts' => true, + 'fields' => 'ids', ]; if ( ! empty( $search_term ) ) { $args['s'] = $search_term; @@ -111,7 +113,7 @@ function ( $post_type ) use ( $allowed_post_types ) { } if ( empty( $posts ) ) { $query = new \WP_Query( $args ); - $posts = wp_list_pluck( $query->posts, 'ID' ); + $posts = $query->posts; } return $posts; } From 497e156c2558c33b2bfd25b594e1f9ad19f60185 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Mon, 4 Mar 2024 19:56:49 -0600 Subject: [PATCH 07/21] add some notes --- src/class-trending-post-queries.php | 2 ++ src/features/class-rest-api.php | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class-trending-post-queries.php b/src/class-trending-post-queries.php index 64e0f266..03102c32 100644 --- a/src/class-trending-post-queries.php +++ b/src/class-trending-post-queries.php @@ -32,6 +32,8 @@ public function __construct( * @return Post_Query */ public function query( array $args ): Post_Query { + // TODO: Check args or something to see if we should pull trending posts. + // If not, return the original query. $parsely = new Parsely_Support(); $trending = $parsely->get_trending_posts( $args ); if ( ! empty( $trending ) ) { diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index 76a0d30f..7e861373 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -39,7 +39,6 @@ public function register_endpoints(): void { 'methods' => 'GET', 'callback' => [ $this, 'get_posts' ], 'permission_callback' => function () { - return true; return current_user_can( 'edit_posts' ); }, ] From 7f80641953245ec80e5f72a6e3a889931c777131 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Tue, 5 Mar 2024 09:26:58 -0600 Subject: [PATCH 08/21] add trending to args. add term support --- src/class-plugin-curated-posts.php | 2 +- src/class-trending-post-queries.php | 32 +++++++++---------- src/features/class-parsely-support.php | 43 ++++++++++++++++++++++++-- src/features/class-rest-api.php | 2 +- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/class-plugin-curated-posts.php b/src/class-plugin-curated-posts.php index d08839c1..4f3f0f44 100644 --- a/src/class-plugin-curated-posts.php +++ b/src/class-plugin-curated-posts.php @@ -43,7 +43,7 @@ public function with_query_context( array $context, array $attributes, WP_Block_ 'no_found_rows' => true, 'offset' => $attributes['offset'] ?? $block_type->attributes['offset']['default'], 'order' => 'DESC', - 'orderby' => 'date', + 'orderby' => $attributes['trending'] ? 'trending' : 'date', 'posts_per_page' => $attributes['numberOfPosts'] ?? $block_type->attributes['numberOfPosts']['default'], 'post_status' => 'publish', 'post_type' => $attributes['postTypes'] ?? $block_type->attributes['postTypes']['default'], diff --git a/src/class-trending-post-queries.php b/src/class-trending-post-queries.php index 03102c32..7174d2cd 100644 --- a/src/class-trending-post-queries.php +++ b/src/class-trending-post-queries.php @@ -5,7 +5,7 @@ * @package wp-type-extensions */ - namespace Alley\WP\WP_Curate; +namespace Alley\WP\WP_Curate; use Alley\WP\Types\Post_Queries; use Alley\WP\Types\Post_Query; @@ -32,21 +32,21 @@ public function __construct( * @return Post_Query */ public function query( array $args ): Post_Query { - // TODO: Check args or something to see if we should pull trending posts. - // If not, return the original query. - $parsely = new Parsely_Support(); - $trending = $parsely->get_trending_posts( $args ); - if ( ! empty( $trending ) ) { - return new WP_Query_Envelope( - new \WP_Query( - [ - 'post__in' => $trending, - 'post_type' => 'any', - 'ignore_sticky_posts' => true, - 'orderby' => 'post__in', - ] - ) - ); + if ( 'trending' === $args['orderby'] ) { + $parsely = new Parsely_Support(); + $trending = $parsely->get_trending_posts( $args ); + if ( ! empty( $trending ) ) { + return new WP_Query_Envelope( + new \WP_Query( + [ + 'post__in' => $trending, + 'post_type' => 'any', + 'ignore_sticky_posts' => true, + 'orderby' => 'post__in', + ] + ) + ); + } } return $this->origin->query( $args ); diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index dad4aa74..bac9ed92 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -41,10 +41,20 @@ public function boot(): void { * @return array Array of post IDs. */ public function add_parsely_trending_posts_query( $posts, $args ) { + $parsely = $GLOBALS['parsely']; + if ( ! $parsely->api_secret_is_set() ) { + return $posts; + } $trending_posts = $this->get_trending_posts( $args ); return $trending_posts; } + /** + * Gets the trending posts from Parsely. + * + * @param array $args The WP_Query args. + * @return array An array of post IDs. + */ public function get_trending_posts( $args ) { // TODO: Add failover if we're not on production. $parsely_args = [ @@ -53,8 +63,18 @@ public function get_trending_posts( $args ) { 'period_start' => '1d', 'period_end' => 'now', ]; - $cache_key = 'parsely_trending_posts_' . md5( wp_json_encode( $parsely_args ) ); - $ids = wp_cache_get( $cache_key ); + if ( isset( $args['tax_query'] ) ) { + foreach ( $args['tax_query'] as $tax_query ) { + if ( isset( $tax_query['taxonomy'] ) && 'category' === $tax_query['taxonomy'] ) { + $parsely_args['section'] = implode( ', ', $this->get_slugs_from_ids( $tax_query['terms'], $tax_query['taxonomy'] ) ); + } + if ( isset( $tax_query['taxonomy'] ) && 'post_tag' === $tax_query['taxonomy'] ) { + $parsely_args['tag'] = implode( ', ', $this->get_slugs_from_ids( $tax_query['terms'], $tax_query['taxonomy'] ) ); + } + } + } + $cache_key = 'parsely_trending_posts_' . md5( wp_json_encode( $parsely_args ) ); + $ids = wp_cache_get( $cache_key ); if ( false === $ids ) { $api = new \Parsely\RemoteAPI\Analytics_Posts_API( $GLOBALS['parsely'] ); $posts = $api->get_posts_analytics( $parsely_args ); @@ -80,4 +100,23 @@ function ( $post ) { return( $ids ); } + + /** + * Get slugs from term IDs. + * + * @param array $ids The list of term ids. + * @param array $taxonomy The taxonomy. + * @return array The list of term slugs. + */ + private function get_slugs_from_ids( $ids, $taxonomy ) { + $terms = array_map( + function ( $id ) use ( $taxonomy ) { + $term = get_term( $id, $taxonomy ); + return $term->slug; + }, + $ids + ); + return $terms; + } + } diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index 7e861373..d168a2a1 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -98,7 +98,7 @@ function ( $post_type ) use ( $allowed_post_types ) { 'posts_per_page' => $per_page, 'offset' => $offset, 'ignore_sticky_posts' => true, - 'fields' => 'ids', + 'fields' => 'ids', ]; if ( ! empty( $search_term ) ) { $args['s'] = $search_term; From 92a34553dc6ee81147b762cdec6d8b8b3b90a781 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Tue, 5 Mar 2024 09:51:23 -0600 Subject: [PATCH 09/21] a few improvements --- src/features/class-parsely-support.php | 28 ++++++++++++++++++++------ src/features/class-rest-api.php | 17 ++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index bac9ed92..221798ad 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -10,7 +10,7 @@ use Alley\WP\Types\Feature; /** - * Add support for Parsely, if the plugin in installed. + * Add support for Parsely, if the plugin is installed. */ final class Parsely_Support implements Feature { /** @@ -25,7 +25,9 @@ public function boot(): void { if ( ! class_exists( 'Parsely\Parsely' ) ) { return; } + // Elsewhere in the plugin, we'll use $GLOBALS['parsely'], but it is not available here. $parsely = new \Parsely\Parsely(); + // If we don't have the API secret, we can't use the Parsely API. if ( ! $parsely->api_secret_is_set() ) { return; } @@ -57,19 +59,26 @@ public function add_parsely_trending_posts_query( $posts, $args ) { */ public function get_trending_posts( $args ) { // TODO: Add failover if we're not on production. + /** + * Filter the period start for the Parsely API. + * + * @param string $period_start The period start. + * @return string The period start. + */ + $period_start = apply_filters( 'wp_curate_parsely_period_start', '1d' ); $parsely_args = [ 'limit' => $args['posts_per_page'], 'sort' => 'views', - 'period_start' => '1d', + 'period_start' => $period_start, 'period_end' => 'now', ]; if ( isset( $args['tax_query'] ) ) { foreach ( $args['tax_query'] as $tax_query ) { if ( isset( $tax_query['taxonomy'] ) && 'category' === $tax_query['taxonomy'] ) { - $parsely_args['section'] = implode( ', ', $this->get_slugs_from_ids( $tax_query['terms'], $tax_query['taxonomy'] ) ); + $parsely_args['section'] = implode( ', ', $this->get_slugs_from_term_ids( $tax_query['terms'], $tax_query['taxonomy'] ) ); } if ( isset( $tax_query['taxonomy'] ) && 'post_tag' === $tax_query['taxonomy'] ) { - $parsely_args['tag'] = implode( ', ', $this->get_slugs_from_ids( $tax_query['terms'], $tax_query['taxonomy'] ) ); + $parsely_args['tag'] = implode( ', ', $this->get_slugs_from_term_ids( $tax_query['terms'], $tax_query['taxonomy'] ) ); } } } @@ -91,7 +100,14 @@ function ( $post ) { $post_id = url_to_postid( $post['url'] ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.url_to_postid_url_to_postid } } - return $post_id; + /** + * Filters the post ID derived from Parsely post object. + * + * @param int $post_id The post ID. + * @param array $post The Parsely post object. + * @return int The post ID. + */ + return apply_filters( 'wp_curate_parsely_post_to_post_id', $post_id, $post );; }, $posts ); @@ -108,7 +124,7 @@ function ( $post ) { * @param array $taxonomy The taxonomy. * @return array The list of term slugs. */ - private function get_slugs_from_ids( $ids, $taxonomy ) { + private function get_slugs_from_term_ids( $ids, $taxonomy ) { $terms = array_map( function ( $id ) use ( $taxonomy ) { $term = get_term( $id, $taxonomy ); diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index d168a2a1..48b2dcd2 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -59,6 +59,11 @@ public function get_posts( WP_REST_Request $request ): array { $trending = 'true' === $request->get_param( 'trending' ) ? true : false; $tax_relation = $request->get_param( 'tax_relation' ) ?? 'OR'; + /** + * Filters the allowed taxonomies. + * @param array $allowed_taxonomies The allowed taxonomies. + * @return array The allowed taxonomies. + */ $allowed_taxonomies = apply_filters( 'wp_curate_allowed_taxonomies', [ 'category', 'post_tag' ] ); $taxonomies = array_map( 'get_taxonomy', $allowed_taxonomies ); $tax_query = []; @@ -84,6 +89,12 @@ public function get_posts( WP_REST_Request $request ): array { } $post_types = explode( ',', $post_type_string ); + /** + * Filters the allowed post types. + * + * @param array $allowed_post_types The allowed post types. + * @return array The allowed post types. + */ $allowed_post_types = apply_filters( 'wp_curate_allowed_post_types', [ 'post' ] ); $post_types = array_filter( @@ -108,6 +119,12 @@ function ( $post_type ) use ( $allowed_post_types ) { } if ( $trending ) { + /** + * Filters the trending posts query. + * + * @param array $posts The posts. + * @param array $args The arguments. + */ $posts = apply_filters( 'wp_curate_trending_posts_query', [], $args ); } if ( empty( $posts ) ) { From bc9c92c38844a46e697d6c96baa2383bfc004d59 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Tue, 5 Mar 2024 10:52:52 -0600 Subject: [PATCH 10/21] phpcs --- src/features/class-parsely-support.php | 12 +++++------- src/features/class-rest-api.php | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index 221798ad..f923f8bb 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -93,12 +93,11 @@ function ( $post ) { $metadata = json_decode( $post['metadata'] ?? '', true ); if ( ! empty( $post['metadata'] ) && isset( $metadata['post_id'] ) ) { $post_id = intval( $metadata['post_id'] ); - } else { - if ( function_exists( 'wpcom_vip_url_to_postid' ) ) { + } elseif ( function_exists( 'wpcom_vip_url_to_postid' ) ) { $post_id = wpcom_vip_url_to_postid( $post['url'] ); - } else { - $post_id = url_to_postid( $post['url'] ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.url_to_postid_url_to_postid - } + } else { + $post_id = url_to_postid( $post['url'] ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.url_to_postid_url_to_postid + } /** * Filters the post ID derived from Parsely post object. @@ -107,7 +106,7 @@ function ( $post ) { * @param array $post The Parsely post object. * @return int The post ID. */ - return apply_filters( 'wp_curate_parsely_post_to_post_id', $post_id, $post );; + return apply_filters( 'wp_curate_parsely_post_to_post_id', $post_id, $post ); }, $posts ); @@ -134,5 +133,4 @@ function ( $id ) use ( $taxonomy ) { ); return $terms; } - } diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index 48b2dcd2..b58c9f54 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -61,6 +61,7 @@ public function get_posts( WP_REST_Request $request ): array { /** * Filters the allowed taxonomies. + * * @param array $allowed_taxonomies The allowed taxonomies. * @return array The allowed taxonomies. */ @@ -88,7 +89,7 @@ public function get_posts( WP_REST_Request $request ): array { $tax_query['relation'] = $tax_relation; } - $post_types = explode( ',', $post_type_string ); + $post_types = explode( ',', $post_type_string ); /** * Filters the allowed post types. * From c62bd5cfe2a38442a017b8b98301cf348a424934 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Tue, 5 Mar 2024 12:30:43 -0600 Subject: [PATCH 11/21] phpstan --- src/features/class-parsely-support.php | 49 ++++++++++++++------------ src/features/class-rest-api.php | 26 ++++++++++---- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index f923f8bb..5efa56f3 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -8,6 +8,7 @@ namespace Alley\WP\WP_Curate\Features; use Alley\WP\Types\Feature; +use Parsely\RemoteAPI\Analytics_Posts_API; /** * Add support for Parsely, if the plugin is installed. @@ -38,11 +39,11 @@ public function boot(): void { /** * Gets the trending posts from Parsely. * - * @param array $posts The posts, which should be an empty array. - * @param array $args The WP_Query args. - * @return array Array of post IDs. + * @param array $posts The posts, which should be an empty array. + * @param array $args The WP_Query args. + * @return array Array of post IDs. */ - public function add_parsely_trending_posts_query( $posts, $args ) { + public function add_parsely_trending_posts_query( array $posts, array $args ): array { $parsely = $GLOBALS['parsely']; if ( ! $parsely->api_secret_is_set() ) { return $posts; @@ -54,10 +55,10 @@ public function add_parsely_trending_posts_query( $posts, $args ) { /** * Gets the trending posts from Parsely. * - * @param array $args The WP_Query args. - * @return array An array of post IDs. + * @param array $args The WP_Query args. + * @return array An array of post IDs. */ - public function get_trending_posts( $args ) { + public function get_trending_posts( array $args ): array { // TODO: Add failover if we're not on production. /** * Filter the period start for the Parsely API. @@ -72,7 +73,7 @@ public function get_trending_posts( $args ) { 'period_start' => $period_start, 'period_end' => 'now', ]; - if ( isset( $args['tax_query'] ) ) { + if ( isset( $args['tax_query'] ) && is_array( $args['tax_query'] ) ) { foreach ( $args['tax_query'] as $tax_query ) { if ( isset( $tax_query['taxonomy'] ) && 'category' === $tax_query['taxonomy'] ) { $parsely_args['section'] = implode( ', ', $this->get_slugs_from_term_ids( $tax_query['terms'], $tax_query['taxonomy'] ) ); @@ -82,22 +83,21 @@ public function get_trending_posts( $args ) { } } } - $cache_key = 'parsely_trending_posts_' . md5( wp_json_encode( $parsely_args ) ); + $cache_key = 'parsely_trending_posts_' . md5( wp_json_encode( $parsely_args ) ); // @phpstan-ignore-line - wp_Json_encode not likely to return false. $ids = wp_cache_get( $cache_key ); if ( false === $ids ) { - $api = new \Parsely\RemoteAPI\Analytics_Posts_API( $GLOBALS['parsely'] ); - $posts = $api->get_posts_analytics( $parsely_args ); + $api = new Analytics_Posts_API( $GLOBALS['parsely'] ); // @phpstan-ignore-line + $posts = $api->get_posts_analytics( $parsely_args ); // @phpstan-ignore-line $ids = array_map( function ( $post ) { // Check if the metadata contains post_id, if not, use the URL to get the post ID. $metadata = json_decode( $post['metadata'] ?? '', true ); - if ( ! empty( $post['metadata'] ) && isset( $metadata['post_id'] ) ) { + if ( is_array( $metadata ) && ! empty( $metadata ) && isset( $metadata['post_id'] ) ) { $post_id = intval( $metadata['post_id'] ); } elseif ( function_exists( 'wpcom_vip_url_to_postid' ) ) { $post_id = wpcom_vip_url_to_postid( $post['url'] ); } else { $post_id = url_to_postid( $post['url'] ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.url_to_postid_url_to_postid - } /** * Filters the post ID derived from Parsely post object. @@ -112,6 +112,7 @@ function ( $post ) { ); wp_cache_set( $cache_key, $ids, '', 10 * MINUTE_IN_SECONDS ); } + $ids = array_map( 'intval', $ids ); // @phpstan-ignore-line return( $ids ); } @@ -119,17 +120,21 @@ function ( $post ) { /** * Get slugs from term IDs. * - * @param array $ids The list of term ids. - * @param array $taxonomy The taxonomy. - * @return array The list of term slugs. + * @param array $ids The list of term ids. + * @param string $taxonomy The taxonomy. + * @return array The list of term slugs. */ private function get_slugs_from_term_ids( $ids, $taxonomy ) { - $terms = array_map( - function ( $id ) use ( $taxonomy ) { - $term = get_term( $id, $taxonomy ); - return $term->slug; - }, - $ids + $terms = array_filter( + array_map( + function ( $id ) use ( $taxonomy ) { + $term = get_term( $id, $taxonomy ); + if ( $term instanceof \WP_Term ) { + return $term->slug; + } + }, + $ids + ) ); return $terms; } diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index b58c9f54..ebb4eb82 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -49,9 +49,9 @@ public function register_endpoints(): void { * Gets the posts. * * @param WP_REST_Request $request The request object. - * @return array + * @return array The post IDs. */ - public function get_posts( WP_REST_Request $request ): array { + public function get_posts( WP_REST_Request $request ): array { // @phpstan-ignore-line $search_term = $request->get_param( 'search' ) ?? ''; $offset = $request->get_param( 'offset' ) ?? 0; $post_type_string = $request->get_param( 'post_type' ) ?? 'post'; @@ -59,6 +59,10 @@ public function get_posts( WP_REST_Request $request ): array { $trending = 'true' === $request->get_param( 'trending' ) ? true : false; $tax_relation = $request->get_param( 'tax_relation' ) ?? 'OR'; + if ( ! is_string( $post_type_string ) ) { + $post_type_string = 'post'; + } + /** * Filters the allowed taxonomies. * @@ -67,17 +71,25 @@ public function get_posts( WP_REST_Request $request ): array { */ $allowed_taxonomies = apply_filters( 'wp_curate_allowed_taxonomies', [ 'category', 'post_tag' ] ); $taxonomies = array_map( 'get_taxonomy', $allowed_taxonomies ); + $taxonomies = array_filter( $taxonomies, 'is_object' ); $tax_query = []; foreach ( $taxonomies as $taxonomy ) { - $tax_param = $request->get_param( $taxonomy->rest_base ); - $terms = $tax_param['terms'] ?? []; - $operator = $tax_param['operator'] ?? 'OR'; + $rest_base = $taxonomy->rest_base; + if ( empty( $rest_base ) || ! is_string( $rest_base ) ) { + continue; + } + $tax_param = $request->get_param( $rest_base ); + if ( ! is_array( $tax_param ) ) { + continue; + } + $terms = isset( $tax_param['terms'] ) ? $tax_param['terms'] : []; + $operator = isset( $tax_param['operator'] ) ? $tax_param['operator'] : 'OR'; if ( empty( $terms ) ) { continue; } $terms = explode( ',', $terms ); $terms = array_map( 'intval', $terms ); - $terms = array_filter( $terms, 'term_exists' ); + $terms = array_filter( $terms, 'term_exists' ); // @phpstan-ignore-line $tax_query[] = [ 'taxonomy' => $taxonomy->name, 'field' => 'term_id', @@ -132,6 +144,6 @@ function ( $post_type ) use ( $allowed_post_types ) { $query = new \WP_Query( $args ); $posts = $query->posts; } - return $posts; + return array_map( 'intval', $posts ); // @phpstan-ignore-line } } From adfd7f996ed790b273830faa39b7539bdedc9cde Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Tue, 5 Mar 2024 12:31:09 -0600 Subject: [PATCH 12/21] phpcs --- src/features/class-parsely-support.php | 4 ++-- src/features/class-rest-api.php | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index 5efa56f3..103b1cfa 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -39,7 +39,7 @@ public function boot(): void { /** * Gets the trending posts from Parsely. * - * @param array $posts The posts, which should be an empty array. + * @param array $posts The posts, which should be an empty array. * @param array $args The WP_Query args. * @return array Array of post IDs. */ @@ -121,7 +121,7 @@ function ( $post ) { * Get slugs from term IDs. * * @param array $ids The list of term ids. - * @param string $taxonomy The taxonomy. + * @param string $taxonomy The taxonomy. * @return array The list of term slugs. */ private function get_slugs_from_term_ids( $ids, $taxonomy ) { diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index ebb4eb82..53ec5621 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -51,7 +51,8 @@ public function register_endpoints(): void { * @param WP_REST_Request $request The request object. * @return array The post IDs. */ - public function get_posts( WP_REST_Request $request ): array { // @phpstan-ignore-line + public function get_posts( WP_REST_Request $request ): array { + // @phpstan-ignore-line $search_term = $request->get_param( 'search' ) ?? ''; $offset = $request->get_param( 'offset' ) ?? 0; $post_type_string = $request->get_param( 'post_type' ) ?? 'post'; @@ -82,8 +83,8 @@ public function get_posts( WP_REST_Request $request ): array { // @phpstan-ignor if ( ! is_array( $tax_param ) ) { continue; } - $terms = isset( $tax_param['terms'] ) ? $tax_param['terms'] : []; - $operator = isset( $tax_param['operator'] ) ? $tax_param['operator'] : 'OR'; + $terms = isset( $tax_param['terms'] ) ? $tax_param['terms'] : []; + $operator = isset( $tax_param['operator'] ) ? $tax_param['operator'] : 'OR'; if ( empty( $terms ) ) { continue; } From 80c60604dc771a1b23adcd0e7efbf6991a922e05 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Tue, 5 Mar 2024 13:14:04 -0600 Subject: [PATCH 13/21] phpcs again --- src/features/class-rest-api.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index 53ec5621..1d29e0b5 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -51,8 +51,7 @@ public function register_endpoints(): void { * @param WP_REST_Request $request The request object. * @return array The post IDs. */ - public function get_posts( WP_REST_Request $request ): array { - // @phpstan-ignore-line + public function get_posts( WP_REST_Request $request ): array { // phpcs:ignore Squiz.Functions.MultiLineFunctionDeclaration.ContentAfterBrace @phpstan-ignore-line $search_term = $request->get_param( 'search' ) ?? ''; $offset = $request->get_param( 'offset' ) ?? 0; $post_type_string = $request->get_param( 'post_type' ) ?? 'post'; From a093e95cfc228fd80636d4b8f5f15e9a1c65fb1b Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Tue, 5 Mar 2024 13:28:10 -0600 Subject: [PATCH 14/21] npm lint --- blocks/query/edit.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/blocks/query/edit.tsx b/blocks/query/edit.tsx index 96eff1ac..a3c98cba 100644 --- a/blocks/query/edit.tsx +++ b/blocks/query/edit.tsx @@ -23,7 +23,6 @@ import { import { __, sprintf } from '@wordpress/i18n'; import { addQueryArgs } from '@wordpress/url'; -import type { WP_REST_API_Post, WP_REST_API_Posts } from 'wp-types'; import { Template } from '@wordpress/blocks'; import type { EditProps, From 3c46a7cee61013897e920800e6de1672243366c3 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Tue, 5 Mar 2024 13:49:51 -0600 Subject: [PATCH 15/21] fix array issue --- src/class-plugin-curated-posts.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class-plugin-curated-posts.php b/src/class-plugin-curated-posts.php index 4f3f0f44..d8633996 100644 --- a/src/class-plugin-curated-posts.php +++ b/src/class-plugin-curated-posts.php @@ -43,7 +43,7 @@ public function with_query_context( array $context, array $attributes, WP_Block_ 'no_found_rows' => true, 'offset' => $attributes['offset'] ?? $block_type->attributes['offset']['default'], 'order' => 'DESC', - 'orderby' => $attributes['trending'] ? 'trending' : 'date', + 'orderby' => isset( $attributes['trending'] ) ? 'trending' : 'date', 'posts_per_page' => $attributes['numberOfPosts'] ?? $block_type->attributes['numberOfPosts']['default'], 'post_status' => 'publish', 'post_type' => $attributes['postTypes'] ?? $block_type->attributes['postTypes']['default'], From ef65e5c06a6622f5a22c9106b8df48a2b5deaebb Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Tue, 5 Mar 2024 16:52:44 -0600 Subject: [PATCH 16/21] review feedback --- blocks/query/block.json | 10 +++++++--- blocks/query/index.php | 12 +++++++++++- src/class-plugin-curated-posts.php | 2 +- src/class-trending-post-queries.php | 21 +++++++-------------- src/features/class-parsely-support.php | 10 ++++------ src/features/class-query-block-context.php | 2 ++ src/features/class-rest-api.php | 7 ++----- 7 files changed, 34 insertions(+), 30 deletions(-) diff --git a/blocks/query/block.json b/blocks/query/block.json index b00b2d93..081a2198 100644 --- a/blocks/query/block.json +++ b/blocks/query/block.json @@ -95,9 +95,13 @@ ], "type": "string" }, - "trending": { - "default": false, - "type": "boolean" + "orderby": { + "default": "date", + "enum": [ + "date", + "trending" + ], + "type": "string" } } } diff --git a/blocks/query/index.php b/blocks/query/index.php index 07a5d4e4..013140da 100644 --- a/blocks/query/index.php +++ b/blocks/query/index.php @@ -31,21 +31,31 @@ function wp_curate_query_block_init(): void { /** * Filter the post types that can be used in the Query block. + * + * @param array $allowed_post_types The allowed post types. */ $allowed_post_types = apply_filters( 'wp_curate_allowed_post_types', [ 'post' ] ); /** * Filter the taxonomies that can be used in the Query block. + * + * @param array $allowed_taxonomies The allowed taxonomies. */ $allowed_taxonomies = apply_filters( 'wp_curate_allowed_taxonomies', [ 'category', 'post_tag' ] ); + /** + * Filter whether to use Parsely. + * + * @param bool $use_parsely Whether to use Parsely. + */ + $use_parsley = apply_filters( 'wp_curate_use_parsely', false ); wp_localize_script( 'wp-curate-query-editor-script', 'wpCurateQueryBlock', [ 'allowedPostTypes' => $allowed_post_types, 'allowedTaxonomies' => $allowed_taxonomies, - 'useParsely' => apply_filters( 'wp_curate_use_parsely', false ) ? 'true' : 'false', + 'useParsely' => $use_parsley ? 'true' : 'false', ] ); } diff --git a/src/class-plugin-curated-posts.php b/src/class-plugin-curated-posts.php index d8633996..1a841bed 100644 --- a/src/class-plugin-curated-posts.php +++ b/src/class-plugin-curated-posts.php @@ -43,7 +43,7 @@ public function with_query_context( array $context, array $attributes, WP_Block_ 'no_found_rows' => true, 'offset' => $attributes['offset'] ?? $block_type->attributes['offset']['default'], 'order' => 'DESC', - 'orderby' => isset( $attributes['trending'] ) ? 'trending' : 'date', + 'orderby' => $attributes['orderby'] ?? 'date', 'posts_per_page' => $attributes['numberOfPosts'] ?? $block_type->attributes['numberOfPosts']['default'], 'post_status' => 'publish', 'post_type' => $attributes['postTypes'] ?? $block_type->attributes['postTypes']['default'], diff --git a/src/class-trending-post-queries.php b/src/class-trending-post-queries.php index 7174d2cd..5114825c 100644 --- a/src/class-trending-post-queries.php +++ b/src/class-trending-post-queries.php @@ -11,6 +11,7 @@ use Alley\WP\Types\Post_Query; use Alley\WP\Post_Query\WP_Query_Envelope; use Alley\WP\WP_Curate\Features\Parsely_Support; +use Alley\WP\Post_Query\Post_IDs_Query; /** * Pull trending posts from Parsely. @@ -19,10 +20,12 @@ final class Trending_Post_Queries implements Post_Queries { /** * Set up. * - * @param Post_Queries $origin Post_Queries object. + * @param Post_Queries $origin Post_Queries object. + * @param Parsely_Support $parsely Parsely_Support object. */ public function __construct( private readonly Post_Queries $origin, + private readonly Parsely_Support $parsely ) {} /** @@ -32,20 +35,10 @@ public function __construct( * @return Post_Query */ public function query( array $args ): Post_Query { - if ( 'trending' === $args['orderby'] ) { - $parsely = new Parsely_Support(); - $trending = $parsely->get_trending_posts( $args ); + if ( isset( $args['orderby'] ) && 'trending' === $args['orderby'] ) { + $trending = $this->parsely->get_trending_posts( $args ); if ( ! empty( $trending ) ) { - return new WP_Query_Envelope( - new \WP_Query( - [ - 'post__in' => $trending, - 'post_type' => 'any', - 'ignore_sticky_posts' => true, - 'orderby' => 'post__in', - ] - ) - ); + return new Post_IDs_Query( $trending ); } } diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index 103b1cfa..ef4a39f8 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -64,11 +64,10 @@ public function get_trending_posts( array $args ): array { * Filter the period start for the Parsely API. * * @param string $period_start The period start. - * @return string The period start. */ $period_start = apply_filters( 'wp_curate_parsely_period_start', '1d' ); $parsely_args = [ - 'limit' => $args['posts_per_page'], + 'limit' => $args['posts_per_page'] ?? 20, 'sort' => 'views', 'period_start' => $period_start, 'period_end' => 'now', @@ -93,9 +92,9 @@ function ( $post ) { // Check if the metadata contains post_id, if not, use the URL to get the post ID. $metadata = json_decode( $post['metadata'] ?? '', true ); if ( is_array( $metadata ) && ! empty( $metadata ) && isset( $metadata['post_id'] ) ) { - $post_id = intval( $metadata['post_id'] ); + $post_id = (int) $metadata['post_id']; } elseif ( function_exists( 'wpcom_vip_url_to_postid' ) ) { - $post_id = wpcom_vip_url_to_postid( $post['url'] ); + $post_id = wpcom_vip_url_to_postid( $post['url'] ); } else { $post_id = url_to_postid( $post['url'] ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.url_to_postid_url_to_postid } @@ -104,7 +103,6 @@ function ( $post ) { * * @param int $post_id The post ID. * @param array $post The Parsely post object. - * @return int The post ID. */ return apply_filters( 'wp_curate_parsely_post_to_post_id', $post_id, $post ); }, @@ -114,7 +112,7 @@ function ( $post ) { } $ids = array_map( 'intval', $ids ); // @phpstan-ignore-line - return( $ids ); + return $ids; } /** diff --git a/src/features/class-query-block-context.php b/src/features/class-query-block-context.php index c1d56186..e9bd5d63 100644 --- a/src/features/class-query-block-context.php +++ b/src/features/class-query-block-context.php @@ -16,6 +16,7 @@ use Alley\WP\Types\Feature; use Alley\WP\Types\Post_Queries; use Alley\WP\Types\Post_Query; +use Alley\WP\WP_Curate\Features\Parsely_Support; use Alley\WP\WP_Curate\Must_Include_Curated_Posts; use Alley\WP\WP_Curate\Plugin_Curated_Posts; use Alley\WP\WP_Curate\Recorded_Curated_Posts; @@ -75,6 +76,7 @@ public function filter_query_context( $context, $parsed_block, $parent_block ): qv: $this->stop_queries_var, origin: new Plugin_Curated_Posts( queries: new Trending_Post_Queries( + parsely: new Parsely_Support(), origin: new Variable_Post_Queries( input: function () use ( $parsed_block ) { $main_query = $this->main_query->query_object(); diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index 1d29e0b5..97bb3438 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -56,7 +56,7 @@ public function get_posts( WP_REST_Request $request ): array { // phpcs:ignore S $offset = $request->get_param( 'offset' ) ?? 0; $post_type_string = $request->get_param( 'post_type' ) ?? 'post'; $per_page = $request->get_param( 'per_page' ) ?? 20; - $trending = 'true' === $request->get_param( 'trending' ) ? true : false; + $trending = 'trending' === $request->get_param( 'orderby' ); $tax_relation = $request->get_param( 'tax_relation' ) ?? 'OR'; if ( ! is_string( $post_type_string ) ) { @@ -67,11 +67,10 @@ public function get_posts( WP_REST_Request $request ): array { // phpcs:ignore S * Filters the allowed taxonomies. * * @param array $allowed_taxonomies The allowed taxonomies. - * @return array The allowed taxonomies. */ $allowed_taxonomies = apply_filters( 'wp_curate_allowed_taxonomies', [ 'category', 'post_tag' ] ); + $allowed_taxonomies = array_filter( $allowed_taxonomies, 'taxonomy_exists' ); $taxonomies = array_map( 'get_taxonomy', $allowed_taxonomies ); - $taxonomies = array_filter( $taxonomies, 'is_object' ); $tax_query = []; foreach ( $taxonomies as $taxonomy ) { $rest_base = $taxonomy->rest_base; @@ -106,7 +105,6 @@ public function get_posts( WP_REST_Request $request ): array { // phpcs:ignore S * Filters the allowed post types. * * @param array $allowed_post_types The allowed post types. - * @return array The allowed post types. */ $allowed_post_types = apply_filters( 'wp_curate_allowed_post_types', [ 'post' ] ); @@ -136,7 +134,6 @@ function ( $post_type ) use ( $allowed_post_types ) { * Filters the trending posts query. * * @param array $posts The posts. - * @param array $args The arguments. */ $posts = apply_filters( 'wp_curate_trending_posts_query', [], $args ); } From 00def61e69c8af6bb346e030626a3699a029b2bb Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Wed, 6 Mar 2024 08:23:58 -0600 Subject: [PATCH 17/21] review feedback and phpstan --- blocks/query/edit.tsx | 10 +++++----- src/features/class-parsely-support.php | 12 +++++++++--- src/features/class-rest-api.php | 3 ++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/blocks/query/edit.tsx b/blocks/query/edit.tsx index a3c98cba..4c92bb12 100644 --- a/blocks/query/edit.tsx +++ b/blocks/query/edit.tsx @@ -70,7 +70,7 @@ export default function Edit({ terms = {}, termRelations = {}, taxRelation = 'AND', - trending = false, + orderby = 'date', }, setAttributes, }: EditProps) { @@ -164,7 +164,7 @@ export default function Edit({ type: postTypeString, status: 'publish', per_page: 20, - trending, + orderby, }, ); path += `&${termQueryArgs}`; @@ -182,7 +182,7 @@ export default function Edit({ offset, postTypeString, availableTaxonomies, - trending, + orderby, setAttributes, ]); @@ -390,8 +390,8 @@ export default function Edit({ setAttributes({ trending: next })} + checked={orderby === 'trending'} + onChange={(next) => setAttributes({ orderby: next ? 'trending' : 'date' })} /> ) : null } diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index ef4a39f8..d567c26c 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -56,10 +56,11 @@ public function add_parsely_trending_posts_query( array $posts, array $args ): a * Gets the trending posts from Parsely. * * @param array $args The WP_Query args. - * @return array An array of post IDs. + * @return array An array of post IDs. */ public function get_trending_posts( array $args ): array { // TODO: Add failover if we're not on production. + $parsely_options = $GLOBALS['parsely']->get_options(); /** * Filter the period start for the Parsely API. * @@ -74,13 +75,18 @@ public function get_trending_posts( array $args ): array { ]; if ( isset( $args['tax_query'] ) && is_array( $args['tax_query'] ) ) { foreach ( $args['tax_query'] as $tax_query ) { - if ( isset( $tax_query['taxonomy'] ) && 'category' === $tax_query['taxonomy'] ) { + if ( isset( $tax_query['taxonomy'] ) && $parsely_options['custom_taxonomy_section'] === $tax_query['taxonomy'] ) { $parsely_args['section'] = implode( ', ', $this->get_slugs_from_term_ids( $tax_query['terms'], $tax_query['taxonomy'] ) ); } if ( isset( $tax_query['taxonomy'] ) && 'post_tag' === $tax_query['taxonomy'] ) { $parsely_args['tag'] = implode( ', ', $this->get_slugs_from_term_ids( $tax_query['terms'], $tax_query['taxonomy'] ) ); } } + if ( $parsely_options['cats_as_tags'] ) { + $tags = explode( ', ', $parsely_args['tag'] ?? '' ); + $sections = explode( ', ', $parsely_args['section'] ?? '' ); + $parsely_args['tag'] = implode( ', ', array_merge( $tags, $sections ) ); + } } $cache_key = 'parsely_trending_posts_' . md5( wp_json_encode( $parsely_args ) ); // @phpstan-ignore-line - wp_Json_encode not likely to return false. $ids = wp_cache_get( $cache_key ); @@ -110,7 +116,7 @@ function ( $post ) { ); wp_cache_set( $cache_key, $ids, '', 10 * MINUTE_IN_SECONDS ); } - $ids = array_map( 'intval', $ids ); // @phpstan-ignore-line + $ids = array_map( 'intval', $ids ); // @phpstan-ignore-line - yes phpstan, 'invtal' is a function. return $ids; } diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index 97bb3438..ac9de381 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -69,8 +69,8 @@ public function get_posts( WP_REST_Request $request ): array { // phpcs:ignore S * @param array $allowed_taxonomies The allowed taxonomies. */ $allowed_taxonomies = apply_filters( 'wp_curate_allowed_taxonomies', [ 'category', 'post_tag' ] ); - $allowed_taxonomies = array_filter( $allowed_taxonomies, 'taxonomy_exists' ); $taxonomies = array_map( 'get_taxonomy', $allowed_taxonomies ); + $taxonomies = array_filter( $taxonomies, 'is_object' ); $tax_query = []; foreach ( $taxonomies as $taxonomy ) { $rest_base = $taxonomy->rest_base; @@ -134,6 +134,7 @@ function ( $post_type ) use ( $allowed_post_types ) { * Filters the trending posts query. * * @param array $posts The posts. + * @param array $args The WP_Query arguments. */ $posts = apply_filters( 'wp_curate_trending_posts_query', [], $args ); } From f6d44114f0388f2156ea50d5ab1120926037bf72 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Wed, 6 Mar 2024 08:38:36 -0600 Subject: [PATCH 18/21] npm linting and version bump --- CHANGELOG.md | 4 ++++ blocks/query/types.ts | 2 +- wp-curate.php | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 919d7c7b..aa2b6554 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `WP Curate` will be documented in this file. +## 1.7.0 - 2024-03-06 + +- Enhancement: Integration with [Parse.ly plugin](https://wordpress.org/plugins/wp-parsely/) to support querying trending posts. + ## 1.6.3 - 2024-02-14 - Bug Fix: Selecting a post more than once in a Query block causes empty slots at the end. diff --git a/blocks/query/types.ts b/blocks/query/types.ts index f1b59503..077b92a1 100644 --- a/blocks/query/types.ts +++ b/blocks/query/types.ts @@ -19,7 +19,7 @@ interface EditProps { [key: string]: string; }; taxRelation?: string; - trending?: boolean; + orderby?: string; }; setAttributes: (attributes: any) => void; } diff --git a/wp-curate.php b/wp-curate.php index 3275f5c5..65cd81ab 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: 1.6.3 + * Version: 1.7.0 * Author: Alley Interactive * Author URI: https://github.com/alleyinteractive/wp-curate * Requires at least: 6.4 From d88feb730426503540c1a3f732103688a598772c Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Wed, 6 Mar 2024 09:26:23 -0600 Subject: [PATCH 19/21] add filter to trending posts --- src/features/class-parsely-support.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index d567c26c..b6aa3dd8 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -59,7 +59,6 @@ public function add_parsely_trending_posts_query( array $posts, array $args ): a * @return array An array of post IDs. */ public function get_trending_posts( array $args ): array { - // TODO: Add failover if we're not on production. $parsely_options = $GLOBALS['parsely']->get_options(); /** * Filter the period start for the Parsely API. @@ -116,6 +115,15 @@ function ( $post ) { ); wp_cache_set( $cache_key, $ids, '', 10 * MINUTE_IN_SECONDS ); } + + /** + * Filters the trending posts from Parsely. + * + * @param array $ids The list of post IDs. + * @param array $parsely_args The Parsely API args. + * @param array $args The WP_Query args. + */ + $ids = apply_filters( 'wp_curate_parsely_trending_posts', $ids, $parsely_args, $args ); $ids = array_map( 'intval', $ids ); // @phpstan-ignore-line - yes phpstan, 'invtal' is a function. return $ids; From ec758c7c88a02a64e0feecf356414e078b941915 Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Wed, 6 Mar 2024 09:32:18 -0600 Subject: [PATCH 20/21] phpstan --- src/features/class-parsely-support.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index b6aa3dd8..da4f2902 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -89,7 +89,7 @@ public function get_trending_posts( array $args ): array { } $cache_key = 'parsely_trending_posts_' . md5( wp_json_encode( $parsely_args ) ); // @phpstan-ignore-line - wp_Json_encode not likely to return false. $ids = wp_cache_get( $cache_key ); - if ( false === $ids ) { + if ( false === $ids || ! is_array( $ids ) ) { $api = new Analytics_Posts_API( $GLOBALS['parsely'] ); // @phpstan-ignore-line $posts = $api->get_posts_analytics( $parsely_args ); // @phpstan-ignore-line $ids = array_map( @@ -124,7 +124,6 @@ function ( $post ) { * @param array $args The WP_Query args. */ $ids = apply_filters( 'wp_curate_parsely_trending_posts', $ids, $parsely_args, $args ); - $ids = array_map( 'intval', $ids ); // @phpstan-ignore-line - yes phpstan, 'invtal' is a function. return $ids; } From c70d5be4baffc1f5e68d444f0c455819e5ff04bc Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Wed, 6 Mar 2024 11:07:15 -0600 Subject: [PATCH 21/21] review feedback --- blocks/query/edit.tsx | 6 ++-- blocks/query/index.php | 4 +-- src/features/class-parsely-support.php | 40 +++++++++++++++++++++----- src/features/class-rest-api.php | 4 +-- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/blocks/query/edit.tsx b/blocks/query/edit.tsx index 4c92bb12..7a73a26f 100644 --- a/blocks/query/edit.tsx +++ b/blocks/query/edit.tsx @@ -44,7 +44,7 @@ interface Window { wpCurateQueryBlock: { allowedPostTypes: Array; allowedTaxonomies: Array; - useParsely: string, + parselyAvailable: string, }; } @@ -78,7 +78,7 @@ export default function Edit({ wpCurateQueryBlock: { allowedPostTypes = [], allowedTaxonomies = [], - useParsely = 'false', + parselyAvailable = 'false', } = {}, } = (window as any as Window); @@ -386,7 +386,7 @@ export default function Edit({ onChange={(next) => setAttributes({ searchTerm: next })} value={searchTerm} /> - { useParsely === 'true' ? ( + { parselyAvailable === 'true' ? ( $allowed_post_types, 'allowedTaxonomies' => $allowed_taxonomies, - 'useParsely' => $use_parsley ? 'true' : 'false', + 'parselyAvailable' => $parsely_available ? 'true' : 'false', ] ); } diff --git a/src/features/class-parsely-support.php b/src/features/class-parsely-support.php index da4f2902..adb9b84f 100644 --- a/src/features/class-parsely-support.php +++ b/src/features/class-parsely-support.php @@ -9,6 +9,7 @@ use Alley\WP\Types\Feature; use Parsely\RemoteAPI\Analytics_Posts_API; +use Parsely\Parsely; /** * Add support for Parsely, if the plugin is installed. @@ -59,18 +60,33 @@ public function add_parsely_trending_posts_query( array $posts, array $args ): a * @return array An array of post IDs. */ public function get_trending_posts( array $args ): array { + if ( ! class_exists( '\Parsely\Parsely' ) || ! isset( $GLOBALS['parsely'] ) || ! $GLOBALS['parsely'] instanceof Parsely ) { + return []; + } + if ( ! class_exists( '\Parsely\RemoteAPI\Analytics_Posts_API' ) ) { + return []; + } + $parsely_options = $GLOBALS['parsely']->get_options(); /** * Filter the period start for the Parsely API. * * @param string $period_start The period start. + * @param array $args The WP_Query args. */ - $period_start = apply_filters( 'wp_curate_parsely_period_start', '1d' ); + $period_start = apply_filters( 'wp_curate_parsely_period_start', '1d', $args ); + /** + * Filter the period end for the Parsely API. + * + * @param string $period_end The period end. + * @param array $args The WP_Query args. + */ + $period_end = apply_filters( 'wp_curate_parsely_period_end', 'now', $args ); $parsely_args = [ - 'limit' => $args['posts_per_page'] ?? 20, + 'limit' => $args['posts_per_page'] ?? get_option( 'posts_per_page' ), 'sort' => 'views', 'period_start' => $period_start, - 'period_end' => 'now', + 'period_end' => $period_end, ]; if ( isset( $args['tax_query'] ) && is_array( $args['tax_query'] ) ) { foreach ( $args['tax_query'] as $tax_query ) { @@ -90,13 +106,13 @@ public function get_trending_posts( array $args ): array { $cache_key = 'parsely_trending_posts_' . md5( wp_json_encode( $parsely_args ) ); // @phpstan-ignore-line - wp_Json_encode not likely to return false. $ids = wp_cache_get( $cache_key ); if ( false === $ids || ! is_array( $ids ) ) { - $api = new Analytics_Posts_API( $GLOBALS['parsely'] ); // @phpstan-ignore-line - $posts = $api->get_posts_analytics( $parsely_args ); // @phpstan-ignore-line + $api = new Analytics_Posts_API( $GLOBALS['parsely'] ); + $posts = $api->get_posts_analytics( $parsely_args ); $ids = array_map( function ( $post ) { // Check if the metadata contains post_id, if not, use the URL to get the post ID. $metadata = json_decode( $post['metadata'] ?? '', true ); - if ( is_array( $metadata ) && ! empty( $metadata ) && isset( $metadata['post_id'] ) ) { + if ( is_array( $metadata ) && isset( $metadata['post_id'] ) ) { $post_id = (int) $metadata['post_id']; } elseif ( function_exists( 'wpcom_vip_url_to_postid' ) ) { $post_id = wpcom_vip_url_to_postid( $post['url'] ); @@ -113,7 +129,17 @@ function ( $post ) { }, $posts ); - wp_cache_set( $cache_key, $ids, '', 10 * MINUTE_IN_SECONDS ); + /** + * Filters the cache duration for the trending posts from Parsely. + * + * @param int $cache_duration The cache duration. + * @param array $args The WP_Query args. + */ + $cache_duration = apply_filters( 'wp_curate_parsely_trending_posts_cache_duration', 10 * MINUTE_IN_SECONDS, $args ); + if ( 300 > $cache_duration ) { + $cache_duration = 300; + } + wp_cache_set( $cache_key, $ids, '', $cache_duration ); // phpcs:ignore WordPressVIPMinimum.Performance.LowExpiryCacheTime.CacheTimeUndetermined } /** diff --git a/src/features/class-rest-api.php b/src/features/class-rest-api.php index ac9de381..f5bda601 100644 --- a/src/features/class-rest-api.php +++ b/src/features/class-rest-api.php @@ -38,9 +38,7 @@ public function register_endpoints(): void { [ 'methods' => 'GET', 'callback' => [ $this, 'get_posts' ], - 'permission_callback' => function () { - return current_user_can( 'edit_posts' ); - }, + 'permission_callback' => 'is_user_logged_in', ] ); }