I am working in a WordPress site that has many custom post types, and extensive use of Advanced Custom Fields (ACF). The site also uses node modules, custom code from scratch, and Git in favor of a pre-built theme and "typical" plugins. Many of the tasks I do involve working with code already written.
The site is a safari business. We have Continents, Countries (sometimes called Destinations in certain contexts), Places, and Testimonials - all are custom posts. None of which use any taxonomies at all, ever. The testimonials already have custom fields via ACF connecting the Testimonials with appropriate Continents, Countries, and Places.
My issue is pretty complex, and I'll do my best to explain it.
My goal
Create an Ajax filter to display Testimonials by Continent, Country, and (eventually) Place, without a plugin. Continent and Country can be select
fields, and only one is required, optionally both can be set.
The site already has an almost identical version of this, working. It has dropdown select
s that filter one of the other custom post types, Itineraries. What I need is exactly like this, just for Testimonials instead of Itineraries. That page is https://extraordinaryjourneys.com/plan-your-trip/itineraries/.
It uses NPM Select-custom and a few PHP and JS files. I've included two of them below.
What I have tried
I have made duplicated files of the Itineraries files for Testimonials, and trying to make those work just like that Itineraries page working example is. It might be easier to write meta_queries
and if so I'll need a little guidance there, but i thought this would be easier. These are the files, including sections I've commented out because they were related to one of the dropdowns from the itineraries page that don't need to be on this testimonials page, like trip budget, or because it's part of me figuring out how this all works.
Where I am stuck I've pushed the code to the staging site, and you can see the console errors. Can you help me troubleshoot the api 404 call? The already existing Itineraries page linked above has the same, but without error. https://staging.extraordinaryjourneys.com/testimonial-troubleshooting You can click the Continent or Country selects and you'll get an alert, which must be related to the api call. Screenshot here showing what you'll see in console.
If there's anything else to include or add I am happy to.
hero-filter-testimonials.js
import '../elements/filter-results-grid';
$(document).ready(function () {
const $body = $('body');
const $filterTestimonials = $('.filter-testimonials');
$body.on('click', '.btn-load-more', function (e) {
$(e.currentTarget).hide();
getResults(null, parseInt(e.currentTarget.dataset.page));
});
$('.clear-all').click(function () {
window.history.replaceState(null, null, '#');
triggerSearch(getParamsObject(), $filterTestimonials);
});
continentContainer.find('.custom-select__option').on('click', function (e) {
let continentId = e.currentTarget.dataset.value;
showCountriesOptions(continentId);
});
function showCountriesOptions(continentId = null) {
const $selectContainer = $filterTestimonials.find('#destination').parent();
console.log('Line 38 hero-filter-testimonials.js: continentId: ' + continentId);
if (continentId) {
$selectContainer.find('.custom-select__option').hide();
$selectContainer.find(".custom-select__option[data-continent='" + continentId + "']").show();
} else {
$selectContainer.find('.custom-select__option').not('[data-value="placeholder"]').show();
}
}
function getResults(origin = null, page = 1) {
console.log("getResults(): " + getResults);
let data = {action: 'get_testimonial_results'};
$filterTestimonials.find('.filter-panel').hide();
const $select = $filterTestimonials.find('.custom-select');
data = getDataFromSelectors(data, $select);
if (origin && origin === 'continent') {
if (data['destination']) {
delete data['destination'];
resetSingleSelector($filterTestimonials.find('#destination')[0]);
}
}
$filterTestimonials.find('#special_departures').prop("checked");
console.log("Line below is log.data");
console.log(data);
console.log("Line below is dir.data");
console.dir(data);
updateUrl(data);
if (Object.keys(data).length === 1) {
getContainer().show();
getResultsContainer().hide();
$body.find('.clear-all-btn-container').hide();
} else {
let $loader = $body.find('.filter-loader');
$body.find('.clear-all-btn-container').show();
getFilterResults('get_testimonial_results', 'Testimonials', data, $loader, page);
}
addBadges($filterTestimonials, ['continent']);
}
window.getResults = getResults;
let data = getParamsObject();
console.log("Line below is data");
console.table(data);
console.log("Line below is $filterTestimonials");
console.table($filterTestimonials);
// console.log(JSON.stringify($filterTestimonials,null,2));
triggerSearch(data, $filterTestimonials);
});
testimonials_results.php
This page makes a custom api call that returns a 404, and I don't know why. It also has the query to get testimonials posts.
<?php
add_action('rest_api_init', function () {
register_rest_route('ejourneysnineteen/v1', '/get_testimonial_results', array(
'methods' => 'POST',
'callback' => 'get_testimonial_results',
'permission_callback' => function () {
return true;
}
));
});
function get_testimonial_results() {
$pageSize = $_REQUEST['pageSize'] ?? 10;
$args = [
'posts_per_page' => $pageSize,
'ignore_sticky_posts' => 1,
'post_type' => 'testimonial',
'orderby' => 'title',
'order' => 'ASC',
];
if (isset($_REQUEST['page'])) {
$args['paged'] = $_REQUEST['page'];
}
if (isset($_REQUEST['continent']) ||
isset($_REQUEST['destination'])
// isset($_REQUEST['region']) ||
// isset($_REQUEST['accommodation_type']
) {
// $metaQueries = ['relation' => 'AND'];
if (isset($_REQUEST['region'])) {
$regions = explode(',', $_REQUEST['region']);
$subquery = [
'relation' => 'OR'
];
foreach ($regions as $region) {
$subquery[] = [
'key' => 'accommodation_region',
'value' => $region,
'compare' => 'LIKE'
];
}
$metaQueries[] = $subquery;
}
else {
if (isset($_REQUEST['destination'])) {
$metaQueries[] = [
'key' => 'testimonial_country',
'value' => $_REQUEST['destination'],
'compare' => 'LIKE',
];
}
else {
if (isset($_REQUEST['continent'])) {
$metaQueries[] = [
'key' => 'testimonial_continent',
'value' => $_REQUEST['continent'],
'compare' => 'LIKE',
];
}
}
}
$args = array_merge($args, [
'meta_query' => $metaQueries
]);
}
$result = [];
if (count($metaQueries) > 1) {
$query = new WP_Query($args);
foreach ($query->get_posts() as $post) {
$post_thumbnail_id = get_post_thumbnail_id($post);
$image_url = fly_get_attachment_image_src($post_thumbnail_id, [500, 500], true);
$result[] = [
'link' => get_the_permalink($post),
'title' => $post->post_title,
'excerpt' => html_entity_decode(ellipsis(get_the_excerpt($post), 80)),
'image_url' => $image_url,
'category' => 'Testimonial'
];
}
}
wp_send_json_success([
'results' => $result,
'total' => $query->found_posts,
'pages' => $query->max_num_pages,
]);
}
There are other files but I'm so stuck I'm not sure if I should add them all there or not. Is this enough to help me troubleshoot the api call 404?
$metaQueries
should be defined before theif (isset($_REQUEST['continent']) ...)
line), but as for the 404 error, the full message I saw (here via a POST request) is, "No route was found matching the URL and request method.", so how are you loading thetestimonials_results.php
file? Is itinclude
-d orrequire
-d from within thefunctions.php
file? Does your AJAX request actually make a POST request?rest_testimonial_query
hook to modify the query args so that you could just use the default endpoint to fetch the testimonial posts..testimonials_results
at all. I added it as arequire_once
infunctions.php
. That got rid of the 404! Thank you for taking a look. What's the best practice for this, here - edit the question for the other issues, upvote comment, or something else?