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 :) )
Related
Background
I'm building a course catalog for a school and am trying to make friendly, dynamic URLs. It has three custom post types:
catalog.
course. This post type contains a title, course number, and course description.
section. This post type contains a cost, start and end dates and times, etc. A section is an instance of a course; for example, there might be two sections of Drawing for Beginners, one on Thursday morning and one on Monday night and taught by two different faculty.
There is a one-to-many relationship between course and section. When viewing a section, it displays the parent course's course name, course number, and course description. It also displays that section's cost, start and end dates and times, etc.
The current URL for a section is this:
http://website.org/section/section-slug/
I would like it to be this:
http://website.org/class/spring-2019/drawing-for-beginners/01/
...where "class" is a 'virtual' folder / synthetic prefix
...where "spring-2019" corresponds to a "catalog" custom post type
...where "drawing-for-beginners" corresponds to a slug for the parent "course" custom post type
...where "01" corresponds to the section of the course.
WordPress should display the section post type that matches these criteria.
Research
I've read quite a bit about both the Rewrite API and the Endpoints API. The best article I could find on a topic closest to what I'm trying to accomplish is this one. Sadly, the example code on the page didn't work for me, resulting in a "too many redirects error." I can provide more details about exactly which portion didn't work, if desired. I also read this article on Make WordPress Plugins but it doesn't cover dynamic lookups.
What I'm trying to accomplish
http://website.org/class/spring-2019/drawing-for-beginners/01/
When the virtual URL is supplied to WordPress, I need the system to perform a query to look up the section whose number is "01" and which belongs to the "spring-2019" catalog and whose parent course has a slug of "drawing-for-beginners." That query isn't a challenge, it's all of the hooks that need to be called to execute that code and return the correct template (for the section page). I'm not sure whether I need to create an Endpoint or can just get away with adding rewrite rules.
Can someone offer some guidance?
--
As a "bonus," I'm also trying to accomplish this:
http://website.org/class/spring-2019/drawing-for-beginners/01/faculty_name
...where "faculty_name" is dynamic and is the name of the person teaching that section (and corresponds to a "faculty" custom post type).
http://website.org/class/spring-2019/drawing-for-beginners/01/gallery
...where "gallery" is a static name and shows a gallery custom post type.
After much investigation, I've found an answer to my question. Here it goes.
This is how to create truly dynamic URLs / slugs in WordPress. The URLs don't correspond to a page. Instead, the parts of the slug are used to look up a post ID and then render that post accordingly.
Step 1: Add the rewrite rule
function pce_rewrite_rules ( ) {
add_rewrite_rule ( '^class/([^/]*)/([^/]*)/([^/]*)/?', 'index.php?post_type=section&catalog_name=$matches[1]&course_name=$matches[2]§ion_no=$matches[3]','top' ) ;
add_action ( 'init', 'pce_rewrite_rules', 10, 0 ) ;
Step 2: Register the query variables
function pce_register_query_vars ( $vars ) {
$vars[] = 'course_name';
$vars[] = 'catalog_name';
$vars[] = 'section_no';
return $vars;
}
add_filter ( 'query_vars', 'pce_register_query_vars' );
Step 3: Modify the WP query
Use pre_get_posts to modify the main query. But you have to force some variables in the query so that WordPress loads the template that you need. To find the variables I needed to manually set, I used a WP plugin (Query Monitor) to examine the contents of the WP query, and I used var_dump on the type of post I wanted to "copy."
function pce_dynamic_section_lookup ( $wp ) {
if ( is_admin() || ! $wp->is_main_query() ){
return;
}
if ( $wp->is_main_query() ) {
// Only defined if we're looking at a "fake" URL.
// Example: http://pce.local/class/spring-2019/handmade-books/01/
if ( get_query_var ('course_name' ) ) {
// These are some of the variables I needed to set manually.
$wp->query_vars['post_type'] = 'section' ;
$wp->query_vars['is_single'] = true ;
$wp->query_vars['is_singular'] = true;
$wp->query_vars['is_archive'] = false;
$course_name = get_query_var ('course_name' ) ;
$catalog_name = get_query_var ('catalog_name' ) ;
$section_no = get_query_var ('section_no' ) ;
// More code is here to look up the post ID I need.
// Set the post ID here. This makes the magic happen.
$wp->query_vars['p'] = $post_id ;
// This also makes the magic happen. It forces the template I need to be selected.
$wp->is_single = true ;
$wp->is_singular = true ;
$wp->is_archive = false ;
$wp->is_post_type_archive = false ;
}
}
}
add_action ( 'pre_get_posts', 'pce_dynamic_section_lookup', 0, 2 ) ;
I had a post with this original URL:
http://pce.local/section/handmade-books-01/
And now I can load it at this URL (and it loads it, it does not forward it):
http://pce.local/class/spring-2019/handmade-books/01/
I needed to do this because multiple sections are going to be added in future catalogs and I wanted to keep the URLs friendly. In the summer if the class is offered, it will be...
http://pce.local/class/summer-2019/handmade-books/01/
Instead of...
http://pce.local/section/handmade-books-01-2/
or whatever slug WordPress assigns it. Having only a couple of sections isn't a big deal, but there will be several in the future.
If i understood good, this might help you.
I am not sure how did you make relationship but i will put the code that i usually use. And lets say that catalog-course also have a relationship.
function add_rewrite_rules( $wp_rewrite )
{
$section_rules = array(
'class/(.+?)/?$' => 'index.php?post_type=post&name='. $wp_rewrite->preg_index(1),
);
$wp_rewrite->rules = $section_rules + $wp_rewrite->rules;
}
add_action('generate_rewrite_rules', 'add_rewrite_rules');
function change_section_links($post_link, $id=0){
$courses = new WP_Query( array(
'post_type' => 'course',
'post__in' => get_post_meta( $catalog_id, '_course', true ),
) );
if ( $courses-> have_posts() ) { while ( $courses->have_posts() ) {
$courses->the_post();
$catalog_name = get_the_title();
}
$sections = new WP_Query( array(
'post_type' => 'section',
'post__in' => get_post_meta( $course_id, '_section', true ),
) );
if ( $sections-> have_posts() ) { while ( $sections->have_posts() ) {
$sections->the_post();
$course_name = get_the_title();
}
$post = get_post($id);
if( is_object($post) && $post->post_type == 'section'){
return home_url('/class/'. $catalog_name. '/'. $course_name. '/'. $post->post_name.'/');
}
return $post_link;
}
add_filter('post_link', 'change_section_links', 1, 3);
I hope that it would help you. If it doesnt, tell me how did you make relationship.
I want to delete all that posts programmatically which are older than two years on my WordPress site. there are around 37000 posts. need help to delete it in bulk. how it is possible.? what will be the easiest way to delete.?
Try with this code.. Please read my comments in the code for more understanding. Function will go into your functions.php
function get_delete_old_post() {
// WP_Query arguments
$args = array(
'fields' => 'ids', // Only get post ID's to improve performance
'post_type' => array( 'post' ), //post type if you are using default than it will be post
'posts_per_page' => '-1',//fetch all posts,
'date_query' => array(
'column' => 'post_date',
'before' => '-2 years'
)//date query for before 2 years you can set date as well here
);
// The Query
$query = new WP_Query( $args );
// The Loop
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
//delete post code
//wp_trash_post( get_the_ID() ); use this function if you have custom post type
wp_delete_post(get_the_ID(),true); //use this function if you are working with default posts
}
} else {
// no posts found
return false;
}
die();
// Restore original Post Data
wp_reset_postdata();
}
add_action('init','get_delete_old_post');
The direct bulk method might be to speak some raw SQL (DELETE FROM ...), but unless you have taken the time to learn WordPress internals, I would not suggest this route. Instead -- as with many tasks WordPress -- look for a plugin. Consider this search, which presents Bulk Delete as the top options.
Indeed, Bulk Delete is a plugin we have used in office for just such an occurrence.
Good luck!
Run this sql query
DELETE FROM `wp_posts` WHERE YEAR(CURDATE()) - YEAR(`post_date`) >= 2;
You might just like this plugin (which I wrote) Auto Prune Posts, it will delete posts after , say 2 years, based on taxonomy + age. https://wordpress.org/plugins/auto-prune-posts/
When you just "DELETE FROM .. " you WILL end up with orphaned data in at least the postmeta table. I think you do not want that.
I've got some custom post types set up in Wordpress using Pods and linking them using relationship fields. Now I'd like to display (and link to) the related custom posts 'postB' from a single post 'postA'. I also just want to display those posts which got a date in the future, which is also stored in a custom field in 'postB'.
This is what I've currently got so far, put into a theme template file (single-posta.php):
<?php
$id = get_the_ID();
$params = array(
'where' => 'postB.ID IN ('.$id.')',
'limit' => -1, // Return all
//'oderby' => 'postB.customDate, (order is not working, so I commented it out)
//'order' => 'ASC'
);
$postsB = pods( 'postB', $params );
if ( 0 < $postsB->total() ) {
while ( $postsB->fetch() ) {
?>
<p>
<?php echo $postsB->display( 'title' ); ?><br>
<?php echo $postsB->display( 'customDate' ); ?><br>
</p>
<?php
}
}
?>
So how can I
order the results?
link to these posts?
limit them to dates in the future?
Btw. is this the right way to get those posts anyway?
You could use WP_Query too, but since you're using the Pods find() syntax, I'll give you the correct code for what you're after using that:
$params = array(
'where' => 'postB.ID IN ('.$id.')',
'limit' => -1, // Return all
'orderby' => 'customDate.meta_value ASC'
);
$postsB = pods( 'postB', $params );
Pods doesn't let you create fields with capital letters though, so it's likely you created that one outside of Pods, correct? Just double checking, if it was created with Pods it would be named 'customdate'
UPDATE: I have tried using the following code:
<?php if (is_category(events)) {
$posts = query_posts($query_string . '&orderby=event_date&order=desc');
} else {
$posts = query_posts($query_string . '&orderby=title&order=asc');
}
?>
Is there any reason why that wouldnt work? It seems to work fine organising posts in alphabetical order, but still no luck on the date order within 'events'.
--
After searching through various existing questions I can't quite find a solution to what I am trying to do.
Currently all posts on my site are ordered alphabetically, which is fine except for one new category that I have added. For this category I want to order all posts by a value that I enter into a custom field. The field is called 'event_date' - so I want to order the posts by date essentially, but not the date the post was created, the date the user manually enters into this field.
I managed to get it working by using:
<?php if (is_category($events)) { $posts = query_posts($query_string . '&orderby=$event_date&order=asc'); } ?>
However this overrides the aphabetical order for all other pages.
For alphabetical order I am using:
<?php if (is_category()) { $posts = query_posts( $query_string . '&orderby=title&order=asc' ); } ?>
Essentially I want a statement that tells the page to order all posts in aphabetical order, unless the category is 'events', where I want to order them by the custom event date.
As you can probably tell I'm very much front end, not back end so a lot of this is fairly new to me, so any help or advice is appreciated.
To order posts by a custom field value, you need add the custom meta field to the query itself. orderby=meta_value in addition to meta_key=metafieldid will allow ordering in this fashion.
I would use the pre_get_posts hook and modify the query object if get_query_var( "cat" ) (or a similar query var) returns the desired post category.
add_action( "pre_get_posts", "custom_event_post_order" );
function custom_event_post_order( $query )
{
$queried_category = $query -> get_query_var( "cat" );
/*
* If the query in question is the template's main query and
* the category ID matches. You can remove the "is_main_query()"
* check if you need to have every single query overridden on
* a page (e.g. secondary queries, internal queries, etc.).
*/
if ( $query -> is_main_query() && $queried_category == 123 )
{
$query -> set( "meta_key", "event_date" ); // Your custom field ID.
$query -> set( "orderby", "meta_value" ); // Or "meta_value_num".
$query -> set( "order", "ASC" ); // Or "DESC".
}
}
Remember that this approach overrides all queries that are using the category in question. You can build custom WP_Query objects that use their own parameters for constructing loops.
You also should standardize the way you save the custom field data to the database. For dates I prefer using UNIX-timestamp formatted times that are easy to move around and manipulate. This way no accidents happen when querying and some data is formatted in another way that the rest is.
Disclaimer: I did not have the time to test the above code in action, but the general idea should work properly.
EDIT: of course the above code should be inserted to functions.php or a similar generic functions file.
What about:
<?php $posts = query_posts($query_string . (is_category($events)?'&orderby='.$event_date:'&orderby=title') . '&order=asc'); ?>
<?php
$recent = new WP_Query(“cat=ID&showposts=x”);
while($recent->have_posts()) : $recent->the_post();
?>
Hopefully I understood your question, use the WP_Query and within the orderby add a space between your order by columns:
$args = array(
'posts_per_page' => 100,
'orderby' => 'title',
'order' => 'ASC',
);
if(is_category($events)){
$args['orderby'] .= " meta_value_num";
$args['meta_key'] = 'event_date';
}
$posts = (array) new WP_Query( $args );
I have the following function that I've added to my functions.php file in WordPress. The idea is that it gathers all of the titles of 'fsmodel' posts (a custom post type that I've created). It then returns these as an array, which I then use to populate a select tag in the custom meta fields for a second custom post type.
Basically, 'fsmodel' will have posts with a boat model, and the 'fsboat' post type will have a drop-down with the names of each of the models to select from.
Now, this appears to works fine in the Dashboard - the drop-down is populated as expected. When I save, however, the post doesn't show up in the Edit list. Also on the website, all pages output as the 404 error page when this function is active.
I'm certain that the problem lies within the following code - does anyone have any idea what I might have done wrong?
function fs_model_array() {
$models_array = array();
$loop = new WP_Query(array(
'post_type' => 'fsmodel',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
'post_status' => 'publish'
));
while ( $loop->have_posts() ) : $loop->the_post();
$models_array[] = get_the_title();
endwhile;
return $models_array;
};
OK, I've come up with a solution (I hope - it's holding up for now).
Instead of creating a loop, I've just used the $wpdb->get_results to search the database for the column with a WHERE filter for the custom post type.
Then run an array builder:
$models_array = array();
$model_db = $wpdb->get_results("SELECT post_title FROM $wpdb->posts WHERE post_type='fsmodel' AND post_status = 'publish'");
foreach ($model_db as $model_db) {
$models_array[] = $model_db->post_title;
}
Thanks again for your time, hsatterwhite! :-)
I think you might find that adding wp_reset_query() to the end of your function will solve your problems :)
I like your solution, but I'd be inclined to say that you need to call the global variable of $post whenever you use the loop like this in a function, as it assigns it to that variable.
function fs_model_array(){
global $post;
$models_array = array();
$loop = new WP_Query(array(
...