I have a custom post type named 'Company' and a basic search on the top right of the screen. Unfortunately, when submitting a basic search the search results populate companies instead of actual pages such as Resources or Tech Advisory Group. http://labbureau.wpengine.com/
I have modified my custom query to search only for pages and ignore all company posts however, the basic search is still displaying companies instead of the actual TITLES of the pages. What can be done of this?
Below is my custom query:
$keyword = $_GET['s'];
$wp_query = new WP_Query(
array(
's' => $keyword,
'post_type' => 'page',
'tax_query' => array(
'taxonomy' => 'company',
'operator' => 'NOT IN'
),
'orderby' => 'title'
)
);
Start of loop:
<?php if ( $wp_query->have_posts() ) while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>
Try add hidden input in the search form with the post type you want to make the search on:
<input type="hidden" name="post_type" value="post_type_name" />
On your theme functions.php use this code
function searchfilter($query) {
if ($query->is_search && !is_admin() ) {
$query->set('post_type',array('page'));
}
return $query;
}
add_filter('pre_get_posts','searchfilter');
Here is a simple solution. Go to your Media Gallery and do a search for a file. If the search title is the same as the image title and no results display you have a conflicting query that is running rampant. More than likely this can be found in the functions.php file and is represented as a filter that looks like the following:
function search_filter( $query ) {
if ( $query->is_search ) {
$query->set( 'post_type', array('company') );
}
return $query;
}
add_filter('pre_get_posts','search_filter');
The function.php file is the king of the hill and will take over all other custom post types you have on your website. If you have multiple searches they will both search for the company post type regardless of whether or not you create a new WordPress query in a template. You need to comment out add_filter. In this example, you need to create a conditional statement for two different search loops. One of your search templates (HTML) needs to have a hidden input that can be retrieved by one of your conditional points to reference a new template with a new query. Do not try the conditional statement with custom post types because you will have to change this in more than one place if it needs to be changed. Here is an example of what this conditional would look like:
if(isset($_GET['search_simple']) && $_GET['search_simple'] = 'search' && !isset($_GET['hdr-search']))
{
get_template_part('loop-search');
}
else if(isset($_GET['search_simple']) && $_GET['search_simple'] = 'search' && isset($_GET['hdr-search']))
{
get_template_part('loop-search2');
}
else
{
get_template_part('loop-search-blog');
}
Related
I need to alter the search behavior of a WordPress site where the theme doesn't use searchform.php at all (it's the Divi theme). I'd rather not employ a plugin to do this as the site has many plugins already.
The default state of the page is to show "all posts from all categories" (/?cat=0) with a category list dropdown generated using wp_dropdown_categories() that allows the user to select other categories.
The desired use case is:
The user selects a category from a dropdown
The browser goes to the selected category's archive
The user types a search query into the search box on the category archive with the intent of seeing only posts and pages in that category that contain the search term.
I figured I could use the pre_get_posts hook to do this. So I did the following:
function search_by_cat()
{
global $wp_query;
if ( is_search() ) {
$currenturl = add_query_arg( $wp->query_vars, home_url( $wp->request ) );
$previousurl = wp_get_referer();
if ( strpos( $previousurl, '/category/' ) !==false ) {
$searchcategoryurl = untrailingslashit( $previousurl ) . $currenturl;
wp_redirect( $searchcategoryurl );
exit();
}
}
}
add_action('pre_get_posts', 'search_by_cat');
But this just results in ERR_TOO_MANY_REDIRECTS in the browser. I think it might be because the user is submitting a search that results in the same destination as the referrer. How do I break out of the redirect loop so I can (essentially) redisplay the page of results? Or is my entire approach all wrong? Is there a better way?
Here's the general idea from my comments, you'll need to change the CPT and taxonomy types to match your code. Tax queries are a little weird because of the nested array syntax. The comments should hopefully help understand it more.
add_action(
'pre_get_posts',
static function (WP_Query $query) {
// We only want to run on the main search query
if (!$query->is_search() || !$query->is_main_query()) {
return;
}
// Attempt to get the parameter, or default to 0
$category_id = (int)($_GET['category_id'] ?? 0);
if (!$category_id) {
return;
}
// Since we're search by a taxonomy, we probably want to bind it to a type, too
$query
->set(
'post_type',
// Change as needed
'events'
);
$query
->set(
'tax_query',
[
// See this for specifics: https://developer.wordpress.org/reference/classes/wp_query/#taxonomy-parameters
[
// Change as needed
'taxonomy' => 'event-type',
'field' => 'term_id',
'terms' => [$category_id],
],
]
);
}
);
I have added this function in my functions.php file to show category option for wordpress pages. It works fine.
function support_category_for_pages() {
// Add category support to pages
register_taxonomy_for_object_type('category', 'page');
}
add_action( 'init', 'support_category_for_pages' );
But is it possible to show/limit some categories for pages only(they must not appear under posts) ?
I hope I am writing this correctly. Basically the requirement is to keep different categories for post & pages and they should not appear in each other's category option.
There are two approaches i can think off. I am not sure how you want it to work regarding the archive page and search page so second approach may not work for you.
First solution creating templates:
For example category-news.php
Inside you can modify the query specificly for this category
$args = array(
'post_type' => 'posts'
//add more arguments if needed
);
$the_query = new WP_Query( $args );
// The Loop
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
// Do Stuff
} // end while
} // endif
// Reset Post Data
wp_reset_postdata();
Second solution using pre_get_posts:
function wp50_exclude_post_type_pages() {
//in the array you can add ids, slugs or names
if ( is_category( array( 9, 'cat2', 'Category 3' )) && $query->is_main_query() ) {
//here we tell the query to show posts type only
$query->set( 'post_type', 'posts' );
return $query;
}
}
add_action( 'pre_get_posts', 'wp50_exclude_post_type_pages');
I just can't find answer nor I can find related articles for my specific cases (or I found but didn't recognize it).
So, I have normal blog posts, and I have custom field name "tag" where I have only 1 word "music" (tag is text type).
My php for selecting all posts which have "music" in "tag" is:
add_filter('query_vars', function( $vars ) {
$vars[] = 'tag';
return $vars;
});
add_action( 'pre_get_posts', function ( $query ) {
if (!empty($_GET)) {
if ($tag = get_query_var('tag', false)) {
$meta_query[] = array(
'key' => 'tag',
'value' => $tag,
'compare' => '='
);
}
$query->query_vars['meta_query'] = $meta_query;
}
}, 1);
Now, when I type in url for example: localhost/myblog/?tag=music none of posts are showing, even tho I have few posts with "music" in "tag" field.
I would like to get solution for this simple case first, cause i duno what im doing wrong.
Also, I would like solution if I want to make multiple value in text field "tag" for example: "music, film, pop, life" so when people type in search "life film" they get all posts with those specific fields. Thank you and sorry for bigger wall of text than expected. Any help will be appriciated.
As I understand from your explanation, "tag" is just a custom field, not taxonomy. So you don't need to check any query var, just use "meta query" and that's all.
add_action('pre_get_posts', 'make_my_query');
function make_my_query($query) {
if (!is_admin() && !empty($_GET) && isset($_GET['tag']) && $query->is_main_query()) {
$query->set('meta_query', array( array(
'key' => 'tag',
'value' => sanitize_text_field($_GET['tag'])
) ) );
}
}
If you use this snippet, main query on page will contain only posts with custom field key "tag" and value from $_GET. I've added some checks, to be sure that we're not viewing admin panel and modified query is main query on page. Otherwise it may be some mess. Also I sanitized GET value.
Now, your second question. It's possible, but we need to modify our snippet. First of all, let's decide, how will people ask for multiple tags? I prefer using commas. So url will look like that: localhost/myblog/?tag=music,film. Now let's send it to WP query:
add_action('pre_get_posts', 'make_my_query');
function make_my_query($query) {
if (!is_admin() && !empty($_GET) && isset($_GET['tag'] && $query->is_main_query()) {
$get_params = explode(',', $_GET['tag']);
$meta_query = array(
'relation' => 'OR'
);
foreach ($get_params as $param) {
$meta_query[] = array(
'key' => 'tag',
'value' => sanitize_text_field($param)
);
}
$query->set('meta_query', $meta_query);
}
}
That's all. Now people, asking for posts with "?tag=film,music" will see posts that have "film" or "music" value of "tag" field. If you want to show posts, that only have all asked tags, change "relation" from "OR" to "AND". Hope that helps!
EDIT: I found actual problem... I can't name my custom field "tag" because for some reason www.example.com/?tag=music gives some weird error. Changed name of custom field into anything else (for example, tags), and it works. Weird and I hope someone find it useful.
I have many categories, but for clearity I will do an example with only two:
News that contains many posts
Products that contains many pages (I've added this feature in functions.php)
I want that archive.php displays:
the posts when the user choose the category News
the pages when the user choose the category Products
At the moment Wordpress by deafult shows only posts and not pages.
I know that this is possible by adding a simple function in functions.php but I can't find it.
EDIT: For another project with custom post type "Books" I used this code
function query_post_type($query) {
$post_types = get_post_types();
if ( is_category() || is_tag()) {
$post_type = get_query_var('books');
if ( $post_type ) {
$post_type = $post_type;
} else {
$post_type = $post_types;
}
$query->set( 'post_type', $post_type );
return $query;
}
}
add_filter('pre_get_posts', 'query_post_type');
Is there something like that for my case?
You can query for solely pages in the WP Query.
PHP:
$args = array(
'post_type' => 'page'
);
$query = new WP_Query( $args );
This will return all pages in your database, and zero posts. Vice versa, you could have 'post_type' => 'post' to query all posts, but that's the default behaviour of the WP Query.
For more documentation on this, check out the WP Query reference in the Wordpress Codex.
I am using Wordpress auto suggests using this snippet of code
and currently it is searching all tags, I want it to search only post titles. Any help is appreciated.
This is sql query calling all the tags which needs to be modified for all posts.
<?php global $wpdb;
$search_tags = $wpdb->get_results("SELECT name from wp_terms WHERE name LIKE '$search%'");
foreach ($search_tags as $mytag)
{
echo $mytag->name. " ";
}
?>
These days i had to do some request in a wordpress theme.
In your case ( getting title can be done easier than getting tags, as in your example link ) the stuff can be done easier (i guess).
Firstly you have to make a php page to get posts. As you maybe know you won't be able to use wp stuff in standalone php files, so your file ( let call it get_posts.php ) will look like
<?php
// Include the file above for being able to use php stuff
// In my case this file was in a folder inside my theme ( my_theme/custom_stuff/get_posts.php ).
// According to this file position you can modify below path to achieve wp-blog-header.php from wp root folder
include( '../../../../wp-blog-header.php' );
// Get all published posts.
$list_posts = get_posts( array( 'numberposts' => -1 ) );
// Get "q" parameter from plugin
$typing = strtolower( $_GET["q"] );
//Save all titles
$list_titles = array();
foreach( $list_posts as $post ) { $list_titles[] = $post->post_title; }
// To see more about this part check search.php from example
foreach( $list_titles as $title ) {
if( strpos( strtolower( $title ), $typing ) ){
echo $title;
}
}
?>
I added some comments trying to help you better.
Now stuff get easy, you only have to call your page through jQuery plugin like
$('#yourInput').autocomplete( "path_to/get_posts.php" );
You can directly use wordpress in-build feature to get all post titles
// The Query
query_posts( 'posts_per_page=-1' );
// The Loop
while ( have_posts() ) : the_post();
echo '<li>';
the_title();
echo '</li>';
endwhile;
None of the answers here answer your real question:
How to query JUST post titles
The "raw SQL" way:
Few important things:
escape search for SQL! (also do that for the tags search!) use $GLOBALS['wpdb']->esc_like()
if you only need 1 column, you can use $GLOBALS['wpdb']->get_col()$GLOBALS['wpdb']->get_results() is if you want to fetch more columns in one row
use $GLOBALS['wpdb']->tableBaseName to make your code portable - takes care of the prefixe.g. $GLOBALS['wpdb']->posts
When querying posts you must also think about which post_type and post_status you want to query=> usually the post_status you want ispublish, but post_type may vary based on what you want
WordPress table "posts" contains ALL post types - post, page, custom, but also navigation, contact forms etc. could be there! => I strongly advice to use explicit post_type condition(s) in WHERE ! :)
...$GLOBALS is same as globalizing variabl -today performance difference is little
<?php
// to get ALL published post titles of ALL post types (posts, pages, custom post types, ...
$search_post_titles = $GLOBALS['wpdb']->get_col(
"SELECT post_title from {$GLOBALS['wpdb']->posts}
WHERE (
(post_status = 'publish')
AND
(post_title LIKE '{$GLOBALS['wpdb']->esc_like($search)}%')
)
ORDER BY post_title ASC
"); // I also added ordering by title (ascending)
// to only get post titles of Posts(Blog)
// you would add this to conditions inside the WHERE()
// AND (post_type = 'post')
// for Posts&Pages
// AND ((post_type = 'post') OR (post_type = 'page'))
// test output:
foreach ($search_post_titles as $my_title) {
echo $my_title . " ";
}
?>
The WP_Query way
This is more wordpress but has a little overhead, because although there is a fields param for new WP_Query()/get_posts(), it only has options:
'all' - all fields (also default), 'ids' - just ids, 'id=>parent' - ... if you pass anything else, you still get all, so you still need to add "all" BUT - WP however has filters for altering fields in SELECT.
I tried to make it the same as the raw SQL version, but it depends on how does WP does it's "search" - which I think is %search% for 1 word + some more logic if there are more words. You could leverage the $clauses filter used for fields to also add your custom where INSTEAD of adding the 's' into $args (remember to append to not-lose existing WHEREs $clauses['where' .= "AND ...;). Also post_type => 'any' does not produce always the same results as the raw query in cases like Navigation, Contact forms etc...
Also WP_Query sanitizes the input variables so actually don't escape $args!
<?php
$args = [
'fields' => 'all', // must give all here and filter SELECT(fields) clause later!
'posts_per_page' => -1, // -1 == get all
'post_status' => 'publish',
's' => $search,
// I also added ordering by title (ascending):
'orderby' => 'title',
'order' => 'ASC',
'post_type' => 'any', // all "normal" post types
// 'post_type' => 'post', // only "blog" Posts
// 'post_type' => ['post', 'page'], // only blog Posts & Pages
];
$onlyTitlesFilter = function($clauses, $query) {
// "fields" overrides the column list after "SELECT" in query
$clauses['fields'] = "{$GLOBALS['wpdb']->posts}.post_title";
return $clauses; // !FILTER! MUST RETURN!
};
$onlyTitlesFilterPriority = 999;
// add filter only for this query
add_filter('posts_clauses', $onlyTitlesFilter, $onlyTitlesFilterPriority, 2);
// Pro-tip: don't use variable names like $post, $posts - they conflict with WP globals!
$my_posts = (new WP_Query($args))->get_posts();
// !IMPORTANT!
// !remove the filter right after so we don't affect other queries!
remove_filter('posts_clauses', $onlyTitlesFilter, $onlyTitlesFilterPriority);
// test output:
// note that I used "my"_post NOT just $post (that's a global!)
foreach($my_posts as $my_post) {
echo $my_post->post_title . " ";
}
?>
Don't be confused - you will still get the array of WP_Posts - WP will throw some default properties&values into it, but in reality it will only query and fill-in with real values the fields you specify in the filter.
PS: I've tested these - they are working codes (at least on WP 5.4 and PHP7 :) )