Timber: How to query posts of a single custom post type in archive.php - wordpress-theming

I'm using Timber for Wordpress and when I use a custom query in archive.php to get posts of a custom post type, it returns posts of multiple post types.
I tried the exact same query in page.php and it worked perfectly.
Here's the query I'm using:
global $paged;
if (!isset($paged) || !$paged){
$paged = 1;
}
$args = array(
'post_type' => 'horse',
'orderby' => 'title',
'order' => 'ASC',
'posts_per_page' => 20,
'paged' => $paged
);
$context['horses'] = new Timber\PostQuery( $args );
I would expect that to return all items of post type 'horse', but other post types are also mixed in.
Any ideas why this might be happening?
I'm not sure if this is related, but I also added this to functions.php, inside the StarterSite class, in order to add my custom post type to the archive page:
function namespace_add_custom_types( $query ) {
if( is_category() || is_tag() && empty( $query->query_vars['suppress_filters'] ) ) {
// Get all your post types
$post_types = get_post_types();
$query->set( 'post_type', $post_types );
return $query;
}
}
And this was added to the existing function named __construct:
add_filter( 'pre_get_posts', array($this, 'namespace_add_custom_types') );

How are you calling it in the twig file?
{% for post in horses %}
{{ post.name }}
{% endfor %}
Also, are you sure the post type name is horse and not horses? If the wrong post type name is included in 'post_type' it would show all post types.

Related

Get ACF gutenberg block data from custom post type

I running into some problems with ACF Gutenberg blocks.
I have registered a Gutenberg block to be used in a custom post type called "Portfolio"
Through a normal wp_query i can display the custom post type on the homepage. But i can not get the ACF Gutenberg block data to show?
Below is the code im currently using.
<?php
// WP_Query arguments
$args = array(
'post_type' => array( 'portfolio' ),
'post_status' => array( 'publish' ),
'nopaging' => false,
'posts_per_page' => '5',
);
// The Query
$query_portfolio = new WP_Query( $args );
// The Loop
if ( $query_portfolio->have_posts() ) {
while ( $query_portfolio->have_posts() ) {
$query_portfolio->the_post();
}
// ACF group
$content = get_field('content');
?>
<!-- // ACF field from within group NOT SHOWING -->
<h1><?php echo $content['title']; ?></h1>
<h2><?php the_title(); ?></h2>
<?php
} else {
// no posts found
}
// Restore original Post Data
wp_reset_postdata();
?>
Im stuck at this point. Somehow i can not get the Gutenberg Block fields to show within the query on the homepage.
All help is appreciated.
Thanks

WordPress query posts without ACF repeater subfields AND specific value

I have two custom post types, playlists and games. Playlists have a ACF repeater field, that contain games.
My goal: I am trying to build a simple query, that gets all playlists that DO NOT have this game listed in the repeater field AND alll playlists that are empty (do not have any repeater fields / database entries at all). I want to use the get_posts() function to achieve my goal, if possible.
My problem: I can only get the query to show ONLY the playlists that HAVE the game by using the = operator in the "game_filter" meta query compare field (but I want the opposite). If I choose the != or <> or IS NOT operator, it spits out all available posts. And if I also include my "empty_playlists" meta query, it ALWAYS shows me all playlists, no matter what operators I use, even tho it is a OR and the listed posts do have entrys.
I tried a lot but just cant get it to work. All exmaples I found were about different things, mostly about the % problem with the repeater field names and its solution. I hope someone can help me with this real quick. What am I doing wrong? Please help fellow and better coders! :-)
This is my code
$excluded_playlists_game_id = 274;
$user_id = 1;
$args = array(
'post_type' => PSiCorePostTypes::PLAYLISTS,
'author' => $user_id,
'order_by' => 'title',
'order' => 'ASC',
'suppress_filters' => false,
'meta_query' => array(
'relation' => 'OR',
'game_filter' => array(
'type' => 'NUMERIC',
'key' => 'psi_playlist_games_%_item',
'compare' => '!=',
'value' => $excluded_playlists_game_id,
),
'empty_playlists' => array(
'key' => 'psi_playlist_games_%_item',
'compare' => 'NOT EXISTS',
),
),
);
$user_playlists = get_posts( $args );
and this function for the % problem.
add_filter( 'posts_where', 'get_user_playlists_query_allow_wildcard' );
function get_user_playlists_query_allow_wildcard( $where ) {
global $wpdb;
$where = str_replace(
"meta_key = 'psi_playlist_games_%_item",
"meta_key LIKE 'psi_playlist_games_%_item",
$wpdb->remove_placeholder_escape( $where )
);
return $where;
}

