PluginProbe ʕ •ᴥ•ʔ
AlphaListing / 4.5.0
AlphaListing v4.5.0
4.5.0 trunk 4.3.4 4.3.5 4.3.6 4.3.7 4.4.0
alphalisting / widgets / class-alphalisting-widget.php
alphalisting / widgets Last commit date
class-alphalisting-widget.php 2 weeks ago
class-alphalisting-widget.php
630 lines
1 <?php
2 /**
3 * Definition for the alphalisting's main widget
4 *
5 * @package alphalisting
6 */
7
8 declare(strict_types=1);
9
10 namespace eslin87\AlphaListing;
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 /**
17 * Definition for the AlphaListing_Widget which displays alphabetically-ordered list of latin letters linking to the AlphaListing page
18 *
19 * @since 0.1
20 */
21 class AlphaListing_Widget extends \WP_Widget {
22 /**
23 * Register the widget's meta information
24 *
25 * @since 0.1
26 * @param string $id_base Optional Base ID for the widget, lowercase and unique. If left empty,
27 * a portion of the widget's class name will be used Has to be unique.
28 * @param string $name Name for the widget displayed on the configuration page.
29 * @param array<string,mixed> $widget_options Optional. Widget options. See wp_register_sidebar_widget() for information
30 * on accepted arguments. Default empty array.
31 * @param array<string,mixed> $control_options Optional. Widget control options. See wp_register_widget_control() for
32 * information on accepted arguments. Default empty array.
33 */
34 public function __construct( $id_base = '', $name = '', $widget_options = array(), $control_options = array() ) {
35 $widget_options['classname'] = $widget_options['classname'] ?? 'alphalisting-widget';
36 $widget_options['description'] = $widget_options['description'] ?? __(
37 'Alphabetized links to the A-Z site map',
38 'alphalisting'
39 );
40
41 parent::__construct(
42 'alphalisting_az_widget',
43 __( 'A-Z Site Map', 'alphalisting' ),
44 $widget_options,
45 $control_options
46 );
47
48 add_action( 'admin_enqueue_scripts', 'alphalisting_enqueue_widget_admin_script' );
49 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_if_active' ) );
50 }
51
52 /**
53 * Enqueue scripts and stylesheets if the widget is active on the page
54 *
55 * @since 4.0.0
56 * @return void
57 */
58 public function enqueue_if_active() {
59 if ( false !== is_active_widget( false, false, $this->id_base, true ) ) {
60 alphalisting_do_enqueue();
61 }
62 }
63
64 /**
65 * Print-out the configuration form for the widget
66 *
67 * @since 0.1
68 * @param array<string,mixed> $instance Widget instance as provided by WordPress core.
69 * @return string
70 */
71 public function form( $instance ) {
72 $args = array(
73 'public' => true,
74 );
75
76 $public_post_types = get_post_types( $args, 'objects' );
77 $public_taxonomies = get_taxonomies( $args, 'objects' );
78
79 $widget_title = $instance['title'] ?? '';
80 $widget_title_id = $this->get_field_id( 'title' );
81 $widget_title_name = $this->get_field_name( 'title' );
82
83 $display_type = ( isset( $instance['type'] ) && 'terms' === $instance['type'] ) ? 'terms' : 'posts';
84 $display_type_id = $this->get_field_id( 'type' );
85 $display_type_name = $this->get_field_name( 'type' );
86
87 $target_post = isset( $instance['post'] ) ? intval( $instance['post'] ) : ( ( isset( $instance['page'] ) ? intval( $instance['page'] ) : 0 ) );
88 $target_post_id = $this->get_field_id( 'post' );
89 $target_post_name = $this->get_field_name( 'post' );
90 $target_post_title = isset( $instance['target_post'] ) ? $instance['target_post'] : ( ( 0 < $target_post ) ? get_the_title( $target_post ) : '' );
91 $target_post_title_id = $this->get_field_id( 'target_post_title' );
92 $target_post_title_name = $this->get_field_name( 'target_post_title' );
93
94 $listing_post_type = $instance['post_type'] ?? 'page';
95 $listing_post_type_id = $this->get_field_id( 'post_type' );
96 $listing_post_type_name = $this->get_field_name( 'post_type' );
97
98 $listing_parent_post = $instance['parent_post'] ?? '';
99 $listing_parent_post_id = $this->get_field_id( 'parent_post' );
100 $listing_parent_post_name = $this->get_field_name( 'parent_post' );
101 $listing_parent_post_title = isset( $instance['parent_post_title'] ) ? $instance['parent_post_title'] : ( ( 0 < $listing_parent_post ) ? get_the_title( $listing_parent_post ) : '' );
102 $listing_parent_post_title_id = $this->get_field_id( 'parent_post_title' );
103 $listing_parent_post_title_name = $this->get_field_name( 'parent_post_title' );
104
105 $listing_all_children = $instance['all_children'] ?? 'true';
106 $listing_all_children_id = $this->get_field_id( 'all_children' );
107 $listing_all_children_name = $this->get_field_name( 'all_children' );
108
109 $listing_taxonomy = $instance['taxonomy'] ?? 'page';
110 $listing_taxonomy_id = $this->get_field_id( 'taxonomy' );
111 $listing_taxonomy_name = $this->get_field_name( 'taxonomy' );
112
113 $listing_parent_term = $instance['parent_term'] ?? '';
114 $listing_parent_term_id = $this->get_field_id( 'parent_term' );
115 $listing_parent_term_name = $this->get_field_name( 'parent_term' );
116
117 $listing_terms_include = $instance['terms'] ?? '';
118 $listing_terms_include_id = $this->get_field_id( 'terms' );
119 $listing_terms_include_name = $this->get_field_name( 'terms' );
120
121 $listing_terms_exclude = $instance['exclude_terms'] ?? ( $instance['terms_exclude'] ?? '' );
122 $listing_terms_exclude_id = $this->get_field_id( 'exclude_terms' );
123 $listing_terms_exclude_name = $this->get_field_name( 'exclude_terms' );
124
125 $listing_hide_empty_terms = $instance['hide_empty_terms'] ?? '';
126 $listing_hide_empty_terms_id = $this->get_field_id( 'hide_empty_terms' );
127 $listing_hide_empty_terms_name = $this->get_field_name( 'hide_empty_terms' );
128 ?>
129
130 <div class="alphalisting-widget">
131 <?php wp_nonce_field( 'posts-by-title', '_posts_by_title_wpnonce', false, true ); ?>
132 <div class="alphalisting-widget-title-wrapper">
133 <p>
134 <label for="<?php echo esc_attr( $widget_title_id ); ?>">
135 <?php esc_html_e( 'Widget Title', 'alphalisting' ); ?>
136 </label>
137 <input type="text" class="widefat alphalisting-title"
138 id="<?php echo esc_attr( $widget_title_id ); ?>"
139 name="<?php echo esc_attr( $widget_title_name ); ?>"
140 placeholder="<?php esc_attr_e( 'Widget Title', 'alphalisting' ); ?>"
141 value="<?php echo esc_attr( $widget_title ); ?>" />
142 </p>
143 <p style="color: #333;">
144 <?php esc_html_e( 'Leave the title field blank, above, to use the title from the page set in the next field', 'alphalisting' ); ?>
145 </p>
146 </div>
147
148 <div class="alphalisting-target-post-wrapper">
149 <p>
150 <label for="<?php echo esc_attr( $target_post_title_id ); ?>">
151 <?php esc_html_e( 'Sitemap A-Z page', 'alphalisting' ); ?>
152 </label>
153 <input type="text" class="widefat alphalisting-target-post-title"
154 id="<?php echo esc_attr( $target_post_title_id ); ?>"
155 name="<?php echo esc_attr( $target_post_title_name ); ?>"
156 value="<?php echo esc_attr( $target_post_title ); ?>" />
157 <input type="hidden"
158 id="<?php echo esc_attr( $target_post_id ); ?>"
159 name="<?php echo esc_attr( $target_post_name ); ?>"
160 value="<?php echo esc_attr( $target_post ); ?>" />
161 </p>
162 <p>
163 <?php esc_html_e( 'Type some or all of the title of the page you want links to point at. Ensure this input field is not selected when you save the settings.', 'alphalisting' ); ?>
164 <?php esc_html_e( 'Matching posts will be shown as you type. Click on the correct post from the matches to update the setting.', 'alphalisting' ); ?>
165 </p>
166 </div>
167
168 <div class="alphalisting-display-type-wrapper">
169 <p>
170 <label for="<?php echo esc_attr( $display_type_id ); ?>">
171 <?php esc_html_e( 'Display posts or terms?', 'alphalisting' ); ?>
172 </label>
173 <select class="widefat alphalisting-display-type"
174 id="<?php echo esc_attr( $display_type_id ); ?>"
175 name="<?php echo esc_attr( $display_type_name ); ?>">
176 <option value="posts"
177 <?php echo ( 'terms' !== $display_type ) ? 'selected' : ''; ?>>
178 <?php esc_html_e( 'Posts', 'alphalisting' ); ?>
179 </option>
180 <option value="terms"
181 <?php echo ( 'terms' === $display_type ) ? 'selected' : ''; ?>>
182 <?php esc_html_e( 'Taxonomy terms', 'alphalisting' ); ?>
183 </option>
184 </select>
185 </p>
186 </div>
187
188 <div class="alphalisting-post-type-wrapper" <?php echo ( 'terms' !== $display_type ) ? '' : 'style="display: none;"'; ?>>
189 <p>
190 <label for="<?php echo esc_attr( $listing_post_type_id ); ?>">
191 <?php esc_html_e( 'Post-type to display', 'alphalisting' ); ?>
192 </label>
193 <select class="widefat alphalisting-post-type"
194 id="<?php echo esc_attr( $listing_post_type_id ); ?>"
195 name="<?php echo esc_attr( $listing_post_type_name ); ?>"
196 <?php echo ( 'terms' !== $display_type ) ? '' : 'disabled'; ?>>
197 <?php foreach ( $public_post_types as $k => $t ) : ?>
198 <option value="<?php echo esc_attr( $k ); ?>"
199 <?php echo ( $k === $listing_post_type ) ? 'selected' : ''; ?>>
200 <?php echo esc_html( $t->labels->name ); ?>
201 </option>
202 <?php endforeach; ?>
203 </select>
204 </p>
205 </div>
206
207 <div class="alphalisting-parent-post-wrapper" <?php echo ( 'terms' !== $display_type ) ? '' : 'style="display: none"'; ?>>
208 <p>
209 <label for="<?php echo esc_attr( $listing_parent_post_title_id ); ?>">
210 <?php esc_html_e( 'Show only children of this post (ID)', 'alphalisting' ); ?>
211 </label>
212 <input type="text" class="widefat alphalisting-parent-post-title"
213 id="<?php echo esc_attr( $listing_parent_post_title_id ); ?>"
214 name="<?php echo esc_attr( $listing_parent_post_title_name ); ?>"
215 <?php echo ( 'terms' !== $display_type ) ? '' : 'disabled'; ?>
216 value="<?php echo esc_attr( $listing_parent_post_title ); ?>" />
217 <input type="hidden"
218 id="<?php echo esc_attr( $listing_parent_post_id ); ?>"
219 name="<?php echo esc_attr( $listing_parent_post_name ); ?>"
220 value="<?php echo esc_attr( $listing_parent_post ); ?>" />
221 </p>
222 <p>
223 <?php esc_html_e( 'Type some or all of the title of the post to limit the listing to only the children of that post. Ensure this input field is not selected when you save the settings.', 'alphalisting' ); ?>
224 <?php esc_html_e( 'Matching posts will be shown as you type. Click on the correct post from the matches to update the setting.', 'alphalisting' ); ?>
225 </p>
226 <p>
227 <label for="<?php echo esc_attr( $listing_all_children_id ); ?>">
228 <?php esc_html_e( 'Include grand-children?', 'alphalisting' ); ?>
229 </label>
230 <input type="checkbox" class="alphalisting-all-children"
231 id="<?php echo esc_attr( $listing_all_children_id ); ?>"
232 name="<?php echo esc_attr( $listing_all_children_name ); ?>"
233 <?php echo ( isset( $listing_all_children ) && 'true' === $listing_all_children ) ? 'checked' : ''; ?> />
234 </p>
235 </div>
236
237 <div class="alphalisting-taxonomy-wrapper" <?php echo ( 'terms' === $display_type ) ? '' : 'style="display: none;"'; ?>>
238 <p>
239 <label for="<?php echo esc_attr( $listing_taxonomy_id ); ?>">
240 <?php esc_html_e( 'Taxonomy to display', 'alphalisting' ); ?>
241 </label>
242 <select class="widefat alphalisting-taxonomy"
243 id="<?php echo esc_attr( $listing_taxonomy_id ); ?>"
244 name="<?php echo esc_attr( $listing_taxonomy_name ); ?>"
245 <?php echo ( 'terms' === $display_type ) ? '' : 'disabled'; ?>>
246 <?php foreach ( $public_taxonomies as $k => $t ) : ?>
247 <option value="<?php echo esc_attr( $k ); ?>"
248 <?php echo ( $k === $listing_taxonomy ) ? 'selected' : ''; ?>>
249 <?php echo esc_html( $t->labels->name ); ?>
250 </option>
251 <?php endforeach; ?>
252 </select>
253 </p>
254 </div>
255
256 <div class="alphalisting-parent-term-wrapper" <?php echo ( 'terms' === $display_type ) ? '' : 'style="display: none;"'; ?>>
257 <p>
258 <label for="<?php echo esc_attr( $listing_parent_term_id ); ?>">
259 <?php esc_html_e( 'Parent term to display children of', 'alphalisting' ); ?>
260 </label>
261 <input type="text" class="widefat alphalisting-parent-term"
262 id="<?php echo esc_attr( $listing_parent_term_id ); ?>"
263 name="<?php echo esc_attr( $listing_parent_term_name ); ?>"
264 value="<?php echo esc_attr( $listing_parent_term ); ?>" />
265 </p>
266 </div>
267
268 <div class="alphalisting-include-terms-wrapper">
269 <p>
270 <label for="<?php echo esc_attr( $listing_terms_include_id ); ?>">
271 <?php esc_html_e( 'Terms to include (IDs)', 'alphalisting' ); ?>
272 </label>
273 <input type="text" class="widefat alphalisting-include-terms"
274 id="<?php echo esc_attr( $listing_terms_include_id ); ?>"
275 name="<?php echo esc_attr( $listing_terms_include_name ); ?>"
276 value="<?php echo esc_attr( $listing_terms_include ); ?>" />
277 </p>
278 </div>
279
280 <div class="alphalisting-exclude-terms-wrapper" <?php echo ( 'terms' === $display_type ) ? '' : 'style="display: none;"'; ?>>
281 <p>
282 <label for="<?php echo esc_attr( $listing_terms_exclude_id ); ?>">
283 <?php esc_html_e( 'Terms to exclude (IDs)', 'alphalisting' ); ?>
284 </label>
285 <input type="text" class="widefat alphalisting-exclude-terms"
286 id="<?php echo esc_attr( $listing_terms_exclude_id ); ?>"
287 name="<?php echo esc_attr( $listing_terms_exclude_name ); ?>"
288 value="<?php echo esc_attr( $listing_terms_exclude ); ?>" />
289 </p>
290 </div>
291
292 <div class="alphalisting-hide-empty-terms-wrapper" <?php echo ( 'terms' === $display_type ) ? '' : 'style="display: none;"'; ?>>
293 <p>
294 <label for="<?php echo esc_attr( $listing_hide_empty_terms_id ); ?>">
295 <?php esc_html_e( 'Hide empty terms', 'alphalisting' ); ?>
296 </label>
297 <input type="checkbox" class="alphalisting-hide-empty-terms"
298 id="<?php echo esc_attr( $listing_hide_empty_terms_id ); ?>"
299 name="<?php echo esc_attr( $listing_hide_empty_terms_name ); ?>"
300 <?php echo ( isset( $listing_hide_empty_terms ) && 'true' === $listing_hide_empty_terms ) ? 'checked' : ''; ?> />
301 </p>
302 </div>
303 </div>
304 <?php
305 return '';
306 }
307
308 /**
309 * Called by WordPress core. Sanitizes changes to the Widget's configuration
310 *
311 * @since 0.1
312 * @param array<string,mixed> $new_instance the new configuration values.
313 * @param array<string,mixed> $old_instance the previous configuration values.
314 * @return array<string,mixed> sanitized version of the new configuration values to be saved
315 */
316 public function update( $new_instance, $old_instance ) {
317 $instance = $old_instance;
318
319 $target_post_title = wp_strip_all_tags( $new_instance['target_post_title'] ?? '' );
320 $parent_post_title = wp_strip_all_tags( $new_instance['parent_post_title'] ?? '' );
321 $all_children_input = $new_instance['all_children'] ?? '';
322 $hide_empty_input = $new_instance['hide_empty_terms'] ?? '';
323
324 // The field was historically named `terms_exclude` in form(); read it as a
325 // fallback so values stored under the old key survive an upgrade.
326 $exclude_terms_input = $new_instance['exclude_terms'] ?? ( $new_instance['terms_exclude'] ?? '' );
327
328 $instance['title'] = wp_strip_all_tags( $new_instance['title'] ?? '' );
329 $instance['type'] = wp_strip_all_tags( $new_instance['type'] ?? '' );
330 $instance['post'] = (int) ( $new_instance['post'] ?? 0 ); // target.
331 $instance['target_post_title'] = $target_post_title;
332 $instance['post_type'] = wp_strip_all_tags( $new_instance['post_type'] ?? '' );
333 $instance['taxonomy'] = wp_strip_all_tags( $new_instance['taxonomy'] ?? '' );
334 $instance['parent_post'] = (int) ( $new_instance['parent_post'] ?? 0 );
335 $instance['all_children'] = 'on' === $all_children_input ? 'true' : 'false';
336 $instance['parent_term'] = wp_strip_all_tags( $new_instance['parent_term'] ?? '' );
337 $instance['terms'] = wp_strip_all_tags( $new_instance['terms'] ?? '' );
338 $instance['exclude_terms'] = wp_strip_all_tags( $exclude_terms_input );
339 $instance['hide_empty_terms'] = 'on' === $hide_empty_input ? 'true' : 'false';
340
341 if ( '' === $target_post_title ) {
342 $instance['post'] = 0;
343 }
344
345 if ( '' === $parent_post_title ) {
346 $instance['parent_post'] = 0;
347 }
348
349 return $instance;
350 }
351
352 /**
353 * Print the user-visible widget to the page
354 *
355 * @since 0.1
356 * @param array<string,mixed> $args General widget configuration. Often shared between all widgets on the site.
357 * @param array<string,mixed> $instance Configuration of this Widget. Unique to this invocation.
358 * @return void
359 */
360 public function widget( $args, $instance ) {
361 the_section_a_z_widget( $args, $instance );
362 }
363 }
364
365 /**
366 * Print the user-visible widget to the page implementation
367 *
368 * @since 0.1
369 * @since 0.8.0 deprecated.
370 * @see A_Z_Widget::the_section_a_z_widget()
371 * @deprecated use the_section_a_z_widget()
372 * @param array<string,mixed> $args General widget configuration. Often shared between all widgets on the site.
373 * @param array<string,mixed> $instance Configuration of this Widget. Unique to this invocation.
374 * @return void
375 */
376 function the_section_az_widget( array $args, array $instance ) {
377 _deprecated_function( __FUNCTION__, '0.8.0', 'the_section_a_z_widget' );
378 the_section_a_z_widget( $args, $instance );
379 }
380
381 /**
382 * Print the user-visible widget to the page implementation
383 *
384 * @since 0.8.0
385 * @param array<string,mixed> $args General widget configuration. Often shared between all widgets on the site.
386 * @param array<string,mixed> $instance Configuration of this Widget. Unique to this invocation.
387 * @return void
388 */
389 function the_section_a_z_widget( array $args, array $instance ) { //phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
390 echo get_the_section_a_z_widget( $args, $instance ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
391 }
392
393 /**
394 * Deprecated print the user-visible widget to the page implementation.
395 *
396 * @since 0.1
397 * @since 0.8.0 deprecated.
398 * @see A_Z_Widget::get_the_section_a_z_widget()
399 * @deprecated use get_the_section_a_z_widget()
400 * @param array<string,mixed> $args General widget configuration. Often shared between all widgets on the site.
401 * @param array<string,mixed> $instance Configuration of this Widget. Unique to this invocation.
402 * @return string The complete A-Z Widget HTML ready for echoing to the page.
403 */
404 function get_the_section_az_widget( array $args, array $instance ): string {
405 _deprecated_function( __FUNCTION__, '0.8.0', 'get_the_section_a_z_widget' );
406 return get_the_section_a_z_widget( $args, $instance );
407 }
408
409 /**
410 * Get the user-visible widget html
411 *
412 * @since 0.8.0
413 * @param array<string,mixed> $args General widget configuration. Often shared between all widgets on the site.
414 * @param array<string,mixed> $instance Configuration of this Widget. Unique to this invocation.
415 * @return string The complete A-Z Widget HTML ready for echoing to the page.
416 */
417 function get_the_section_a_z_widget( array $args, array $instance ): string { //phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
418 do_action( 'alphalisting_log', 'AlphaListing: Running widget' );
419
420 $instance = wp_parse_args(
421 $instance,
422 array(
423 'all_children' => 'true',
424 'exclude_terms' => '',
425 'hide_empty_terms' => false,
426 'parent_post' => '',
427 'parent_term' => '',
428 'post' => -1, // target.
429 'page' => -1, // obsolete target.
430 'post_type' => 'page',
431 'taxonomy' => '',
432 'terms' => '',
433 'title' => '',
434 'type' => 'posts',
435 )
436 );
437
438 $title = esc_html( $instance['title'] );
439 $target_url = '';
440 if ( 0 < $instance['post'] || 0 < $instance['page'] ) { // target.
441 $target_id = (int) $instance['post']; // target.
442 if ( ! ( 0 < $instance['post'] ) ) {
443 $target_id = (int) $instance['page']; // obsolete target.
444 }
445
446 $target_url = get_the_permalink( $target_id );
447 if ( empty( $title ) ) {
448 $title = get_the_title( $target_id );
449 }
450 } elseif ( empty( $title ) ) {
451 $title = esc_html__( 'A-Z Site Map', 'alphalisting' );
452 }
453
454 // `update()` stores this as the string 'true'/'false' while `wp_parse_args()`
455 // above defaults it to a boolean, so compare truthiness rather than identity.
456 $hide_empty_terms = alphalisting_is_truthy( $instance['hide_empty_terms'] ) ? 'true' : 'false';
457
458 $ret = '';
459 $ret .= $args['before_widget'];
460 $ret .= '<div class="alphalisting-widget widget">';
461
462 $ret .= $args['before_title'];
463 $ret .= $title;
464 $ret .= $args['after_title'];
465
466 /*
467 * Pass the attributes to the shortcode handler directly rather than building a
468 * `[alphalisting ...]` string. Interpolating stored widget values into shortcode
469 * syntax is unsafe -- a `'` closes the attribute early and a `]` terminates the
470 * shortcode, letting following text be parsed as new shortcodes -- and no escaper
471 * covers both characters. This is the same mechanism GutenBlock::render() uses,
472 * so the widget, block, and shortcode all share one render path.
473 */
474 $attributes = array(
475 'alphabet' => '',
476 'display' => (string) $instance['type'],
477 'exclude-posts' => '',
478 'exclude-terms' => (string) $instance['exclude_terms'],
479 'get-all-children' => (string) $instance['all_children'],
480 'group-numbers' => '',
481 'grouping' => '',
482 'hide-empty-terms' => $hide_empty_terms,
483 'numbers' => 'hide',
484 'parent-post' => (string) $instance['parent_post'],
485 'parent-term' => (string) $instance['parent_term'],
486 'post-type' => (string) $instance['post_type'],
487 'return' => 'letters',
488 'target' => (string) $target_url,
489 'taxonomy' => (string) $instance['taxonomy'],
490 'terms' => (string) $instance['terms'],
491 );
492
493 global $shortcode_tags;
494 if ( isset( $shortcode_tags['alphalisting'] ) ) {
495 $ret .= call_user_func( $shortcode_tags['alphalisting'], $attributes );
496 }
497
498 $ret .= '</div>';
499 $ret .= $args['after_widget'];
500
501 return $ret;
502 }
503
504 /**
505 * Replace the WP_Query search parameters to search just the title.
506 *
507 * @since 4.0.0
508 * @param string $search The search database query snippet.
509 * @param WP_Query $wp_query The WP_Query.
510 * @return string The updated search database query snippet.
511 */
512 function alphalisting_search_titles_only( $search, $wp_query ) {
513 if ( empty( $search ) || empty( $wp_query->query_vars['search_terms'] ) ) {
514 return $search;
515 }
516
517 global $wpdb;
518 $search = array();
519 $params = $wp_query->query_vars;
520
521 $n = empty( $params['exact'] ) ? '%' : '';
522 foreach ( $params['search_terms'] as $term ) {
523 $search[] = $wpdb->prepare( "$wpdb->posts.post_title LIKE %s", $n . $wpdb->esc_like( $term ) . $n );
524 }
525
526 if ( ! is_user_logged_in() ) {
527 $search[] = "$wpdb->posts.post_password = ''";
528 }
529
530 return ' AND ' . implode( ' AND ', $search );
531 }
532
533 /**
534 * Retrieve posts by title.
535 *
536 * @since 2.1.0
537 * @since 4.0.0 Use WP_Query
538 * @param string $post_title the title to search for.
539 * @param string $post_type the post type to search within.
540 * @return array<int,object> the post IDs that are found.
541 */
542 function alphalisting_get_posts_by_title( string $post_title, string $post_type = '' ): array {
543 $params = array(
544 's' => $post_title,
545 'update_post_meta_cache' => false,
546 'update_post_term_cache' => false,
547 );
548 if ( ! empty( $post_type ) ) {
549 $params['post_type'] = $post_type;
550 }
551
552 add_filter( 'posts_search', __NAMESPACE__ . '\\alphalisting_search_titles_only', 10, 2 );
553 $query = new \WP_Query( $params );
554 $results = $query->posts;
555 remove_filter( 'posts_search', __NAMESPACE__ . '\\alphalisting_search_titles_only' );
556
557 return $results;
558 }
559
560 /**
561 * Ajax responder for AlphaListing_Widget configuration
562 *
563 * @since 2.0.0
564 * @return void
565 */
566 function alphalisting_get_autocomplete_post_titles() {
567 $nonce = '';
568 if ( isset( $_REQUEST['_posts_by_title_wpnonce'] ) ) {
569 $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_posts_by_title_wpnonce'] ) );
570 }
571 if ( ! check_ajax_referer( 'posts-by-title', '_posts_by_title_wpnonce', false ) || ! wp_verify_nonce( $nonce, 'posts-by-title' ) ) {
572 wp_send_json_error(
573 array(
574 'message' => __( 'Security check failed.', 'alphalisting' ),
575 ),
576 403
577 );
578 }
579
580 if ( ! current_user_can( 'edit_theme_options' ) ) {
581 wp_send_json_error(
582 array(
583 'message' => __( 'You are not allowed to perform this action.', 'alphalisting' ),
584 ),
585 403
586 );
587 }
588
589 $post_title = '';
590 $post_type = '';
591 if ( isset( $_POST['post_title']['term'] ) ) {
592 $post_title = sanitize_text_field( wp_unslash( $_POST['post_title']['term'] ) );
593 } else {
594 wp_send_json_error(
595 array(
596 'message' => __( 'Invalid request payload.', 'alphalisting' ),
597 ),
598 400
599 );
600 }
601 if ( isset( $_POST['post_type'] ) ) {
602 $post_type = sanitize_text_field( wp_unslash( $_POST['post_type'] ) );
603 }
604
605 $results = alphalisting_get_posts_by_title( $post_title, $post_type );
606
607 $titles = array();
608 foreach ( $results as $result ) {
609 $titles[] = array(
610 'value' => intval( $result->ID ),
611 'label' => $result->post_title,
612 );
613 }
614
615 wp_send_json( $titles );
616 }
617
618 add_action( 'wp_ajax_alphalisting_get_autocomplete_post_titles', __NAMESPACE__ . '\\alphalisting_get_autocomplete_post_titles' );
619
620 /**
621 * Register the A_Z_Widget widget
622 *
623 * @since 2.0.0
624 * @return void
625 */
626 function alphalisting_widget() {
627 register_widget( __NAMESPACE__ . '\\AlphaListing_Widget' );
628 }
629 add_action( 'widgets_init', __NAMESPACE__ . '\\alphalisting_widget' );
630