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() { }
}