Populate WordPress Advanced Custom Fields with remote JSON in backend

I have custom post types called "Products". and using the AFC(Advanced Custom Fields) plugin with this post type.
Below is what ACF has in fields group
- one filed called 'Product Description' as text area
- three text fields called 'Feature 1, Feature 2,Feature 3'
What I want to achieve is to get the data from external JSON file and populate the above ACF fields in the backend. I did some research and found Wordpress offers wp_remote_get() function to request the remote file. But I have no clue where to begin with to use this function or any other approach to use external JSON and populate these fields. Will really appreciate it someone points me to the right direction or any tutorial that shows how to achieve that. Thanks
I figured it out. View the working code below.
// Get JSON and Decode
$json_request = wp_remote_get( 'http://wp-test/test/data.json');
if( is_wp_error( $json_request ) ) {
return false;
}
$json_body = wp_remote_retrieve_body( $json_request );
$json_data = json_decode( $json_body );
// Create the new post and populate the fields
foreach( $json_data->products as $item ) {
$title = $item->title;
$desc = $item->content;
$status = $item->status;
$new_post = array(
'post_title' => $title,
'post_content' => $desc,
'post_status' => $status,
'post_author' => $userID,
'post_type' => 'products'
);
$post_id = post_exists( $title );
if (!$post_id) {
$post_id = wp_insert_post($new_post);
}
}

Advanced custom fields: can't query posts by custom field

I'm trying to query posts whose ACF field "show_on_frontpage" value is equal to "yes" (see definition of this field in screenshot below). As prescribed in ACF docs here's my code:
$args = array(
'posts_per_page' => -1,
'meta_key' => 'show_on_frontpage',
'meta_value' => 'yes'
);
$my_posts = new WP_Query($args);
if ($my_posts->have_posts()) {
while ($my_posts->have_posts()) : $my_posts->the_post();
if (get_field('show_on_frontpage')) the_field('show_on_frontpage'); ?>
endwhile;
}
This returns/displays nothing. If I used instead simply $args = array('posts_per_page' => -1); then I get all my posts and "yes" shows up for those that have "yes" as the value of their "show_on_frontpage" field.
What's wrong with my code?
According to this question/answer on the ACF forum:
https://support.advancedcustomfields.com/forums/topic/using-checkbox-fields-in-custom-queries/
It would be better to switch your checkbox field to a True/False field instead, since it appears that your checkbox group field only contains a single option.
Checkboxes are stored as serialized data and you’re not going to be able to use WP_Query to filter by a checkbox field.
If you use a true/false field then you can use WP_Query, the values of
a true/false field are 0 (zero) for false and 1 for true.
So if you switched your checkbox field to a True/False field, you would rewrite your code as follows:
$args = array(
'posts_per_page' => -1,
'meta_key' => 'show_on_frontpage',
'meta_value' => 1 /* or true */
);
$my_posts = new WP_Query($args);
if ($my_posts->have_posts()) {
while ($my_posts->have_posts()) : $my_posts->the_post();
/* My content for each post with the checkbox checked goes here */
endwhile;
}
This should work if you use the more recent meta_query => array() syntax:
$args = array(
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'show_on_frontpage',
'value' => 'yes',
'compare' => 'LIKE',
)
),
);
$my_posts = new WP_Query($args);
if ($my_posts->have_posts()) {
while ($my_posts->have_posts()) : $my_posts->the_post();
echo get_the_title();
// Post stuff
endwhile;
/* Restore original Post Data */
wp_reset_postdata();
}
Note that you need to give the post ID to the ACF helper functions get_field() & the_field() within the while loop.
See https://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters
On a wider note, this article calls into question the wisdom of using post_meta keys for this purpose and is worth a read: https://tomjn.com/2016/12/05/post-meta-abuse/. The article suggests using a custom taxonomy to achieve what you need - being better for performance.

