Show latest posts from each custom post type with pre_get_posts - custom-post-type

What I have
On my front page I have managed to alter the main query on the front page to show my custom post types with "pre_get_posts" like this:
function custom_post_types_in_home_loop( $query ) {
if ( ! is_admin() && is_home() && $query->is_main_query() ) {
$query->set( 'post_type', array( 'member', 'press', 'calendar_event' ) );
}
return $query;
}
add_filter( 'pre_get_posts', 'custom_post_types_in_home_loop' );
What I want
The problem is that some post types have way more posts than others, so I want to show only 3 posts per post type to get a little variation in the loop.
What I've tried
With some help from this and this answer ive managed to do this but nothing's happening, what am I doing wrong?
function custom_post_types_in_home_loop( $query ) {
if ( ! is_admin() && is_home() && $query->is_main_query() ) {
$query->set( 'post_type', array( 'member', 'press', 'calendar_event' ) );
if ( $query->get( 'post_type' ) == 'member' ) {
$query->set('posts_per_page', 3);
}
/* And the same 'if' statement for 'press' and 'calendar_event' */
}
return $query;
}
add_filter( 'pre_get_posts', 'custom_post_types_in_home_loop' );

You are setting post_type on the main query to an array. And then comparing it against a string. None of these conditionals are true and hence aren't executing.
If you simply want to limit the number of queries and pick a random order you can do so with,
$query->set('posts_per_page', 9);
$query->set('orderby', 'rand);
This will give you 9 posts, 3 each, randomly choosen between the different Custom Post Types.
To keep the different types together, you'll need to build a more complex and resource intensive groupby query. If you need this, I'd suggest building 3 different Custom Loops for each post_type instead.

Related

Better URL formatting with Custom Post Types and Taxonomies

I'm using Toolset Types and wondering how easy it is to set up the URL's how I want.
I have a custom post type of venues and I have a custom category taxonomy of location.
Currently the urls are coming out like
http://domain.com/venue/location/manchester/
http://domain.com/venue/manchester/the-venue-name/
But I want the URL's to be structured like
http://domain.com/manchester/
http://domain.com/manchester/the-venue-name/
Where do I need to look to make these changes?
Is this all .htaccess work or can something be done within the permalinks section?
Thanks in advance
If i understand right, this hack must work in your template.
First of all we have to remove the Post type name from url Slug.
function ft_remove_postType_slug_fromUrl( $post_link, $post, $leavename ) {
if ( 'venue' != $post->post_type || 'publish' != $post->post_status ) {
return $post_link;
}
$post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
return $post_link;
}
add_filter( 'post_type_link', 'ft_remove_postType_slug_fromUrl', 10, 3 );
But this is not gonna work by itself. If u pate this code in your functions.php u should get 404 Error.Bbecause WordPress only expects posts and pages to behave this way.
So, you have to add this action also.
function ft_change_parsingRequest( $query ) {
if ( ! $query->is_main_query() || 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
return;
}
if ( ! empty( $query->query['name'] ) ) {
$query->set( 'post_type', array( 'post', 'venue', 'page' ) );
}
}
add_action( 'pre_get_posts', 'ft_change_parsingRequest' );
After this, you renew / refresh yours post type / permalink tree (It calls flush_rewrites i guess.), It means, re-update your permalink settings on your admin panel area.
Or if you want to see or do some magic, you can check it out from source url.
https://core.trac.wordpress.org/browser/tags/4.3/src/wp-includes/post.php#L1454
This Line says;
add_permastruct( $post_type, "{$args->rewrite['slug']}/%$post_type%", $permastruct_args );
Happy Coding.

Show only authors post except a single post ID

I am working with Wordpress, and I have a post type using ACF fields.
The fact is that I used a function in function.php to show only author's posts but I completely forgot that It wont show the ACFgroupfields
Here is my function
function posts_for_current_author($query) {
global $user_level;
if($query->is_admin && $user_level < 5) {
global $user_ID;
$query->set('author', $user_ID);
unset($user_ID);
}
unset($user_level);
return $query;
}
add_filter('pre_get_posts', 'posts_for_current_author');
How to make an exception for an ID for a post ?
Thank you very much !
Might be a bit late to respond to this. But what you could try is something like this.
add_action( 'pre_get_posts', 'pre_check', 10, 2);
function pre_check($query) {
global $user_ID;
if ( !current_user_can( 'edit_others_posts' ) && $query->query['post_type'] != 'acf-field-group' && $query->query['post_type'] != 'acf-field') {
$query->set('author', $user_ID);
}
return $query;
}
This way it will not list posts/pages other than what belongs to the author. And still display the ACF fields on the posts/pages itself.

Search through related model in Yii

I have a problem with searching in Yii. I have two models: Teams and Workers. On website there is a page called 'Team Workers' where I want to display CGridView widget with searching that displays Workers from the team (team id is passed as a _GET parameter).
I did this in TeamsController:
public function actionWorkers($id)
{
$model = Teams::model()->findByPk($id);
$workers = Workers::model();
$workers->unsetAttributes();
if(isset($_GET['Workers']))
{
$_GET['Workers']['idTeam'] = $id;
$workers->attributes = $_GET['Workers'];
}
else {
$workers->attributes = array('idTeam' => $id);
}
$teamWorkers = $workers;
$this->render('workers', array(
'model' => $model,
'teamWorkers' => $teamWorkers
));
}
And in the view file:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'team-workers-grid',
'dataProvider'=>$teamWorkers->search(),
'filter' => $teamWorkers,
'columns'=>array(
'name',
'surname',
array(
'id' => 'idWorker',
'class' => 'CCheckBoxColumn',
'checked' => '$data->confirmer',
'selectableRows' => '2',
// 'headerTemplate' => '{item}'
)
),
)); ?>
I got the error:
CDbCommand nie zdołał wykonać instrukcji SQL: SQLSTATE[23000]: Integrity constraint
violation: 1052 Column 'idTeam' in where clause is ambiguous. The SQL statement
executed was: SELECT COUNT(DISTINCT `t`.`idWorker`) FROM `workers` `t` LEFT OUTER JOIN
`teams` `Team` ON (`t`.`idTeam`=`Team`.`idTeam`) WHERE ((idTeam=:ycp0) AND (Team.name
LIKE :ycp1))
When I dont set idTeam attribute - it works fine. It's pretty weird - at the regular CRUD admin page - idTeam attribute is passed and that works fine.
Hot to deal with it?
In Workers::search() you have something like
$criteria->compare('idTeam',$this->idTeam);
Change it to
$criteria->compare('t.idTeam',$this->idTeam);
i.e prefix sql attribute with t. if it is from current model or with relation name if from other table/model
Also instead of:
$workers->attributes = array('idTeam' => $id);
yould could keep it simpler with:
$workers->idTeam = $id;
You have defined the column idTeam in Team and Workers. By joining those tables you would have a duplicate ("ambiguous") column in the result. That's what the error message tells you.
To solve this you have to use an alias for one of the columns.

Infinitescroll to finish after a certain number of posts

I am using Paul Irish's infinitescroll with masonry js on a wordpress site. It is a site with a lot of content. I want infintescroll to stop adding new content when it reaches post number 40 and to give the "No additional items" message at that point. I tried to customize the wordpress loop to only return 40 posts but that did not seem to work.
I thought that maybe one of the options in infinitecroll might do the trick but the infintescroll documentation is very sparse. For example, there is an infinitescroll option in the "loading" init section called "finished: undefined" Is it possible to change that parameter to stop the scrolling after a certain number of content items?
Is there some other obvious way to control when infinitescroll stops loading new content?
Any assistance would be greatly appreciated.
In the Administration -> Settings -> Reading you can set Blog pages show at most to 40.
With code:
Two ways I've done Masonry by numbers like your question I've had success with the following:
limit posts_per_page in your query arguments
$args = array(
'posts_per_page' => 40,
'offset' => 5,
'orderby' => 'post_date',
'order' => 'DESC',
'exclude' => 'none',
'post_type' => 'post',
'post_status' => 'publish',
'suppress_filters' => true
);
$posts = new WP_Query( $args );
if ( $posts -> have_posts()) {
while ( $posts -> have_posts() ) : $posts->the_post(); {
//do stuff with the posts returned here
}
}
or by incrementing:
$counts = 0 ;
$posts = new WP_Query( $args );
if ( $posts -> have_posts()) {
while ( $posts -> have_posts() ) : $posts->the_post(); {
//do stuff with the posts returned here
$counts = ++;
if($counts == 40) { return }
}
}

Drupal: Create custom search

I'm trying to create a custom search but getting stuck.
What I want is to have a dropdownbox so the user can choose where to search in.
These options can mean 1 or more content types.
So if he chooses options A, then the search will look in node-type P,Q,R.
But he may not give those results, but only the uid's which will be then themed to gather specific data for that user.
To make it a little bit clearer, Suppose I want to llok for people. The what I'm searching in is 2 content profile types. But ofcourse you dont want to display those as a result, but a nice picture of the user and some data.
I started with creating a form with a textfield and the dropdown box.
Then, in the submit handler, i created the keys and redirected to another pages with those keys as a tail. This page has been defined in the menu hook, just like how search does it.
After that I want to call hook_view to do the actual search by calling node_search, and give back the results.
Unfortunately, it goes wrong. When i click the Search button, it gives me a 404.
But am I on the right track? Is this the way to create a custom search?
Thx for your help.
Here's the code for some clarity:
<?php
// $Id$
/*
* #file
* Searches on Project, Person, Portfolio or Group.
*/
/**
* returns an array of menu items
* #return array of menu items
*/
function vm_search_menu() {
$subjects = _vm_search_get_subjects();
foreach ($subjects as $name => $description) {
$items['zoek/'. $name .'/%menu_tail'] = array(
'page callback' => 'vm_search_view',
'page arguments' => array($name),
'type' => MENU_LOCAL_TASK,
);
}
return $items;
}
/**
* create a block to put the form into.
* #param $op
* #param $delta
* #param $edit
* #return mixed
*/
function vm_search_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Algemene zoek');
return $blocks;
case 'view':
if (0 == $delta) {
$block['subject'] = t('');
$block['content'] = drupal_get_form('vm_search_general_form');
}
return $block;
}
}
/**
* Define the form.
*/
function vm_search_general_form() {
$subjects = _vm_search_get_subjects();
foreach ($subjects as $key => $subject) {
$options[$key] = $subject['desc'];
}
$form['subjects'] = array(
'#type' => 'select',
'#options' => $options,
'#required' => TRUE,
);
$form['keys'] = array(
'#type' => 'textfield',
'#required' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Zoek'),
);
return $form;
}
function vm_search_general_form_submit($form, &$form_state) {
$subjects = _vm_search_get_subjects();
$keys = $form_state['values']['keys']; //the search keys
//the content types to search in
$keys .= ' type:' . implode(',', $subjects[$form_state['values']['subjects']]['types']);
//redirect to the page, where vm_search_view will handle the actual search
$form_state['redirect'] = 'zoek/'. $form_state['values']['subjects'] .'/'. $keys;
}
/**
* Menu callback; presents the search results.
*/
function vm_search_view($type = 'node') {
// Search form submits with POST but redirects to GET. This way we can keep
// the search query URL clean as a whistle:
// search/type/keyword+keyword
if (!isset($_POST['form_id'])) {
if ($type == '') {
// Note: search/node can not be a default tab because it would take on the
// path of its parent (search). It would prevent remembering keywords when
// switching tabs. This is why we drupal_goto to it from the parent instead.
drupal_goto($front_page);
}
$keys = search_get_keys();
// Only perform search if there is non-whitespace search term:
$results = '';
if (trim($keys)) {
// Log the search keys:
watchdog('vm_search', '%keys (#type).', array('%keys' => $keys, '#type' => $type));
// Collect the search results:
$results = node_search('search', $type);
if ($results) {
$results = theme('box', t('Zoek resultaten'), $results);
}
else {
$results = theme('box', t('Je zoek heeft geen resultaten opgeleverd.'));
}
}
}
return $results;
}
/**
* returns array where to look for
* #return array
*/
function _vm_search_get_subjects() {
$subjects['opdracht'] =
array('desc' => t('Opdracht'),
'types' => array('project')
);
$subjects['persoon'] =
array('desc' => t('Persoon'),
'types' => array('types_specialisatie', 'smaak_en_interesses')
);
$subjects['groep'] =
array('desc' => t('Groep'),
'types' => array('Villamedia_groep')
);
$subjects['portfolio'] =
array('desc' => t('Portfolio'),
'types' => array('artikel')
);
return $subjects;
}
To be honest, I haven't seen many people implement hook_search. Most just use Views, or, for advanced things, something like Faceted Search.
Did you consider using either for your current project? Why didn't it work?
you could also use a combination of hook_menu for your results, and db_queries with your custom (and optimized so faster) queries.
For example:
search/%/%
where the arguments could be whatever you need, for example the first one for minimum price, the second price to the maximum price, third for minimal bedrooms... Your url would look always like that:
search/200/400/null/3/ ...
I have used a null, but it could be anything that you prefer to consider this field as empty.
Then, from your select form you have just to redirect following the structure of this url and adding the parameters in its correct place.
It is probalby not the most beautiful way of building a url, but using this technique and hook_theme will allow you to have an unlimited flexibility. I can show you a project where we are using this technique and, I think it looks pretty good :-).
Any comment regarding this would be much aprreciated :-).

Resources