From 85d94577e5f2578fd7fc0c81798a4362cd622f23 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Sun, 23 Jun 2024 06:52:34 +0530 Subject: [PATCH 01/22] Add categories to pull screen --- includes/classes/PullListTable.php | 22 +++- includes/utils.php | 176 +++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+), 4 deletions(-) diff --git a/includes/classes/PullListTable.php b/includes/classes/PullListTable.php index 531d6f408..57f206438 100644 --- a/includes/classes/PullListTable.php +++ b/includes/classes/PullListTable.php @@ -7,6 +7,8 @@ namespace Distributor; +use function Distributor\Utils\generate_taxonomy_links; + /** * List table class for pull screen */ @@ -54,10 +56,11 @@ public function __construct() { */ public function get_columns() { $columns = [ - 'cb' => '', - 'name' => esc_html__( 'Name', 'distributor' ), - 'post_type' => esc_html__( 'Post Type', 'distributor' ), - 'date' => esc_html__( 'Date', 'distributor' ), + 'cb' => '', + 'name' => esc_html__( 'Name', 'distributor' ), + 'post_type' => esc_html__( 'Post Type', 'distributor' ), + 'categories' => esc_html__( 'Categories', 'distributor' ), + 'date' => esc_html__( 'Date', 'distributor' ), ]; /** @@ -247,6 +250,17 @@ public function column_date( $post ) { } } + /** + * Output categories column + * + * @param \WP_Post $post Post object. + * @since 0.8 + */ + public function column_categories( $post ) { + $categories = $post->terms['category'] ?? []; + echo wp_kses_post( generate_taxonomy_links( 'category', $post, $categories ) ); + } + /** * Output standard table columns. * diff --git a/includes/utils.php b/includes/utils.php index 1e53a57f9..642c02bdc 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -483,6 +483,182 @@ function prepare_meta( $post_id ) { return $prepared_meta; } +/** + * Generates taxonomy term links for a given post. + * + * The code is taken from WP_Posts_List_Table::column_default and modified + * lightly to work in our context. + * + * @param string $taxonomy The taxonomy name. + * @param object $post The post object. + * @param array $terms Optional. Array of terms. + * @return string The generated HTML for the taxonomy links. + */ +function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { + $taxonomy_object = get_taxonomy( $taxonomy ); + + if ( ! $terms ) { + $terms = get_the_terms( $post, $taxonomy ); + } + + /** + * Filter the taxonomy terms that should be synced. + * + * @since x.x.x + * @hook dt_syncable_taxonomy_terms + * + * @param {array} $terms Array of terms. + * @param {string} $taxonomy Taxonomy name. + * @param {object} $post Post Object. + * + * @return {array} Array of terms. + */ + $terms = apply_filters( "dt_syncable_{$taxonomy}_terms", $terms, $taxonomy, $post ); + + + /** + * Filter the terms that should be synced. + * + * @since x.x.x + * @hook dt_syncable_terms + * + * @param {array} $terms Array of categories. + * @param {string} $taxonomy Taxonomy name. + * @param {object} $post Post Object. + * + * @return {array} Array of categories. + */ + $terms = apply_filters( 'dt_syncable_terms', $terms, $taxonomy, $post ); + + if ( is_array( $terms ) ) { + $term_links = array(); + + foreach ( $terms as $t ) { + if ( is_array( $t ) ) { + $t = (object) $t; + } + $posts_in_term_qv = array(); + + if ( 'post' !== $post->post_type ) { + $posts_in_term_qv['post_type'] = $post->post_type; + } + + if ( $taxonomy_object->query_var ) { + $posts_in_term_qv[ $taxonomy_object->query_var ] = $t->slug; + } else { + $posts_in_term_qv['taxonomy'] = $taxonomy; + $posts_in_term_qv['term'] = $t->slug; + } + + $label = esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) ); + + $term_links[] = get_edit_link( $posts_in_term_qv, $label ); + } + + /** + * Filters the links in `$taxonomy` column of edit.php. + * + * @since x.x.x + * @hook dt_taxonomy_links + * + * @param string[] $term_links Array of term editing links. + * @param string $taxonomy Taxonomy name. + * @param WP_Term[] $terms Array of term objects appearing in the post row. + */ + $term_links = apply_filters( 'dt_taxonomy_links', $term_links, $taxonomy, $terms ); + + return implode( wp_get_list_item_separator(), $term_links ); + } else { + return '' . $taxonomy_object->labels->no_terms . ''; + } +} + +/** + * Creates a link to edit.php with params. + * + * The edit link is created in such a way that it will link to source site. + * + * @since x.x.x + * + * @param string[] $args Associative array of URL parameters for the link. + * @param string $link_text Link text. + * @param string $css_class Optional. Class attribute. Default empty string. + * @return string The formatted link string. + */ +function get_edit_link( $args, $link_text, $css_class = '' ) { + $url = ''; + if ( is_internal_connection() ) { + $url = add_query_arg( $args, get_admin_url( null, 'edit.php' ) ); + } else { + $url = add_query_arg( $args, get_root_url() . 'wp-admin/edit.php' ); + } + + $class_html = ''; + $aria_current = ''; + + if ( ! empty( $css_class ) ) { + $class_html = sprintf( + ' class="%s"', + esc_attr( $css_class ) + ); + + if ( 'current' === $css_class ) { + $aria_current = ' aria-current="page"'; + } + } + + return sprintf( + '%s', + esc_url( $url ), + $class_html, + $aria_current, + $link_text + ); +} + +/** + * Is current connection an external connection? + * + * @return boolean + */ +function is_external_connection() { + global $connection_now; + return is_a( $connection_now, '\Distributor\ExternalConnection' ); +} + +/** + * Is current connection an internal connection? + * + * @return boolean + */ +function is_internal_connection() { + global $connection_now; + return is_a( $connection_now, '\Distributor\InternalConnections\NetworkSiteConnection' ); +} + +/** + * Get the root URL of the current connection + * + * @return string + */ +function get_root_url() { + $base_url = get_conn_base_url(); + return str_replace( '/wp-json', '', $base_url ); +} + +/** + * Get the base URL of the current connection + * + * @return string + */ +function get_conn_base_url() { + if ( ! is_external_connection() ) { + return get_site_url(); + } + global $connection_now; + return $connection_now->base_url; +} + /** * Format media items for consumption * From 8ef5b57c66877d967b738f93b83439c70d869961 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 05:31:25 +0530 Subject: [PATCH 02/22] Add trailing slash to cat urls --- includes/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/utils.php b/includes/utils.php index 642c02bdc..fc312c3cc 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -590,7 +590,7 @@ function get_edit_link( $args, $link_text, $css_class = '' ) { if ( is_internal_connection() ) { $url = add_query_arg( $args, get_admin_url( null, 'edit.php' ) ); } else { - $url = add_query_arg( $args, get_root_url() . 'wp-admin/edit.php' ); + $url = add_query_arg( $args, trailingslashit( get_root_url() ) . 'wp-admin/edit.php' ); } $class_html = ''; From 32c11d09d59509e38e6e7efb2bdca5cdb2683f13 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 05:33:38 +0530 Subject: [PATCH 03/22] Add a full stop. Co-authored-by: Faisal Alvi --- includes/classes/PullListTable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/classes/PullListTable.php b/includes/classes/PullListTable.php index 57f206438..e02602f8b 100644 --- a/includes/classes/PullListTable.php +++ b/includes/classes/PullListTable.php @@ -251,7 +251,7 @@ public function column_date( $post ) { } /** - * Output categories column + * Output categories column. * * @param \WP_Post $post Post object. * @since 0.8 From d3d6648083768218142a056fc10c6f26c96760dc Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 06:32:07 +0530 Subject: [PATCH 04/22] Address PR feedback --- includes/classes/PullListTable.php | 7 ++++++- includes/utils.php | 21 +++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/includes/classes/PullListTable.php b/includes/classes/PullListTable.php index e02602f8b..9b6638e86 100644 --- a/includes/classes/PullListTable.php +++ b/includes/classes/PullListTable.php @@ -258,6 +258,11 @@ public function column_date( $post ) { */ public function column_categories( $post ) { $categories = $post->terms['category'] ?? []; + + if ( empty( $categories ) ) { + return; + } + echo wp_kses_post( generate_taxonomy_links( 'category', $post, $categories ) ); } @@ -268,7 +273,7 @@ public function column_categories( $post ) { * @param string $column_name Column name. * * @return string. - * @since 0.8 + * @since 2.0.5 */ public function column_default( $item, $column_name ) { if ( 'post_type' === $column_name ) { diff --git a/includes/utils.php b/includes/utils.php index fc312c3cc..0409c4cd9 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -492,11 +492,16 @@ function prepare_meta( $post_id ) { * @param string $taxonomy The taxonomy name. * @param object $post The post object. * @param array $terms Optional. Array of terms. + * * @return string The generated HTML for the taxonomy links. */ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { $taxonomy_object = get_taxonomy( $taxonomy ); + if ( ! $taxonomy_object ) { + return ''; + } + if ( ! $terms ) { $terms = get_the_terms( $post, $taxonomy ); } @@ -515,7 +520,6 @@ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { */ $terms = apply_filters( "dt_syncable_{$taxonomy}_terms", $terms, $taxonomy, $post ); - /** * Filter the terms that should be synced. * @@ -583,6 +587,7 @@ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { * @param string[] $args Associative array of URL parameters for the link. * @param string $link_text Link text. * @param string $css_class Optional. Class attribute. Default empty string. + * * @return string The formatted link string. */ function get_edit_link( $args, $link_text, $css_class = '' ) { @@ -619,36 +624,47 @@ function get_edit_link( $args, $link_text, $css_class = '' ) { /** * Is current connection an external connection? * + * @since 2.0.5 + * * @return boolean */ function is_external_connection() { global $connection_now; + return is_a( $connection_now, '\Distributor\ExternalConnection' ); } /** * Is current connection an internal connection? * + * @since 2.0.5 + * * @return boolean */ function is_internal_connection() { global $connection_now; + return is_a( $connection_now, '\Distributor\InternalConnections\NetworkSiteConnection' ); } /** * Get the root URL of the current connection * + * @since 2.0.5 + * * @return string */ function get_root_url() { $base_url = get_conn_base_url(); + return str_replace( '/wp-json', '', $base_url ); } /** * Get the base URL of the current connection * + * @since 2.0.5 + * * @return string */ function get_conn_base_url() { @@ -656,7 +672,8 @@ function get_conn_base_url() { return get_site_url(); } global $connection_now; - return $connection_now->base_url; + + return $connection_now?->base_url; } /** From 4ad5180dc05e76fc7e954f6a2fc6a31e4f096a83 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 06:33:53 +0530 Subject: [PATCH 05/22] Address PR feedback --- includes/classes/PullListTable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/classes/PullListTable.php b/includes/classes/PullListTable.php index 9b6638e86..a0f052a17 100644 --- a/includes/classes/PullListTable.php +++ b/includes/classes/PullListTable.php @@ -254,7 +254,7 @@ public function column_date( $post ) { * Output categories column. * * @param \WP_Post $post Post object. - * @since 0.8 + * @since 2.0.5 */ public function column_categories( $post ) { $categories = $post->terms['category'] ?? []; From 8d71ce7fd44995b17a21d4deb96c0842e6aa06b5 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 17:30:44 +0530 Subject: [PATCH 06/22] Update wp-env --- package-lock.json | 58 ++++++++++++++++++++++++++++++++++------------- package.json | 2 +- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index a90feccc9..ff047351e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ }, "devDependencies": { "@10up/cypress-wp-utils": "^0.2.0", - "@wordpress/env": "^5.16.0", + "@wordpress/env": "^9.10.0", "@wordpress/scripts": "^26.19.0", "compare-versions": "^4.1.3", "cypress": "^13.1.0", @@ -4814,14 +4814,14 @@ } }, "node_modules/@wordpress/env": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-5.16.0.tgz", - "integrity": "sha512-zx6UO8PuJBrQ34cfeedK1HlGHLFaj7oWzTo9tTt+noB79Ttqc4+a0lYwDqBLLJhlHU+cWgcyOP2lB6TboXH0xA==", + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-9.10.0.tgz", + "integrity": "sha512-GqUg1XdrUXI3l5NhHhEZisrccW+VPqJSU5xO1IXybI6KOvmSecidxWEqlMj26vzu2P5aLCWZcx28QkrrY3jvdg==", "dev": true, "dependencies": { "chalk": "^4.0.0", "copy-dir": "^1.3.0", - "docker-compose": "^0.22.2", + "docker-compose": "^0.24.3", "extract-zip": "^1.6.7", "got": "^11.8.5", "inquirer": "^7.1.0", @@ -8388,14 +8388,29 @@ } }, "node_modules/docker-compose": { - "version": "0.22.2", - "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.22.2.tgz", - "integrity": "sha512-iXWb5+LiYmylIMFXvGTYsjI1F+Xyx78Jm/uj1dxwwZLbWkUdH6yOXY5Nr3RjbYX15EgbGJCq78d29CmWQQQMPg==", + "version": "0.24.8", + "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.24.8.tgz", + "integrity": "sha512-plizRs/Vf15H+GCVxq2EUvyPK7ei9b/cVesHvjnX4xaXjM9spHe2Ytq0BitndFgvTJ3E3NljPNUEl7BAN43iZw==", "dev": true, + "dependencies": { + "yaml": "^2.2.2" + }, "engines": { "node": ">= 6.0.0" } }, + "node_modules/docker-compose/node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -24809,14 +24824,14 @@ } }, "@wordpress/env": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-5.16.0.tgz", - "integrity": "sha512-zx6UO8PuJBrQ34cfeedK1HlGHLFaj7oWzTo9tTt+noB79Ttqc4+a0lYwDqBLLJhlHU+cWgcyOP2lB6TboXH0xA==", + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-9.10.0.tgz", + "integrity": "sha512-GqUg1XdrUXI3l5NhHhEZisrccW+VPqJSU5xO1IXybI6KOvmSecidxWEqlMj26vzu2P5aLCWZcx28QkrrY3jvdg==", "dev": true, "requires": { "chalk": "^4.0.0", "copy-dir": "^1.3.0", - "docker-compose": "^0.22.2", + "docker-compose": "^0.24.3", "extract-zip": "^1.6.7", "got": "^11.8.5", "inquirer": "^7.1.0", @@ -27471,10 +27486,21 @@ } }, "docker-compose": { - "version": "0.22.2", - "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.22.2.tgz", - "integrity": "sha512-iXWb5+LiYmylIMFXvGTYsjI1F+Xyx78Jm/uj1dxwwZLbWkUdH6yOXY5Nr3RjbYX15EgbGJCq78d29CmWQQQMPg==", - "dev": true + "version": "0.24.8", + "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.24.8.tgz", + "integrity": "sha512-plizRs/Vf15H+GCVxq2EUvyPK7ei9b/cVesHvjnX4xaXjM9spHe2Ytq0BitndFgvTJ3E3NljPNUEl7BAN43iZw==", + "dev": true, + "requires": { + "yaml": "^2.2.2" + }, + "dependencies": { + "yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true + } + } }, "doctrine": { "version": "3.0.0", diff --git a/package.json b/package.json index d39ed73c8..01b1e57be 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ }, "devDependencies": { "@10up/cypress-wp-utils": "^0.2.0", - "@wordpress/env": "^5.16.0", + "@wordpress/env": "^9.10.0", "@wordpress/scripts": "^26.19.0", "compare-versions": "^4.1.3", "cypress": "^13.1.0", From 0a82a88b10b9a477654e36aef4b1c282feaf10de Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 17:48:43 +0530 Subject: [PATCH 07/22] Update connection_now object --- includes/utils.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/includes/utils.php b/includes/utils.php index 0409c4cd9..b7bf9c51c 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -673,7 +673,11 @@ function get_conn_base_url() { } global $connection_now; - return $connection_now?->base_url; + if ( ! $connection_now || ! property_exists( $connection_now, 'base_url' ) ) { + return ''; + } + + return $connection_now->base_url; } /** From 98d63464f89a3bb2449258289dfd3d0bee66c8a7 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:26:54 +0530 Subject: [PATCH 08/22] Update wp-env version --- package-lock.json | 18 +++++++++++------- package.json | 2 +- tests/cypress/config.js | 6 ++++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index ff047351e..f472e27ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ }, "devDependencies": { "@10up/cypress-wp-utils": "^0.2.0", - "@wordpress/env": "^9.10.0", + "@wordpress/env": "^10.1.0", "@wordpress/scripts": "^26.19.0", "compare-versions": "^4.1.3", "cypress": "^13.1.0", @@ -4814,9 +4814,9 @@ } }, "node_modules/@wordpress/env": { - "version": "9.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-9.10.0.tgz", - "integrity": "sha512-GqUg1XdrUXI3l5NhHhEZisrccW+VPqJSU5xO1IXybI6KOvmSecidxWEqlMj26vzu2P5aLCWZcx28QkrrY3jvdg==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-10.2.0.tgz", + "integrity": "sha512-EToZYPGXpl42Asw3bxpX8aKmHfRUdGxKPjQ9CHZVQoTAL27Af4FyjyGnepsnDpnYdIeI8VPb2S3k2NL/1+fpIA==", "dev": true, "dependencies": { "chalk": "^4.0.0", @@ -4834,6 +4834,10 @@ }, "bin": { "wp-env": "bin/wp-env" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" } }, "node_modules/@wordpress/eslint-plugin": { @@ -24824,9 +24828,9 @@ } }, "@wordpress/env": { - "version": "9.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-9.10.0.tgz", - "integrity": "sha512-GqUg1XdrUXI3l5NhHhEZisrccW+VPqJSU5xO1IXybI6KOvmSecidxWEqlMj26vzu2P5aLCWZcx28QkrrY3jvdg==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-10.2.0.tgz", + "integrity": "sha512-EToZYPGXpl42Asw3bxpX8aKmHfRUdGxKPjQ9CHZVQoTAL27Af4FyjyGnepsnDpnYdIeI8VPb2S3k2NL/1+fpIA==", "dev": true, "requires": { "chalk": "^4.0.0", diff --git a/package.json b/package.json index 01b1e57be..c66efaa2a 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ }, "devDependencies": { "@10up/cypress-wp-utils": "^0.2.0", - "@wordpress/env": "^9.10.0", + "@wordpress/env": "^10.1.0", "@wordpress/scripts": "^26.19.0", "compare-versions": "^4.1.3", "cypress": "^13.1.0", diff --git a/tests/cypress/config.js b/tests/cypress/config.js index 103de3a39..1d34e7abf 100644 --- a/tests/cypress/config.js +++ b/tests/cypress/config.js @@ -1,5 +1,6 @@ const { defineConfig } = require( 'cypress' ); -const { readConfig } = require( '@wordpress/env/lib/config' ); +const { loadConfig } = require( '@wordpress/env/lib/config' ); +const getCacheDirectory = require( '@wordpress/env/lib/config/get-cache-directory' ); module.exports = defineConfig( { chromeWebSecurity: false, @@ -34,7 +35,8 @@ module.exports = defineConfig( { * @return {Object} Updated Cypress Config object. */ const setBaseUrl = async ( on, config ) => { - const wpEnvConfig = await readConfig( 'wp-env' ); + const cacheDirectory = await getCacheDirectory(); + const wpEnvConfig = await loadConfig( cacheDirectory ); if ( wpEnvConfig ) { const port = wpEnvConfig.env.tests.port || null; From 93090a0960601a343fb1031d51e8f8ecbfc27c13 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:35:52 +0530 Subject: [PATCH 09/22] Remove initialization file --- tests/bin/initialize.sh | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/tests/bin/initialize.sh b/tests/bin/initialize.sh index 06c8cae4f..e69de29bb 100755 --- a/tests/bin/initialize.sh +++ b/tests/bin/initialize.sh @@ -1,21 +0,0 @@ -#!/bin/bash -set -e - -npm run env run tests-wordpress "chmod -c ugo+w /var/www/html" -npm run env run tests-cli "wp rewrite structure '/%postname%/' --hard" - -status=0 -npm run env run tests-cli "wp site list" || status=$? - -if [ $status -eq 0 ] -then - echo "Multisite already initialized" -else - echo "Converting to multisite" - npm run env run tests-cli "wp core multisite-convert --title='Distributor Multisite'" - npm run env run tests-cli "wp user create second 'second@admin.local' --user_pass=password --role=administrator" - npm run env run tests-cli "wp site create --slug=second --title='Second Site' --email='second@admin.local'" - npm run env run tests-cli "wp theme enable twentytwentyone --activate" - npm run env run tests-cli "wp theme enable twentytwentyone --url=localhost/second --activate" - npm run env run tests-cli "cp wp-content/plugins/distributor/tests/cypress/.htaccess .htaccess" -fi From 4c249a8297a5bd1a3c80ab5a571a1ecc381e281d Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 21:09:04 +0530 Subject: [PATCH 10/22] Fix initialize file --- tests/bin/initialize.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/bin/initialize.sh b/tests/bin/initialize.sh index e69de29bb..4d4ab192b 100755 --- a/tests/bin/initialize.sh +++ b/tests/bin/initialize.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e + +npx wp-env run tests-wordpress chmod -c ugo+w /var/www/html +npm run env run tests-cli wp rewrite structure '/%postname%/' --hard + +status=0 +npm run env run tests-cli wp site list || status=$? + +if [ $status -eq 0 ] +then + echo "Multisite already initialized" +else + echo "Converting to multisite" + npm run env run tests-cli wp core multisite-convert --title='Distributor Multisite' + npm run env run tests-cli wp user create second 'second@admin.local' --user_pass=password --role=administrator + npm run env run tests-cli wp site create --slug=second --title='Second Site' --email='second@admin.local' + npm run env run tests-cli wp theme enable twentytwentyone --activate + npm run env run tests-cli wp theme enable twentytwentyone --url=localhost/second --activate + npm run env run tests-cli cp wp-content/plugins/distributor/tests/cypress/.htaccess .htaccess +fi From b1ad11db9308f51c5ff534e55543ce83a991a542 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 21:14:53 +0530 Subject: [PATCH 11/22] Convert all npm run to npx --- tests/bin/initialize.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/bin/initialize.sh b/tests/bin/initialize.sh index 4d4ab192b..4d2e7d920 100755 --- a/tests/bin/initialize.sh +++ b/tests/bin/initialize.sh @@ -2,20 +2,20 @@ set -e npx wp-env run tests-wordpress chmod -c ugo+w /var/www/html -npm run env run tests-cli wp rewrite structure '/%postname%/' --hard +npx wp-env run tests-cli wp rewrite structure '/%postname%/' --hard status=0 -npm run env run tests-cli wp site list || status=$? +npx wp-env run tests-cli wp site list || status=$? if [ $status -eq 0 ] then echo "Multisite already initialized" else echo "Converting to multisite" - npm run env run tests-cli wp core multisite-convert --title='Distributor Multisite' - npm run env run tests-cli wp user create second 'second@admin.local' --user_pass=password --role=administrator - npm run env run tests-cli wp site create --slug=second --title='Second Site' --email='second@admin.local' - npm run env run tests-cli wp theme enable twentytwentyone --activate - npm run env run tests-cli wp theme enable twentytwentyone --url=localhost/second --activate - npm run env run tests-cli cp wp-content/plugins/distributor/tests/cypress/.htaccess .htaccess + npx wp-env run tests-cli wp core multisite-convert --title='Distributor Multisite' + npx wp-env run tests-cli wp user create second 'second@admin.local' --user_pass=password --role=administrator + npx wp-env run tests-cli wp site create --slug=second --title='Second Site' --email='second@admin.local' + npx wp-env run tests-cli wp theme enable twentytwentyone --activate + npx wp-env run tests-cli wp theme enable twentytwentyone --url=localhost/second --activate + npx wp-env run tests-cli cp wp-content/plugins/distributor/tests/cypress/.htaccess .htaccess fi From 26480c1f42195a1b06a49fb983dbebb34b2c3141 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Thu, 4 Jul 2024 21:34:43 +0530 Subject: [PATCH 12/22] Convert all npm run to npx --- .github/workflows/cypress.yml | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index 65ef3ed29..20939439a 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -93,8 +93,8 @@ jobs: - name: Log WP environment versions run: | - npx wp-env run cli "wp core version" - npx wp-env run cli "php --version" + npx wp-env run cli wp core version + npx wp-env run cli php --version - name: Test run: npm run cypress:run diff --git a/package.json b/package.json index c66efaa2a..c512c5a3a 100644 --- a/package.json +++ b/package.json @@ -61,8 +61,8 @@ "env:start": "wp-env start", "env:stop": "wp-env stop", "env:destroy": "wp-env destroy", - "to-multisite": "wp-env run tests-cli \"wp core multisite-convert --title='Distributor Multisite'\"", - "copy-htaccess": "wp-env run tests-cli \"cp wp-content/plugins/distributor/tests/cypress/.htaccess .htaccess\"", + "to-multisite": "wp-env run tests-cli wp core multisite-convert --title='Distributor Multisite'", + "copy-htaccess": "wp-env run tests-cli cp wp-content/plugins/distributor/tests/cypress/.htaccess .htaccess", "postenv:start": "./tests/bin/initialize.sh" }, "files": [ From e31a1710c5314a621b6864f60ee0237a4140ec35 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:30:46 +0530 Subject: [PATCH 13/22] Add plugin version --- includes/utils.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/includes/utils.php b/includes/utils.php index b7bf9c51c..4251c5b5e 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -509,7 +509,7 @@ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { /** * Filter the taxonomy terms that should be synced. * - * @since x.x.x + * @since 2.0.5 * @hook dt_syncable_taxonomy_terms * * @param {array} $terms Array of terms. @@ -523,7 +523,7 @@ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { /** * Filter the terms that should be synced. * - * @since x.x.x + * @since 2.0.5 * @hook dt_syncable_terms * * @param {array} $terms Array of categories. @@ -562,7 +562,7 @@ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { /** * Filters the links in `$taxonomy` column of edit.php. * - * @since x.x.x + * @since 2.0.5 * @hook dt_taxonomy_links * * @param string[] $term_links Array of term editing links. @@ -582,7 +582,7 @@ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { * * The edit link is created in such a way that it will link to source site. * - * @since x.x.x + * @since 2.0.5 * * @param string[] $args Associative array of URL parameters for the link. * @param string $link_text Link text. From 4e8ed85951daf834eb2151c907907fc786697bc7 Mon Sep 17 00:00:00 2001 From: Kirtan Gajjar <8456197+kirtangajjar@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:46:05 +0530 Subject: [PATCH 14/22] Update filter doccomment --- includes/utils.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/includes/utils.php b/includes/utils.php index 4251c5b5e..43c88dca7 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -565,9 +565,11 @@ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { * @since 2.0.5 * @hook dt_taxonomy_links * - * @param string[] $term_links Array of term editing links. - * @param string $taxonomy Taxonomy name. - * @param WP_Term[] $terms Array of term objects appearing in the post row. + * @param {string[]} $term_links Array of term editing links. + * @param {string} $taxonomy Taxonomy name. + * @param {WP_Term[]} $terms Array of term objects appearing in the post row. + * + * @return {string[]} Array of term editing links. */ $term_links = apply_filters( 'dt_taxonomy_links', $term_links, $taxonomy, $terms ); From cbdf94f2769b35e873fd85ca87185157608a2ad0 Mon Sep 17 00:00:00 2001 From: Sanketio Date: Mon, 11 Aug 2025 15:47:43 +0530 Subject: [PATCH 15/22] Revert @since --- includes/classes/PullListTable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/classes/PullListTable.php b/includes/classes/PullListTable.php index 6cfa97196..ce770828d 100644 --- a/includes/classes/PullListTable.php +++ b/includes/classes/PullListTable.php @@ -273,7 +273,7 @@ public function column_categories( $post ) { * @param string $column_name Column name. * * @return string. - * @since 2.0.5 + * @since 0.8 */ public function column_default( $item, $column_name ) { if ( 'post_type' === $column_name ) { From f867c436cfc9618761fef0a5b8a7f3a6d26b4ef2 Mon Sep 17 00:00:00 2001 From: Sanketio Date: Mon, 11 Aug 2025 16:32:53 +0530 Subject: [PATCH 16/22] Fix category link for the connection --- includes/utils.php | 77 +++++++++------------------------------------- 1 file changed, 14 insertions(+), 63 deletions(-) diff --git a/includes/utils.php b/includes/utils.php index dba1ade23..e7d026a94 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -601,11 +601,21 @@ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { * @return string The formatted link string. */ function get_edit_link( $args, $link_text, $css_class = '' ) { + + global $connection_now; + + // Get the admin URL for the current connection. $url = ''; - if ( is_internal_connection() ) { - $url = add_query_arg( $args, get_admin_url( null, 'edit.php' ) ); - } else { - $url = add_query_arg( $args, trailingslashit( get_root_url() ) . 'wp-admin/edit.php' ); + if ( is_a( $connection_now, '\Distributor\InternalConnections\NetworkSiteConnection' ) ) { + $url = add_query_arg( $args, get_admin_url( $connection_now->site->blog_id, 'edit.php' ) ); + } elseif ( is_a( $connection_now, '\Distributor\ExternalConnection' ) && ! empty( $connection_now->base_url ) ) { + $base_url = str_replace( '/wp-json', '', $connection_now->base_url ); + $url = add_query_arg( $args, trailingslashit( $base_url ) . 'wp-admin/edit.php' ); + } + + // If the URL is empty, return an empty string. + if ( empty( $url ) ) { + return ''; } $class_html = ''; @@ -631,65 +641,6 @@ function get_edit_link( $args, $link_text, $css_class = '' ) { ); } -/** - * Is current connection an external connection? - * - * @since 2.0.5 - * - * @return boolean - */ -function is_external_connection() { - global $connection_now; - - return is_a( $connection_now, '\Distributor\ExternalConnection' ); -} - -/** - * Is current connection an internal connection? - * - * @since 2.0.5 - * - * @return boolean - */ -function is_internal_connection() { - global $connection_now; - - return is_a( $connection_now, '\Distributor\InternalConnections\NetworkSiteConnection' ); -} - -/** - * Get the root URL of the current connection - * - * @since 2.0.5 - * - * @return string - */ -function get_root_url() { - $base_url = get_conn_base_url(); - - return str_replace( '/wp-json', '', $base_url ); -} - -/** - * Get the base URL of the current connection - * - * @since 2.0.5 - * - * @return string - */ -function get_conn_base_url() { - if ( ! is_external_connection() ) { - return get_site_url(); - } - global $connection_now; - - if ( ! $connection_now || ! property_exists( $connection_now, 'base_url' ) ) { - return ''; - } - - return $connection_now->base_url; -} - /** * Format media items for consumption * From e41fd700930885b1e85b0524dd2d42f466782524 Mon Sep 17 00:00:00 2001 From: Sanketio Date: Tue, 12 Aug 2025 21:35:39 +0530 Subject: [PATCH 17/22] Allow taxonomy filter with remote site posts when pulling content --- assets/css/admin-pull-table.scss | 15 ++ assets/js/admin-pull.js | 85 ++++++- includes/classes/Connection.php | 16 ++ .../WordPressExternalConnection.php | 138 +++++++++++ .../NetworkSiteConnection.php | 56 +++++ includes/classes/PullListTable.php | 70 +++++- includes/pull-ui.php | 24 ++ includes/rest-api.php | 43 ++++ includes/utils.php | 230 +++++++++++++++++- 9 files changed, 671 insertions(+), 6 deletions(-) diff --git a/assets/css/admin-pull-table.scss b/assets/css/admin-pull-table.scss index a5d37a417..bb6ee71df 100644 --- a/assets/css/admin-pull-table.scss +++ b/assets/css/admin-pull-table.scss @@ -18,6 +18,21 @@ padding-left: 10px; } } + + .pull-taxonomy { + + &.hide { + display: none; + } + + &.show { + display: block; + } + } + + .dt-reset-filters-button { + margin-left: 6px + } } .wp-list-table .disabled { diff --git a/assets/js/admin-pull.js b/assets/js/admin-pull.js index 4488187a4..60cfa0c89 100755 --- a/assets/js/admin-pull.js +++ b/assets/js/admin-pull.js @@ -22,11 +22,13 @@ const escapeURLComponent = ( str ) => { const chooseConnection = document.getElementById( 'pull_connections' ); const choosePostType = document.getElementById( 'pull_post_type' ); const choosePostTypeBtn = document.getElementById( 'pull_post_type_submit' ); +const choosePostTypeReset = document.getElementById( 'pull_post_type_reset' ); const searchField = document.getElementById( 'post-search-input' ); const searchBtn = document.getElementById( 'search-submit' ); const form = document.getElementById( 'posts-filter' ); const asDraftCheckboxes = document.querySelectorAll( '[name=dt_as_draft]' ); const pullLinks = document.querySelectorAll( '.distributor_page_pull .pull a' ); +const pullTaxonomies = document.querySelectorAll( '.pull-taxonomy' ); jQuery( chooseConnection ).on( 'change', ( event ) => { const pullUrlId = @@ -39,6 +41,41 @@ jQuery( chooseConnection ).on( 'change', ( event ) => { } ); if ( chooseConnection && choosePostType && form ) { + /** + * When the post type is changed, show/hide the taxonomy fields based on the post type. + */ + jQuery( choosePostType ).on( 'change', ( event ) => { + const selectedPostType = + event.currentTarget.options[ event.currentTarget.selectedIndex ]; + if ( selectedPostType ) { + const dataTaxonomies = + selectedPostType.getAttribute( 'data-taxonomies' ); + if ( dataTaxonomies ) { + const supportedTaxonomies = JSON.parse( dataTaxonomies ); + if ( supportedTaxonomies.length > 0 ) { + pullTaxonomies.forEach( ( taxonomyField ) => { + if ( + supportedTaxonomies.includes( + taxonomyField.id.replace( 'pull_', '' ) + ) + ) { + jQuery( taxonomyField ).addClass( 'show' ); + jQuery( taxonomyField ).removeClass( 'hide' ); + } else { + jQuery( taxonomyField ).addClass( 'hide' ); + jQuery( taxonomyField ).removeClass( 'show' ); + } + } ); + } else { + pullTaxonomies.forEach( ( taxonomyField ) => { + jQuery( taxonomyField ).addClass( 'hide' ); + jQuery( taxonomyField ).removeClass( 'show' ); + } ); + } + } + } + } ); + if ( choosePostTypeBtn ) { jQuery( choosePostTypeBtn ).on( 'click', ( event ) => { event.preventDefault(); @@ -49,6 +86,35 @@ if ( chooseConnection && choosePostType && form ) { } ); } + /** + * When the reset filters button is clicked, reset the filters and reload the page. + */ + if ( choosePostTypeReset ) { + jQuery( choosePostTypeReset ).on( 'click', ( event ) => { + event.preventDefault(); + + const pullUrlId = escapeURLComponent( + chooseConnection.options[ + chooseConnection.selectedIndex + ].getAttribute( 'data-pull-url-id' ) + ); + + const baseURL = getPullUrl( pullUrlId ); + let status = 'new'; + + if ( -1 < ` ${ form.className } `.indexOf( ' status-skipped ' ) ) { + status = 'skipped'; + } else if ( + -1 < ` ${ form.className } `.indexOf( ' status-pulled ' ) + ) { + status = 'pulled'; + } + + document.location = `${ baseURL }&status=${ status }`; + document.body.className += ' ' + 'dt-loading'; + } ); + } + if ( searchField && searchBtn ) { jQuery( searchBtn ).on( 'click', ( event ) => { event.preventDefault(); @@ -99,6 +165,23 @@ const getURL = () => { const postType = escapeURLComponent( choosePostType.options[ choosePostType.selectedIndex ].value ); + + // Build the taxonomies query string. + let taxonomies = ''; + if ( pullTaxonomies ) { + pullTaxonomies.forEach( ( taxonomyField ) => { + if ( jQuery( taxonomyField ).hasClass( 'show' ) ) { + taxonomies += `${ taxonomyField.id }=${ + taxonomyField.options[ taxonomyField.selectedIndex ].value + }&`; + } + } ); + } + + if ( taxonomies ) { + taxonomies = taxonomies.slice( 0, -1 ); + } + const pullUrlId = escapeURLComponent( chooseConnection.options[ chooseConnection.selectedIndex ].getAttribute( 'data-pull-url-id' @@ -113,5 +196,5 @@ const getURL = () => { status = 'pulled'; } - return `${ baseURL }&pull_post_type=${ postType }&status=${ status }`; + return `${ baseURL }&pull_post_type=${ postType }&status=${ status }&${ taxonomies }`; }; diff --git a/includes/classes/Connection.php b/includes/classes/Connection.php index 9e22f5441..00e1e12f2 100644 --- a/includes/classes/Connection.php +++ b/includes/classes/Connection.php @@ -65,6 +65,22 @@ abstract public function get_sync_log( $id ); */ abstract public function get_post_types(); + /** + * Get available post type taxonomies from a connection + * + * @param string $post_type Post type. + * + * @return array + */ + abstract public function get_post_type_taxonomies( $post_type ); + + /** + * Get available taxonomy terms from a connection + * + * @return array + */ + abstract public function get_taxonomy_terms(); + /** * This method is called on every page load. It's helpful for canonicalization * diff --git a/includes/classes/ExternalConnections/WordPressExternalConnection.php b/includes/classes/ExternalConnections/WordPressExternalConnection.php index 75f3a7f0c..699412155 100644 --- a/includes/classes/ExternalConnections/WordPressExternalConnection.php +++ b/includes/classes/ExternalConnections/WordPressExternalConnection.php @@ -72,6 +72,20 @@ class WordPressExternalConnection extends ExternalConnection { */ public $pull_post_types; + /** + * Default taxonomy term to pull. + * + * @var string + */ + public $pull_taxonomy_term; + + /** + * Default taxonomy terms to show in filter. + * + * @var string + */ + public $pull_taxonomy_terms; + /** * This is a utility function for parsing annoying API link headers returned by the types endpoint * @@ -168,6 +182,11 @@ public function remote_get( $args = array() ) { } } + // Add the tax query to the query args. + if ( isset( $args['tax_query'] ) ) { + $query_args['tax_query'] = $args['tax_query']; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query + } + // When running a query for the Pull screen, make a POST request instead if ( empty( $id ) ) { $query_args['post_type'] = isset( $post_type ) ? $post_type : 'post'; @@ -682,6 +701,125 @@ public function get_post_types() { return $types_body_array; } + /** + * Get the available post type taxonomies. + * The taxonomies with external connection are already available in the post type object. + * + * @param string $post_type Post type. + * + * @return array + */ + public function get_post_type_taxonomies( $post_type ) { + return array(); + } + + /** + * Get the available taxonomies from the remote connection. + * + * @param array $taxonomies Taxonomies to get. + * + * @return array|\WP_Error Array of taxonomies with rest_base and label, or WP_Error if the request fails. + */ + private function get_remote_taxonomies( $taxonomies = array() ) { + + $path = self::$namespace; + + $taxonomies_path = untrailingslashit( $this->base_url ) . '/' . $path . '/taxonomies'; + + $taxonomies_response = Utils\remote_http_request( + $taxonomies_path, + $this->auth_handler->format_get_args( array( 'timeout' => self::$timeout ) ) + ); + + if ( is_wp_error( $taxonomies_response ) ) { + return $taxonomies_response; + } + + if ( 404 === wp_remote_retrieve_response_code( $taxonomies_response ) ) { + return new \WP_Error( 'bad-endpoint', esc_html__( 'Could not connect to API endpoint.', 'distributor' ) ); + } + + $taxonomies_body = wp_remote_retrieve_body( $taxonomies_response ); + + if ( empty( $taxonomies_body ) ) { + return new \WP_Error( 'no-response-body', esc_html__( 'Response body is empty.', 'distributor' ) ); + } + + $taxonomies_body_array = json_decode( $taxonomies_body, true ); + + $taxonomies_exists = array(); + foreach ( $taxonomies as $taxonomy ) { + if ( isset( $taxonomies_body_array[ $taxonomy ] ) ) { + $taxonomies_exists[ $taxonomy ] = array( + 'rest_base' => $taxonomies_body_array[ $taxonomy ]['rest_base'], + 'label' => $taxonomies_body_array[ $taxonomy ]['name'], + ); + } + } + + if ( empty( $taxonomies_exists ) ) { + return new \WP_Error( 'no-taxonomies', esc_html__( 'No taxonomies found.', 'distributor' ) ); + } + + return $taxonomies_exists; + } + + /** + * Get the available taxonomy terms. + * + * @param array $taxonomies Taxonomies to get terms for. + * + * @return array|\WP_Error Array of taxonomy terms with items and label, or WP_Error if the request fails. + */ + public function get_taxonomy_terms( $taxonomies = array() ) { + + // Get the remote taxonomies, if the request fails, return an empty array. + $remote_taxonomies = $this->get_remote_taxonomies( $taxonomies ); + if ( empty( $remote_taxonomies ) || is_wp_error( $remote_taxonomies ) ) { + return array(); + } + + $path = self::$namespace; + + $taxonomy_terms = array(); + + /** + * Loop through the remote taxonomies and get the terms for each taxonomy. + */ + foreach ( $remote_taxonomies as $taxonomy => $taxonomy_data ) { + + $taxonomy_path = untrailingslashit( $this->base_url ) . '/' . $path . '/' . $taxonomy_data['rest_base']; + + $taxonomy_response = Utils\remote_http_request( + $taxonomy_path, + $this->auth_handler->format_get_args( array( 'timeout' => self::$timeout ) ) + ); + + if ( is_wp_error( $taxonomy_response ) ) { + continue; + } + + if ( 404 === wp_remote_retrieve_response_code( $taxonomy_response ) ) { + continue; + } + + $taxonomy_body = wp_remote_retrieve_body( $taxonomy_response ); + + if ( empty( $taxonomy_body ) ) { + continue; + } + + $taxonomy_body_array = json_decode( $taxonomy_body, true ); + + $taxonomy_terms[ $taxonomy ] = array( + 'items' => $taxonomy_body_array, + 'label' => $taxonomy_data['label'], + ); + } + + return $taxonomy_terms; + } + /** * Check what we can do with a given external connection (push or pull) * diff --git a/includes/classes/InternalConnections/NetworkSiteConnection.php b/includes/classes/InternalConnections/NetworkSiteConnection.php index 12d5742d2..c7f90f40c 100644 --- a/includes/classes/InternalConnections/NetworkSiteConnection.php +++ b/includes/classes/InternalConnections/NetworkSiteConnection.php @@ -46,6 +46,20 @@ class NetworkSiteConnection extends Connection { */ public $pull_post_types; + /** + * Default taxonomy term to pull. + * + * @var string + */ + public $pull_taxonomy_term; + + /** + * Default taxonomy terms to show in filter. + * + * @var string + */ + public $pull_taxonomy_terms; + /** * Set up network site connection * @@ -520,6 +534,43 @@ public function get_post_types() { return $post_types; } + /** + * Get the available post type taxonomies. + * + * @param string $post_type Post type. + * + * @return array + */ + public function get_post_type_taxonomies( $post_type ) { + switch_to_blog( $this->site->blog_id ); + + $post_type_taxonomies = array(); + + $object_taxonomies = get_object_taxonomies( $post_type, 'objects' ); + foreach ( $object_taxonomies as $taxonomy_name => $taxonomy_object ) { + $post_type_taxonomies[ $taxonomy_name ] = $taxonomy_object->label; + } + + restore_current_blog(); + + return $post_type_taxonomies; + } + + /** + * Get the available taxonomy terms. + * + * @param array $taxonomies Taxonomies to get terms for. + * + * @return array|\WP_Error Array of taxonomy terms with items and label, or WP_Error if the request fails. + */ + public function get_taxonomy_terms( $taxonomies = array() ) { + switch_to_blog( $this->site->blog_id ); + $taxonomy_terms = Utils\distributable_taxonomy_terms( $taxonomies ); + restore_current_blog(); + + return $taxonomy_terms; + } + /** * Remotely get posts so we can list them for pulling * @@ -567,6 +618,11 @@ public function remote_get( $args = array(), $new_post_args = array() ) { $query_args['post__not_in'] = $args['post__not_in']; } + // Add the tax query to the query args. + if ( isset( $args['tax_query'] ) ) { + $query_args['tax_query'] = $args['tax_query']; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query + } + $query_args['post_type'] = ( empty( $args['post_type'] ) ) ? 'post' : $args['post_type']; $query_args['post_status'] = ( empty( $args['post_status'] ) ) ? [ 'publish', 'draft', 'private', 'pending', 'future' ] : $args['post_status']; $query_args['posts_per_page'] = ( empty( $args['posts_per_page'] ) ) ? get_option( 'posts_per_page' ) : $args['posts_per_page']; diff --git a/includes/classes/PullListTable.php b/includes/classes/PullListTable.php index ce770828d..1a72aaea2 100644 --- a/includes/classes/PullListTable.php +++ b/includes/classes/PullListTable.php @@ -480,6 +480,23 @@ public function prepare_items() { $remote_get_args['s'] = rawurlencode( $_GET['s'] ); // @codingStandardsIgnoreLine Nonce isn't required. } + // Add taxonomy filters to the remote get arguments. + if ( ! empty( $connection_now->pull_taxonomy_terms ) ) { + + foreach ( $connection_now->pull_taxonomy_terms as $taxonomy => $taxonomy_data ) { + + if ( 'all' === $connection_now->pull_taxonomy_term[ $taxonomy ] ) { + continue; + } + + $remote_get_args['tax_query'][] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query + 'taxonomy' => $taxonomy, + 'field' => 'slug', + 'terms' => $connection_now->pull_taxonomy_term[ $taxonomy ], + ); + } + } + if ( is_a( $connection_now, '\Distributor\ExternalConnection' ) ) { $this->sync_log = get_post_meta( $connection_now->id, 'dt_sync_log', true ); } else { @@ -626,6 +643,14 @@ public function get_bulk_actions() { * @param string $which Whether above or below the table. */ public function extra_tablenav( $which ) { + + /** + * This is to avoid the filter being displayed twice with the same HTML id. + */ + if ( 'bottom' === $which ) { + return; + } + global $connection_now; if ( is_a( $connection_now, '\Distributor\InternalConnections\NetworkSiteConnection' ) ) { @@ -634,6 +659,15 @@ public function extra_tablenav( $which ) { $connection_type = 'external'; } + // Check if there are any filters applied. + $has_filters = false; + foreach ( $connection_now->pull_taxonomy_term as $taxonomy => $selected_term ) { + if ( 'all' !== $selected_term ) { + $has_filters = true; + break; + } + } + if ( $connection_now && $connection_now->pull_post_types ) : ?> @@ -644,13 +678,47 @@ public function extra_tablenav( $which ) { pull_post_types as $post_type ) : ?> - + pull_taxonomy_terms ) ) : ?> + pull_taxonomy_terms as $taxonomy => $taxonomy_data ) : ?> + pull_post_type, $taxonomy_data['post_types'], true ) ) { + $toggle_class = 'hide'; + } + ?> + + + + + + + pull_post_types as $post_type ) { + $supported_taxonomies[ $post_type['slug'] ] = $post_type['taxonomies']; + } + + // Get the available taxonomy terms. + $connection_now->pull_taxonomy_term = []; + $connection_now->pull_taxonomy_terms = \Distributor\Utils\available_pull_taxonomy_terms( $connection_now, $connection_type, $supported_taxonomies ); + if ( ! empty( $connection_now->pull_taxonomy_terms ) ) { + + foreach ( $connection_now->pull_taxonomy_terms as $taxonomy => $taxonomy_data ) { + + $term_slugs = wp_list_pluck( $taxonomy_data['items'], 'slug' ); + + // Set the taxonomy term to pull. + if ( isset( $_GET["pull_{$taxonomy}"] ) && in_array( $_GET["pull_{$taxonomy}"], $term_slugs, true ) ) { + $connection_now->pull_taxonomy_term[ $taxonomy ] = $_GET["pull_{$taxonomy}"]; + } else { + $connection_now->pull_taxonomy_term[ $taxonomy ] = 'all'; + } + } + } ?> diff --git a/includes/rest-api.php b/includes/rest-api.php index 8d60a4f7c..9ae60d639 100644 --- a/includes/rest-api.php +++ b/includes/rest-api.php @@ -378,6 +378,44 @@ function( $post_type ) { 'title', ), ), + 'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query + 'description' => esc_html__( 'Filter posts by taxonomy terms.', 'distributor' ), + 'type' => 'array', + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'taxonomy' => array( + 'description' => esc_html__( 'Taxonomy name.', 'distributor' ), + 'type' => 'string', + ), + 'field' => array( + 'description' => esc_html__( 'Field to match terms by (slug, term_id, name).', 'distributor' ), + 'type' => 'string', + 'enum' => array( 'slug', 'term_id', 'name' ), + 'default' => 'slug', + ), + 'terms' => array( + 'description' => esc_html__( 'Term(s) to filter by.', 'distributor' ), + 'type' => array( 'array', 'string', 'integer' ), + 'items' => array( + 'type' => array( 'string', 'integer' ), + ), + ), + 'operator' => array( + 'description' => esc_html__( 'Taxonomy query operator.', 'distributor' ), + 'type' => 'string', + 'enum' => array( 'IN', 'NOT IN', 'AND', 'EXISTS', 'NOT EXISTS' ), + 'default' => 'IN', + ), + 'include_children' => array( + 'description' => esc_html__( 'Whether to include child terms.', 'distributor' ), + 'type' => 'boolean', + 'default' => true, + ), + ), + 'required' => array( 'taxonomy', 'terms' ), + ), + ), ); } @@ -669,6 +707,11 @@ function get_pull_content_list( $request ) { $args['orderby'] = 'relevance'; } + // Add the tax query to the query args. + if ( isset( $request['tax_query'] ) ) { + $args['tax_query'] = $request['tax_query']; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query + } + if ( ! empty( $request['exclude'] ) && ! empty( $request['include'] ) ) { /* * Use only `post__in` if both `include` and `exclude` are populated. diff --git a/includes/utils.php b/includes/utils.php index e7d026a94..eaa3e3c43 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -243,14 +243,51 @@ function available_pull_post_types( $connection, $type ) { return []; } - $local_post_types = array_diff_key( get_post_types( [ 'public' => true ], 'objects' ), array_flip( [ 'attachment', 'dt_ext_connection', 'dt_subscription' ] ) ); - $available_post_types = array_intersect_key( $remote_post_types, $local_post_types ); + // Get the local post types. + $local_post_types = array_diff_key( get_post_types( [ 'public' => true ], 'objects' ), array_flip( [ 'attachment', 'dt_ext_connection', 'dt_subscription' ] ) ); + + /** + * Loop through the remote post types and get the taxonomies for each post type. + * If the post type is not available on the local site, skip it. + */ + $available_post_types = array(); + foreach ( $remote_post_types as $post_type_slug => $post_type_data ) { + + // Skip if the post type is not available on the local site. + if ( empty( $local_post_types[ $post_type_slug ] ) ) { + continue; + } + + // Get the taxonomies for the post type. + if ( 'external' === $type ) { + $remote_post_type_taxonomies = $post_type_data['taxonomies']; + } else { + $remote_post_type_taxonomies = $connection->get_post_type_taxonomies( $post_type_slug ); + } + + // Update the post type data with the taxonomies. + $updated_post_type_data = $post_type_data; + + // If the post type has taxonomies, update the post type data with the taxonomies. + if ( ! empty( $remote_post_type_taxonomies ) ) { + + if ( 'external' === $type ) { + $updated_post_type_data['taxonomies'] = array_combine( $remote_post_type_taxonomies, $remote_post_type_taxonomies ); + } else { + $updated_post_type_data->taxonomies = $remote_post_type_taxonomies; + } + } + + // Add the post type data to the available post types array. + $available_post_types[ $post_type_slug ] = $updated_post_type_data; + } if ( ! empty( $available_post_types ) ) { foreach ( $available_post_types as $post_type ) { $post_types[] = array( - 'name' => 'external' === $type ? $post_type['name'] : $post_type->label, - 'slug' => 'external' === $type ? $post_type['slug'] : $post_type->name, + 'name' => 'external' === $type ? $post_type['name'] : $post_type->label, + 'slug' => 'external' === $type ? $post_type['slug'] : $post_type->name, + 'taxonomies' => 'external' === $type ? $post_type['taxonomies'] : $post_type->taxonomies, ); } } @@ -285,6 +322,128 @@ function available_pull_post_types( $connection, $type ) { return $post_types; } +/** + * Get the taxonomy terms that are available for pull. + * + * @param \Distributor\Connection $connection Connection object. + * @param string $type Connection type. + * @param array $supported_taxonomies Supported taxonomies. + * + * @return array Array of taxonomy terms. + */ +function available_pull_taxonomy_terms( $connection, $type, $supported_taxonomies ) { + + // Generate the taxonomy post type relation. + $taxonomy_post_type_relation = array(); + foreach ( $supported_taxonomies as $post_type => $taxonomies ) { + + foreach ( $taxonomies as $taxonomy_slug => $taxonomy_name ) { + + if ( isset( $taxonomy_post_type_relation[ $taxonomy_slug ] ) ) { + $taxonomy_post_type_relation[ $taxonomy_slug ][] = $post_type; + } else { + $taxonomy_post_type_relation[ $taxonomy_slug ] = array( $post_type ); + } + } + } + + /** + * Get the common supported taxonomies. + * Include all taxonomies from all post types. + */ + $common_supported_taxonomies = array(); + foreach ( $supported_taxonomies as $taxonomies ) { + $common_supported_taxonomies = array_merge( $common_supported_taxonomies, array_keys( $taxonomies ) ); + } + $common_supported_taxonomies = array_unique( $common_supported_taxonomies ); + + /** + * Filter the taxonomies that should be allowed to be pulled. + * + * @hook dt_allowed_pull_taxonomies + * + * @param {array} $allowed_taxonomies Array of allowed taxonomies. + * @param {array} $common_supported_taxonomies Array of common supported taxonomies from all post types. + * + * @return {array} Array of allowed taxonomies. + */ + $allowed_taxonomies = apply_filters( 'dt_allowed_pull_taxonomies', array( 'category' ), $common_supported_taxonomies ); + + // Return empty array, if no taxonomies are allowed to be pulled. + if ( empty( $allowed_taxonomies ) || ! is_array( $allowed_taxonomies ) ) { + return array(); + } + + // Remove taxonomies that are not supported by the remote site. + $allowed_taxonomies = array_intersect( $allowed_taxonomies, $common_supported_taxonomies ); + + // Get the taxonomy terms from the remote site. + $remote_taxonomy_terms = $connection->get_taxonomy_terms( $allowed_taxonomies ); + if ( empty( $remote_taxonomy_terms ) || is_wp_error( $remote_taxonomy_terms ) ) { + return array(); + } + + // Get the distributable taxonomy terms. + $distributable_taxonomy_terms = distributable_taxonomy_terms( $allowed_taxonomies, $remote_taxonomy_terms ); + + $taxonomy_terms = array(); + foreach ( $remote_taxonomy_terms as $taxonomy => $taxonomy_data ) { + + $taxonomy_terms[ $taxonomy ]['label'] = empty( $taxonomy_data['label'] ) ? '' : $taxonomy_data['label']; + + foreach ( $taxonomy_data['items'] as $term ) { + $taxonomy_terms[ $taxonomy ]['items'][] = array( + 'name' => 'external' === $type ? $term['name'] : $term->name, + 'slug' => 'external' === $type ? $term['slug'] : $term->slug, + ); + } + } + + /** + * Filter the taxonomy terms that should be available for pull. + * + * @param array $taxonomy_terms Taxonomy terms available for pull with name and slug. + * @param array $remote_taxonomy_terms Taxonomy terms available from the remote connection. + * @param Connection $connection Distributor connection object. + * @param string $type Distributor connection type. + * + * @return array Categories available for pull with name and slug. + */ + $pull_taxonomy_terms = apply_filters( 'dt_available_pull_taxonomy_terms', $taxonomy_terms, $remote_taxonomy_terms, $connection, $type ); + if ( empty( $pull_taxonomy_terms ) || ! is_array( $pull_taxonomy_terms ) ) { + return array(); + } + + $final_taxonomy_terms = array(); + + /** + * Loop through the pull taxonomy terms and add the distributable terms to the final taxonomy terms array. + * If the taxonomy or term is not distributable, skip it. + */ + foreach ( $pull_taxonomy_terms as $taxonomy => $taxonomy_data ) { + + // Skip if the taxonomy is not distributable. + if ( ! isset( $distributable_taxonomy_terms[ $taxonomy ] ) || empty( $distributable_taxonomy_terms[ $taxonomy ]['items'] ) ) { + continue; + } + + // Add the taxonomy label. + $final_taxonomy_terms[ $taxonomy ]['label'] = empty( $taxonomy_data['label'] ) ? '' : $taxonomy_data['label']; + + // Add the post types that support the taxonomy. + $final_taxonomy_terms[ $taxonomy ]['post_types'] = empty( $taxonomy_post_type_relation[ $taxonomy ] ) ? array() : $taxonomy_post_type_relation[ $taxonomy ]; + + // Skip if the term is not distributable. + foreach ( $taxonomy_data['items'] as $term ) { + if ( in_array( $term['slug'], $distributable_taxonomy_terms[ $taxonomy ]['items'], true ) ) { + $final_taxonomy_terms[ $taxonomy ]['items'][] = $term; + } + } + } + + return $final_taxonomy_terms; +} + /** * Return post types that are allowed to be distributed * @@ -332,6 +491,69 @@ function distributable_post_types( $output = 'names' ) { return $post_types; } +/** + * Get the distributable taxonomy terms. + * Loop through the taxonomies and get the terms. + * Filter the terms to only include the distributable terms. + * Return the terms. + * + * @param array $taxonomies Array of taxonomies. + * @param array $terms Array of terms. + * + * @return array Array of distributable taxonomy terms. + */ +function distributable_taxonomy_terms( $taxonomies = array(), $terms = array() ) { + + // Return empty array, if no taxonomies are provided. + if ( empty( $taxonomies ) ) { + return array(); + } + + $found_all_terms = array(); + + foreach ( $taxonomies as $taxonomy ) { + + // Get the terms, if the terms are not provided. + if ( empty( $terms[ $taxonomy ]['items'] ) ) { + $found_terms = get_terms( + array( + 'taxonomy' => $taxonomy, + 'hide_empty' => false, + ) + ); + } else { + $found_terms = wp_list_pluck( $terms[ $taxonomy ]['items'], 'slug' ); + } + + /** + * Filter the taxonomy terms that should be distributable. + * + * @hook distributable_{$taxonomy}_terms + * + * @param {array} $terms Array of terms. + * @param {string} $taxonomy Taxonomy name. + * + * @return {array} Array of terms. + */ + $found_terms = apply_filters( "distributable_{$taxonomy}_terms", $found_terms, $taxonomy ); + + // Skip if the terms are empty, a WP_Error, or not an array. + if ( empty( $found_terms ) || is_wp_error( $found_terms ) || ! is_array( $found_terms ) ) { + continue; + } + + // Get the taxonomy label. + $taxonomy_label = empty( $terms[ $taxonomy ]['label'] ) ? get_taxonomy( $taxonomy )->labels->name : $terms[ $taxonomy ]['label']; + + $found_all_terms[ $taxonomy ] = array( + 'items' => $found_terms, + 'label' => $taxonomy_label, + ); + } + + return $found_all_terms; +} + /** * Return post statuses that are allowed to be distributed. * From bd41e0a7cd9e6cd739997e0a79ade59d0da8e9a2 Mon Sep 17 00:00:00 2001 From: Sanket Parmar Date: Tue, 12 Aug 2025 21:39:40 +0530 Subject: [PATCH 18/22] Potential fix for code scanning alert no. 3: DOM text reinterpreted as HTML Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- assets/js/admin-pull.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/assets/js/admin-pull.js b/assets/js/admin-pull.js index 60cfa0c89..c142f9e86 100755 --- a/assets/js/admin-pull.js +++ b/assets/js/admin-pull.js @@ -172,7 +172,9 @@ const getURL = () => { pullTaxonomies.forEach( ( taxonomyField ) => { if ( jQuery( taxonomyField ).hasClass( 'show' ) ) { taxonomies += `${ taxonomyField.id }=${ - taxonomyField.options[ taxonomyField.selectedIndex ].value + escapeURLComponent( + taxonomyField.options[ taxonomyField.selectedIndex ].value + ) }&`; } } ); From 0947ec3ee6f76974661eea2e22f39c0c4cb28444 Mon Sep 17 00:00:00 2001 From: Sanketio Date: Tue, 12 Aug 2025 23:08:34 +0530 Subject: [PATCH 19/22] Dynamically add columns to the list table for the supported taxonomies --- assets/js/admin-pull.js | 8 ++-- includes/classes/PullListTable.php | 61 ++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/assets/js/admin-pull.js b/assets/js/admin-pull.js index c142f9e86..12bb16392 100755 --- a/assets/js/admin-pull.js +++ b/assets/js/admin-pull.js @@ -171,11 +171,9 @@ const getURL = () => { if ( pullTaxonomies ) { pullTaxonomies.forEach( ( taxonomyField ) => { if ( jQuery( taxonomyField ).hasClass( 'show' ) ) { - taxonomies += `${ taxonomyField.id }=${ - escapeURLComponent( - taxonomyField.options[ taxonomyField.selectedIndex ].value - ) - }&`; + taxonomies += `${ taxonomyField.id }=${ escapeURLComponent( + taxonomyField.options[ taxonomyField.selectedIndex ].value + ) }&`; } } ); } diff --git a/includes/classes/PullListTable.php b/includes/classes/PullListTable.php index 1a72aaea2..c3dae721c 100644 --- a/includes/classes/PullListTable.php +++ b/includes/classes/PullListTable.php @@ -55,14 +55,30 @@ public function __construct() { * @return array */ public function get_columns() { + + global $connection_now; + $columns = [ - 'cb' => '', - 'name' => esc_html__( 'Name', 'distributor' ), - 'post_type' => esc_html__( 'Post Type', 'distributor' ), - 'categories' => esc_html__( 'Categories', 'distributor' ), - 'date' => esc_html__( 'Date', 'distributor' ), + 'cb' => '', + 'name' => esc_html__( 'Name', 'distributor' ), + 'post_type' => esc_html__( 'Post Type', 'distributor' ), ]; + /** + * Dynamically add the taxonomies to the columns, only if the post type supports the taxonomy. + */ + if ( ! empty( $connection_now->pull_taxonomy_terms ) ) { + + foreach ( $connection_now->pull_taxonomy_terms as $taxonomy => $taxonomy_data ) { + + if ( ! empty( $taxonomy_data['post_types'] ) && in_array( $connection_now->pull_post_type, $taxonomy_data['post_types'], true ) ) { + $columns[ $taxonomy ] = $taxonomy_data['label']; + } + } + } + + $columns['date'] = esc_html__( 'Date', 'distributor' ); + /** * Filters the columns displayed in the pull list table. * @@ -250,22 +266,6 @@ public function column_date( $post ) { } } - /** - * Output categories column. - * - * @param \WP_Post $post Post object. - * @since 2.0.5 - */ - public function column_categories( $post ) { - $categories = $post->terms['category'] ?? []; - - if ( empty( $categories ) ) { - return; - } - - echo wp_kses_post( generate_taxonomy_links( 'category', $post, $categories ) ); - } - /** * Output standard table columns. * @@ -276,6 +276,9 @@ public function column_categories( $post ) { * @since 0.8 */ public function column_default( $item, $column_name ) { + + global $connection_now; + if ( 'post_type' === $column_name ) { $post_type = get_post_type_object( $item->post_type ); @@ -284,6 +287,22 @@ public function column_default( $item, $column_name ) { } } + // If the post type supports the taxonomy, output the taxonomy links. + if ( ! empty( $connection_now->pull_taxonomy_terms ) ) { + + foreach ( $connection_now->pull_taxonomy_terms as $taxonomy => $taxonomy_data ) { + + // If the post type does not support the taxonomy, skip it. + if ( empty( $taxonomy_data['post_types'] ) || ! in_array( $connection_now->pull_post_type, $taxonomy_data['post_types'], true ) ) { + continue; + } + + if ( $column_name === $taxonomy ) { + return wp_kses_post( generate_taxonomy_links( $taxonomy, $item, $item->terms[ $taxonomy ] ) ); + } + } + } + /** * Fires for each column in the pull list table. * From 49f4a33e17f4c85d2176374000caad27261f1fbd Mon Sep 17 00:00:00 2001 From: Sanketio Date: Wed, 13 Aug 2025 20:02:13 +0530 Subject: [PATCH 20/22] Toggle reset button when post type changes --- assets/css/admin-pull-table.scss | 3 ++- assets/js/admin-pull.js | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/assets/css/admin-pull-table.scss b/assets/css/admin-pull-table.scss index bb6ee71df..c4e968051 100644 --- a/assets/css/admin-pull-table.scss +++ b/assets/css/admin-pull-table.scss @@ -19,7 +19,8 @@ } } - .pull-taxonomy { + .pull-taxonomy, + .dt-reset-filters-button { &.hide { display: none; diff --git a/assets/js/admin-pull.js b/assets/js/admin-pull.js index 12bb16392..b0c5d5231 100755 --- a/assets/js/admin-pull.js +++ b/assets/js/admin-pull.js @@ -45,6 +45,7 @@ if ( chooseConnection && choosePostType && form ) { * When the post type is changed, show/hide the taxonomy fields based on the post type. */ jQuery( choosePostType ).on( 'change', ( event ) => { + let shouldHideResetFiltersButton = false; const selectedPostType = event.currentTarget.options[ event.currentTarget.selectedIndex ]; if ( selectedPostType ) { @@ -65,15 +66,35 @@ if ( chooseConnection && choosePostType && form ) { jQuery( taxonomyField ).addClass( 'hide' ); jQuery( taxonomyField ).removeClass( 'show' ); } + + if ( + ! shouldHideResetFiltersButton && + 'all' !== + taxonomyField.options[ + taxonomyField.selectedIndex + ].value + ) { + shouldHideResetFiltersButton = true; + } } ); } else { pullTaxonomies.forEach( ( taxonomyField ) => { jQuery( taxonomyField ).addClass( 'hide' ); jQuery( taxonomyField ).removeClass( 'show' ); } ); + + shouldHideResetFiltersButton = true; } } } + + if ( shouldHideResetFiltersButton ) { + jQuery( choosePostTypeReset ).addClass( 'hide' ); + jQuery( choosePostTypeReset ).removeClass( 'show' ); + } else { + jQuery( choosePostTypeReset ).addClass( 'show' ); + jQuery( choosePostTypeReset ).removeClass( 'hide' ); + } } ); if ( choosePostTypeBtn ) { From ffbafbc63bbd72ae86e6fbb4fb54f8878ce9d4ce Mon Sep 17 00:00:00 2001 From: Sanketio Date: Thu, 21 Aug 2025 18:37:38 +0530 Subject: [PATCH 21/22] Open taxonomy terms from the remote site in a new tab --- includes/utils.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/includes/utils.php b/includes/utils.php index eaa3e3c43..6709e402c 100644 --- a/includes/utils.php +++ b/includes/utils.php @@ -786,7 +786,7 @@ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { $label = esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) ); - $term_links[] = get_edit_link( $posts_in_term_qv, $label ); + $term_links[] = get_edit_link( $posts_in_term_qv, $label, '', true ); } /** @@ -816,13 +816,14 @@ function generate_taxonomy_links( $taxonomy, $post, $terms = [] ) { * * @since 2.0.5 * - * @param string[] $args Associative array of URL parameters for the link. - * @param string $link_text Link text. - * @param string $css_class Optional. Class attribute. Default empty string. + * @param string[] $args Associative array of URL parameters for the link. + * @param string $link_text Link text. + * @param string $css_class Optional. Class attribute. Default empty string. + * @param bool $should_open_in_new_tab Optional. Whether to open the link in a new tab. Default false. * * @return string The formatted link string. */ -function get_edit_link( $args, $link_text, $css_class = '' ) { +function get_edit_link( $args, $link_text, $css_class = '', $should_open_in_new_tab = false ) { global $connection_now; @@ -842,6 +843,7 @@ function get_edit_link( $args, $link_text, $css_class = '' ) { $class_html = ''; $aria_current = ''; + $target = ''; if ( ! empty( $css_class ) ) { $class_html = sprintf( @@ -854,11 +856,16 @@ function get_edit_link( $args, $link_text, $css_class = '' ) { } } + if ( $should_open_in_new_tab ) { + $target = ' target="_blank"'; + } + return sprintf( - '%s', + '%s', esc_url( $url ), $class_html, $aria_current, + $target, $link_text ); } From 8cafad18d0bc91878d8949693656d27183f4494a Mon Sep 17 00:00:00 2001 From: Sanketio Date: Fri, 5 Sep 2025 16:41:35 +0530 Subject: [PATCH 22/22] Add missing abstract methods for test cases --- tests/php/includes/common.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/php/includes/common.php b/tests/php/includes/common.php index ea3e10088..225ebcda7 100644 --- a/tests/php/includes/common.php +++ b/tests/php/includes/common.php @@ -358,6 +358,10 @@ public function check_connections() { } public function remote_get( $args ) { } public function get_post_types() { } + + public function get_post_type_taxonomies( $post_type ) { } + + public function get_taxonomy_terms() { } } class TestInternalConnection extends \Distributor\Connection { @@ -374,4 +378,8 @@ public function log_sync( array $item_id_mappings, $id, $overwrite ) {} public function get_sync_log( $id ) {} public function get_post_types() { } + + public function get_post_type_taxonomies( $post_type ) { } + + public function get_taxonomy_terms() { } }