Skip to content

Instantly share code, notes, and snippets.

@dbranes
Last active February 29, 2020 07:24
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dbranes/d49c9b1ddc817fdffc3a to your computer and use it in GitHub Desktop.
Save dbranes/d49c9b1ddc817fdffc3a to your computer and use it in GitHub Desktop.
WooCommerce - search by product dimensions
<?php
/**
* Plugin Name: WooCommerce - Search by product dimensions, pa_colour and SKU
* Description: Shortcodes [wpq_search] and [wpq_results] to search products by length, height, width, attribute colour taxonomy and SKU
* Plugin URI: http://www.wpquestions.com/question/showChronoLoggedIn/id/9732
* Author: dbranes
* Version: 0.2.1
*/
/**
* Changelog:
*
* 0.2.1
* - Fixed a minor bug.
* 0.2.0
* - Plugin rewrite to handle the 'pa_colour' attribute taxonomy.
* - Added automatic construction of the color select box in the search form.
* - Added a search support for the 'pa_colour' taxonomy.
* - Added the 'color_tax' attribute to the [wp_search] shortcoce. Example: [wp_search color_tax="pa_colour"].
* - Removed the 'save_post_product' action hook. don't need it for attribute taxonomies.
* 0.1.1
* - Changed the product attribute 'pa_colour' to 'colour'
* 0.1
* - Plugin rewrite
* - Added automatic color collection
* - Added support shortcode in text widgets
* - Added support for search form to recall last used critera
* - Added a new [wpq_results] shortcode
* - Added new parameters in [wpq_search] to support dimensional ranges
* - Removed dimensional range selectbox from the form
* - Changed from POST to GET
* - Changed attribute name from 'color' to 'pa_colour'
* 0.0.4
* - Added a way to automatically save the "color" attribute value to the "_wpq_color" custom field value
* - Added color selectbox to the search form
* 0.0.3
* - Added helper functions to make it easier to modify
* - Added search range
* 0.0.2
* - Fixed a bug with meta variable
* 0.0.1
* - Init
*
*/
/**
* Support shortcodes in Text Widgets
*/
add_filter( 'widget_text', 'do_shortcode' );
/**
* Shortcode: [wpq_results]
*/
add_shortcode( 'wpq_results',
function( $atts = array(), $content ='' )
{
// Get GET inputs:
$inputs = filter_input_array( INPUT_GET, array(
'wpq_sku' => FILTER_SANITIZE_STRING,
'wpq_length' => FILTER_SANITIZE_NUMBER_INT,
'wpq_length_range' => FILTER_SANITIZE_NUMBER_INT,
'wpq_width' => FILTER_SANITIZE_NUMBER_INT,
'wpq_width_range' => FILTER_SANITIZE_NUMBER_INT,
'wpq_height' => FILTER_SANITIZE_NUMBER_INT,
'wpq_height_range' => FILTER_SANITIZE_NUMBER_INT,
'wpq_color' => FILTER_SANITIZE_STRING,
'wpq_color_tax' => FILTER_SANITIZE_STRING,
'wpq_post' => FILTER_SANITIZE_NUMBER_INT,
'wpq_nonce' => FILTER_SANITIZE_STRING,
) );
// Check if the search form was sent:
if( ! empty( $inputs['wpq_post'] ) )
{
// Check security nonce:
if( ! wp_verify_nonce( $inputs['wpq_nonce'], 'wpq_search' ) )
{
return sprintf( '<div class="wpq_error">%s</div>', __( 'The nonce is not valid! Please try again!' ) );
}
else
{
// Construct the Meta query:
$meta = array();
if( ! function_exists( 'wpq_generate_meta_from_dimension' ) )
{
return sprintf( '<div class="wpq_error">%s</div>', __( 'Error: Search setup is not correct!' ) );
}
// Height:
if( ! empty( $inputs['wpq_height'] ) )
{
$meta[] = wpq_generate_meta_from_dimension ( $inputs['wpq_height'], $inputs['wpq_height_range'], '_height' );
}
// Width:
if( ! empty( $inputs['wpq_width'] ) )
{
$meta[] = wpq_generate_meta_from_dimension ( $inputs['wpq_width'], $inputs['wpq_width_range'], '_width' );
}
// Length:
if( ! empty( $inputs['wpq_length'] ) )
{
$meta[] = wpq_generate_meta_from_dimension ( $inputs['wpq_length'], $inputs['wpq_length_range'], '_length' );
}
// Sku:
if( ! empty( $inputs['wpq_sku'] ) )
{
$meta[] = array( 'key' => '_sku', 'value' => $inputs['wpq_sku'] );
}
// Construct the Tax query:
$tax = array();
// Color:
if( ! empty( $inputs['wpq_color'] ) && ! empty( $inputs['wpq_color_tax'] ) && taxonomy_exists( $inputs['wpq_color_tax'] ) )
{
$tax[] = array( 'taxonomy' => $inputs['wpq_color_tax'], 'terms' => $inputs['wpq_color'], 'field' => 'slug' );
}
// Search query arguments:
$args = array(
'posts_per_page' => -1,
'post_type' => 'product',
);
// Add the dynamic meta/tax queries to the search query arguments:
if( count( $meta ) > 0 || count( $tax ) > 0 )
{
// Meta query:
if( count( $meta ) > 0 )
{
$args['meta_query'] = $meta;
}
// Meta query relations:
if( count( $meta ) > 1 )
{
$meta[] = array( 'relation' => 'AND' );
}
// Tax query:
if( count( $tax ) > 0 )
{
$args['tax_query'] = $tax;
}
// Run search query:
$results = new WP_Query( $args );
// Render the results view:
if( function_exists( 'wpq_results_view' ) )
{
ob_start();
wpq_results_view( $results );
return ob_get_clean();
}
}
else
{
return printf( '<div class="wpq_error">%s</div>', __( 'Please enter your search criteria!' ) );
}
}
}
} // end function
);
/**
* Shortcode: [wpq_search]
*
* Example: [wpq_search url="http://example.com/product-search/" width_range="10" height_range="0" length_range="20" ]
*/
add_shortcode( 'wpq_search',
function( $atts = array(), $content ='' )
{
// Get shortcode inputs:
$atts = shortcode_atts( array(
'width_range' => '0',
'height_range' => '0',
'length_range' => '0',
'color_tax' => 'pa_colour',
'url' => '',
), $atts, 'wpq_search' );
$atts['width_range'] = intval( $atts['width_range'] );
$atts['height_range'] = intval( $atts['height_range'] );
$atts['length_range'] = intval( $atts['length_range'] );
$atts['color_tax'] = sanitize_key( $atts['color_tax'] );
$atts['url'] = esc_url( $atts['url'] );
// Get GET inputs:
$inputs = filter_input_array( INPUT_GET, array(
'wpq_sku' => FILTER_SANITIZE_STRING,
'wpq_length' => FILTER_SANITIZE_NUMBER_INT,
'wpq_length_range' => FILTER_SANITIZE_NUMBER_INT,
'wpq_width' => FILTER_SANITIZE_NUMBER_INT,
'wpq_width_range' => FILTER_SANITIZE_NUMBER_INT,
'wpq_height' => FILTER_SANITIZE_NUMBER_INT,
'wpq_height_range' => FILTER_SANITIZE_NUMBER_INT,
'wpq_color' => FILTER_SANITIZE_STRING,
'wpq_color_tax' => FILTER_SANITIZE_STRING,
'wpq_post' => FILTER_SANITIZE_NUMBER_INT,
'wpq_nonce' => FILTER_SANITIZE_STRING,
) );
// Render the search form view:
if( function_exists( 'wpq_form_view' ) )
{
ob_start();
wpq_form_view( $inputs, $atts );
return ob_get_clean();
}
} // end function
);
/**
* Helper functions
*/
function wpq_results_view( WP_Query $results )
{
// Display search results: ?>
<h2><?php printf( __( 'Search results (%d):' ), $results->found_posts );?></h2>
<?php if( $results->have_posts() ): ?>
<ul>
<?php while ( $results->have_posts() ) : $results->the_post(); ?>
<li>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</li>
<?php endwhile; ?>
</ul><?php
wp_reset_query();
else: ?>
<p><?php _e( 'No products matched your criteria! ' );?></p>
<?php
endif;
}
function wpq_form_view( $inputs = array(), $atts = array() )
{ ?>
<form method="get" action="<?php echo ( ! empty( $atts['url'] ) ) ? esc_url( $atts['url'] ) : '' ;?>">
<p>
<label for="wpq_length"><?php _e( 'Length:' );?></label>
<input type="text" id="wpq_length" name="wpq_length" value="<?php echo ( ! empty( $inputs['wpq_length'] ) ? $inputs['wpq_length'] : '' ) ;?>" />
</p>
<p>
<label for="wpq_width"><?php _e( 'Width:' );?></label>
<input type="text" id="wpq_width" name="wpq_width" value="<?php echo ( ! empty( $inputs['wpq_width'] ) ? $inputs['wpq_width'] : '' ) ;?>" />
</p>
<p>
<label for="wpq_height"><?php _e( 'Height:' );?></label>
<input type="text" id="wpq_height" name="wpq_height" value="<?php echo ( ! empty( $inputs['wpq_height'] ) ? $inputs['wpq_height'] : '' ) ;?>" />
</p>
<p>
<label for="wpq_sku"><?php _e( 'Sku:' );?></label>
<input type="text" id="wpq_sku" name="wpq_sku" value="<?php echo ( ! empty( $inputs['wpq_sku'] ) ? esc_attr( $inputs['wpq_sku'] ) : '' ) ;?>"/>
</p>
<p>
<label for="wpq_color"><?php _e( 'Color:' );?></label>
<select id="wpq_color" name="wpq_color">
<option value=""><?php _e( 'Select color' );?></option>
<?php
if( taxonomy_exists( $atts['color_tax'] ) )
{
$colors = get_terms( $atts['color_tax'] );
}
foreach( (array) $colors as $color ): ?>
<option value="<?php echo esc_attr( $color->slug );?>" <?php selected( $color->slug, $inputs['wpq_color'] );?> ><?php echo esc_attr( $color->name );?></option>
<?php endforeach; ?>
</select>
</p>
<p>
<?php wp_nonce_field('wpq_search','wpq_nonce'); ?>
<input type="hidden" name="wpq_post" value="<?php the_ID();?>" />
<input type="hidden" name="wpq_length_range" value="<?php echo ( ! empty( $inputs['wpq_length_range'] ) ? $inputs['wpq_length_range'] : $atts['length_range'] ); ?>" />
<input type="hidden" name="wpq_width_range" value="<?php echo ( ! empty( $inputs['wpq_width_range'] ) ? $inputs['wpq_width_range'] : $atts['width_range'] ); ?>" />
<input type="hidden" name="wpq_height_range" value="<?php echo ( ! empty( $inputs['wpq_height_range'] ) ? $inputs['wpq_height_range'] : $atts['height_range'] ); ?>" />
<input type="hidden" name="wpq_color_tax" value="<?php echo $atts['color_tax']; ?>" />
<input type="submit" name="wpq_submit" value="<?php _e( 'Search ');?>" />
</p>
</form>
<?php
}
function wpq_generate_meta_from_dimension ( $dim, $range, $key )
{
// Sanitize input:
$dim = intval( $dim );
$range = intval( $range );
$key = sanitize_key( $key );
// Construct Sub Meta query:
$meta = array();
if( 0 == $range )
{
// Exact:
$meta = array(
'key' => $key,
'value' => $dim
);
}
else
{
// Range:
$ratio = ( 1 * $range / 100 );
$down = floor( ( 1 - $ratio ) * $dim );
$up = floor( ( 1 + $ratio ) * $dim );
$meta = array(
'key' => $key,
'compare' => 'BETWEEN',
'type' => 'NUMERIC',
'value' => array( $down, $up )
);
}
return $meta;
}
@tycrawfordmedia
Copy link

I'm trying to understand how this code is working. When I create all the data in my woocommerce custom fields (wpq_length, wpq_height, and wpq_width) and do a search for either the length, width, or height that should match what I typed in on the value for wpq_length, wpq_height, and wpq_width, the results show no products found. But if I type in 10 for either the length, width, or height the results find a product but the number 10 isn't associated with that product in any way.

Any guidance would be greatly appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment