Skip to content

Commit 9e67cc8

Browse files
authored
Merge pull request #61 from WebberZone/product-migrator
New product taxonomy feature
2 parents 805a0d3 + e60d2ba commit 9e67cc8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3512
-778
lines changed

includes/admin/class-admin-columns.php

Lines changed: 182 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
<?php
22
/**
3-
* Admin columns class
4-
*
5-
* @since 2.3.0
3+
* Admin Columns.
64
*
75
* @package WebberZone\Knowledge_Base
86
*/
@@ -15,7 +13,7 @@
1513
}
1614

1715
/**
18-
* Class to register the Better Search Admin Area.
16+
* Admin Columns class.
1917
*
2018
* @since 2.3.0
2119
*/
@@ -28,12 +26,19 @@ class Admin_Columns {
2826
*/
2927
public function __construct() {
3028
add_filter( 'manage_edit-wzkb_category_columns', array( $this, 'tax_columns' ) );
31-
add_filter( 'manage_edit-wzkb_category_sortable_columns', array( $this, 'tax_columns' ) );
29+
add_filter( 'manage_edit-wzkb_category_sortable_columns', array( $this, 'tax_sortable_columns' ) );
3230
add_filter( 'manage_edit-wzkb_tag_columns', array( $this, 'tax_columns' ) );
33-
add_filter( 'manage_edit-wzkb_tag_sortable_columns', array( $this, 'tax_columns' ) );
31+
add_filter( 'manage_edit-wzkb_tag_sortable_columns', array( $this, 'tax_sortable_columns' ) );
3432

3533
add_filter( 'manage_wzkb_category_custom_column', array( $this, 'tax_id' ), 10, 3 );
3634
add_filter( 'manage_wzkb_tag_custom_column', array( $this, 'tax_id' ), 10, 3 );
35+
36+
// Register Product filter for Articles admin screen.
37+
add_action( 'restrict_manage_posts', array( $this, 'add_product_filter_dropdown' ) );
38+
add_action( 'pre_get_posts', array( $this, 'filter_articles_by_product' ) );
39+
40+
// Add sorting.
41+
add_filter( 'terms_clauses', array( $this, 'sort_terms_by_product' ), 10, 2 );
3742
}
3843

3944
/**
@@ -45,19 +50,37 @@ public function __construct() {
4550
* @return array Updated columns.
4651
*/
4752
public static function tax_columns( $columns ) {
48-
4953
// Remove the description column.
5054
unset( $columns['description'] );
5155

5256
$new_columns = array(
5357
'tax_id' => 'ID',
5458
);
5559

60+
// Only add Product column for wzkb_category taxonomy.
61+
$screen = get_current_screen();
62+
if ( isset( $screen->taxonomy ) && 'wzkb_category' === $screen->taxonomy ) {
63+
$new_columns['product'] = __( 'Product', 'knowledgebase' );
64+
}
65+
5666
return array_merge( $columns, $new_columns );
5767
}
5868

5969
/**
60-
* Add taxonomy ID to the admin column.
70+
* Make the Product column sortable.
71+
*
72+
* @since 3.0.0
73+
*
74+
* @param array $columns Array of sortable columns.
75+
* @return array Modified array of sortable columns.
76+
*/
77+
public function tax_sortable_columns( $columns ) {
78+
$columns['product'] = 'product';
79+
return $columns;
80+
}
81+
82+
/**
83+
* Add taxonomy ID and Product to the admin column.
6184
*
6285
* @since 2.3.0
6386
*
@@ -67,6 +90,156 @@ public static function tax_columns( $columns ) {
6790
* @return int|string
6891
*/
6992
public static function tax_id( $value, $name, $id ) {
70-
return 'tax_id' === $name ? $id : $value;
93+
if ( 'tax_id' === $name ) {
94+
return $id;
95+
}
96+
if ( 'product' === $name ) {
97+
// Get linked product for this section.
98+
$product_id = get_term_meta( $id, 'product_id', true );
99+
if ( $product_id ) {
100+
$product = get_term( $product_id, 'wzkb_product' );
101+
if ( $product && ! is_wp_error( $product ) ) {
102+
return sprintf(
103+
'<a href="%s">%s</a>',
104+
esc_url( admin_url( 'edit.php?post_type=wz_knowledgebase&wzkb_product=' . $product->slug ) ),
105+
esc_html( $product->name )
106+
);
107+
}
108+
}
109+
return '&mdash;'; // Em dash if not linked.
110+
}
111+
return $value;
112+
}
113+
114+
/**
115+
* Sort wzkb_category terms by wzkb_product name.
116+
*
117+
* @since 3.0.0
118+
*
119+
* @param array $pieces Array of query SQL clauses.
120+
* @param array $taxonomies Array of taxonomy names.
121+
* @return array Modified clauses.
122+
*/
123+
public function sort_terms_by_product( $pieces, $taxonomies ) {
124+
global $wpdb;
125+
126+
// Only run for wzkb_category in admin.
127+
if ( ! is_admin() || ! in_array( 'wzkb_category', $taxonomies, true ) ) {
128+
return $pieces;
129+
}
130+
131+
// Check if sorting by product.
132+
$orderby = isset( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
133+
if ( 'product' !== $orderby ) {
134+
return $pieces;
135+
}
136+
137+
// Get sort order.
138+
$order = isset( $_GET['order'] ) ? strtoupper( sanitize_text_field( wp_unslash( $_GET['order'] ) ) ) : 'ASC'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
139+
$order = in_array( $order, array( 'ASC', 'DESC' ), true ) ? $order : 'ASC';
140+
141+
// Join with termmeta to get product_id.
142+
$pieces['join'] .= " LEFT JOIN {$wpdb->termmeta} AS tm ON t.term_id = tm.term_id AND tm.meta_key = 'product_id'";
143+
144+
// Join with terms and term_taxonomy to get wzkb_product name.
145+
$pieces['join'] .= " LEFT JOIN {$wpdb->terms} AS pt ON tm.meta_value = pt.term_id";
146+
$pieces['join'] .= " LEFT JOIN {$wpdb->term_taxonomy} AS ptt ON pt.term_id = ptt.term_id AND ptt.taxonomy = 'wzkb_product'";
147+
148+
// Set the ORDER BY clause with the "ORDER BY" prefix.
149+
$pieces['orderby'] = "ORDER BY COALESCE(pt.name, '') $order, t.name $order";
150+
151+
// Prevent WordPress from appending the order.
152+
$pieces['order'] = '';
153+
154+
return $pieces;
155+
}
156+
157+
/**
158+
* Add product filter dropdown to Knowledgebase admin screen.
159+
*
160+
* @since 3.0.0
161+
*/
162+
public function add_product_filter_dropdown() {
163+
global $pagenow;
164+
165+
// Only run on the edit.php page for wz_knowledgebase post type.
166+
if ( 'edit.php' !== $pagenow || ! isset( $_GET['post_type'] ) || 'wz_knowledgebase' !== $_GET['post_type'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
167+
return;
168+
}
169+
170+
// Get all wzkb_product terms.
171+
$terms = get_terms(
172+
array(
173+
'taxonomy' => 'wzkb_product',
174+
'hide_empty' => false,
175+
)
176+
);
177+
178+
if ( empty( $terms ) || is_wp_error( $terms ) ) {
179+
return;
180+
}
181+
182+
// Get the currently selected product filter.
183+
$selected = isset( $_GET['wzkb_product'] ) ? sanitize_text_field( wp_unslash( $_GET['wzkb_product'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
184+
185+
// Output the dropdown.
186+
?>
187+
<select name="wzkb_product" id="wzkb_product_filter">
188+
<option value=""><?php esc_html_e( 'All Products', 'knowledgebase' ); ?></option>
189+
<?php
190+
foreach ( $terms as $term ) {
191+
printf(
192+
'<option value="%s" %s>%s</option>',
193+
esc_attr( $term->slug ),
194+
selected( $selected, $term->slug, false ),
195+
esc_html( $term->name )
196+
);
197+
}
198+
?>
199+
</select>
200+
<?php
201+
}
202+
203+
/**
204+
* Apply Product filter to Articles admin query.
205+
*
206+
* @since 3.0.0
207+
*
208+
* @param \WP_Query $query The current WP_Query instance (passed by reference).
209+
*/
210+
public function filter_articles_by_product( $query ) {
211+
global $pagenow;
212+
213+
// Only run in admin post list, main query, and correct post type.
214+
if ( ! is_admin() || 'edit.php' !== $pagenow || ! $query->is_main_query() ) {
215+
return;
216+
}
217+
218+
$post_type = isset( $_GET['post_type'] ) ? sanitize_text_field( wp_unslash( $_GET['post_type'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
219+
if ( 'wz_knowledgebase' !== $post_type ) {
220+
return;
221+
}
222+
223+
// Get the product filter value.
224+
$product = isset( $_GET['wzkb_product'] ) ? sanitize_text_field( wp_unslash( $_GET['wzkb_product'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
225+
if ( empty( $product ) ) {
226+
return;
227+
}
228+
229+
// Ensure the taxonomy exists.
230+
if ( ! taxonomy_exists( 'wzkb_product' ) ) {
231+
return;
232+
}
233+
234+
// Add the tax query.
235+
$tax_query = array(
236+
array(
237+
'taxonomy' => 'wzkb_product',
238+
'field' => is_numeric( $product ) ? 'term_id' : 'slug',
239+
'terms' => is_numeric( $product ) ? absint( $product ) : $product,
240+
),
241+
);
242+
243+
$query->set( 'tax_query', $tax_query );
71244
}
72245
}

includes/admin/class-admin.php

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
namespace WebberZone\Knowledge_Base\Admin;
1111

1212
use WebberZone\Knowledge_Base\Util\Cache;
13-
use WebberZone\Knowledge_Base\Admin\Activator;
1413

1514
// If this file is called directly, abort.
1615
if ( ! defined( 'WPINC' ) ) {
@@ -60,6 +59,15 @@ class Admin {
6059
*/
6160
public $admin_columns;
6261

62+
/**
63+
* Product Migrator class.
64+
*
65+
* @since 3.0.0
66+
*
67+
* @var object Product Migrator class.
68+
*/
69+
public $product_migrator;
70+
6371
/**
6472
* Main constructor class.
6573
*
@@ -69,10 +77,11 @@ public function __construct() {
6977
$this->hooks();
7078

7179
// Initialise admin classes.
72-
$this->settings = new Settings\Settings();
73-
$this->activator = new Activator();
74-
$this->cache = new Cache();
75-
$this->admin_columns = new Admin_Columns();
80+
$this->settings = new Settings();
81+
$this->activator = new Activator();
82+
$this->cache = new Cache();
83+
$this->admin_columns = new Admin_Columns();
84+
$this->product_migrator = new Product_Migrator();
7685
}
7786

7887
/**
@@ -98,28 +107,36 @@ public function admin_enqueue_scripts() {
98107
$minimize = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
99108

100109
wp_register_script(
101-
'wzkb-admin-js',
102-
plugins_url( 'js/admin-scripts' . $minimize . '.js', __FILE__ ),
110+
'wzkb-admin',
111+
plugins_url( "js/admin-scripts{$minimize}.js", __FILE__ ),
103112
array( 'jquery', 'jquery-ui-tabs' ),
104113
WZKB_VERSION,
105114
true
106115
);
107116
wp_localize_script(
108-
'wzkb-admin-js',
109-
'wzkb_admin',
117+
'wzkb-admin',
118+
'WZKBAdminData',
110119
array(
111-
'nonce' => wp_create_nonce( 'wzkb_admin_nonce' ),
120+
'ajax_url' => admin_url( 'admin-ajax.php' ),
121+
'security' => wp_create_nonce( 'wzkb-admin' ),
122+
'strings' => array(
123+
'confirm_message' => esc_html__( 'Are you sure you want to clear the cache?', 'knowledgebase' ),
124+
'success_message' => esc_html__( 'Cache cleared successfully!', 'knowledgebase' ),
125+
'fail_message' => esc_html__( 'Failed to clear cache. Please try again.', 'knowledgebase' ),
126+
'request_fail_message' => esc_html__( 'Request failed: ', 'knowledgebase' ),
127+
),
112128
)
113129
);
130+
114131
wp_register_style(
115-
'wzkb-admin-ui-css',
116-
plugins_url( 'css/admin' . $minimize . '.css', __FILE__ ),
132+
'wzkb-admin-ui',
133+
plugins_url( "css/admin{$minimize}.css", __FILE__ ),
117134
array(),
118135
WZKB_VERSION
119136
);
120137

121138
if ( isset( $_GET['post_type'] ) && 'wz_knowledgebase' === $_GET['post_type'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
122-
wp_enqueue_style( 'wzkb-admin-ui-css' );
139+
wp_enqueue_style( 'wzkb-admin-ui' );
123140
}
124141
}
125142

@@ -129,23 +146,27 @@ public function admin_enqueue_scripts() {
129146
* @since 2.3.0
130147
*/
131148
public function admin_notices() {
132-
$kbslug = \wzkb_get_option( 'kb_slug', 'not-set-random-string' );
133-
$catslug = \wzkb_get_option( 'category_slug', 'not-set-random-string' );
134-
$tagslug = \wzkb_get_option( 'tag_slug', 'not-set-random-string' );
149+
$kb_slug = \wzkb_get_option( 'kb_slug', 'not-set-random-string' );
150+
$product_slug = \wzkb_get_option( 'product_slug', 'not-set-random-string' );
151+
$cat_slug = \wzkb_get_option( 'category_slug', 'not-set-random-string' );
152+
$tag_slug = \wzkb_get_option( 'tag_slug', 'not-set-random-string' );
135153

136154
// Only add the notice if the user is an admin.
137155
if ( ! current_user_can( 'manage_options' ) ) {
138156
return;
139157
}
140158

141159
// Only add the notice if the settings cannot be found.
142-
if ( 'not-set-random-string' === $kbslug || 'not-set-random-string' === $catslug || 'not-set-random-string' === $tagslug ) {
160+
if ( 'not-set-random-string' === $kb_slug || 'not-set-random-string' === $product_slug || 'not-set-random-string' === $cat_slug || 'not-set-random-string' === $tag_slug ) {
143161
?>
144162
<div class="updated">
145163
<p>
146164
<?php
147-
/* translators: 1. Link to admin page. */
148-
printf( __( 'Knowledge Base settings for the slug have not been registered. Please visit the <a href="%s">admin page</a> to update and save the options.', 'knowledgebase' ), esc_url( admin_url( 'edit.php?post_type=wz_knowledgebase&page=wzkb-settings' ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
165+
printf(
166+
/* translators: 1. Link to admin page. */
167+
esc_html__( 'Knowledge Base settings for the slug have not been registered. Please visit the <a href="%s">admin page</a> to update and save the options.', 'knowledgebase' ),
168+
esc_url( admin_url( 'edit.php?post_type=wz_knowledgebase&page=wzkb-settings' ) )
169+
);
149170
?>
150171
</p>
151172
</div>

0 commit comments

Comments
 (0)