I stumbled upon an issue, where I have registered a custom query variable in Wordpress. However, I would like to pass several values with same custom query and return this in an array, but it redirects/only takes into account the last query value.
I have done like so:
function custom_query_vars( $qvars ) {
$qvars[] = 'filter_fabric';
return $qvars;
}
add_filter( 'query_vars', 'custom_query_vars' );
However, if I pass the url like:
example.com/category/page/2?filter_fabric=cotton&filter_fabric=polyester
I can see in the $query that only the last parameter, in this case 'polyester' is passed, which results in an error with pagination (when I click on a pagination link with the address example.com/category/page/2?filter_fabric=cotton&filter_fabric=polyester it redirects me to example.com/category/page/2?filter_fabric=polyester
Does anyone know how to solve this issue?
Would be of great help!
I have tried adding with this code as well, but it did not work:
function custom_query_vars( $qvars ) {
$qvars[] .= 'filter_fabric';
return $qvars;
}
add_filter( 'query_vars', 'custom_query_vars' );
I would assume it has something to do with a foreach loop, which pushes into into $qvars[] as array, but I am not sure how to do that.
EDIT #1
Here is my code for doing the filter with ajax.
In functions.php
function rg_product_filter() {
//unserialize query string in PHP
//parse_str($_POST['value'], $data); We change this to our custom proper_parse_str function in order to get multiple parameters with same name e.g. "/?filter_tygmaterial=sammet&filter_tygmaterial=bomull"
$data = proper_parse_str($_POST['value']);
$product_color = $data['filter_color'];
$product_material = $data['filter_material'];
$product_fabric = $data['filter_fabric'];
$wpquery_vars = $_POST['query_vars'];
//Get current product category id
$product_category = $wpquery_vars['queried_object'];
$product_cat_id = $product_category['term_id'];
//Get current order + orderby if exists, part 2
$args_orderby = $data['filter_orderby'];
//#TODO: Right now it does not work with pagination.
$per_page = $_POST['per_page'];
$current = $_POST['current'];
$args = array(
'post_type' => 'product',
'posts_per_page' => $per_page,
'paged' => $current,
);
if ($args_orderby) {
if ($args_orderby === 'price') {
$args['orderby'] = 'meta_value_num';
$args['order'] = 'asc';
$args['meta_key'] = '_price';
} elseif ($args_orderby === 'price-desc') {
$args['orderby'] = 'meta_value_num';
$args['order'] = 'desc';
$args['meta_key'] = '_price';
} else {
$args['orderby'] = $args_orderby;
}
}
if ($product_category) {
$args['tax_query'][] = array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => $product_cat_id,
);
}
if ($product_color) {
$args['tax_query'][] = array(
'taxonomy' => 'pa_color',
'field' => 'slug',
'terms' => $product_color,
);
}
if ($product_material) {
$args['tax_query'][] = array(
'taxonomy' => 'pa_material',
'field' => 'slug',
'terms' => $product_material,
);
}
if ($product_fabric) {
$args['tax_query'][] = array(
'taxonomy' => 'pa_tygmaterial',
'field' => 'slug',
'terms' => $product_fabric,
);
}
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post();
wc_get_template_part( 'content', 'product' );
endwhile;
} else {
do_action( 'woocommerce_no_products_found' );
}
wp_reset_postdata();
wp_die();
}
add_action('wp_ajax_rg_product_filter', 'rg_product_filter');
add_action('wp_ajax_nopriv_rg_product_filter', 'rg_product_filter');
In customjs.js
//WooCommerce Filters using AJAX
window.addEventListener("load", (event) => {
$filterForm = $('#filter-form') ? $('#filter-form') : '';
$filterForm.on('submit', function (e) {
e.preventDefault();
var values = $(this).serialize();
var product_container = $('.woocommerce ul.products');
// console.log('values', values);
//append browser URL with filters
let url = window.location.href;
let filterParams = values.replace(/[^&]+=&/g, '').replace(/&[^&]+=$/g, '') //remove empty values from URL
let baseUrl = url.includes('?') ? url.split('?')[0] : '',
paramsInUrl = url.includes('?') ? url.split(('?'))[1] : '',
paramsInUrlWithoutFilter = paramsInUrl.startsWith('filter') ? '' : paramsInUrl.split('&filter')[0]; //Get all params that are before "filter" if exists any
if (filterParams.endsWith('=') && paramsInUrlWithoutFilter) { //Removing from URL when exists other parameters than filter
filterParams = '';
url_with_filters = '?' + paramsInUrlWithoutFilter;
window.history.pushState(null, null, url_with_filters);
} else if (filterParams.endsWith('=') && !paramsInUrlWithoutFilter) { //Removing from URL when no other parameteres except filter exists
filterParams = '';
url_with_filters = location.pathname;
window.history.pushState(null, null, url_with_filters);
} else if (paramsInUrlWithoutFilter) { //Appending to browser URL when exists other parameters than filter
filterParams = filterParams;
url_with_filters = '?' + paramsInUrlWithoutFilter + '&' + filterParams;
window.history.pushState(null, null, url_with_filters);
} else { //Appending to browser URL when no other parameters except filter exists
filterParams = filterParams;
url_with_filters = '?' + filterParams;
window.history.pushState(null, null, url_with_filters);
}
//Update product results text
var resultCountElement = $('.title-wrapper .woocommerce-result-count.rg_woocommerce-total-count');
// Add loader
product_container.block({
message: null,
overlayCSS: {
cursor: 'none',
backgroundColor: '#fff',
},
});
$.ajax({
url: wp_ajax.ajax_url,
method: 'POST',
data: {
value: values,
action: 'rg_product_filter',
per_page: wp_ajax.per_page,
current: wp_ajax.current,
query_vars: wp_ajax.wp_query_vars,
},
success: (res) => {
// console.log(res);
$('.woocommerce ul.products').html(res);
product_container.unblock();
//Update product results text
resultCount = $('ul.products li.product').length;
resultCountElement.html(resultCount + ' produkter');
},
error: (res) => {
console.log(res);
}
});
});
//Select forms (not e.g. input groups)
$('select.form-control').each( function () {
$(this).on('change', $(this), (e) => {
if (e.handled !== true) { //Adding this if statement, because otherwise code $filterForm.submit(); is fired several times
e.handled = true;
$('.wc-filter .sorting__submit').css('display', 'block');
return;
}
});
});
//Input groups
$('.input-group').each( function () {
$(this).on('change', ':checkbox', (e) => {
$('.wc-filter .sorting__submit').css('display', 'block');
});
});
// Orderby
$( '.input-group' ).on( 'change', 'input[type="radio"]', function() {
$('.wc-filter .sorting__submit').css('display', 'block');
});
$('.wc-filter').on('click', '.sorting__submit', function () {
$filterForm.submit();
var filterOverlay = document.getElementsByClassName('product-filters-bg-overlay')[0] ? document.getElementsByClassName('product-filters-bg-overlay')[0] : '';
var filterContainer = document.getElementsByClassName('wc-filter')[0] ? document.getElementsByClassName('wc-filter')[0] : '';
filterOverlay.classList.toggle('toggled');
filterContainer.classList.toggle('toggled');
$('body.woocommerce').css('overflow', '');
});
and lastly, i have filters.php:
Ps: Please note that I have changed the name of the input group of fabrics from name=filter_fabric to name=filter_fabric[] as per recommendations
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$color_terms = get_terms('pa_color');
$material_terms = get_terms('pa_material');
$fabric_terms = get_terms(
array(
'taxonomy' => 'pa_tygmaterial',
));
?>
<div class="product-filters__panelbody">
<form id="filter-form" method="get" action="rg_product_filter">
<div class="product-filters-wrapper">
<?php /* Order By */ ?>
<div class="product-filters-item catalog-ordering">
<div class="product-filters-item-heading collapse-button"
data-toggle="collapse"
data-target="#tab_filter-sorting"
aria-expanded="false"
aria-controls="#tab_filter-sorting"
>Sortering
<svg viewBox="0 0 24 24" class="icon__product-filters-item">
<path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</div>
<div class="collapse-body collapse-element collapse"
id="tab_filter-sorting"
>
<div class="product-filters-item-content">
<?php echo woocommerce_catalog_ordering(); ?>
</div>
</div>
</div>
<?php /* Color */ ?>
<div class="product-filters-item">
<div class="product-filters-item-heading collapse-button"
data-toggle="collapse"
data-target="#tab_filter-color"
aria-expanded="false"
aria-controls="#tab_filter-color"
>Color
<svg viewBox="0 0 24 24" class="icon__product-filters-item">
<path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</div>
<div class="collapse-body collapse-element collapse"
id="tab_filter-color"
>
<div class="product-filters-item-content">
<select name="filter_color" id="filter_color" class="form-control">
<option value="" class="">Color</option>
<?php foreach ($color_terms as $color_term) {
$selected = $color_term->slug === $_GET['filter_color'] ? 'selected' : '';
echo '<option ' . $selected . ' value="' . $color_term->slug . '">' . $color_term->name . '</option>';
}?>
</select>
</div>
</div>
</div>
<?php /* Material */ ?>
<div class="product-filters-item">
<div class="product-filters-item-heading collapse-button"
data-toggle="collapse"
data-target="#tab_filter-material"
aria-expanded="false"
aria-controls="#tab_filter-material"
>Material
<svg viewBox="0 0 24 24" class="icon__product-filters-item">
<path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</div>
<div class="collapse-body collapse-element collapse"
id="tab_filter-material">
<div class="product-filters-item-content">
<select name="filter_material" id="filter_material" class="form-control">
<option value="" class="">Material</option>
<?php foreach ($material_terms as $material_term) {
$selected = $material_term->slug === $_GET['filter_material'] ? 'selected' : '';
echo '<option ' . $selected . ' value="' . $material_term->slug . '">' . $material_term->name . '</option>';
}?>
</select>
</div>
</div>
</div>
<?php /* Fabrics */ ?>
<div class="product-filters-item">
<div class="product-filters-item-heading collapse-button"
data-toggle="collapse"
data-target="#tab_filter-fabrics"
aria-expanded="false"
aria-controls="#tab_filter-fabrics"
>Fabrics
<svg viewBox="0 0 24 24" class="icon__product-filters-item">
<path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</div>
<div class="collapse-body collapse-element collapse"
id="tab_filter-fabrics">
<div class="product-filters-item-content">
<?php foreach ($fabric_terms as $fabric_term) {
//Get parameters from URL
$url_parameters = $_SERVER['QUERY_STRING'];
$data = proper_parse_str($url_parameters);
$product_fabrics = $data['filter_fabric'];
//Check if filter input is in array of parameters from URL, and mark the input as "checked"
if (isset($product_fabrics)) {
if (is_array($product_fabrics)) { //If more than one parameter is checked, $product_tygmaterial becomes array
$checked = in_array($fabric_term->slug, $product_fabrics) ? 'checked' : '';
} else { //If only one parameter is checked, $product_tygmaterial becomes string
$checked = $fabric_term->slug === $product_fabrics ? 'checked' : '';
}
} else {
$checked = '';
}
?>
<div class="input-group">
<input type="checkbox" id="<?php echo $fabric_term->slug; ?>" name="filter_fabric[]" value="<?php echo $fabric_term->slug ?>" <?php echo $checked; ?>>
<label for="<?php echo $fabric_term->slug; ?>"><?php echo $fabric_term->name; ?></label>
</div>
<?php }
?>
</div>
</div>
</div>
</div>
</form>
</div>
<?php /* Submit Button for Product Sorting */?>
<div class="submit__button-wrapper">
<button style="display: none;" class="sorting__submit">Show products</button>
</div>
<?php
Please let me know if this makes sense, I realize it is a lot of code in filters.php but the important part is the part noted with "Fabrics" as that is the input group that I am having trouble with.
Edit #2
I realized there might be an important function in my functions.php file that needs to be mentioned.
This works fine if the parameters are in the "clean/beautiful" state in the URL (i.e. example.com/category/page/2?filter_fabric=cotton&filter_fabric=polyester), but when I am on the paginated link, it automatically redirects to example.com/category/page/2?filter_fabric=polyester. It does this before the page is loaded, as I can see in my dev tools that a 301 request is sent to the second url with only the last parameter. I would assume this is some Wordpress automatic function that does that - is there any way to disable this?
function _url_parameters_query( $query ) {
//Check if query is for archive pages (otherwise this breaks e.g. nav header WP_Query)
if ($query->query_vars['wc_query'] !== 'product_query' || is_admin() ) {
return;
}
$url_parameters = $_SERVER['QUERY_STRING'];
$data = proper_parse_str($url_parameters);
$product_fabric = $data['filter_fabric'] ? $data['filter_fabric'] : null;
//Check if filter input is in array of parameters from URL, and mark the input as "checked"
if (isset($product_fabric)) {
// you can't use the query->set here for tax_query as tax query has already been made so you need to need add the data to any existing tax query
$tax_query = array(
'taxonomy' => 'pa_tygmaterial',
'field' => 'slug',
'terms' => $product_fabric,
'relation' => 'AND',
);
$query->tax_query->queries[] = $tax_query;
$query->query_vars['tax_query'] = $query->tax_query->queries;
if (array_key_exists('filter_fabric', $query->query)) {
// echo 'hello there Renjo!';
$query->query['filter_fabric'] = $product_fabric;
}
}
}
add_action( 'pre_get_posts', '_url_parameters_query' );
I think I resolved this issue by adding the following function in functions.php. I realized it was the redirect that was making problems for me, so I added the following:
//Remove redirection when filters with same name are set in URL (i.e. filters from input_groups), otherwise only passes last value
# e.g. example.com/category/page/2/?filter_fabric=cotton&filter_fabric=polyester => example.com/category/page/2/?filter_fabric=polyester
function _disable_redirect_query_params() {
global $wp_query;
if ($wp_query->query_vars['wc_query'] !== 'product_query' || is_admin() ) {
return;
}
if (isset($_GET['filter_tygmaterial']) ) {
remove_action('template_redirect', 'redirect_canonical');
}
}
add_action( 'wp', '_disable_redirect_query_params' );
I am not sure if there are any potential side effects of this, so if anyone has something in mind, please comment or let me know!
Related
I have a question related with Wordpress Ajax posts request. And I can't figure out for hours... Maybe someone will give me advice what I'm doing wrong!
Problem:
So I have infinite scroll on my archive pages. Everything is working as it should but for some reason it loads all the time the same 20 posts... What I need to change to have infinite scroll as long as created posts exists.
Here is my JS code:
function loadArticle() {
var loading = false;
$(window).bind('scroll', function() {
var page = $(this).data('page');
var newPage = page + 1;
var maxPages = $("#content").data('max-pages');
var postType = false;
var search = getQueryVariable("s");
if ( $('body').hasClass('post-type-archive-news') ) {
postType = 'news';
} else if ( $('body').hasClass('post-type-archive-ebooks') ) {
postType = 'ebooks';
} else if ( $('body').hasClass('post-type-archive-lookbooks') ) {
postType = 'lookbooks';
} else if ( $('body').hasClass('post-type-archive-case-studies') ) {
postType = 'case-studies';
} else if ( $('body').hasClass('post-type-archive-events') ) {
postType = 'events';
} else if ( $('body').hasClass('search-results') ) {
postType = false;
} else {
postType = 'post';
}
var query = 'action=infinite_scroll';
if ( newPage ) {
query = query + '&page_no=' + newPage;
}
if ( typeof postType == "string" ) {
query = query + "&post_type=" + postType;
}
if ( typeof search == "string" ) {
query = query + "&search=" + search;
}
// Show Loader
//$('a#inifiniteLoader').show('fast');
// Load Next Page
if(!loading && $(window).scrollTop() >= ($('#content').offset().top + $('#content').outerHeight() - window.innerHeight)) {
loading = true;
$.ajax({
url: "/wp-admin/admin-ajax.php",
type:'POST',
data: query,
success: function(html){
$("#content").append(html); // This will be the div where our content will be loaded
loading = false;
}
});
}
return false;
});
}
And this is my PHP
function yieldify_infinite_scroll(){
//init ajax
$ajax = false;
//check ajax call or not
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$ajax = true;
}
$paged = $_POST['page_no'] + 1;
$post_type = $_POST['post_type'];
$search = $_POST['s'];
$args = array(
'posts_per_page' => get_option('posts_per_page'),
'paged' => $paged,
'orderby' => 'date',
'order' => 'DESC',
'post_status' => 'publish'
);
if ( $post_type ) {
$args['post_type'] = $post_type;
}
if ( $search ) {
$args['s'] = $post_type;
}
// Load the posts
//query_posts( $args );
$ajax_query = new WP_query( $args );
//echo "<pre>";
//$print_query = json_encode( $ajax_query, JSON_PRETTY_PRINT );
//$print_query = htmlentities( $print_query, ENT_QUOTES, 'utf-8' );
//print_r( $print_query );
//echo "</pre>";
if( $ajax_query->have_posts() ) {
while( $ajax_query->have_posts() ) { $ajax_query->the_post();
if ( $post_type ) { ?>
<div class='col-12 col-md-6 col-lg-4 d-flex'>
<?php get_template_part('loops/card-new'); ?>
</div><!-- .col -->
<?php } else {
echo "<div class='col-12'>";
get_template_part('loops/search-results');
echo "</div>";
}
}
}
wp_reset_postdata();
//check ajax call
if($ajax) die();
exit;
}
add_action('wp_ajax_infinite_scroll', 'yieldify_infinite_scroll'); // for logged in user
add_action('wp_ajax_nopriv_infinite_scroll', 'yieldify_infinite_scroll');
My archive layout looks like that:
<?php if( have_posts() ) : $paged = (get_query_var('paged')) ? get_query_var('paged') : 1; ?>
<section id="blog-listing" class="resources-section">
<div class='container'>
<div class='row' id="content">
<?php while( have_posts() ) : the_post(); ?>
<div class='col-12 col-md-6 col-lg-4 d-flex'>
<?php get_template_part('loops/card-new'); ?>
</div><!-- .col -->
<?php endwhile; ?>
</div><!-- .row -->
<div class='row'>
<div class='col-12 text-center'>
Show More
</div><!-- .col -->
</div><!-- .row -->
</div><!-- .container -->
</section><!-- #blog-listing -->
<?php endif; ?>
I would be appreciated for any help!
It seems to me that you need to update the value in $(this).data('page')
You get it, do an increment on the variable, but you do not store it back. Try to modify as follow.
var page = $(this).data('page');
var newPage = page + 1;
$(this).data('page', newPage);
I am new into settings api , but still can't find much about media uploader from wp.
I have followed a tutorial but I am stuck at the point where I cannot save the image src into option.
Im sorry in advance for writting this much code , I don't know how I can reproduce my problem and I wanna cover all the aspects for a good answer. I will provide a image as well for a visual view.
Thank you.
Image: https://prnt.sc/6p9gfxc51FDA
AdminClass.php
public $settings; // class that builds the fields oop;
public $callbacks; // class that handle callbacks;
public function register() {
// instantiate classes;
$this->settings = new SettingsApi();
$this->callbacks = new AdminCallbacks();
}
public function setFields(){
$args = array(
array(
'id' => 'promo_image1',
'title' => 'Promotional Image',
'callback' => array( $this->callbacks, 'ss_PromoImage' ),
'page' => SS_PLUGIN,
'section' => 'ss_options_zone',
'args' => array(
'label_for' => 'promo_image1',
'class' => 'ss_image_field'
)
)
);
$this->settings->setFields( $args );
}
SettingsApi
public $settings = array();
public $fields = array();
public function registerCustomFields(){
// add setting
foreach ( $this->settings as $setting ):
register_setting(
$setting["option_group"],
$setting["option_name"],
( isset( $setting["callback"] ) ? $setting["callback"] : '' )
);
endforeach;
// add settings field
foreach ( $this->fields as $field ):
add_settings_field(
$field["id"],
$field["title"],
( isset( $field["callback"] ) ? $field["callback"] : '' ),
$field["page"],
$field["section"],
( isset( $field["args"] ) ? $field["args"] : '' )
);
endforeach;
}
public function setFields( array $fields ){
$this->fields = $fields;
return $this;
}
CallbackClass.php
public function ss_PromoImage() {
// Set variables
// $value is always empty and I dont know why
$value = esc_attr( get_option ('promo_image1') );
$default_image = SS_PLUGIN_URL . 'assets/images/sales.png';
if ( !empty($value ) ) {
$image_attributes = wp_get_attachment_image_src( $value );
$src = $image_attributes[0];
update_option( $value , $src );
$value = $src;
} else {
$src = $default_image;
$value = '';
}
$text = __( 'Upload', '' );
// Print HTML field
echo '
<div class="upload">
<img style="max-width: 300px;" data-src="' . ( !empty($value) ? $value : $src ) . '" src="' . ( !empty($value) ? $value : $src ) . '" />
<div>
<input type="hidden" class="value_option" name="'. $value .'" value="' . $value . '" />
<button type="button" class="upload_image_button button">' . $text . '</button>
<button type="button" class="remove_image_button button">Remove</button>
</div>
</div>
';
?>
<script>
jQuery(document).ready(function($){
// The "Upload" button
$('.upload_image_button').click(function() {
var send_attachment_bkp = wp.media.editor.send.attachment;
var button = $(this);
wp.media.editor.send.attachment = function(props, attachment) {
$(button).parent().prev().attr('src', attachment.url);
$(button).find('.value_option').val(attachment.id);
wp.media.editor.send.attachment = send_attachment_bkp;
}
wp.media.editor.open(button);
return false;
});
// The "Remove" button (remove the value from input type='hidden')
$('.remove_image_button').click(function() {
var src = $(this).parent().prev().attr('src', '');
});
});
</script>
<?php
}
and here is the output:
<form method="post" action="options.php">
<?php
settings_errors();
settings_fields( 'ss_options_group' );
do_settings_sections( SS_PLUGIN );
submit_button();
?>
</form>
Here is My code, it should be filtering by category, it displays all posts on any checkbox I click, I don't know how to fix this, I have tried everything.
<form id="filter">
<?php
if( $terms = get_terms( 'category', 'orderby=name' ) ) : // to make it simple I use default categories
foreach ( $terms as $term ) :
echo '<input type="checkbox" name="category[]" value="' . $term->term_id . '" class="br">' . $term->name;
echo '';
endforeach;
endif;
?>
<div class="filter-output"></div>
</form>
Here is the js (coded inside a template page)
jQuery('#filter .br').click(function(){
// Declaratie van array
var choices = {};
jQuery('.contents').remove();
jQuery('.filter-output').empty();
jQuery('input[type=checkbox]:checked').each(function() {
if (!choices.hasOwnProperty(this.name))
choices[this.name] = [this.value];
else
choices[this.name].push(this.value);
});
console.log(choices);
jQuery.ajax({
url: '<?php echo admin_url('admin-ajax.php'); ?>',
type :'POST',
data : {
'action' : 'call_post', // Naam van de PHP functie
'choices' : choices,
},
success: function (result) {
jQuery('.filter-output').append(result);
// Voor testen - Resultaat (Kan later verwijderd worden)
//console.log(Resultaat);
//console.log(Keuzes);
},
error: function(err){
// Voor testen - Error (Kan later verwijderd worden)
console.log(err);
console.log(choices);
}
});
})
funstions.php
add_action('wp_ajax_call_post', 'call_post');
add_action('wp_ajax_nopriv_call_post', 'call_post');
function call_post(){
// Verkijgen van AJAX data:
$choices = $_POST['choices'];
$meta_query = array('relation' => 'OR');
foreach($choices as $Key=>$Value){
if(count($Value)){
foreach ($Value as $Inkey => $Invalue) {
$meta_query[] = array( 'key' => $Key, 'value' => $Invalue, 'compare' => '=' );
}
}
}
$args = array(
'post_type' => 'post',
'meta_query' =>$meta_query
);
$query = new WP_Query($args);
//if( ! empty ($params['template'])) {
////$template = $params['template'];
if( $query->have_posts() ) :
while( $query->have_posts() ): $query->the_post();
the_title();
endwhile;
wp_reset_query();
else :
wp_send_json($query->posts);
endif;
//}
die(); }
Anyone please help, I have been trying to make this work since yesterday and with no luck at all
I've refactored your code and made it work:
Template:
<?php
/**
*
* Template Name: Filter Posts
*
*/
get_header();
$args = array(
'post_type' => 'post',
'posts_per_page' => -1,
);
$tax_query = array();
$categories = get_terms( 'category', 'orderby=name' );
if ( ! empty( $choices = get_request_param( 'choices' ) ) ) {
$term_ids = explode(',', $choices);
$tax_query[] = array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => $term_ids
);
$args['tax_query'] = $tax_query;
}
$query = new WP_Query( $args );
if ( ! empty( $categories ) ) : ?>
<form action="?" method="post" class="form-filter">
<?php foreach ( $categories as $category ) : ?>
<div class="checkbox">
<input type="checkbox" name="category[]" data-category="<?php echo esc_attr( $category->term_id ); ?>" id="<?php echo esc_attr( $category->slug ); ?>">
<label for="<?php echo esc_attr( $category->slug ); ?>">
<?php echo esc_html( $category->name ); ?>
</label>
</div><!-- /.checkbox -->
<?php endforeach; ?>
</form><!-- /.form-filter -->
<?php endif; ?>
<div class="filter-output">
<ul>
<?php while ( $query->have_posts() ) : $query->the_post(); ?>
<li>
<?php the_title(); ?>
</li>
<?php endwhile; ?>
</ul>
</div><!-- /.filter-output -->
<?php
wp_reset_postdata();
get_footer();
Javascript:
;(function(window, document, $) {
var $win = $(window);
var $doc = $(document);
$doc.on('change', '.form-filter', function() {
var choices = '';
$('.form-filter input:checked').each(function() {
if ( choices === '' ) {
choices += $(this).data('category');
} else {
choices += ',' + $(this).data('category');
}
});
$.ajax({
url: window.location.href,
type: 'GET',
data: {
'choices' : choices,
},
success: function(response) {
var newPosts = $(response).filter('.filter-output').html();
$('.filter-output').html(newPosts);
}
});
});
})(window, document, window.jQuery);
functions.php
function get_request_param( $key = '' ) {
$value = false;
if ( ! $key ) {
return $value;
}
if ( isset( $_POST[$key] ) ) {
$value = $_POST[$key];
} elseif ( isset( $_GET[$key] ) ) {
$value = $_GET[$key];
}
return $value;
}
Few notes:
1) Use jquery change event, instead of click for the filter form.
2) WP AJAX is not needed in this case. You can simply make a GET request to the same page and change the HTML where needed.
3) Use GET method instead of POST
I am a beginner front-end developer, and these are my first steps with Wordpress.
How can I show posts which have the search term from the search input in their title or in their content? I don't want to use plugins or the built-in Wordpress searching with its reload page.
This is my code:
HTML
<form class="search__form" action="" method="POST">
<div class="search__input-container">
<input type="text" name="search" class="search__input search__input-js" placeholder="Search">
</div>
</form>
JavaScript
$('.search__input-js').on('change', function(){
var search = $('.search__input').val();
search = search.toLowerCase();
$.ajax({
type: 'POST',
url: ajax_options.admin_ajax_url,
data:{
search: search,
action: 'ajax_func'
},
success: function(result) {
$('.return-msg').html('');
$('.return-msg').html(result);
},
error: function(e) {
console.log(e);
}
});
});
Functions.php
function ajax_func() {
wp_reset_postdata();
$search_term = '';
$result = '';
if(isset($_POST['search'])){
$search_term .= $_POST['search'];
}else{
$search_term = '';
}
$args= array(
'post_type' => array('post', 'case-study'),
'HERE'
);
$the_query_posts = new WP_Query( $args );
if ( $the_query_posts->have_posts() ) {
while ( $the_query_posts->have_posts() ) {
$the_query_posts->the_post();
$result .='
<div class="col-lg-4">';
$result .='
<a class="post__link" href="'.get_the_permalink().'">
<div class="post__container">';
if (has_post_thumbnail()) {
$result .= '
'.get_the_post_thumbnail(get_the_ID(), 'post-thumbnail', ['class' => 'post__img', 'alt' => get_the_title()]).'
';
} else {
$result .= '
<img class="img-responsive responsive--full post__img" src="" />
';
}
$result .='
<div class="post__background">
<p class="post__category">'.get_the_category(get_the_ID())[0]->name .'</p>';
$result .='<p class="post__name">'.get_the_title().'</p>';
$result .='<div class="post__desc">'.get_field('post_short_desc').'</div>';
$result .='
</div>
</div>
</a>
</div>';
}
wp_reset_postdata();
} else {
$result .= '<div class="col-12">0 posts</div>';
wp_reset_postdata();
}
echo $result;
die();
}
remove_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
add_action('wp_ajax_nopriv_ajax_func', 'ajax_func');
add_action('wp_ajax_ajax_func', 'ajax_func');
Ajax works correctly, and I know that I should write some function and set up a special WP query to find my posts where I write 'HERE', but I don't know how. Could anybody give me a hint?
WP_Query has a search parameter you can pass into it. It's also built in should you not want to use AJAX ( example.com/?s=query+here ). Altogether it would look like this:
$args= array(
'post_type' => array( 'post', 'case-study' ),
's' => $search_term
);
It's an old topic, I know, but if you are looking for a solution, in doc, in WP_Query class you can see the s parameter, but there's sentence parameter also, even though it doesn't appear in the doc.
$args = array(
'post_type' => array( 'post', 'case-study' ),
'sentence' => true,
's' => $search_term
);
I have searched all over here and the web but cant seem to get this to work - hopefully you all can help.
I am trying to setup product filters for WooCommerce on the category page (like filter products depending on color etc)
I have the ajax working but I have a shortcode that I want to display for each product and this doesnt work - any ideas how to get it to show?
Code below:
PHP
function ajax_filter_posts_scripts() {
// Enqueue script
wp_register_script('afp_script', plugins_url() . '/plugin-name/js/product-filter-ajax.js', false, null, false);
wp_enqueue_script('afp_script');
wp_localize_script( 'afp_script', 'afp_vars', array(
'afp_nonce' => wp_create_nonce( 'afp_nonce' ), // Create nonce which we later will use to verify AJAX request
'afp_ajax_url' => admin_url( 'admin-ajax.php' ),
)
);
}
add_action('wp_enqueue_scripts', 'ajax_filter_posts_scripts', 100);
JS
jQuery(document).ready(function($) {
$(".loading").hide();
var taxonomy = [];
var terms = [];
$('.filter-option input').click( function(event) {
var taxonomy_idx = $.inArray($(this).closest(".filter-title-wrapper").attr('data-attribute'), taxonomy);
if (taxonomy_idx == -1) {
taxonomy.push($(this).closest(".filter-title-wrapper").attr('data-attribute'));
} else {
taxonomy.splice(taxonomy_idx, 1);
}
var terms_idx = $.inArray($(this).val(), terms);
if (terms_idx == -1) {
terms.push($(this).val());
} else {
terms.splice(terms_idx, 1);
}
// Prevent default action - opening tag page
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
// Get tag slug from title attirbute
var selecetd_taxonomy = taxonomy.toString();;
var selected_term = terms.toString();
var selected_term_speach = '\'' + selected_term.split(',').join('\',\'') + '\'';
console.log(selecetd_taxonomy);
console.log(selected_term_speach);
// After user click on tag, fade out list of posts
$('.products').fadeOut();
$(".loading").fadeIn();
data = {
action: 'filter_posts', // function to execute
afp_nonce: afp_vars.afp_nonce, // wp_nonce
taxonomy: selecetd_taxonomy, // selected tag
term: selected_term_speach,
};
$.post( afp_vars.afp_ajax_url, data, function(response) {
$(".loading").fadeOut();
if( response ) {
// Display posts on page
$('.products').html( response );
// Restore div visibility
$('.products').fadeIn();
};
});
});
});
PHP TO GET POSTS
// Script for getting posts
function ajax_filter_get_posts( $taxonomy, $term ) {
ob_start();
global $woocommerce, $product;
// Verify nonce
if( !isset( $_POST['afp_nonce'] ) || !wp_verify_nonce( $_POST['afp_nonce'], 'afp_nonce' ) )
die('Permission denied');
$taxonomy = $_POST['taxonomy'];
$term = $_POST['term'];
$term = str_replace("\\", '', $term);
// WP Query
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => -1,
);
if ($term == "''") {
}
else {
$args = array(
'tax_query' => array(
array(
'taxonomy' => $taxonomy,
'terms' => array($term),
'field' => 'slug',
'operator' => 'IN'
),
)
);
}
?>
<h1> <?php echo $term ?> </h1>
<?php
$query = new WP_Query( $args );
if ( $query->have_posts() ) : while ( $query->have_posts() ) : $query->the_post(); ?>
<li <?php wc_product_class(); ?>>
<?php echo do_shortcode('[product_shortcode]'); ?>
</li>
<?php
?>
<?php endwhile; ?>
<?php else: ?>
<h2>No posts found</h2>
<?php endif;
die();
return ob_get_clean();
}
add_action('wp_ajax_filter_posts', 'ajax_filter_get_posts');
add_action('wp_ajax_nopriv_filter_posts', 'ajax_filter_get_posts');
Excuse the messyness of the code, just trying to get it to work before I can start to neaten it up. Any advice on how to approach this in a better way please let me know.
Thanks and appreciate the help!
UPDATE-----
Tried to add the shortcode callback, but this doesnt work or I have the wrong code
add_action( 'init', function() {
ps_register_shortcode_ajax( 'ajax_filter_get_posts', 'ajax_filter_get_posts' );
} );
function ps_register_shortcode_ajax( $callable, $action ) {
if ( empty( $_POST['action'] ) || $_POST['action'] != $action )
return;
call_user_func( $callable );
}
WordPress Ajax calls don't have the access to whole WordPress environment and that's why your shortcode not working. Instead of calling the shortcode directly, call its callback. Refer https://wordpress.stackexchange.com/questions/53309/why-might-a-plugins-do-shortcode-not-work-in-an-ajax-request for more details.