I have created a custom taxonomy and added the below script for the search in the function.php. This works so far. But if the title of the taxonomy has a space, it will not be found.
So if the title of the taxonomy is e.g. dog, then it is found with "dog".
But if the title is called dog food, it will not be found with "dog food".
What can be the reason for this?
add_filter( 'posts_search', 'woocommerce_search_product_tag_extended', 999, 2 );
function woocommerce_search_product_tag_extended( $search, $query ) {
global $wpdb, $wp;
$qvars = $wp->query_vars;
if ( is_admin() || empty($search) || ! ( isset($qvars['s'])
&& isset($qvars['post_type']) && ! empty($qvars['s'])
&& $qvars['post_type'] === 'product' ) ) {
return $search;
}
// Here set your custom taxonomy
$taxonomy = 'CUSTOMTAXONOMY'; // WooCommerce product tag
// Get the product Ids
$ids = get_posts( array(
'posts_per_page' => -1,
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => array( array(
'taxonomy' => $taxonomy,
'field' => 'name',
'terms' => esc_attr($qvars['s']),
)),
));
if ( count( $ids ) > 0 ) {
$search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode( ',', $ids ) . ")) OR (", $search);
}
return $search;
}
Related
I am currently working on a new wordpress website which uses the Newspaper theme, which lets me compose pages with the tagdiv composer plugin.
This plugin makes it fairly easy to show posts of your choosing; with blocks/modules that have built in filters, that allow you to select the posts to be shown based upon the categories, authors, etc. that you choose.
However I would like to show custom taxonomies in there as well, so that I can choose for instance album reviews, which have the custom taxonomy of the letter A attached to it.
For my client I would need to do that since he requested a glossary (alphabetical index).
So far I have created a custom taxonomy called "alphabetical_letter", which houses all 26 characters with the linked posts to it.
The code which I need to alter is this one, preferrably I'd have a drop down list. However I keep failing in getting it right. Could anyone point me in the right direction please ?
/**
* the filter array (used by blocks and by the loop filters)
* #return array
*/
static function get_map_filter_array ($group = 'Filter') {
return array(
array(
"param_name" => "separator",
"type" => "text_separator",
'heading' => 'Filters',
"value" => "",
"class" => "",
'group' => $group
),
array(
"param_name" => "post_ids",
"type" => "textfield",
"value" => '',
"heading" => 'Post ID filter:',
"description" => "Filter multiple posts by ID. Enter here the post IDs separated by commas (ex: 10,27,233). To exclude posts from this block add them with '-' (ex: -7, -16)",
"holder" => "div",
"class" => "tdc-textfield-big",
'group' => $group
),
array(
"param_name" => "category_id",
"type" => "dropdown",
"value" => td_util::get_category2id_array(),
"heading" => 'Category filter:',
"description" => "A single category filter. If you want to filter multiple categories, use the 'Multiple categories filter' and leave this to default",
"holder" => "div",
"class" => "tdc-dropdown-big",
'group' => $group
),
array(
"param_name" => "category_ids",
"type" => "textfield",
"value" => '',
"heading" => 'Multiple categories filter:',
"description" => "Filter multiple categories by ID. Enter here the category IDs separated by commas (ex: 13,23,18). To exclude categories from this block add them with '-' (ex: -9, -10)",
"holder" => "div",
"class" => "tdc-textfield-big",
'group' => $group
),
array(
"param_name" => "alphabetical_letter_id",
"type" => "dropdown",
"value" => td_util::get_alphabetical_letter_id_array(),
"heading" => 'Custom taxonomy:',
"description" => "alphabetical letter custom taxonomy",
"holder" => "div",
"class" => "tdc-dropdown-big",
'group' => $group
),
array(
"param_name" => "tag_slug",
"type" => "textfield",
"value" => '',
"heading" => 'Filter by tag slug:',
"description" => "To filter multiple tag slugs, enter here the tag slugs separated by commas (ex: tag1,tag2,tag3)",
"holder" => "div",
"class" => "tdc-textfield-big",
'group' => $group
),`enter code here`
Edit:
in the meantime I have tried to figure out the td_util I keep seeing.
There is a file called td_util.php one folder up from where this file is, and it mentions the category2id_array so I am currently trying to find out if the problem lies here.
for completeness, this is the bit of text that refers to the category2id array function above (or the other way around more likely).
/**
* generates a category tree, only on /wp_admin/, uses a buffer
* #param bool $add_all_category = if true ads - All categories - at the begining of the list (used for dropdowns)
* #return array
*/
private static $td_category2id_array_walker_buffer = array();
static function get_category2id_array($add_all_category = true) {
if (is_admin() === false) {
return array();
}
if (empty(self::$td_category2id_array_walker_buffer)) {
$categories = get_categories(array(
'hide_empty' => 0,
'number' => 1500
));
$td_category2id_array_walker = new td_category2id_array_walker;
$td_category2id_array_walker->walk($categories, 4);
self::$td_category2id_array_walker_buffer = $td_category2id_array_walker->td_array_buffer;
}
if ($add_all_category === true) {
$categories_buffer['- All categories -'] = '';
return array_merge(
$categories_buffer,
self::$td_category2id_array_walker_buffer
);
} else {
return self::$td_category2id_array_walker_buffer;
}
}
And a bit further down the file it pops up one last time
class td_category2id_array_walker extends Walker {
var $tree_type = 'category';
var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
var $td_array_buffer = array();
function start_lvl( &$output, $depth = 0, $args = array() ) {
}
function end_lvl( &$output, $depth = 0, $args = array() ) {
}
function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
$this->td_array_buffer[str_repeat(' - ', $depth) . $category->name . ' - [ id: ' . $category->term_id . ' ]' ] = $category->term_id;
}
function end_el( &$output, $page, $depth = 0, $args = array() ) {
}
}
I have a working search query with offset and post_per_page (the user can go through pages)
$args = array(
'post_type' => 'type',
's'=>$the_str,
'posts_per_page' => $the_count,
'offset' => ($the_count*$the_c_page )-$the_count
);
$the_query = new WP_Query( $args );
It works great.
But now I need to add a meta field to the search function. It should get all post where s=>$query OR meta-field=>$query
Something like this:
$args = array(
'post_type' => 'type',
'posts_per_page' => $the_count,
'offset' => ($the_count*$the_c_page )-$the_count,
'meta_query' => array(
'relation' => 'OR',
's'=>$the_str,
array(
'key' => 'key',
'value' => $the_str
)
);
$the_query = new WP_Query( $args );
Unfortunately this will only search after the second condition. Does anybody have an idea?
If you crack open query.php you'll see that it really isn't built with this in mind. It isn't that it isn't a great idea, it's just that each individual query part is concatenated onto the main WHERE using an AND. So "title contains XYZ" AND "whatever the meta query is" AND "whatever the tax query is", etc. Meta and Tax both have sub logic within them that supports AND and OR but there's no way to perform this between these outer parts.
However, you might be able to do what you're looking for by tapping into one of the filters, possibly get_meta_sql. The meta query returns a statement that puts in the AND that you want to be an OR so you can just look for that and replace it:
function change_and_to_or_for_meta( $meta_query, $type, $primary_table, $primary_id_column, $context )
{
if( 0 === strpos( $meta_query['where'], ' AND' ) )
{
$meta_query['where'] = ' OR' . substr( $meta_query['where'], 4 );
}
return $meta_query;
}
//Add our filter to replace the AND at the start with OR
add_filter( 'get_meta_sql', 'change_and_to_or_for_meta', 10, 5 );
$query = new WP_Query( $args );
//Remove our filter so we don't mess other things up
remove_filter( 'get_meta_sql', 'change_and_to_or_for_meta', 10 );
I have created an archive page for my 'Event' custom post ape called archive-event.php.
I used the content from the standard archive.php template and it listed my 4 events in the order they were posted.
The next step was to change the order by the custom field event_date. I did this no problems. Then I wanted to not show any events that event_date had passed. The below code does this perfectly.
The issue I now have is my pagination is all messed up. I have the default reading settings set to 2 posts per page and I have a 'Load more' button to bring up the next two.
When I click 'Load more' it duplicates the two events already showing. Any ideas where I've gone wrong?
<?php
$today = date("Ymd");
$args = array (
'post_type' => 'event',
'meta_key' => 'event_date',
'orderby' => 'meta_value',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => 'event_date',
'value' => $today,
'type' => 'numeric',
'compare' => '>=',
)
),
);
$wp_query = new WP_Query( $args );
while( $wp_query->have_posts() )
{
$wp_query->the_post();
?>
<div>Content goes here</div>
<?php } wp_reset_postdata(); ?>
Depending on how the plugin builds the UI it may or may not be respecting the pagination functionality built into WordPress.
Try forcing the paged setting into your query like so:
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array (
'post_type' => 'event',
'paged' => $paged, // this will be set to what WordPress thinks is the proper page to start
'meta_key' => 'event_date',
'orderby' => 'meta_value',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => 'event_date',
'value' => $today,
'type' => 'numeric',
'compare' => '>=',
)
),
);
Next, if this still doesn't work, you can test the assumption that the paged parameter isn't working for some reason by changing the default paged value like so (again, just to test):
$paged = 2; // just force it to start on the second page to see if that works
If the above test works, I would say that get_query_var() believes you're on the first page.
Being a newbie and altering the site-wide form and fields using hook_form_Form_ID_alter() was a big accomplishment but now I'm beginning to run into walls involving validation of some of the custom fields I've added. Following is the code from my custom_form.module file.
<?php
/**
* Implementation of hook_form_Form_ID_alter().
* #see http://api.drupal.org/api/function/hook_form_Form_ID_alter
* Targets only request catalog form and adds a few custom fields to the default Drupal contact form and removes some fields.
*/
function states_list() {
return array(
'- Select -',
'AL' => 'Alabama',
//rest of states....,
);
}
function request_catalog_form_local_contact_page_alter(&$form, $form_state) {
$form['parts_catalog'] = array(
'#title' => t('Retail Parts Catalog'),
'#type' => 'checkbox',
);
$form['sprayer_catalog'] = array(
'#title' => t('Sprayer Parts Catalog'),
'#type' => 'checkbox',
);
$form['address'] = array(
'#title' => t('Address'),
'#type' => 'textfield',
'#required' => true,
);
$form['city'] = array(
'#title' => t('City'),
'#type' => 'textfield',
'#size' => 30,
'#required' => true,
);
$form['state'] = array(
'#title' => t('State'),
'#type' => 'select',
'#options' => states_list(),
'#required' => true,
);
$form['country'] = array(
'#title' => t('Country'),
'#type' => 'select',
'#options' => array(
'US' => t('United States'),
'Canada' => t('Canada'),
),
'#required' => true,
);
$form['zip'] = array(
'#title' => t('Zip'),
'#type' => 'textfield',
'#size' => 6,
'#maxlength' => 6,
'#required' => true,
);
$form['phone'] = array(
'#title' => t('Phone (xxx-xxx-xxxx)'),
'#type' => 'textfield',
'#size' => 12,
'#maxlength' => 12,
'#required' => true,
);
//Removes the textfield Message and the dropdown Subject choice.
$form['message']['#access']=false;
$form['subject']['#access']=false;
//Remove the Send Email submit button text by setting it to nothing and changing it.
$form['submit']['#title'] = '';
$form['submit']['#value'] = 'Submit Your Request';
// reorder the elements in the form to include the elements being inserted
$order = array('parts_catalog', 'sprayer_catalog', 'name', 'address', 'city', 'state', 'country', 'zip', 'phone', 'mail', 'copy', 'submit');
foreach($order as $key => $field) {
$form[$field]['#weight'] = $key;
}
}
// The custom email message sent using the data gathered in the form
function request_catalog_mail_alter(&$message) {
if ($message['id'] == 'contact_page_mail') {
$message['body'][1] = $message['params']['name'].' '.'has requested the following catalogs:';
$message['body'][2] = 'Parts Catalog: ' . $message['params']['parts_catalog']. ' ' . 'Sprayer Parts Catalog: ' .$message['params']['sprayer_catalog'];
$message['body'][4] = 'Send to: ' . $message['params']['address'].', '. $message['params']['city'].', ' . $message['params']['state'].' ' . $message['params']['zip']. ' ' . $message['params']['country'];
}
}
At this point I am most interested in how to show " - Select - " in the US States drop-down field BUT not let the user choose that as a choice. At this point they can leave -Select- in that required field and Drupal allows the form to submit. The data sent via email for that particular field = 0. I want to force the user to actually select a state.
I have tried all of the following methods.
http://www.chromaticsites.com/blog/drupal-tutorial-form-overrides-and-element-specific-validations/
Drupal form validation not working for me
http://befused.com/drupal/additional-validation-function
I have tried multiple code trial-an-error variations of these and nothing has worked as advertized...
Your questions for clarification or your suggestions are greatly appreciated. Remember to be specific and simple in your explanations and define terms please - presently for me most of php is like reading shakespeare.
Thanks so much.
I slept on this problem and then retried one of the links I had tried before. Drupal form validation not working for me
I was able to make it work to my satisfaction: I used this within
function request_catalog_form_local_contact_page_alter(&$form, $form_state) right after setting the $order value.
// reorder the elements in the form to include the elements being inserted
$order = array('parts_catalog', 'sprayer_catalog', 'name', 'address', 'city', 'state', 'country', 'zip', 'phone', 'mail', 'copy', 'submit');
foreach($order as $key => $field) {
$form[$field]['#weight'] = $key;
}
$form['#validate'][] = 'request_catalog_local_contact_page_validate';
function request_catalog_local_contact_page_validate(&$form, &$form_state) {
if ($form_state['values']['state'] == '0') {
form_set_error('state', t('Please Select a State'));
};
if ($form_state['values']['parts_catalog'] == '0' and $form_state['values']['sprayer_catalog'] =='0') {
form_set_error('parts_catalog' and 'sprayer_catalog', t('Please Select a Catalog'));
};
}
// The custom email message sent using the data gathered in the form
function request_catalog_mail_alter(&$message) {
if ($message['id'] == 'contact_page_mail') {
$message['body'][1] = $message['params']['name'].' '.'has requested the following catalogs:';
$message['body'][2] = 'Parts Catalog: ' . $message['params']['parts_catalog']. ' ' . 'Sprayer Parts Catalog: ' .$message['params']['sprayer_catalog'];
$message['body'][4] = 'Send to: ' . $message['params']['address'].', '. $message['params']['city'].', ' . $message['params']['state'].' ' . $message['params']['zip']. ' ' . $message['params']['country'];
}
}
}
Works for what I need now.
There is another way you can avoid this.
Just assign NULL value as ket to the first option.
Ex:
function states_list() {
return array(
'' =>'- Select -',
'AL' => 'Alabama',
//rest of states....,
);
}
This will do.
I have a Custom Post Type using the Custom Post Type UI plugin called Case Studies. I'm also using the Custom Fields to add a capability field to the Case Studies.
How can I query Case Studies where the capability is equal to some ID?
$query = array('post_type' => 'case-studies','posts_per_page' => 3);
is my query so far
It could be
$query = array(
'post_type' => 'case-studies',
'meta_key' => 'capability',
'meta_value' => 10, // some ID
'posts_per_page' => 3
);
$the_query = new WP_Query( $query );
while ( $the_query->have_posts() ) : $the_query->the_post();
// echo here
endwhile;
wp_reset_postdata();
You need to set your key to capability, and then query value by your post ID.
'meta_query' => array(
array(
'key' => 'capability',
'value' => $post->ID,
'compare' => 'example'
)
)