Get post id inside shortcode used in loop - wordpress

I feel like I'm missing something here. So I'm using visual composer masonry grid to show posts. I'm trying to create a shortcode to use in the Visual composer grid builder that shows the date timestamp but even though the shortcode is being used in a loop I can't get the post id or things like the_title or the_date in the shortcode. I can even use other shortcodes within this one to pull in the title and other meta info and it shows post specific info.
This is my attempt... it outputs nothing, no errors at least, but no result...
function lmi_features_time_ago_shortcode( $atts, $post ) {
global $post;
$output = '';
$timestamp = get_the_date('Y-m-d g:i:s', $post->id);
// $timestamp = time_elapsed_string($timestamp);
$output .= $timestamp;
return $output;
}
add_shortcode( 'social_feed_ago', 'lmi_features_time_ago_shortcode' );

Do a var_dump($post) and check if it's actually the post object. If the loop is set to return ids only then the $post variable will be the ID itself.

Related

Replace shortcode with a link

First sorry for the improper question format. Not sure how to write this.
My problem:
I've created a shortcode which fetches content from a post id and renders the post content in a text editor in the Divi theme (Elegant Themes - Divi). Now Divi releases a new Visual Builder which does not output the shortcode as it cannot parse this when the Visual Builder is enabled. But it shows when it's not enabled.
My Shortcode
function fetch_content_shortcode() {
global $post;
$id = "987453719"; // my post ID
ob_start();
$output = apply_filters('the_content', get_post_field('post_content', $id));
$output .= ob_get_contents();
ob_end_clean();
return $output;
}
add_shortcode('divi_content', 'fetch_content_shortcode');
Now I want to replace/convert the entire [divi_content] into a link which will take them to that custom post type post (post id 987453719). How I can achieve this.
Thanks and sorry for the bad explanation.
function fetch_content_shortcode( ) {
$link = get_the_permalink(get_the_ID());
return 'Click';
}
add_shortcode( 'divi_content', 'fetch_content_shortcode' );

Get a sidebar widget that show products of the same categories in Woocommerce

I’m trying to set a sidebar in the single product page that show all products of the same categories as the product displayed.
That's how I proceed:
1) First I’ve created a sidebar called “Products_of_same_Category” to put in there a widget to show what I needed, then in function.php of my child theme I added the following snippet to execute php code in text widget:
// Enable PHP in widgets
add_filter('widget_text','execute_php',100);
function execute_php($html){
if(strpos($html,"<"."?php")!==false){
ob_start();
eval("?".">".$html);
$html=ob_get_contents();
ob_end_clean();
}
return $html;
}
2) Then when I saw that the snippet runs ok I added that code to test it:
<?php
$prod=get_the_term_list( $post->ID, 'product_cat');
echo $prod;
?>
And all worked fine, it gave me the exact name of the current category of the product displayed in the single product page.
3) So I've tried another test, deleting the previous code, to view if a shortcode translated in php should works in a widget too (writing at this time the exact category name requested, in this case "towels" - in the code below I substitute it with THE-CATEGORY-I-LIKE):
<?php echo do_shortcode('[product_category category=“THE-CATEGORY-I-LIKE” per_page="20" columns="1" orderby="title" order="desc"]'); ?>`
And all was again well done!
4) Finally I mixed all in this code to show the list of products of same categories but something goes wrong:
<?php $prod=get_the_term_list( $post->ID, 'product_cat', '', '', '' );
echo do_shortcode('[product_category category="'.$prod.'" per_page="20" columns="1" orderby="title" order="desc"]'); ?>
In last case the code doesn't display anything. I don't understand where I made mistakes, the syntax is wrong or the solving approach is illogical?
I really appreciate any help about this.
The problem is how you get the category slug. get_the_term_list will give you a formatted linked list of the categories, so it will display category names, not category slugs, which are different things. "Towels" would be your category name, but the category slug would be "towels". And product_category shortcode expect a slug, not a name.
The correct approach to get the category product slug is the following:
$terms = get_the_terms($post, 'product_cat');
if($terms && ! is_wp_error($terms)) {
foreach($terms as $term) {
echo do_shortcode('[product_category category="'.$term->slug.'" per_page="20" columns="1" orderby="title" order="desc"]');
}
}
This will display the products of all the categories associated to your product. See get_the_terms doc for reference.
In order to remove from the results the current product shown, you can make use of the woocommerce_shortcode_products_query filter. It isn't documented, but you can find it by looking at the product_category shortcode code located in includes/class-wc-shortcodes.php. In the product_category() method you will find the following line:
$return = self::product_loop( $query_args, $atts, 'product_cat' );
Where $query_args is a WP_Query parameters array. In the same class you will find the method product_loop() called here and see the following:
$products = new WP_Query( apply_filters( 'woocommerce_shortcode_products_query', $query_args, $atts ) );
So the query arguments are filtered - you will be able to work with that to add the desirated behavour. What you want to do is to use the post__not_in parameter to the query like this:
function remove_current_product_from_wc_shortcode($args, $atts) {
if(is_product()) { // check if we're on a single product page
$args['post__not_in'] = array(get_queried_object_id());
}
return $args;
}
add_filter('woocommerce_shortcode_products_query', 'remove_current_product_from_wc_shortcode');
This code should go in your theme functions.php - please not this is untested, so if it doesn't work look at the get_queried_object_id() return if it contain the current product ID.

wordpress post the_content filter

I want write function which add to my post content <!--nextpage--> tags, I write this function:
<?php
function output($content) {
$output = $content.'<!--nextpage-->'.$content;
return $output;
}
add_filter('the_content','output');
?>
Function add <!--nextpage--> tags, but this tags not works when I display posts, it are like html comments, maybe are some solution to solve this problem ?
Maybe I must use not the_content but wp_insert_post_data ?
The conversion from text with <!--nextpage--> into "pages" happens in setup_postdata. But the hook you use executes when the template tag with the same name, the_content is called. So what this means is you have to change the content before the loop starts. It can be a bit tricky. Off the top of my head I don't know of any suitable hooks but you can check the source code for setup_postdata and there might be one. In the theme, though, you can access $posts so if you put this in a template, it should work:
global $posts;
array_map( function( $apost ) {
$apost->post_content = $apost->post_content.'<!--nextpage-->'.$apost->post_content;
return $apost;
}, $posts );
If you don't have PHP version => 5.3 you can't use anonymous functions. In that case, this version will work:
global $posts;
function output( $apost ) {
$apost->post_content = $apost->post_content.'<!--nextpage-->'.$apost->post_content;
return $apost;
}
array_map( 'output', $posts );

Wordpress skipping functions with apply_filters?

I'm using a translation plugin which creates a hook for the_title, the_content and other things.
All is working fine except one bit of code that does not display the title.
It uses this code:
$page_title = apply_filters('the_title',get_the_title());
If i try to use get_the_title() or the_title(), it breaks.
What does apply filters do, and how do i make it not skip the hook from the translation plugin?
the_title and the_content also exist in the Wordpress core. They are utilized for many things. Why a line like that is useful is apparent if you know what hooks are.
Filter hooks and Action hooks are essentially laundry lists. You can put functions on a hook, one after another so they form a queue, and when this hook is called on (by do_action and apply_filters respectively) Wordpress will unqueue one function after another. As it does, it will execute them.
add_action( 'test', 'func1' );
add_action( 'test', 'func2' );
do_action( 'test' ); // Executes func1 and then func2
The difference between actions and filters is that while they can both accept values, only filters will return a modified value. Actions do something that is important in and of itself; filters take a value and return a modified version of it that can be used later on. For example, to capitalize every title that's printed with the_title we can use the following piece of code:
add_filter( 'the_title', function( $title ) {
return strtoupper( $title );
});
Since we know that all functions hooked on the_title - the hook and not the function - will be executed only by apply_filters we expect to find it somewhere in function the_title. Actually that function is basically echo get_the_title and here's how get_the_title looks:
function get_the_title( $id = 0 ) {
$post = &get_post($id);
$title = isset($post->post_title) ? $post->post_title : '';
$id = isset($post->ID) ? $post->ID : (int) $id;
if ( !is_admin() ) {
if ( !empty($post->post_password) ) {
$protected_title_format = apply_filters('protected_title_format', __('Protected: %s'));
$title = sprintf($protected_title_format, $title);
} else if ( isset($post->post_status) && 'private' == $post->post_status ) {
$private_title_format = apply_filters('private_title_format', __('Private: %s'));
$title = sprintf($private_title_format, $title);
}
}
return apply_filters( 'the_title', $title, $id );
}
I'm posting the entire function because learning to look for hooks in the source code is of utmost importance for bourgeoning Wordpress developers. The source code is littered with hooks, and so they can be used to modify many aspects of the built-in functions of Wordpress. Now that you've located apply_filters( 'the_title', ... ) in the source code, you can appreciate its importance!
the_title simply echoes the value given to it by get_the_title and you can modify or even replace the value that get_the_title returns by attaching a filter to the hook the_title!
Now, I hope you don't think all that I've written so far is gratuitous. In fact, now we can easily answer your main question which was "why does it not work?"
First of all, you can never pass the_title to a function! It would be like writing somefunction( $var1, echo $var2, $var3 ). We cannot pass a value to a function by using echo, because echo sends its output to the browser.
The better attempt is the one you posted
$page_title = apply_filters('the_title',get_the_title());
But as we've seen, get_the_title has applied the_title to its return value already. You're simply applying all those functions a second time. It could result in strangeness if you have some custom filters attached to the_title or it could do nothing. So it either muddles the result or is gratuitous. Which is why you should simply do this:
$page_title = get_the_title();
Now, you also said
All is working fine except one bit of code that does not display the
title
This is confusing, because we would not expect a variable assignment to output anything! To output the title, you could do this
$page_title = get_the_title();
echo $page_title;
But as we've learned, this is really (look at the source code for the slight difference) the same as:
the_title();
So I wrote quite a lot just to come to the conclusion that you probably want to use the_title on its own. But I hope this can be a good resource on filter/action hooks as well.
Any questions are welcome.

Do I have to add_filter() before apply_filters() in Wordpress?

I'm trying to understand Wordpress plugin like:
apply_filters( 'gettext', $translations->translate( $text ), $text, $domain );
I'm looking for all codes in Wordpress, I can't find:
add_filter( 'gettext', ....);
Why there is no add_filter for this plugin? Or I missed something? Same thing like:
do_action('wp_loaded');
I can't find:
add_action('wp_loaded', ....);
apply_filters is like, 'if there are any filters with this name, run the attached callbacks with these parameters'. So if there is no add_filter for that name, it means that there is no filter that's going to be run with the apply_filters call at the moment.
The same goes with do_action and add_action.
I am a beginner in PHP - WordPress stack as well, but this is from my understanding.
The plugins call apply_filters without having any add_filter in their codes is to allow the website users to add custom logic to their plugins. We - the users, can add our own function and use add_filter to register our functions.
For example, this piece of code is from the plugin. Normally, it shows all products but it provides us a way to not show a specific product.
// Plugin's
if (apply_filters( 'plugin_show_products', true, $product->get_id() ) ) {
$this->show_products();
}
So, if we - the users, want to customize a bit. We can add our own function as following (maybe in functions.php)
// Our custom changes
function my_own_changes($boolean, $product_id) {
if ( $product_id === 5 ) return false;
return true;
}
add_filter( 'plugin_show_products', 'my_own_changes', 10, 2 );
This translates to: The plugin will behave normally but for my own site, it will not show the product with ID of 5!
I have come across this type of code in a plugin or theme where the apply_filter is used without necessarily having an existing filter or add_filter
In this case, where the apply_filters is used without a filter you will have to call the function again where you want to run it. For example, in the header of a theme.
The following is an example of apply filters used in a function that is again called in the header.php
if ( ! function_exists( 'header_apply_filter_test' ) ) {
function header_apply_filter_test() {
$filter_this_content = "Example of content to filter";
ob_start();
echo $filter_this_content;
$output = ob_get_clean();
echo apply_filters( 'header_apply_filter_test', $output );//used here
}
}
Now in the header.php file, you would have to call this function since it is not hooked anywhere. So, in this case, to display the output in the header you would call the function like this :
<?php header_apply_filter_test(); ?>
You could as well write this code with a hook and it would do the same thing i.e display the output in the header.
add_filter('wp_head', 'header_apply_filter_test');
if ( ! function_exists( 'header_apply_filter_test' ) ) {
function header_apply_filter_test() {
$filter_this_content = "Example of content to filter";
ob_start();
echo $filter_this_content;
$output = ob_get_clean();
echo $output;
}
}
For this second option, you would still have the capability of using apply_filters anywhere else to call the callback function header_apply_filter_test() since the filter now exists.
So the bottom line in my view is a use case since either approach works!

Resources