$widget_options Optional. Widget options. See wp_register_sidebar_widget() for information * on accepted arguments. Default empty array. * @param array $control_options Optional. Widget control options. See wp_register_widget_control() for * information on accepted arguments. Default empty array. */ public function __construct( $id_base = '', $name = '', $widget_options = array(), $control_options = array() ) { $widget_options['classname'] = $widget_options['classname'] ?? 'a-z-listing-widget'; $widget_options['description'] = $widget_options['description'] ?? __( 'Alphabetised links to the A-Z site map', 'a-z-listing' ); parent::__construct( $id_base ?? 'bh_az_widget', $name ?? __( 'A-Z Site Map', 'a-z-listing' ), $widget_options, $control_options ); add_action( 'admin_enqueue_scripts', 'a_z_listing_enqueue_widget_admin_script' ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_if_active' ) ); } /** * Enqueue scripts and stylesheets if the widget is active on the page * * @since 4.0.0 * @return void */ public function enqueue_if_active() { if ( false !== is_active_widget( false, false, $this->id_base, true ) ) { a_z_listing_do_enqueue(); } } /** * Print-out the configuration form for the widget * * @since 0.1 * @param array $instance Widget instance as provided by WordPress core. * @return string */ public function form( $instance ) { $args = array( 'public' => true, ); $public_post_types = get_post_types( $args, 'objects' ); $public_taxonomies = get_taxonomies( $args, 'objects' ); $widget_title = $instance['title'] ?? ''; $widget_title_id = $this->get_field_id( 'title' ); $widget_title_name = $this->get_field_name( 'title' ); $display_type = ( isset( $instance['type'] ) && 'terms' === $instance['type'] ) ? 'terms' : 'posts'; $display_type_id = $this->get_field_id( 'type' ); $display_type_name = $this->get_field_name( 'type' ); $target_post = isset( $instance['post'] ) ? intval( $instance['post'] ) : ( ( isset( $instance['page'] ) ? intval( $instance['page'] ) : 0 ) ); $target_post_id = $this->get_field_id( 'post' ); $target_post_name = $this->get_field_name( 'post' ); $target_post_title = isset( $instance['target_post'] ) ? $instance['target_post'] : ( ( 0 < $target_post ) ? get_the_title( $target_post ) : '' ); $target_post_title_id = $this->get_field_id( 'target_post_title' ); $target_post_title_name = $this->get_field_name( 'target_post_title' ); $listing_post_type = $instance['post_type'] ?? 'page'; $listing_post_type_id = $this->get_field_id( 'post_type' ); $listing_post_type_name = $this->get_field_name( 'post_type' ); $listing_parent_post = $instance['parent_post'] ?? ''; $listing_parent_post_id = $this->get_field_id( 'parent_post' ); $listing_parent_post_name = $this->get_field_name( 'parent_post' ); $listing_parent_post_title = isset( $instance['parent_post_title'] ) ? $instance['parent_post_title'] : ( ( 0 < $listing_parent_post ) ? get_the_title( $listing_parent_post ) : '' ); $listing_parent_post_title_id = $this->get_field_id( 'parent_post_title' ); $listing_parent_post_title_name = $this->get_field_name( 'parent_post_title' ); $listing_all_children = $instance['all_children'] ?? 'true'; $listing_all_children_id = $this->get_field_id( 'all_children' ); $listing_all_children_name = $this->get_field_name( 'all_children' ); $listing_taxonomy = $instance['taxonomy'] ?? 'page'; $listing_taxonomy_id = $this->get_field_id( 'taxonomy' ); $listing_taxonomy_name = $this->get_field_name( 'taxonomy' ); $listing_parent_term = $instance['parent_term'] ?? ''; $listing_parent_term_id = $this->get_field_id( 'parent_term' ); $listing_parent_term_name = $this->get_field_name( 'parent_term' ); $listing_terms_include = $instance['terms'] ?? ''; $listing_terms_include_id = $this->get_field_id( 'terms' ); $listing_terms_include_name = $this->get_field_name( 'terms' ); $listing_terms_exclude = $instance['terms_exclude'] ?? ''; $listing_terms_exclude_id = $this->get_field_id( 'terms_exclude' ); $listing_terms_exclude_name = $this->get_field_name( 'terms_exclude' ); $listing_hide_empty_terms = $instance['hide_empty_terms'] ?? ''; $listing_hide_empty_terms_id = $this->get_field_id( 'hide_empty_terms' ); $listing_hide_empty_terms_name = $this->get_field_name( 'hide_empty_terms' ); wp_nonce_field( 'posts-by-title', '_posts_by_title_wpnonce', false, true ); ?>

>

>

value="" />

/>

>

>

>

>

/>

$new_instance the new configuration values. * @param array $old_instance the previous configuration values. * @return array sanitised version of the new configuration values to be saved */ public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = wp_strip_all_tags( $new_instance['title'] ); $instance['type'] = wp_strip_all_tags( $new_instance['type'] ); $instance['post'] = (int) $new_instance['post']; // target. $instance['target_post_title'] = wp_strip_all_tags( $new_instance['target_post_title'] ); $instance['post_type'] = wp_strip_all_tags( $new_instance['post_type'] ); $instance['taxonomy'] = wp_strip_all_tags( $new_instance['taxonomy'] ); $instance['parent_post'] = (int) $new_instance['parent_post']; $instance['all_children'] = 'on' === $new_instance['all_children'] ? 'true' : 'false'; $instance['parent_term'] = wp_strip_all_tags( $new_instance['parent_term'] ); $instance['terms'] = wp_strip_all_tags( $new_instance['terms'] ); $instance['exclude_terms'] = wp_strip_all_tags( $new_instance['exclude_terms'] ); $instance['hide_empty_terms'] = 'on' === $new_instance['hide_empty_terms'] ? 'true' : 'false'; if ( empty( $new_instance['target_post_title'] ) ) { $instance['post'] = 0; } if ( empty( $new_instance['parent_post_title'] ) ) { $instance['parent_post'] = 0; } return $instance; } /** * Print the user-visible widget to the page * * @since 0.1 * @param array $args General widget configuration. Often shared between all widgets on the site. * @param array $instance Configuration of this Widget. Unique to this invocation. * @return void */ public function widget( $args, $instance ) { the_section_a_z_widget( $args, $instance ); } } /** * Print the user-visible widget to the page implentation * * @since 0.1 * @since 0.8.0 deprecated. * @see A_Z_Widget::the_section_a_z_widget() * @deprecated use the_section_a_z_widget() * @param array $args General widget configuration. Often shared between all widgets on the site. * @param array $instance Configuration of this Widget. Unique to this invocation. * @return void */ function the_section_az_widget( array $args, array $instance ) { _deprecated_function( __FUNCTION__, '0.8.0', 'the_section_a_z_widget' ); the_section_a_z_widget( $args, $instance ); } /** * Print the user-visible widget to the page implentation * * @since 0.8.0 * @param array $args General widget configuration. Often shared between all widgets on the site. * @param array $instance Configuration of this Widget. Unique to this invocation. * @return void */ function the_section_a_z_widget( array $args, array $instance ) { //phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound echo get_the_section_a_z_widget( $args, $instance ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** * Deprecated print the user-visible widget to the page implementation. * * @since 0.1 * @since 0.8.0 deprecated. * @see A_Z_Widget::get_the_section_a_z_widget() * @deprecated use get_the_section_a_z_widget() * @param array $args General widget configuration. Often shared between all widgets on the site. * @param array $instance Configuration of this Widget. Unique to this invocation. * @return string The complete A-Z Widget HTML ready for echoing to the page. */ function get_the_section_az_widget( array $args, array $instance ): string { _deprecated_function( __FUNCTION__, '0.8.0', 'get_the_section_a_z_widget' ); return get_the_section_a_z_widget( $args, $instance ); } /** * Get the user-visible widget html * * @since 0.8.0 * @param array $args General widget configuration. Often shared between all widgets on the site. * @param array $instance Configuration of this Widget. Unique to this invocation. * @return string The complete A-Z Widget HTML ready for echoing to the page. */ function get_the_section_a_z_widget( array $args, array $instance ): string { //phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound do_action( 'a_z_listing_log', 'A-Z Listing: Running widget' ); $instance = wp_parse_args( $instance, array( 'all_children' => 'true', 'exclude_terms' => '', 'hide_empty_terms' => false, 'parent_post' => '', 'parent_term' => '', 'post' => -1, // target. 'page' => -1, // obsolete target. 'post_type' => 'page', 'taxonomy' => '', 'terms' => '', 'title' => '', 'type' => 'posts', ) ); $title = esc_html( $instance['title'] ); $target_url = ''; if ( 0 < $instance['post'] || 0 < $instance['page'] ) { // target. $target_id = (int) $instance['post']; // target. if ( ! ( 0 < $instance['post'] ) ) { $target_id = (int) $instance['page']; // obsolete target. } $target_url = get_the_permalink( $target_id ); if ( empty( $title ) ) { $title = get_the_title( $target_id ); } } elseif ( empty( $title ) ) { $title = esc_html__( 'A-Z Listing', 'a-z-listing' ); } $hide_empty_terms = true === $instance['hide_empty_terms'] ? 'true' : 'false'; $ret = ''; $ret .= $args['before_widget']; $ret .= $args['before_title']; $ret .= $title; $ret .= $args['after_title']; $ret .= do_shortcode( "[a-z-listing alphabet='' display='{$instance['type']}' exclude-posts='' exclude-terms='{$instance['exclude_terms']}' get-all-children='{$instance['all_children']}' group-numbers='' grouping='' hide-empty-terms='{$hide_empty_terms}' numbers='hide' parent-post='{$instance['parent_post']}' parent-term='{$instance['parent_term']}' post-type='{$instance['post_type']}' return='letters' target='{$target_url}' taxonomy='{$instance['taxonomy']}' terms='{$instance['terms']}' ]" ); $ret .= $args['after_widget']; return $ret; } /** * Replace the WP_Query search parameters to search just the title. * * @since 4.0.0 * @param string $search The search database query snippet. * @param WP_Query $wp_query The WP_Query. * @return string The updated search database query snippet. */ function a_z_listing_search_titles_only( $search, $wp_query ) { if ( empty( $search ) || empty( $wp_query->query_vars['search_terms'] ) ) { return $search; } global $wpdb; $search = array(); $params = $wp_query->query_vars; $n = empty( $params['exact'] ) ? '%' : ''; foreach ( $params['search_terms'] as $term ) { $search[] = $wpdb->prepare( "$wpdb->posts.post_title LIKE %s", $n . $wpdb->esc_like( $term ) . $n ); } if ( ! is_user_logged_in() ) { $search[] = "$wpdb->posts.post_password = ''"; } return ' AND ' . implode( ' AND ', $search ); } /** * Retrive posts by title. * * @since 2.1.0 * @since 4.0.0 Use WP_Query * @param string $post_title the title to search for. * @param string $post_type the post type to search within. * @return array the post IDs that are found. */ function a_z_listing_get_posts_by_title( string $post_title, string $post_type = '' ): array { global $wpdb; $params = array( 's' => $post_title, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ); if ( ! empty( $post_type ) ) { $params['post_type'] = $post_type; } add_filter( 'posts_search', 'a_z_listing_search_titles_only', 10, 2 ); $query = new WP_Query( $params ); $results = $query->posts; remove_filter( 'posts_search', 'a_z_listing_search_titles_only' ); return $results; } /** * Ajax responder for A_Z_Listing_Widget configuration * * @since 2.0.0 * @return void */ function a_z_listing_autocomplete_post_titles() { check_ajax_referer( 'posts-by-title' ); $nonce = ''; if ( isset( $_REQUEST['_posts_by_title_wpnonce'] ) ) { $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_posts_by_title_wpnonce'] ) ); } if ( ! wp_verify_nonce( $nonce, 'posts-by-title' ) ) { die( esc_html( __( 'Security check failed', 'a-z-listing' ) ) ); } $post_title = ''; $post_type = ''; if ( isset( $_POST['post_title']['term'] ) ) { $post_title = sanitize_text_field( wp_unslash( $_POST['post_title']['term'] ) ); } if ( isset( $_POST['post_type'] ) ) { $post_type = sanitize_text_field( wp_unslash( $_POST['post_type'] ) ); } $results = a_z_listing_get_posts_by_title( $post_title, $post_type ); $titles = array(); foreach ( $results as $result ) { $titles[] = array( 'value' => intval( $result->ID ), 'label' => addslashes( $result->post_title ), ); } echo wp_json_encode( $titles ); exit(); } add_action( 'wp_ajax_nopriv_get_a_z_listing_autocomplete_post_titles', 'a_z_listing_autocomplete_post_titles' ); add_action( 'wp_ajax_get_a_z_listing_autocomplete_post_titles', 'a_z_listing_autocomplete_post_titles' ); /** * Register the A_Z_Widget widget * * @since 2.0.0 * @return void */ function a_z_listing_widget() { register_widget( 'A_Z_Listing_Widget' ); } add_action( 'widgets_init', 'a_z_listing_widget' ); /** * Enqueue the jquery-ui autocomplete script * * @since 2.0.0 * @return void */ function a_z_listing_autocomplete_script() { wp_enqueue_script( 'jquery-ui-autocomplete' ); } add_action( 'admin_enqueue_scripts', 'a_z_listing_autocomplete_script' );