Adding multiple values to a query variable in WordPress - php

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

Ajax request loads the same posts

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);

Can't save option of a media upload file using SettingsApi form worpdress

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>

Wordpress ajax filter returning all posts when it should be filtering by category

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

Wordpress query to find posts with exactly sentence from search input

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
);

Echo shortcode in WordPress AJAX function return

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.

Categories