-
-
Save jgangso/cb20ff8fd9e5e14ac58ba6055ea638ba to your computer and use it in GitHub Desktop.
Building An Advanced WordPress Search With WP_Query https://www.smashingmagazine.com/2016/03/advanced-wordpress-search-with-wp_query/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @package Smashing_plugin | |
* @version 1.0 | |
*/ | |
/* | |
Plugin Name: Smashing plugin | |
Plugin URI: https://www.smashingmagazine.com/2016/03/advanced-wordpress-search-with-wp_query/ | |
Description: This is an example plugin for Smashing Magazine readers. | |
Author: Carlo Daniele | |
Version: 1.0 | |
Author URI: http://carlodaniele.it/en/ | |
*/ | |
/** | |
* Plugin setup | |
* Register post type and shortocode | |
*/ | |
function sm_setup() { | |
$labels = array( | |
'name' => __( 'Accommodation', 'smashing_plugin' ), | |
'singular_name' => __( 'Accommodation', 'smashing_plugin' ), | |
'add_new_item' => __( 'Add New Accommodation', 'smashing_plugin' ) | |
); | |
$args = array( | |
'labels' => $labels, | |
'description' => '', | |
'public' => true, | |
'show_ui' => true, | |
'has_archive' => true, | |
'show_in_menu' => true, | |
'exclude_from_search' => false, | |
'capability_type' => 'post', | |
'map_meta_cap' => true, | |
'hierarchical' => false, | |
'rewrite' => array( 'slug' => 'accommodation', 'with_front' => true ), | |
'query_var' => true, | |
'menu_icon' => 'dashicons-admin-multisite', | |
'supports' => array( 'title', 'editor', 'thumbnail', 'author', 'custom-fields' ), | |
'register_meta_box_cb' => 'sm_add_meta_boxes', | |
'taxonomies' => array( 'typology' ) | |
); | |
register_post_type( 'accommodation', $args ); | |
add_shortcode( 'sm_search_form', 'sm_search_form' ); | |
} | |
add_action( 'init', 'sm_setup' ); | |
/** | |
* Register custom taxonomy | |
*/ | |
function sm_register_custom_taxonomies() { | |
$labels = array( | |
'name' => __( 'Typologies', 'smashing_plugin' ), | |
'label' => __( 'Typologies', 'smashing_plugin' ), | |
'add_new_item' => __( 'Add new Typology', 'smashing_plugin' ), | |
); | |
$args = array( | |
'labels' => $labels, | |
'hierarchical' => true, | |
'label' => __( 'Typologies', 'smashing_plugin' ), | |
'show_ui' => true, | |
'query_var' => true, | |
'rewrite' => array( 'slug' => 'typology', 'with_front' => true ), | |
'show_admin_column' => true, | |
); | |
register_taxonomy( 'typology', array( 'accommodation' ), $args ); | |
} | |
add_action( 'init', 'sm_register_custom_taxonomies' ); | |
/** | |
* Add custom meta boxes | |
*/ | |
function sm_add_meta_boxes(){ | |
add_meta_box( 'sm_features_meta_box', __( 'Features', 'smashing_plugin' ), 'sm_build_features_meta_box', 'accommodation', 'side' ); | |
add_meta_box( 'sm_location_meta_box', __( 'Location', 'smashing_plugin' ), 'sm_build_location_meta_box', 'accommodation', 'normal' ); | |
} | |
/** | |
* Print custom meta box | |
*/ | |
function sm_build_features_meta_box( $post ){ | |
// make sure the form request comes from WordPress | |
wp_nonce_field( basename( __FILE__ ), 'sm_features_meta_box_nonce' ); | |
// retrieve current field values | |
$type = get_post_meta( $post->ID, '_sm_accommodation_type', true ); | |
$facilities = get_post_meta( $post->ID, '_sm_accommodation_facilities', false ); | |
// an array of default facilities | |
$available_facilities = array( 'essentials', 'kitchen', 'internet', 'parking', 'tv', 'washer', 'wireless' ); | |
?> | |
<div class='inside'> | |
<p><strong>Type of accommodation</strong></p> | |
<p> | |
<select name="customfields[type]"> | |
<option value="" <?php selected( $type, "" ); ?>>Select</option> | |
<option value="entire" <?php selected( $type, 'entire' ); ?>><?php _e( 'Entire house', 'smashing_plugin' ); ?></option> | |
<option value="private" <?php selected( $type, 'private' ); ?>><?php _e( 'Private room', 'smashing_plugin' ); ?></option> | |
<option value="shared" <?php selected( $type, 'shared' ); ?>><?php _e( 'Shared room', 'smashing_plugin' ); ?></option> | |
</select> | |
</p> | |
<p><strong><?php _e( 'Facilities', 'smashing_plugin' ); ?></strong></p> | |
<p> | |
<?php | |
foreach ( $available_facilities as $f ) { | |
if( !isset( $facilities[0][$f] ) ){ | |
$facilities[0][$f] = 0; | |
} | |
?> | |
<input type="checkbox" name="customfields[facilities][<?php echo $f; ?>]" value="<?php echo $f; ?>" <?php checked( $facilities[0][$f], $f ); ?>><?php echo ucfirst($f); ?><br /> | |
<?php | |
} | |
?> | |
</p> | |
</div> | |
<?php | |
} | |
/** | |
* Print custom meta box | |
*/ | |
function sm_build_location_meta_box( $post ){ | |
wp_nonce_field( basename( __FILE__ ), 'sm_location_meta_box_nonce' ); | |
$custom_fields = get_post_custom( $post->ID ); | |
$address = isset( $custom_fields['_sm_accommodation_address'][0] ) ? $custom_fields['_sm_accommodation_address'][0] : ''; | |
$city = isset( $custom_fields['_sm_accommodation_city'][0] ) ? $custom_fields['_sm_accommodation_city'][0] : ''; | |
$country = isset( $custom_fields['_sm_accommodation_country'][0] ) ? $custom_fields['_sm_accommodation_country'][0] : ''; | |
?> | |
<div class="inside"> | |
<p><strong>Address</strong></p> | |
<p><input type="text" id="sm_accommodation_address" name="customfields[address]" value="<?php echo esc_attr( $address ); ?>" /></p> | |
<p><strong>City</strong></p> | |
<p><input type="text" id="sm_accommodation_city" name="customfields[city]" value="<?php echo esc_attr( $city ); ?>" /></p> | |
<p><strong>Country</strong></p> | |
<p><input type="text" id="sm_accommodation_country" name="customfields[country]" value="<?php echo esc_attr( $country ); ?>" /></p> | |
</div> | |
<?php | |
} | |
/** | |
* Store custom meta box data | |
*/ | |
function sm_save_meta_boxes_data( $post_id ){ | |
// verify first meta box nonce | |
if ( !isset( $_POST['sm_features_meta_box_nonce'] ) || !wp_verify_nonce( $_POST['sm_features_meta_box_nonce'], basename( __FILE__ ) ) ){ | |
return; | |
} | |
// verify second meta box nonce | |
if ( !isset( $_POST['sm_location_meta_box_nonce'] ) || !wp_verify_nonce( $_POST['sm_location_meta_box_nonce'], basename( __FILE__ ) ) ){ | |
return; | |
} | |
// return if autosave | |
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ){ | |
return; | |
} | |
// Check the user's permissions. | |
if ( isset( $_POST['post_type'] ) && 'accommodation' == $_POST['post_type'] ) { | |
if ( ! current_user_can( 'edit_post', $post_id ) ){ | |
return; | |
} | |
} | |
// custom fields values | |
$customfields = ( isset( $_POST['customfields'] ) ) ? (array) $_POST['customfields'] : array(); | |
if( count( $customfields ) == 0 ){ | |
return; | |
} | |
foreach ($customfields as $key => $value) { | |
// checks if is bidimensional array | |
// and sanitize values | |
if( is_array( $value ) ){ | |
$value = array_map( 'sanitize_text_field', $value ); | |
// if not an array | |
// sanitize value | |
}else{ | |
$value = sanitize_text_field( $value ); | |
} | |
update_post_meta( $post_id, '_sm_accommodation_' . $key, $value ); | |
} | |
} | |
add_action( 'save_post', 'sm_save_meta_boxes_data' ); | |
/** | |
* Register custom query vars | |
* | |
* @link https://codex.wordpress.org/Plugin_API/Filter_Reference/query_vars | |
*/ | |
function sm_register_query_vars( $vars ) { | |
$vars[] = 'type'; | |
$vars[] = 'city'; | |
return $vars; | |
} | |
add_filter( 'query_vars', 'sm_register_query_vars' ); | |
/** | |
* Build a custom query based on several conditions | |
* The pre_get_posts action gives developers access to the $query object by reference | |
* any changes you make to $query are made directly to the original object - no return value is requested | |
* | |
* @link https://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts | |
* | |
*/ | |
function sm_pre_get_posts( $query ) { | |
// check if the user is requesting an admin page | |
// or current query is not the main query | |
if ( is_admin() || ! $query->is_main_query() ){ | |
return; | |
} | |
// edit the query only when post type is 'accommodation' | |
// if it isn't, return | |
if ( !is_post_type_archive( 'accommodation' ) ){ | |
return; | |
} | |
$meta_query = array(); | |
// get query var values | |
// defaults to empty string | |
if( !empty( get_query_var( 'city' ) ) ){ | |
$meta_query[] = array( 'key' => '_sm_accommodation_city', 'value' => get_query_var( 'city' ), 'compare' => 'LIKE' ); | |
} | |
if( !empty( get_query_var( 'type' ) ) ){ | |
$meta_query[] = array( 'key' => '_sm_accommodation_type', 'value' => get_query_var( 'type' ), 'compare' => 'LIKE' ); | |
} | |
if( count( $meta_query ) > 1 ){ | |
$meta_query['relation'] = 'AND'; | |
} | |
if( count( $meta_query ) > 0 ){ | |
$query->set( 'meta_query', $meta_query ); | |
} | |
} | |
add_action( 'pre_get_posts', 'sm_pre_get_posts', 1 ); | |
/** | |
* Build search form markup | |
*/ | |
function sm_search_form( $args ){ | |
// The Query | |
// meta_query expects nested arrays, even if you only have one query | |
// to add the category param | |
$sm_query = new WP_Query( array( 'post_type' => 'accommodation', 'posts_per_page' => '-1', 'meta_query' => array( array( 'key' => '_sm_accommodation_city' ) ) ) ); | |
// The Loop | |
if ( $sm_query->have_posts() ) { | |
$cities = array(); | |
while ( $sm_query->have_posts() ) { | |
$sm_query->the_post(); | |
$city = get_post_meta( get_the_ID(), '_sm_accommodation_city', true ); | |
// populate an array of all occurrences (non duplicated) | |
if( !in_array( $city, $cities ) ){ | |
$cities[] = $city; | |
} | |
} | |
} | |
/* Restore original Post Data */ | |
wp_reset_postdata(); | |
if( count($cities) == 0){ | |
return; | |
} | |
asort($cities); | |
$select_city = '<select name="city">'; | |
$select_city .= '<option value="">' . __( 'Select city', 'smashing_plugin' ) . '</option>'; | |
foreach ($cities as $city ) { | |
$select_city .= '<option value="' . $city . '">' . $city . '</option>'; | |
} | |
$select_city .= '</select>' . "\n"; | |
reset($cities); | |
$args = array( 'hide_empty' => false ); | |
$typology_terms = get_terms( 'typology', $args ); | |
if( is_array( $typology_terms ) ){ | |
$select_typology = '<select name="typology">'; | |
$select_typology .= '<option value="" selected="selected">' . __( 'Select typology', 'smashing_plugin' ) . '</option>'; | |
foreach ( $typology_terms as $term ) { | |
$select_typology .= '<option value="' . $term->slug . '">' . $term->name . '</option>'; | |
} | |
$select_typology .= '</select>' . "\n"; | |
} | |
$select_type = '<select name="type">'; | |
$select_type .= '<option value="" selected="selected">' . __( 'Select room type', 'smashing_plugin' ) . '</option>'; | |
$select_type .= '<option value="entire">' . __( 'Entire house', 'smashing_plugin' ) . '</option>'; | |
$select_type .= '<option value="private">' . __( 'Private room', 'smashing_plugin' ) . '</option>'; | |
$select_type .= '<option value="shared">' . __( 'Shared room', 'smashing_plugin' ) . '</option>'; | |
$select_type .= '</select>' . "\n"; | |
$output = '<form id="smform" action="' . esc_url( home_url() ) . '" method="GET" role="search">'; | |
$output .= '<div class="smtextfield">' . '<input type="text" name="s" placeholder="Search key..." value="' . get_search_query() . '" /></div>'; | |
$output .= '<div class="smselectbox">' . $select_city . '</div>'; | |
$output .= '<div class="smselectbox">' . $select_typology . '</div>'; | |
$output .= '<div class="smselectbox">' . $select_type . '</div>'; | |
$output .= '<input type="hidden" name="post_type" value="accommodation" />'; | |
$output .= '<p><input type="submit" value="Go!" class="button" /></p></form>'; | |
return $output; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment