hide password protected posts from wordpress loop - php

I found this in the codex:
// Filter to hide protected posts
function exclude_protected($where) {
global $wpdb;
return $where .= " AND {$wpdb->posts}.post_password = '' ";
}
// Decide where to display them
function exclude_protected_action($query) {
if( !is_single() && !is_page() && !is_admin() ) {
add_filter( 'posts_where', 'exclude_protected' );
}
}
// Action to queue the filter at the right time
add_action('pre_get_posts', 'exclude_protected_action');
But it didn't work. Perhaps because I've customised my loop. I was hoping to do something simple, along these lines:
<?php $postsLatest = get_posts('numberposts=10&passwordproteced=false'); foreach($postsLatest as $post) { ?>
Is that possible?

The has_password and post_password parameters in WordPress 3.9+
You wrote:
I was hoping to do something simple, along these lines:
passwordproteced=false
You're pretty close, because you can use the boolean has_password parameter:
$postsLatest = get_posts( 'has_password=false' );
to fetch posts without passwords.
You can read more about this parameter in the Codex for WP_Query(), since get_posts just a wrapper for WP_Query(), and shares the input parameters.
Notice that this will only work on WordPress 3.9+:
has_password (bool) - true for posts with passwords ; false for posts
without passwords ; null for all posts with and without passwords
(available with Version 3.9).
There's also another new post_password parameter with possible values:
null (ignore)
false (only posts without passwords)
true (only posts with passwords)
a string (posts with this exact password)
You can check this Trac Ticket.
Using pre_get_posts filter with get_posts:
The reason why you didn't succeed with the pre_get_posts filter, is that get_posts() suppresses all pre_get_posts filters by default. Use the suppress_filters=false parameter to apply it.

You can do this inside your custom loop.
<?php
if ( post_password_required() ) {
continue;
} else {
echo 'normal post';
}
?>

Related

Using current post ID in Wordpress shortcode

I'm using an event management plugin, and I want to display some specific event details via shortcodes.
I've found this very useful guide regarding this plugin's shortcodes:
https://urjtechhelp.zendesk.com/hc/en-us/articles/115002801594-Embedding-Single-Events-with-the-tribe-event-inline-Shortcode
But I have one problem. As stated in the guide you must always supply an event’s ID via the id shortcode attribute, like this:
[tribe_event_inline id="167"]
What I'm trying to achieve is for the shortcode to always use the ID of the post it's placed in.
I've tried adding additional shortcode
add_shortcode( 'return_post_id', 'the_dramatist_return_post_id' );
function the_dramatist_return_post_id() {
return get_the_ID();
}
And then nest the shortcode in the original one, but apparently it doesn't work that way.
Any idea on how to achieve this?
Thank you in advance for any ideas.
Maybe it's help:
add_shortcode( 'return_post_id', 'the_dramatist_return_post_id' );
function the_dramatist_return_post_id() {
global $post;
return $post->ID ?? '';
}
This would not work using the WP text editor. It would also not be a clean implementation.
I would recommend going straight to the problem and edit the function responsible for the "tribe_event_inline" shortcode.
Try searching for add_shortcode('tribe_event_inline' in your source code files.
Here is one my function what I use time to time. I simplify it for you but with small work can be expanded to more levels.
function current_ID($post_id=NULL){
global $product, $page;
if(is_numeric($post_id) && $post_id == intval($post_id)) {} else {
// Get ID from the current object
if(!is_object($post_id)) {} else if(property_exists($post_id, 'ID')) {
$post_id = $post_id->ID;
}
// Woocommerce product page
if(empty($post_id) && property_exists($product, 'ID')) $post_id = $product->ID;
// Standard page/post ID
if(empty($post_id)) $post_id = get_the_ID();
// Get ID from the $page global
if(empty($post_id) && property_exists($page, 'ID')) $post_id = $page->ID;
// GET request
if(isset($_GET['post']) && is_numeric($_GET['post']) && $_GET['post'] > 0 && intval($_GET['post']) == $_GET['post']) $post_id = intval($_GET['post']);
if(isset($_GET['p']) && is_numeric($_GET['p']) && $_GET['p'] > 0 && intval($_GET['p']) == $_GET['p']) $post_id = intval($_GET['p']);
// Get ID from the get_queried_object_id() function
if(empty($post_id) && function_exists('get_queried_object_id')) $post_id = get_queried_object_id(); // Need tests
}
// The end
return $post_id;
}
It support also Woocommerce.
Now you need to include it into your project and add it to shortcode or combine with some other function to accept it.
Idea:
Use a template for your shortcode like [tribe_event_inline id="ZXZX"]
Add filter for the_content.
Use your filter to replace ZXZX with post ID.

Excluding posts on WooCommerce 'shop order' archive page based on meta key/value

I am trying to exclude certain posts from the Shop Order page e.g. '/wp-admin/edit.php?post_type=shop_order' if don't have a certain meta_key/meta_value combination present.
I have tried two approaches and neither seems to work properly:
Option 1: Pre Get Posts
add_action( 'pre_get_posts', 'so_filter_shop_order' );
function so_filter_shop_order($query) {
global $typenow;
/** #var $query WP_Query */
if ($query->is_main_query() && $typenow === 'shop_order' && is_admin()) {
$query->set( 'meta_key', '_method_created' );
$query->set( 'meta_value', 'booking' );
}
}
Limitations of Option 1 The problem with this option is that it doesn't seem to target other queries on this page (e.g. the count of different post statuses). I am also worried that this code will be targeting other queries elsewhere.
Option 2: Filter 'request'
This was an idea I got from WooCommerce CSV Export Plugin (as they filter this loop too).
add_filter( 'request', 'so_order_filters');
function so_order_filters( $vars ) {
global $typenow;
if ( 'shop_order' === $typenow ) {
$vars['meta_key'] = '_method_created';
$vars['meta_value'] = 'booking';
}
return $vars;
}
Limitations of Option 2 This approach also does not target other things on the page and it also conflicts with the CSV Export plugin because only one 'meta_key' can be added to the $vars array. I am also 95% sure this is not the right way to do it.
Where I would like help
It would be great to get some feedback on if either approach is worth pursuing or a suggested alternative please.
It would also be good to know if there are other things I can add to Option 1 to make sure it is only targeting the correct queries
Finally, any advice on how to target the other things on the other related queries on the page would be extremely useful.
Thanks in advance.
Here is another approach.
To get all post ID-s which has certain metakey+metavalue combination via SQL.
To include it with post__in parameter.
add_action( 'pre_get_posts', 'so_filter_shop_order' );
function so_filter_shop_order($query) {
global $wpdb;$excluded_results=array();
$excluded_results=$wpdb->query("select post_id from $wpdb->postmeta where meta_key='_method_created' and meta_value='booking' ");
foreach ($variable as $key => $value) {$excluded_results[]=$value;}
if (strpos($_SERVER["REQUEST_URI"],'post_type=shop_order') && is_admin()) {
$query->set( 'post__in', $excluded_results);
}
}
To affect table header part which shows the number of posts can't be done with pre_get_posts. It works through wp_count_posts filter. So you need to create a filter for this. Here is sample boilerplate for that:
add_filter('wp_count_posts','changenumbers',0,3);
function changenumbers ($counts, $type, $perm){
if (strpos($_SERVER["REQUEST_URI"],'post_type=product') && is_admin()) {
$counts->publish=0;
//var_dump($counts);
//you need to write some wp_query there which would get the number of posts by their status. Then you will only need to return those values.
}
return $counts;
}

How to exclude a post by id from the category.php query in wordpress

I have a template where there is a main latest featured post (tagged as featured), and then 8 more below it.
On the homepage, i was able to query for the latest featured post, and then pass its id to a function in the pre_get_posts wordpress filter. it works great there
function mh_exclude_featured_query( $query ) {
if(is_home()){
if ( $query->is_home() ) {
$feat = get_featured_post();
$query->query_vars['post__not_in'] = array($feat->ID);
}
}
}
add_action( 'pre_get_posts', 'mh_exclude_featured_query' );
but i'm also trying to do the same thing in the category.php, where i would show the latest post tagged as featured from that category. and then the remaining posts below with the featured post excluded.
Unfortnately, when i try the same method as above by using the pre_get_posts filter, i get stuck in an infinite loop and run out of memory.
if($query->is_category() && $query->is_main_query()){
$cur_cat_id = get_cat_id( single_cat_title("",false) );
$feat = get_featured_post($cur_cat_id);
$query->query_vars['post__not_in'] = array($feat->ID);
}
not sure what i'm doing differently that leads to a memory exhaustion. the category.php and index.php are near identical in their structure.
use the pre_get_posts filter:
<?php
function excludePostId($query) {
$postIds = array(
24, 10
);
if (is_category() && is_main_query()) {
set_query_var('post__not_in', $postIds);
}
}
add_action('pre_get_posts', 'excludePostId');
is_category() will accept a category slug or ID. You can limit which categories the post will be excluded from.
Add This Code
<?php if(!is_category('category_id')){
echo 'Your Code Here';
}?>

How to modify page title in shortcode?

How do I modify a page title for specific pages in shortcode?
The following will change the title but it executes for every page. I need more control over where it executes.
function assignPageTitle(){
return "Title goes here";
}
add_filter('wp_title', 'assignPageTitle');
Is there a way to call the above in a shortcode function? I know how to use do_shortcode() but the above is a filter.
My goal is to modify the page title based on a URL parameter. This only happens for specific pages.
Although WordPress shortcodes was not designed to do this, it can be done. The problem is shortcodes are processed AFTER the head section is sent so the solution is to process the shortcode BEFORE the head section is sent.
add_filter( 'pre_get_document_title', function( $title ) {
global $post;
if ( ! $post || ! $post->post_content ) {
return $title;
}
if ( preg_match( '#\[mc_set_title.*\]#', $post->post_content, $matches ) !== 1 ) {
return '';
}
return do_shortcode( $matches[0] );
} );
add_shortcode( 'mc_set_title', function( $atts ) {
if ( ! doing_filter( 'pre_get_document_title' ) ) {
# just remove the shortcode from post content in normal shortcode processing
return '';
}
# in filter 'pre_get_document_title' - you can use $atts and global $post to compute the title
return 'MC TITLE';
} );
The critical point is when the filter 'pre_get_document_title' is done the global $post object is set and $post->post_content is available. So, you can find the shortcodes for this post at this time.
When the shortcode is normally called it replaces itself with the empty string so it has no effect on the post_content. However, when called from the filter 'pre_get_document_title' it can compute the title from its arguments $atts and the global $post.
Taken from the WordPress Codex
Introduced in WordPress 2.5 is the Shortcode API, a simple set of
functions for creating macro codes for use in post content.
This would suggest that you can't control page titles using shortcodes as the shortcode is run inside the post content at which point the title tag has already been rendered and is then too late.
What is it exactly that you want to do? Using the Yoast SEO Plugin you can set Post and Page titles within each post if this is what you want to do?
You could create your custom plugin based on your URL parameters as so:
function assignPageTitle(){
if( $_GET['query'] == 'something' ) { return 'something'; }
elseif( $_GET['query'] == 'something-else' ) { return 'something-else'; }
else { return "Default Title"; }
}
add_filter('wp_title', 'assignPageTitle');

Restrict certain tags from non-admins in Wordpress

I run a multiple author website. I want to restrict a few tags from being selected by my authors.
The only options that I found so far was techniques to replace the free tag text field with a list (similar to the category list). This is not a solution for me as I will need my authors to be able to create new tags.
Surely there must be a way to restrict specific tags from non-admins? Do you know how? Any brainstorming or proper solutions are welcome.
I think the ideal solution would be to conditionally filter the taxonomy query used in post_tags_meta_box as it ajaxes its suggestions, and maybe even providing some error-handling if someone tried to manually type the tag you don't want them to use, but I'm not aware of a filter that could aid in pulling that off.
Expanding on Giordano's suggestion and referencing this other question, you could use something like this in functions.php
add_action('save_post', 'remove_tags_function', 10, 1); //whenever a post is saved, run the below function
function remove_tags_function( $post_id ){
if(!current_user_can('manage_options')){ // if the logged in user cannot manage options (only admin can)
$post_tags = wp_get_post_terms( $post_id, 'post_tag', array( 'fields'=>'names' ) ); //grab all assigned post tags
$pos = array_search( 'tag-to-be-deleted', $post_tags ); //check for the prohibited tag
if( false !== $pos ) { //if found
unset( $post_tags[$pos] ); //unset the tag
wp_set_post_terms ($post_id, $post_tags, 'post_tag'); //override the posts tags with all prior tags, excluding the tag we just unset
}
}//end if. If the current user CAN manage options, the above lines will be skipped, and the tag will remain
}
Non-admin users will still be able to type in and add tag-to-be-deleted, but it will not stick to the post. Once saved, the tag will be stripped. If the user is really dedicated, they could spell it differently, or, as you saw, change the capitalization, but whatever they do it wont technically be the same tag, and you will be able to keep it pure for whatever theme purpose you need. I can't imagine a situation in which a user without admin capabilities could add the forbidden tag, but I know better than to never say never.
If you want to allow certain non-admin users to assign the forbidden tag to a post, you'll have to revise the parameter passed into line 4 if(!current_user_can('...'){. For information on other capabilities you can pass to this conditional statement, check the Wordpress documentation of Roles & Capabilities. It's much easier to check for a capability than a role, so pick a logical capability that is restricted to the levels of user that you wish to be exempt from the tag deletion.
You could probably create a simple plugin that deletes the specified tags from the post when saved if the author is not you.
You can call your function when the post is saved with add_action('save_post', 'remove_tags_function',10,2);
Then you would create a function like
function remove_tags_function($postID, $post){
if($parent_id = wp_is_post_revision($postID))
{
$postID = $parent_id;
$post = get_post($postID);
}
if($post->post_author != 'YOUR AUTHOR NUMBER'){
$tags = wp_get_post_tags( $post_id );
$i = 0;
foreach($tags as $tag){
if(in_array("TAG NAME", $tag)) unset $tags[$i];
$i++;
}
}}
I have not tested it, but logically it would work.
EDIT:
That's not gonna work!
Try to put the following in a .php file in your plugin folder. Not tested for now, but it looks fine.
<?php
add_action('save_post', 'remove_tags_function',10,2);
function remove_tags_function($postID, $post){
if($parent_id = wp_is_post_revision($postID))
{
$postID = $parent_id;
$post = get_post($postID);
}
$user_info = $user_info = get_userdata($post->post_author);
if($user_info->user_level != 10){ // 10 = admin
untag_post($postID, array('TAGS', ... ));
}}
function untag_post($post_ids, $tags) {
global $wpdb;
if(! is_array($post_ids) ) {
$post_ids = array($post_ids);
}
if(! is_array($tags) ) {
$tags = array($tags);
}
foreach($post_ids as $post_id) {
$terms = wp_get_object_terms($post_id, 'post_tag');
$newterms = array();
foreach($terms as $term) {
if ( !in_array($term->name,$tags) ) { //$term will be a wordpress Term object.
$newterms[] = $term;
}
}
wp_set_object_terms($post_id, $newterms, 'post_tag', FALSE);
}
} // I got this from http://wordpress.stackexchange.com/questions/49248/remove-tags-from-posts-in-php/49256#49256
?>
based on crowjonah's wonderful answer, here is a function to remove multiple tags:
<?php
/** block non-admins from using specific post tags **/
function remove_tags_function( $post_id ){
if(!current_user_can('manage_options')){ // if the logged in user cannot manage options (only admin can)
$post_tags = wp_get_post_terms( $post_id, 'post_tag', array( 'fields'=>'names' ) ); //grab all assigned post tags
$pos = array_intersect( array('TAG1', 'TAG2', 'TAG3', 'ETC...'), $post_tags ); //check for the prohibited tag
if( !empty($pos) ) { //if found
$post_tags = array_diff($post_tags, $pos);
wp_set_post_terms ($post_id, $post_tags, 'post_tag'); //override the posts tags with all prior tags, excluding the tag we just unset
}
}//end if. If the current user CAN manage options, the above lines will be skipped, and the tag will remain
}
add_action('save_post', 'remove_tags_function', 10, 1); //whenever a post is saved, run the below function
?>
Itamar

Categories