I use the_posts filter to add an object to each queried post. When access the added object, I get different result by using $post or get_post.
This is the code to attach the object to posts:
add_filter( 'the_posts', 'populate_posts_obj', 10,2 );
function populate_posts_obj( $posts, $query ){
if ( !count( $posts ) || !isset($query->query['post_type']) )
return $posts;
if( in_array( $query->query['post_type'], get_valid_grade_types())){
foreach ( $posts as $post ) {
if ( $obj = new Gradebook( $post->ID ) )
$post->gradebook = $obj;
}
}
return $posts;
}
Then, access the obj via $post, sometimes get the obj, sometimes not (even when it's the same post):
function get_the_gradebook(){
global $post;
return isset($post->gradebook) ? $post->gradebook : null;
}
Access the obj via get_post(), always get the obj:
function get_the_gradebook(){
global $post;
$p = get_post($post->ID);
return isset($p->gradebook) ? $p->gradebook : null;
}
I can just use the get_post() version, but it would be useful if I know why the difference.
Additional info:
If you ask the reason I attach an obj to each post, I think WordPress may take care of the caching process at the first place. Then, other caching plugins can work on my obj as if working on standard WP posts.
Lets explain you with a little bit pseudo code. I am trying to be broad with my approach so that my answer is relevant to StackOverflow however I still don't know how many down votes I may be receiving for this.
The simple difference is $post is a variable and get_post() is a method that means you can expect a different output from get_post() due to several dependencies however $post will only change when you explicitly do that.
Lets assume something like this
function get_post() {
return rand(0, 5);
}
$post = get_post(); /* lets assume random
value that was generated
this time was "2" */
Now each time you call get_post() its value be keep changing however the value of $post is always 2.
Coming back to the context of wordpress, $post is set using get_post() within the Loop and corresponds to the object referring to default post ID for current URL where as get_post() will take post ID as an input and return the post object.
$post is what WordPress considers to be the current "post" (post/page/custom post type) and can quite often end up giving you data you didn't quite expect. This is especially true if you perform WP_Query's in your template or have a template that uses data from several "posts".
By using get_post() with the ID you want the data from, you can be assured that you are getting the data you really want.
Related
I want to override the get_stock_quantity for a specific product to allow for a single variant to not ever run out of stock ( its virtual so no stock, but you can't switch off stock management for a single variant )
I can get my method called
function test_get_digital_stock_quantity( $value) {
echo "<br/>STOCK!<br/>";
var_dump($value);
return $value;
}
add_filter( 'woocommerce_product_variation_get_stock_quantity', 'test_get_digital_stock_quantity',10,1);
Which is great, however I only want to do it for specific variations not all. So I need to access the thing this was called on. However the function only seems to take a single parameter even though the calling code suggests its passing $this.
$value = apply_filters( $this->get_hook_prefix() . $prop, $value, $this );
So the question is, how do I get the thing that the get_prop was called on in the function that I have written. I need to be able to access the SKU in order to make the decision about the stock quantity to return...
Just realised the add_filter required a 2 not a 1 for it to be passed.
add_filter( 'woocommerce_product_variation_get_stock_quantity', 'test_get_digital_stock_quantity',10,2)
I have posts with slugs with special characters. One of them is the following:
http://localhost/wp-json/wp/v2/posts?slug=my-post!
Unfortunately, WP REST API not showing the content since it has (!) within the slug.
Is there any solution you guys would recommend?
I have found the solution (at least for my case), not sure if it'll work for you but may indicate you the way to go. We need to tap into the function used to sanitize the slugs, as I said in my comment, by default is wp_parse_slug_list. Looking at the code the function that actually sanitizes the slug is sanitize_title.
Looking at the source code, wp_parse_slug_list calls sanitize_title with only one argument, which means that the context used is save. This means that, for posts that were already saved without being sanitized by this function, the slug won't match and the post will be inaccessible through the API. The solution is to change the sanitizing function slightly by adding a filter:
add_filter('rest_post_collection_params', function($query_params) {
$query_params['slug']['sanitize_callback'] = 'sanitize_rest_api_slug';
return $query_params;
}, 20, 1);
function sanitize_rest_api_slug( $list ) {
if ( ! is_array( $list ) ) {
$list = preg_split( '/[\s,]+/', $list );
}
foreach ( $list as $key => $value ) {
$list[ $key ] = sanitize_title( $value, '', 'query' );
}
return array_unique( $list );
}
The filter is actually being applied on the function get_collection_params() on the class-wp-rest-posts-controller class, but if you look at the source code, the filter has a variable depending on the post_type, so if you have another special kind of posts defined (besides post) you need to add/change a filter for that kind as well.
I hope this helps somebody else like me, even if it's too late for your issue.
I'm building a childtheme for an excisting Wordpress theme.
The parent theme creates a custom post type, that has a property "rewrite" property that I would like to get rid of.
'rewrite' => array(
'slug' => 'project'
)
I found that it is possible to alter / add taxonomies on excisting custom post types like this:
register_taxonomy_for_object_type( 'category', 'CUSTOM_POST_NAME' );
But is it posible to change this (and other) properties?
The key here is the call to register_post_type. This is what actually registers the post type within WordPress.
In the docs, we see that the function is defined in /wp-includes/post.php. We can also see the full source code of the function, which is very handy.
In the source code of the function, we can see that there's only a single do_action() and that's called after the post type is fully registered.
So, the next place to look at is in the WP_Post_Type class. We can again expand the full source code(or you can look through the source code in your favorite text/code editor). The first place to look at is the __construct() method of the class. This currently(WordPress 4.8) consists of the following:
public function __construct( $post_type, $args = array() ) {
$this->name = $post_type;
$this->set_props( $args );
}
So, as you can see, the name is assigned to $this->name and then the method set_props() is called with the passed $args(which is the array of parameters sent to register_post_type().
The next logical place to look at is inside of the set_props() method. And at pretty much the very top of that method is the following code:
/**
* Filters the arguments for registering a post type.
*
* #since 4.4.0
*
* #param array $args Array of arguments for registering a post type.
* #param string $post_type Post type key.
*/
$args = apply_filters( 'register_post_type_args', $args, $this->name );
Bingo! The passed $args are passed through the register_post_type_args filter before they're used in initializing the post type.
So now, the final piece of the puzzle is to create your own function, attach it to the register_post_type_args filter, make sure you're changing the correct post type and you're free to do whatever you want with that post type. Here's a sample code to help you out:
function my_filter_register_post_type_args( $args, $post_type ) {
// We only want to edit the 'CUSTOM_POST_NAME' post type - if that's not it, then bail
if ( 'CUSTOM_POST_NAME' != $post_type ) {
return $args;
}
$args['rewrite'] = false;
return $args;
}
add_filter( 'register_post_type_args', 'my_filter_register_post_type_args', 10, 2 );
I hope this will help you and anyone else out there see how easy it can be to dive into the source code of WordPress(you can even do it from your browser now :) ) in order to figure out something that might not always be just a search away. With some critical thinking, you can follow the breadcrumb trail in order to figure out what the best way to tweak something is.
Hello I am trying to get lowest priority number from all the functions that hook into wp_head.
My code is this.
function wpcrown_wpcss_loaded() {
global $wp_filter;
$lowest_priority = max(array_keys($wp_filter['wp_head']));
add_action('wp_head', 'wpcrown_wpcss_head', $lowest_priority + 1);
$arr = $wp_filter['wp_head'];
}
add_action('wp_head', "wpcrown_wpcss_loaded");
But its shown error like this.
Warning: array_keys() expects parameter 1 to be array
Warning: max() [<a href='function.max'>function.max</a>]: When only one parameter is given, it must be an array in
Please help to solve this.
Thanks
As Benoti said $wp_filter is no longer an array so array_keys is throwing these warnings because expects an array.
If you want to add scripts / styles / whatever you have in wpcrown_wpcss_head at the end of the head (to give priority) this should work:
1) Comment this action:
// add_action('wp_head', "wpcrown_wpcss_loaded");
2) Use this one instead:
add_action('wp_head', "wpcrown_wpcss_head");
Hope it helps.
Be carefull on the use of $wp_filters as an array since WordPress 4.7,
Here is the guidelines for wp .4.,7
Make.wordpress that explain:
If your plugin directly accesses the $wp_filter global rather than using the public hooks API, you might run into compatibility issues.
Case 1: Directly setting callbacks in the $wp_filter array
$wp_filter['save_post'][10]['my_special_key'] = array( 'function' => 'my_callback_function', 'accepted_args' => 2 );
This will no longer work, and will cause a fatal error. $wp_filter['save_post'] is no longer a simple array. Rather, it is an object that implements the ArrayAccess interface.
You have two options to work around. The first (and preferred) method is to use the add_filter() or add_action() functions.
add_action( 'save_post', 'my_callback_function', 10, 2 );
If, for some reason, you absolutely cannot, you can still work around this.
if ( ! isset( $wp_filter['save_post'] ) ) {
$wp_filter['save_post'] = new WP_Hook();
}
$wp_filter[ 'save_post' ]->callbacks[10]['my_special_key'] = array( 'function' => 'my_callback_function', 'accepted_args' => 2 );
Case 2: Directly unsetting callbacks in the $wp_filter array
unset( $wp_filter['save_post'][10][ $my_callback_id ] );
This will fail for the same reason as case one. To work around, you can use the standard remove_filter() / remove_action() functions.
remove_action( 'save_post', 'my_callback_function', 10, 2 );
Or, if you absolutely must access the array directly:
if ( isset( $wp_filter[ 'save_post' ] ) ) {
unset( $wp_filter['save_post']->callbacks[10][ $my_callback_id ] );
}
Case 3: Checking if a hook is an array
if ( isset( $wp_filter['save_post'] ) && is_array( $wp_filter['save_post'] ) ) {
// do something
}
This will always return false. $wp_filter['save_post'] is a WP_Hook object. To check if a hook has callbacks, use has_action() or has_filter()
if ( has_action( 'save_post' ) ) {
// do something
}
Case 4: Moving the $wp_filter array pointer manually
If you’re calling next() or prev() on the $wp_filter array pointer to manually manage the order that callbacks are called in (or if you’re doing it to work around #17817), you will likely be unsuccessful. Use callback priorities, add_action() / add_filter(), and remove_action() / remove_filter() appropriately and let WordPress manage execution order.
I am building my first plugin, and I am using as a reference the following link.
http://www.sitepoint.com/create-a-voting-plugin-for-wordpress/
and I am trying to underestand the following part of the code:
function voteme_addvote()
{
$results = '';
global $wpdb;
$post_ID = $_POST['postid'];
$votemecount = get_post_meta($post_ID, '_votemecount', true) != '' ? get_post_meta($post_ID, '_votemecount', true) : '0';
$votemecountNew = $votemecount + 1;
update_post_meta($post_ID, '_votemecount', $votemecountNew);
$results.='<div class="votescore" >'.$votemecountNew.'</div>';
// Return the String
die($results);
}
I run the code and it works, but I just dont understand the following:
What is "get_post_meta" doing?
Does it create a custom meta field, the same as add_post_meta?, if it doesnt why there is not an add_post_meta?
I checked the DB, and it looks like it is creating a custom meta field... so in that order what is the difference between get_post_meta and add_post_meta?
Thanks very much for helping me understand this.
The first time your code runs, get_post_meta returns '' so $votemecount is set to 0. The following update_post_meta creates the new meta field as documented below. Values that start with _ are not displayed (are hidden meta fields).
The function, update_post_meta(), updates the value of an existing meta key (custom field) for the specified post.
This may be used in place of add_post_meta() function. The first thing this function will do is make sure that $meta_key already exists on $post_id. If it does not, add_post_meta($post_id, $meta_key, $meta_value) is called instead and its result is returned.