Skip to content

Commit 3cb5fda

Browse files
committed
Admin updates
- Filter sections by product - Updated Sections meta to select a product - Parent dropdown includes the product name.
1 parent 96d4822 commit 3cb5fda

File tree

8 files changed

+510
-9
lines changed

8 files changed

+510
-9
lines changed

includes/admin/class-admin-columns.php

Lines changed: 154 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ public function __construct() {
3939
Hook_Registry::add_action( 'restrict_manage_posts', array( $this, 'add_product_filter_dropdown' ) );
4040
Hook_Registry::add_action( 'pre_get_posts', array( $this, 'filter_articles_by_product' ) );
4141

42+
// Register Product filter for Sections taxonomy screen.
43+
Hook_Registry::add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_sections_filter_script' ) );
44+
Hook_Registry::add_filter( 'terms_clauses', array( $this, 'filter_sections_by_product' ), 10, 2 );
45+
4246
// Add sorting.
4347
Hook_Registry::add_filter( 'terms_clauses', array( $this, 'sort_terms_by_product' ), 10, 2 );
4448
}
@@ -203,7 +207,7 @@ public function add_product_filter_dropdown() {
203207
}
204208

205209
/**
206-
* Apply Product filter to Articles admin query.
210+
* Filter articles by the product in the admin.
207211
*
208212
* @since 3.0.0
209213
*
@@ -244,4 +248,152 @@ public function filter_articles_by_product( $query ) {
244248

245249
$query->set( 'tax_query', $tax_query );
246250
}
247-
}
251+
252+
/**
253+
* Enqueue script for product filter on Sections taxonomy screen.
254+
*
255+
* @since 3.0.0
256+
*/
257+
public function enqueue_sections_filter_script() {
258+
$screen = get_current_screen();
259+
if ( ! $screen || 'edit-tags' !== $screen->base || 'wzkb_category' !== $screen->taxonomy ) {
260+
return;
261+
}
262+
263+
if ( ! current_user_can( 'manage_categories' ) ) {
264+
return;
265+
}
266+
267+
$products = get_terms(
268+
array(
269+
'taxonomy' => 'wzkb_product',
270+
'hide_empty' => false,
271+
'orderby' => 'name',
272+
'order' => 'ASC',
273+
)
274+
);
275+
276+
if ( empty( $products ) || is_wp_error( $products ) ) {
277+
return;
278+
}
279+
280+
// Format products data for JS.
281+
$products_data = array();
282+
foreach ( $products as $product ) {
283+
$products_data[] = array(
284+
'term_id' => $product->term_id,
285+
'name' => $product->name,
286+
);
287+
}
288+
289+
// Get current query parameters to preserve them.
290+
$query_params = array();
291+
// phpcs:disable WordPress.Security.NonceVerification.Recommended
292+
if ( ! empty( $_GET ) ) {
293+
foreach ( $_GET as $key => $value ) {
294+
if ( 'wzkb_product' !== $key ) {
295+
// Properly sanitize GET parameters based on expected types.
296+
$sanitized_key = sanitize_key( $key );
297+
298+
// Handle common WordPress admin parameters appropriately.
299+
switch ( $sanitized_key ) {
300+
case 'taxonomy':
301+
case 'post_type':
302+
case 'orderby':
303+
case 'order':
304+
$query_params[ $sanitized_key ] = sanitize_text_field( $value );
305+
break;
306+
307+
case 'page':
308+
case 'paged':
309+
$query_params[ $sanitized_key ] = absint( $value );
310+
break;
311+
312+
case 's': // Search term.
313+
$query_params[ $sanitized_key ] = sanitize_text_field( $value );
314+
break;
315+
316+
default:
317+
// For any other parameters, apply general sanitization.
318+
if ( is_array( $value ) ) {
319+
$query_params[ $sanitized_key ] = array_map( 'sanitize_text_field', $value );
320+
} else {
321+
$query_params[ $sanitized_key ] = sanitize_text_field( $value );
322+
}
323+
break;
324+
}
325+
}
326+
}
327+
}
328+
// phpcs:enable WordPress.Security.NonceVerification.Recommended
329+
330+
$selected = isset( $_GET['wzkb_product'] ) ? absint( $_GET['wzkb_product'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
331+
332+
// Register and enqueue script.
333+
$minimize = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
334+
wp_register_script(
335+
'wzkb-sections-product-filter',
336+
plugins_url( 'js/sections-product-filter' . $minimize . '.js', __FILE__ ),
337+
array( 'jquery' ),
338+
WZKB_VERSION,
339+
true
340+
);
341+
342+
wp_localize_script(
343+
'wzkb-sections-product-filter',
344+
'knowledgebaseProductFilter',
345+
array(
346+
'products' => $products_data,
347+
'selectedProduct' => $selected,
348+
'queryParams' => $query_params,
349+
'strings' => array(
350+
'allProducts' => __( 'All Products', 'knowledgebase' ),
351+
'filter' => __( 'Filter', 'knowledgebase' ),
352+
'productLabel' => __( 'Product:', 'knowledgebase' ),
353+
'searchPlaceholder' => __( 'Search sections...', 'knowledgebase' ),
354+
),
355+
)
356+
);
357+
358+
wp_enqueue_script( 'wzkb-sections-product-filter' );
359+
}
360+
361+
/**
362+
* Filter Sections by selected Product.
363+
*
364+
* @since 3.0.0
365+
*
366+
* @param array $pieces Array of query SQL clauses.
367+
* @param array $taxonomies Array of taxonomy names.
368+
* @return array Modified query SQL clauses.
369+
*/
370+
public function filter_sections_by_product( $pieces, $taxonomies ) {
371+
global $wpdb;
372+
373+
// Only run for wzkb_category taxonomy queries.
374+
if ( ! in_array( 'wzkb_category', $taxonomies, true ) ) {
375+
return $pieces;
376+
}
377+
378+
$screen = get_current_screen();
379+
if ( ! $screen || 'edit-tags' !== $screen->base || 'wzkb_category' !== $screen->taxonomy ) {
380+
return $pieces;
381+
}
382+
383+
if ( ! current_user_can( 'manage_categories' ) ) {
384+
return $pieces;
385+
}
386+
387+
if ( empty( $_GET['wzkb_product'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
388+
return $pieces;
389+
}
390+
391+
$product_id = absint( $_GET['wzkb_product'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
392+
if ( $product_id ) {
393+
$pieces['join'] .= " INNER JOIN {$wpdb->termmeta} AS tm ON t.term_id = tm.term_id ";
394+
$pieces['where'] .= $wpdb->prepare( " AND tm.meta_key = 'product_id' AND tm.meta_value = %d ", $product_id );
395+
}
396+
397+
return $pieces;
398+
}
399+
}

includes/admin/class-admin.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ class Admin {
7979
*/
8080
public $product_migrator;
8181

82+
/**
83+
* Section Product Meta class.
84+
*
85+
* @since 3.0.0
86+
*
87+
* @var object Section Product Meta class.
88+
*/
89+
public $section_product_meta;
90+
8291
/**
8392
* Main constructor class.
8493
*
@@ -88,12 +97,13 @@ public function __construct() {
8897
$this->hooks();
8998

9099
// Initialise admin classes.
91-
$this->settings = new Settings();
92-
$this->activator = new Activator();
93-
$this->cache = new Cache();
94-
$this->admin_columns = new Admin_Columns();
95-
$this->product_migrator = new Product_Migrator();
96-
$this->setup_wizard = new Setup_Wizard();
100+
$this->settings = new Settings();
101+
$this->activator = new Activator();
102+
$this->cache = new Cache();
103+
$this->admin_columns = new Admin_Columns();
104+
$this->section_product_meta = new Section_Product_Meta();
105+
$this->product_migrator = new Product_Migrator();
106+
$this->setup_wizard = new Setup_Wizard();
97107
}
98108

99109
/**
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
<?php
2+
/**
3+
* Admin Columns.
4+
*
5+
* @package WebberZone\Knowledge_Base
6+
*/
7+
8+
namespace WebberZone\Knowledge_Base\Admin;
9+
10+
use WebberZone\Knowledge_Base\Util\Hook_Registry;
11+
12+
// If this file is called directly, abort.
13+
if ( ! defined( 'WPINC' ) ) {
14+
die;
15+
}
16+
17+
/**
18+
* Section Product Meta class.
19+
*
20+
* @since 3.0.0
21+
*/
22+
class Section_Product_Meta {
23+
24+
/**
25+
* Main constructor class.
26+
*
27+
* @since 2.3.0
28+
*/
29+
public function __construct() {
30+
// Add product selector to section add/edit forms.
31+
Hook_Registry::add_action( 'wzkb_category_add_form_fields', array( $this, 'add_product_field' ) );
32+
Hook_Registry::add_action( 'wzkb_category_edit_form_fields', array( $this, 'edit_product_field' ), 10, 2 );
33+
34+
// Save product selection when adding/editing sections.
35+
Hook_Registry::add_action( 'created_wzkb_category', array( $this, 'save_product_meta' ), 10 );
36+
Hook_Registry::add_action( 'edited_wzkb_category', array( $this, 'save_product_meta' ), 10 );
37+
38+
// Enhance parent dropdown for sections.
39+
Hook_Registry::add_filter( 'taxonomy_parent_dropdown_args', array( $this, 'filter_parent_dropdown_args' ), 10, 2 );
40+
}
41+
42+
/**
43+
* Filter dropdown args to use custom walker for parent selection.
44+
*
45+
* @since 3.0.0
46+
* @param array $args Dropdown args.
47+
* @param string $taxonomy Taxonomy name.
48+
* @return array Modified args.
49+
*/
50+
public function filter_parent_dropdown_args( $args, $taxonomy ) {
51+
if ( 'wzkb_category' === $taxonomy ) {
52+
$args['walker'] = new Walker_Category_Dropdown();
53+
}
54+
return $args;
55+
}
56+
57+
/**
58+
* Add product dropdown field to add new section form.
59+
*
60+
* @since 3.0.0
61+
*/
62+
public function add_product_field() {
63+
// Only show in multi-product mode.
64+
if ( 0 === (int) wzkb_get_option( 'multi_product', 0 ) ) {
65+
return;
66+
}
67+
68+
// Get all products.
69+
$products = get_terms(
70+
array(
71+
'taxonomy' => 'wzkb_product',
72+
'hide_empty' => false,
73+
'orderby' => 'name',
74+
'order' => 'ASC',
75+
)
76+
);
77+
78+
if ( empty( $products ) || is_wp_error( $products ) ) {
79+
return;
80+
}
81+
?>
82+
<div class="form-field term-product-wrap">
83+
<label for="term-product"><?php esc_html_e( 'Product', 'knowledgebase' ); ?></label>
84+
<select name="term_product" id="term-product">
85+
<option value=""><?php esc_html_e( '— Select Product —', 'knowledgebase' ); ?></option>
86+
<?php
87+
foreach ( $products as $product ) {
88+
printf(
89+
'<option value="%d">%s</option>',
90+
absint( $product->term_id ),
91+
esc_html( $product->name )
92+
);
93+
}
94+
?>
95+
</select>
96+
<p class="description"><?php esc_html_e( 'Select the product this section belongs to.', 'knowledgebase' ); ?></p>
97+
</div>
98+
<?php
99+
}
100+
101+
/**
102+
* Add product dropdown field to edit section form.
103+
*
104+
* @since 3.0.0
105+
*
106+
* @param \WP_Term $term The term being edited.
107+
*/
108+
public function edit_product_field( $term ) {
109+
// Only show in multi-product mode.
110+
if ( 0 === (int) wzkb_get_option( 'multi_product', 0 ) ) {
111+
return;
112+
}
113+
114+
// Get all products.
115+
$products = get_terms(
116+
array(
117+
'taxonomy' => 'wzkb_product',
118+
'hide_empty' => false,
119+
'orderby' => 'name',
120+
'order' => 'ASC',
121+
)
122+
);
123+
124+
if ( empty( $products ) || is_wp_error( $products ) ) {
125+
return;
126+
}
127+
128+
// Get current product assignment.
129+
$product_id = get_term_meta( $term->term_id, 'product_id', true );
130+
?>
131+
<tr class="form-field term-product-wrap">
132+
<th scope="row"><label for="term-product"><?php esc_html_e( 'Product', 'knowledgebase' ); ?></label></th>
133+
<td>
134+
<select name="term_product" id="term-product">
135+
<option value=""><?php esc_html_e( '— Select Product —', 'knowledgebase' ); ?></option>
136+
<?php
137+
foreach ( $products as $product ) {
138+
printf(
139+
'<option value="%d" %s>%s</option>',
140+
absint( $product->term_id ),
141+
selected( $product_id, $product->term_id, false ),
142+
esc_html( $product->name )
143+
);
144+
}
145+
?>
146+
</select>
147+
<p class="description"><?php esc_html_e( 'Select the product this section belongs to.', 'knowledgebase' ); ?></p>
148+
</td>
149+
</tr>
150+
<?php
151+
}
152+
153+
/**
154+
* Save product assignment when section is added or edited.
155+
*
156+
* @since 3.0.0
157+
*
158+
* @param int $term_id Term ID.
159+
*/
160+
public function save_product_meta( $term_id ) {
161+
// Only process in multi-product mode.
162+
if ( 0 === (int) wzkb_get_option( 'multi_product', 0 ) ) {
163+
return;
164+
}
165+
166+
// Check if product field was submitted.
167+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
168+
if ( isset( $_POST['term_product'] ) ) {
169+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
170+
$product_id = sanitize_text_field( wp_unslash( $_POST['term_product'] ) );
171+
172+
// Update term meta if product is selected, otherwise delete it.
173+
if ( ! empty( $product_id ) ) {
174+
update_term_meta( $term_id, 'product_id', absint( $product_id ) );
175+
} else {
176+
delete_term_meta( $term_id, 'product_id' );
177+
}
178+
}
179+
}
180+
}

0 commit comments

Comments
 (0)