I'm currently making a plug-in and need some help regarding a subject. I want to use all the the_loop goodness but need a raw sql query.
/**
* Get all the posts neccessarry
* return array<WP_Post> returns an array of all constructed WP_Posts
*/
public static function get_posts($o){
global $wpdb;
$posts = array();
$tax= $o['tax'];
$q=$wpdb->get_results(
"SELECT * FROM {$wpdb->posts} p
LEFT OUTER JOIN
(SELECT * FROM {$wpdb->postmeta}
WHERE meta_key='/$p/_faq_prio'
GROUP BY post_id
) AS pm
ON ( p.ID = pm.post_ID ),
{$wpdb->term_relationships} t
WHERE p.post_type='faq' AND t.object_id = p.ID AND t.term_taxonomy_id = '{$tax}'
ORDER BY pm.meta_value ASC, ISNULL(pm.meta_key)", OBJECT_K);
foreach ($q as $p) {
array_push($posts, get_post($p) );
}
return $posts;
}
I have the following questions:
Does the get_post constructs a WP_Post object based on the data it
receives, or does it extract the post_id parameters and queries the
database yet again? I couldn't find this behavior from the
reference guides.
How can I initilize a WP_Query object based on all the Posts object (should I manually set all parameters like postcount, etc or is there a better way?
Related
I have 2 SQL queries as below:
$results2 = $wpdb->get_results("SELECT * FROM `wp_posts` WHERE id IN (".implode(",", $product_ids).")");
$getprice = $wpdb->get_results("SELECT * FROM `wp_postmeta` WHERE meta_key='_regular_price' AND post_id IN (".implode(",", $product_ids).")");
I have combined them as below query:
$yeni = $wpdb->get_results("SELECT wp_posts.id, wp_posts.post_title, wp_postmeta.meta_value
FROM wp_posts
INNER JOIN wp_postmeta ON wp_posts.id = wp_postmeta.post_id
WHERE meta_key = '_regular_price'
WHERE wp_posts.id IN (".implode(",", $product_ids).")");
After combining the queries, it's giving an empty result. I can't find the issue with the updated query.
Try this sql.
I have replace this WHERE meta_key = '_regular_price'
$yeni = $wpdb->get_results("SELECT wp_posts.id, wp_posts.post_title, wp_postmeta.meta_value FROM wp_posts INNER JOIN wp_postmeta ON wp_posts.id = wp_postmeta.post_id WHERE wp_posts.id IN (".implode(",", $product_ids).") and wp_postmeta.meta_key = '_regular_price'");
I don't understand why you don't use the native Wordpress features via OOP procedure.
Your simple query, it can be translated like this:
<?php
$loop = new WP_Query(
array(
'post_type' => 'page', // post type: page, post, attachment etc..
'post__in' => $productIds, // array[]
)
);
// after that, you can use a standard wordpress loop
if($loop->have_posts()) {
while($loop->have_posts()) {
: $loop->the_post();
the_title();
print "<br>";
// access to meta key _regular_price
print get_post_meta(get_the_ID(), '_regular_price', true);
}
}
This is the right way.
Cheers
Class reference here: https://developer.wordpress.org/reference/classes/wp_query/
I am using custom field on custom post types.
To display value of single custom field I use this code:
$gym_title = get_post_meta($post->ID, 'cast', true);
echo $gym_title;
Is there a way to display all custom fields with key ="gym" ?
(I have tried to use foreach and to write custom database search but no luck for now.)
Here's an example function which queries the database for all posts and returns all custom fields with a specific key:
function get_all_custom_fields( $key ) {
global $wpdb;
$r = $wpdb->get_col( $wpdb->prepare( "
SELECT pm.meta_value FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = '%s'
", $key) );
return $r;
}
Usage:
$gym_titles = get_all_custom_fields('gym');
I have a lot of categories configured on WordPress and I want a way to let the user search (in a free-text input form) for a particular category.
Then, in the results page I only want to list those categories (NOT POSTS!) and show a link to the category page.
It's there a way (or plugin way) to achieve this easily?
UPDATE
And also how about searching for nested categories?, I mean, I have category A with a lot of child categories. It is possible to search for only those child categories (knowing the ID of A)?
UPDATED: SOLUTION
As #AhmadAssaf suggested I ended up making my own query. Here I post the code that I have used in my web:
UPDATED
The JOIN must be done with taxonomies.term_id and not taxonomies.term_taxonomy_id
function getCategories($string) {
global $wpdb;
$categories = $wpdb->get_results("
SELECT terms.term_id, terms.name, taxonomies.description
FROM wp_terms as terms
LEFT JOIN wp_term_taxonomy as taxonomies ON taxonomies.term_id = terms.term_id
WHERE taxonomies.taxonomy = 'category' && terms.name LIKE '%".$string."%'
GROUP BY taxonomies.term_id
");
return $categories;
}
you can issue a custom mysql query to get all the categories details for a category that its name matches a string you pass
function getCat($string) {
global $wpdb;
$cat= $wpdb->get_results("
SELECT *
FROM wp__term_relationships
LEFT JOIN wp__term_taxonomy
ON (wp__term_relationships.term_taxonomy_id = wp__term_taxonomy.term_taxonomy_id)
LEFT JOIN wp__terms on wp__term_taxonomy.term_taxonomy_id = wp__terms.term_id
WHERE wp__term_taxonomy.taxonomy = 'category' && wp__terms.name LIKE '%".$string."%'
GROUP BY wp__term_taxonomy.term_id
");
return $cat;
}
In "category.php" file I need to order my posts in this strange way:
First all the posts where author is different than "admin" (in alphabetical order by title)
Than all the post by "admin" (in the same alphabetical order)
Here is the standard code I use to do my query:
<?php global
$wp_query;
query_posts(
array_merge(
array('orderby' => 'title', 'order' => 'ASC'),
$wp_query->query
)
);
?>
Any idea about how to accomplish it without nesting two queries?
Thanks in advance!
EDIT: Following is some code that was tried, as suggested by Sepster in a previous version of his answer. But at the moment this code starts showing all the posts from 'admin' (instead of the others) until the posts with author different than 'admin' come. At that point it breaks the results and jump to the next page of results.
<?php
global $wp_query;
query_posts(
array_merge(
array('orderby' => 'title', 'order' => 'ASC'),
$wp_query->query
)
);
$adminPosts = false;
for ($i=1; $i<=2; $i++) {
while ( $wp_query->have_posts() ) {
$wp_query->the_post();
$author = get_the_author();
if ($author == 'admin' && $adminPosts == false) break;
if ($author != 'admin' && $adminPosts == true) break;
// ALL MY STUFF
} // end while
rewind_posts();
$adminPosts=true;
} // end FOR
?>
Update:
I've finally come up with a somewhat workable solution for this, but it's fair to say this really is an excercise in academics; Yes, it's do-able without executing a second loop, but really, it's pretty convoluted.
The solution is, in summary
Develop a custom SQL statement that will return the rows in the order required.
This is because in SQL, the only way to get the results in the order you need is by doing a UNION of your two subsets. To my knowledge there's no way of doing that using the "normal" WP query operations.
Execute this query, and loop over its results rather than a standard "the loop".
This is because we're getting back a recordset, rather than a WP_Query object.
Set the "Blog pages show at most X posts" setting to 1.
(on /wp-admin/options-reading.php)
A common complaint is pagination breaking when using custom queries (incidentally, the query_posts() method you're using is susceptible to this issue).
There are numerous turorials on how to do this properly, eg:
https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination
https://codex.wordpress.org/Pagination#Troubleshooting_Broken_Pagination
The first of those recommends the implementation of "Offset and Manual Pagination".
The closest I've found to an implementation of this in conjunction with a custom SQL statement is this https://wordpress.stackexchange.com/a/28717. I've borrowed heavily from this answer (and so I recommend you go over and give it an up-vote!).
However, this technique (among other more "standard" custom query approaches) suffers from a known behaviour where WP produces a 404 on the final page (if I understand correctly, because WP is still using its own query and associated max-page=posts-per-page/posts calculations to map between the page number in the URL and the delivered content).
Refer http://wordpress.org/support/topic/explanation-and-workaround-for-error-404-on-category-pagination?replies=14 for details about this issue, and a proposed solution (which unfortunately won't work for our custom SQL approach).
A known "work-around" for this issue is to reduce the number of posts-per-page to 1, as per eg http://wordpress.org/support/topic/custom-post-type-pagination-404-on-last-page
So, assuming you're happy with a global setting of 1 posts-per-page (remember you'd need to override this manually in your custom queries), here's the code:
functions.php:
...
function get_users_posts_last($userDisplayName = 'Admin', $categoryName = '') {
global $wpdb, $paged, $max_num_pages;
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$post_per_page = 5;
$offset = ($paged - 1)*$post_per_page;
$sql = "
SELECT SQL_CALC_FOUND_ROWS q.* FROM
(
(
SELECT
p.*
FROM
{$wpdb->posts} p
INNER JOIN {$wpdb->users} u ON p.post_author = u.ID
LEFT JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
LEFT JOIN {$wpdb->terms} t ON tt.term_id = t.term_id
WHERE
tt.taxonomy = 'category'
AND p.post_status = 'publish'
AND p.post_type = 'post'
AND u.display_name != '{$userDisplayName}'
" . ( $categoryName != '' ? "AND t.name = '{$categoryName}'" : "" ) . "
ORDER BY
p.post_title ASC
)
UNION
(
SELECT
p.*
FROM
{$wpdb->posts} p
INNER JOIN {$wpdb->users} u ON p.post_author = u.ID
LEFT JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
LEFT JOIN {$wpdb->terms} t ON tt.term_id = t.term_id
WHERE
tt.taxonomy = 'category'
AND p.post_status = 'publish'
AND p.post_type = 'post'
AND u.display_name = '{$userDisplayName}'
" . ( $categoryName != '' ? "AND t.name = '{$categoryName}'" : "" ) . "
ORDER BY
p.post_title ASC
)
) q
LIMIT {$offset}, {$post_per_page};
";
$sql_result = $wpdb->get_results( $sql, OBJECT);
$sql_posts_total = $wpdb->get_var( "SELECT FOUND_ROWS();" );
$max_num_pages = ceil($sql_posts_total / $post_per_page);
return $sql_result;
}
...
category.php:
...
$postList = get_users_posts_last('admin'); // Note you can also pass a category name if necessary
if($postList) {
global $post;
foreach( $postList as $key=>$post ) {
setup_postdata($post);
// Render the post here
?>
<header class='entry-header'><h1 class='entry-title'><?php the_title(); ?></h1></header>
<div class='entry-content'><?php the_content(); ?></div>
<?php
}
// Render pagination here
?>
<div class="navigation">
<div class="previous panel"><?php previous_posts_link('« Previous page',$max_num_pages) ?></div>
<div class="next panel"><?php next_posts_link('Next page »',$max_num_pages) ?></div>
</div>
<?php
}
...
Or, just set up two separate queries ;-)
I’ve a small piece of code I’ve tried to wrap my brain around for some hours now.
I’m trying to create a query which retrieves some elements and in the end group them by a selector.
I’ll try to demonstrate: I’m querying all the members in my organization. Each member is a member of a “department” and there can be several members in each department, but only one department for each member.
So I’ve created the query to select all members in my organization group by departments.
When I’m displaying it using a simple foreach($my_query as $q) … I want to output $q->department_name but only once for that department. Right now it says “Marketing” under all five members and then it changes to “HR” for all those members. I’ve tried some different methods such as array_unique, creating a function that checks for the string to see if it is the same and other but with no result.
I could create two foreach loops but if it is at all possible not to I would prefer that because two foreach loops would affect the performance.
Any help or suggestion would be very much appreciated.
Sinerely
- Mestika
--- Edited ---
By the way, my query looks like this:
SELECT *
FROM wp_term_taxonomy AS cat_term_taxonomy
INNER JOIN wp_terms AS cat_terms ON cat_term_taxonomy.term_id = cat_terms.term_id
INNER JOIN wp_term_relationships AS cat_term_relationships ON cat_term_taxonomy.term_taxonomy_id = cat_term_relationships.term_taxonomy_id
INNER JOIN wp_posts AS cat_posts ON cat_term_relationships.object_id = cat_posts.ID
INNER JOIN wp_postmeta AS meta ON cat_posts.ID = meta.post_id
WHERE cat_posts.post_status = 'publish'
AND meta.meta_key = 'active'
AND meta.meta_value = 'active'
AND cat_posts.post_type = 'member'
AND cat_term_taxonomy.taxonomy = 'deparment'
GROUP BY cat_terms.slug, cat_term_relationships.object_id
$prev_department = NULL;
foreach ($my_query AS $q)
{
if ($prev_department != $q->department_name)
echo '<h2>'. htmlentities($q->department_name, ENT_COMPAT, 'UTF-8') .'</h2>';
// ...
$prev_department = $q->department_name;
}