CakePHP - trying to order posts by relevance to tags shared with main post and date created

I'm trying to display eight of the most relevant posts, in order of relevance, based on tags shared with the current post being viewed and the date created...
Models:
Tag habtm Post
Post habtm Tag
DB:
posts(id, slug, ...)
tags(id, tag, ...)
posts_tags(post_id, tag_id)
Within controller action:
$post = $this->Post->find('first', array('conditions' => array('slug' => $slug)));
$this->set('post', $post);
$tags = $post['Tag'];
$relOrd = '';
foreach($tags as $tag){
$tagId = $tag['id'];
$relOrd .= " + (CASE WHEN PostsTag.tag_id = ".$tagId." THEN 1 ELSE 0 END)";
}
$relOrd = '(' . substr($relOrd, 3) . ') AS Relevance';
$morePosts = $this->Post->find('all', array(
'joins' => array(
array(
'table' => 'posts_tags',
'alias' => 'PostsTag',
'type' => 'LEFT',
'conditions' => array(
'PostsTag.post_id = Post.id',
)
)
),
'group' => 'Post.id',
'fields' => array($relOrd, 'Post.*'),
'order' => array('Relevance' => 'DESC', 'Post.created' => 'DESC'),
'limit' => 8,
));
$this->log($morePosts);
$this->set('morePosts', $morePosts);
It's almost working, although the relevance value is being treated as if each post has only one tag (being only 0 or 1). So it seems that the relevance value for each post is taking either 0 or 1 depending on the posts LAST tag rather than being accumulative based on ALL tags.
First of all, I'd take all of the logic out of the controller. Consider this:
$post = $this->Post->find('first', array('conditions' => array('slug' => $slug)));
$this->set('post', $post);
$this->set('morePosts', $this->Post->findRelevant($post));
Now your controller is easy to read and does it's job. You essentially start by describing what data you want by naming an imaginary model function, and then you write the model code to fulfill that request.
So here's a stab at the model code:
var $actsAs = array('Containable');
function findRelevant($post, $limit = 8) {
// create an array of ids of the tags from this post
$tags = array();
foreach($post['Tag'] as $num => $tag) {
$tags[$tag['id']] = $tag['id'];
}
// find other posts that have any of those tags
$relevant = $this->find('all', array(
'conditions' => array('Post.id <>' => $post['Post']['id']),
'order' => 'Post.created desc',
'contain' => array('Tag' => array('conditions' => array(
'Tag.id' => $tags
))),
));
// count the number of tags of each post and call it relevance
// (this number is essentially the number of tags in common
// with the original post because we used contain to get only
// the tags from the original post)
foreach($relevant as &$p) {
$p['Post']['relevance'] = count($p['Tag']);
}
// sort by relevance
$relevant = Set::sort($relevant, '{n}.Post.relevance', 'desc');
// limit the number of posts returned (defaults to 8)
return array_splice($relevant, 0, $limit);
}
Obviously it would be great to use the database logic to fetch the records (as you are attempting to do) so that it's as fast as possible and so that you minimize the amount of data that you retrieve, but I can't see how to do that for what you're trying to achieve.
This method should work fine and is not database specific. :)