Wordpress wp_trash_post hooks not working as expected - wordpress

This applies to all the hooks associated with wp_trash_post(); pre_trash_post, wp_trash_post, trashed_post and the transition hooks, eg publish_to_trash. All behave in exactly the same way.
I have a piece of code to run on this hook;
function to_fire_on_hook($post_id) {
... do stuff
// Get the slug of the $post_id above - the post being trashed
$slug = $post->post_name;
... more stuff that then
do_something(..., $slug, ...);
// doesn't work unless I put
die; //here
}
}
add_action('wp_trashed_post', 'to_fire_on_hook');
if I put die in the function, it completes OK, if I remove it the function doesn't complete.
I thought it might be to do with the fact that putting the post in the trash appends _trash to its name but appending that to $slug doesn't make any difference (neither does using the post ID).
I have swapped out all variables for static values and the result is the same. If the execution stops with die or wp_die() the last function executes, if not it doesn't.
Using echo statements before the die shows the correct values.
Any light on what could cause this behaviour?

Related

Custom function error to produce a shortcode resulted in white screen of death

I followed the syntax the best I could to create a shortcode on execution, I got the wsod. Once removed, all was well. But I don't know what is wrong with my code. This code sits inside 'My Custom Functions', a plugin for wp.
In researching how to write a custom shortcode, I discovered instructions here: https://torquemag.io/2017/06/custom-shortcode/ My expertise is in mysql and use mostly plugins in our wordpress website. I am very limited with coding.
function last_updated_shortcode {
$last_updated = $wpdb->get_results( "SELECT MAX(process_time) FROM
qgotv.last_updated");
return $last_updated;
}
add_shortcode( 'last_updated', 'last_updated_shortcode' );
This shortcode should retrieve a max(datetime value) from a db table so it can be displayed on a page. The query works. The qgotv db is separate from the wordpress db but can be accessed through wp.
Two issues I can see, one is that you have a syntax error in your function. When defining a function in PHP, you need to include the arguments parenthesis: function my_function(){ /* Do Stuff */ }. Also, you probably need to reference the $wpdb with the global keyword.
You can read up a bit on the $wpdb class as well as creating your own functions.
This should get you sorted out:
add_shortcode( 'last_updated', 'last_updated_shortcode' );
function last_updated_shortcode(){
global $wpdb;
$last_updated = $wpdb->get_results( "SELECT MAX(process_time) FROM qgotv.last_updated");
return $last_updated;
}

How to override default do_action output in Wordpress

I'm trying to override the output in the footer of a Wordpress theme. The given section just has a do_action('action_name')
In my functions.php I've added:
add_action('action_name', 'action_name');
function action_name() {
echo "<p>Additional text</p>";
}
However, this outputs the content I wish to replace along with the content I want to add. I'm fairly new to themeing Wordpress so I'm fairly lost here. What am I doing wrong?
If you can find which function is doing the output you want to remove you can use remove_action() to remove it:
remove_action( $tag, $function_to_remove, $priority );
To find this you will have to look through the code of the theme or plugin that generates it. Somewhere will be a add_action() call similar to yours. Note the function name and priority and use remove_action() along with it in your plugin/theme.
The hard solution would be to remove all functions for that action with remove_all_actions().
Afterwards you can add your own output as you are doing now.
Note: Be mindful that using remove_all_actions() is not advisable on all actions. For example, the action wp_footer is used to load JavaScript at the end of the page. Removing all functions there will render plugins and themes that depend on it useless.
Check add_action related code here-
add_action ( string $tag, callable $function_to_add, int $priority =
10, int $accepted_args = 1 )
$tags (string) (Required) The name of the action to which the
$function_to_add is hooked.
$function_to_add (callable) (Required) The name of the function you
wish to be called
$priority (int) (Optional) Used to specify the order in which the
functions associated with a particular action are executed. Lower
numbers correspond with earlier execution, and functions with the same
priority are executed in the order in which they were added to the
action. Default value: 10
$accepted_args (int) (Optional) The number of arguments the function
accepts. Default value: 1
Have a look over below thread hope this will help you-
https://developer.wordpress.org/reference/functions/add_action/

Wordpress: cant derive error

I've got a strange one going on here. Tried to implement is_wp_error in multiple situations, but it fails. Here's the thing, illustrated with my last attempt:
I want to login a user by wp_signon(), check if there are errors and if so, display them.
So I wrote the following lines of code:
$user = wp_signon();
if(is_wp_error($user)){
$result = 'Error-' .
$user->get_error_message();
} else {
$result = 'Login succeed';
}
echo $result;
The strange thing is, is_wp_error() doesn't return false (so there is an error). But $user->get_error_message(); is empty.
Tried it in different actions. When debugging, echo is_wp_error(); returns 0.
var_dump(wp_is_error()); returns empty arrays.
Furthermore, even when valid credentials are given, is_wp_error() still returns true. Also when testing in other circumstances (and on a clean WP installation)
Any thoughts?
I took a look through the wp_signon() code (located at http://core.trac.wordpress.org/browser/tags/3.5/wp-includes/user.php#L0 )
Looks like the error is blanked out if a blank username or password is passed in. (lines 56 and 57 of that file.)

Negating certain words from a custom rewrite expression?

I have a WP page named Book (/book/) which displays a book in various languages. The language and chapter variables
are passed as query variables. So the URL structure looks like:
/book/english/ (This displays a list of chapters in English)
/book/english/foreword/ (This displays the Foreword of the book in English)
Here is what I have come up with:
add_action('init', 'book_init');
add_filter('rewrite_rules_array', 'book_rewrite_rules_array');
add_filter('query_vars', 'book_query_vars');
function book_init() {
global $wp_rewrite;
$wp_rewrite->flush_rules();
}
function book_rewrite_rules_array($rewrite_rules) {
global $wp_rewrite;
$custom['(book)/(.+)/(.+)$'] = 'index.php?pagename=$matches[1]&book_language=$matches[2]&book_chapter=$matches[3]';
$custom['(book)/(.+)$'] = 'index.php?pagename=$matches[1]&book_language=$matches[2]';
return $custom + $rewrite_rules;
}
function book_query_vars($query) {
array_push($query, 'book_language', 'book_chapter');
return $query;
}
Everything is working but the problem is that, the rewrite rules I have added are also catching /book/feed/ which I don't
want. So I am looking for an expression which would negate feed from '(book)/(.+)/(.+)$' and '(book)/(.+)$'
Also I want to know, if assume the query variables supplied are invalid, which filter should I use to check this in and how
can I stop WP from continuing and instead make it send a 404 error and have it show the 404 page?
You should be able to exclude 'feed' from your route using a negative lookahead, something like this: (book)/(?!feed$)(.+)$.
As to the second part of your question, you can hook into the request filter examine the query variables and then add an 'error' value to the variables array to cause Wordpress to throw a 404 error.
add_filter('request', 'book_request');
function book_request($vars) {
if (!in_array($vars['book_language'], array('english', 'spanish'))) {
$vars['error'] = '404';
}
return $vars;
}

Removing [nid:n] in nodereference autocomplete

Using the autocomplete field for a cck nodereference always displays the node id as a cryptic bracketed extension:
Page Title [nid:23]
I understand that this ensures that selections are unique in case nodes have the same title, but obviously this is a nasty thing to expose to the user.
Has anyone had any success in removing these brackets, or adding a different unique identifier?
Ultimately, you need to change the output of nodereference_autocomplete() in nodereference.module.
To do this properly, you want a custom module to cleanly override the function.
This function is defined as a menu callback, thus,
/**
* Implementation of hook_menu_alter().
*/
function custom_module_menu_alter(&$items) {
$items['nodereference/autocomplete']['page callback'] = 'custom_module_new_nodereference_autocomplete';
}
Then, copy the nodereference_autocomplete function into your custom module, changing it's name to match your callback. Then change this one line:
$matches[$row['title'] ." [nid:$id]"] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';
Dropping the nid reference.
$matches[$row['title']] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';
I believe the identifier is purely cosmetic at this point, which means you could also change the text however you like. If it is not purely cosmetic, well, I haven't tested to see what will happen in the wrong conditions.
I always meant to identify how to do this. Thank you for motivating me with your question.
What Grayside has posted will work... as long as you don't have two nodes with the same title. In other words, if you want to do as Grayside has proposed, you need to be aware that the nid is not entirely unimportant. The nodereference_autocomplete_validate() function does two things. It checks to see if there is a node that matches, and if so, it passes the nid on, setting it to the $form_state array. If it can't find a node, it will set an error. If the nid is present, it will be used to get the node, which also is faster, the code is here:
preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $value, $matches);
if (!empty($matches)) {
// Explicit [nid:n].
list(, $title, $nid) = $matches;
if (!empty($title) && ($n = node_load($nid)) && $title != $n->title) {
form_error($element[$field_key], t('%name: title mismatch. Please check your selection.', array('%name' => t($field['widget']['label']))));
}
}
This just checks to see if there is a nid and checks if that node matches with the title, if so the nid is passed on.
The 2nd option is a bit slower, but it is here errors can happen. If you follow the execution, you will see, that if will try to find a node based on title alone, and will take the first node that matches. The result of this, is that if you have two nodes with the same title, one of them will always be used. This might not be a problem for you, but the thing is, that you will never find out if this happens. Everything will work just fine and the user will think that he selected the node he wanted to. This might be the case, but he might as well have chosen the wrong node.
So in short, you can get rid of the nid in the autocomplete callback, but it has 2 drawbacks:
performance (little)
uncertainty in selecting the correct node.
So you have to think about it, before going this route. Especially, since you most likely wont be able to find the problem of the selection of the wrong nodes, should it happen. Another thing to be aware of, is that the nid showing up, also brings some valuable info to the users, a quick way to lookup the node, should they be in doubt if it is the one they want, if several nodes have similar titles.
I got Grayside's answer to work, but I had to use MENU alter, instead of the FORM alter he posted. No biggy!
function custommodule_menu_alter(&$items) {
$items['nodereference/autocomplete']['page callback'] = 'fp_tweaks_nodereference_autocomplete';
}
I've found an alternative solution is to change your widget type to select list and then use the chosen module to convert your list to an autocomplete field.
This handles nodes with the same title, and actually I think the UI is better than the one provided by the autocomplete widget.
To anyone coming across this (rather old) topic by way of a google search - for Drupal 7 please consider using entityreference module and "Entity Reference" field type if possible.
You can acheive a lot more in configuration with an "Entity Reference" field. It doesn't have this problem with the nid in square brackets.
Here is the full Drupal 7 version (References 7.x-2.1) of Grayside's answer. This goes in your custom module:
/**
* Implementation of hook_menu_alter().
*/
function custom_menu_alter(&$items) {
$items['node_reference/autocomplete/%/%/%']['page callback'] = 'custom_new_node_reference_autocomplete';
}
/**
* Implementation of Menu callback for the autocomplete results.
*/
function custom_new_node_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
$field = field_info_field($field_name);
$instance = field_info_instance($entity_type, $field_name, $bundle);
$options = array(
'string' => $string,
'match' => $instance['widget']['settings']['autocomplete_match'],
'limit' => 10,
);
$references = node_reference_potential_references($field, $options);
$matches = array();
foreach ($references as $id => $row) {
// Markup is fine in autocompletion results (might happen when rendered
// through Views) but we want to remove hyperlinks.
$suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
// Add a class wrapper for a few required CSS overrides.
$matches[$row['title']] = '<div class="reference-autocomplete">' . $suggestion . '</div>'; // this is the line that was modified to remove the "[nid:XX]" disambiguator
}
drupal_json_output($matches);
}

Resources