wordpress add_action('save_post', 'my_function) not working - wordpress

I am trying to trigger an even upon saving / updating a post in wordpress... see here:
add_action('save_post', 'generate_location');
function generate_location($post_id) {
echo "hey";
}
the problem is that its not working...
any ideas why? Syntax?

WordPress implements the Post/Redirect/Get pattern to avoid duplicate form submissions, so you're not going to see anything echo'd from a save_post callback.
Instead, you can do a wp_die( 'hey' ) instead, or log something to the database or file system.

I don't know whether you got this working, but I was having the same issue and discovered how to fix it!
in wp-includes/post.php on line 2940 (at the time of writing), this if/else is run whilst saving a post:
if ( !empty($page_template) && 'page' == $data['post_type'] ) {
You will notice that, if there is an error with the template the function stops there and save_post is never called.
In my case, the posts I was trying to save were imported from a pre-existing site. The new site had no page templates at all, so WP was still trying to save the page with the template from before, failing, and thus; save_post was never called.
I added
/* Template Name: Default Template */
to page.php, bulk edit, selected the template and saved. Remove the template name from page.php (as it shows up twice(, and now save_post is triggered every time.
This was the solution in my case anyway. i'm sure it'll affect someone else, somewhere down the line.

Related

How to POST to admin-post.php from Avada formbuilder form

Using the Avada theme's form builder functionality, I’m attempting to use the “Send to URL” option to POST the form and then run an api call in a plugin I’ve written.
I was thinking I could set the “Send to URL” value to /wp-admin/admin-post.php and add a hidden field to the form named “action” with a value of “make_api_call” to get it to run the code in my plugin set up like so:
add_action('admin_post_make_api_call', 'make_api_call');
function make_api_call()
{
//todo: make the api call
wp_redirect(‘another-page’);
}
However, this does not work and returns this from the server: {"status":"error","info":"url_failed"}
What I want to do is to POST the form to admin-post.php, have my plugin run code when it POSTs, and then redirect to another page.
I've checked the documentation for the AVADA theme and it only says that you can specify a url to post to but doesn't give any additional details.
So I eventually got something to work, and I'm not knowledgeable or experienced enough with WordPress development to know if it is the "right" way, but it works well.
I realized that using the "Send to Url" option on the Avada form, it was POSTing the form to the admin-ajax.php file. There's plenty of documentation on that and I was able to partially make that work but I was not able to make it fit my use case b/c even though there is a way to configure the Avada form to redirect to a different URL on success I couldn't append parameters to that URL based on the return value from admin-ajax.php.
For future reference, here's what I was able to make work but not fit my use case by having the Avada form submission set to Send to Url. (I'm recreating this and some of it's from memory since I went with a different solution, so it may not be 100% runnable.)
The way admin-ajax works is all requests to admin-ajax.php are eventually handled by a WordPress action (filter?) like so:
add_action( 'wp_ajax_my_action', 'my_function' );
In the above, my_action is what you've set as the form's action by creating a hidden input element on your html form named action and setting it's value to "my_action". The my_function argument is the name of the function you want to run when the action happens.
add_action( 'wp_ajax_my_action', 'my_function' );
function my_function(){
//do stuff
}
Watching the request in Chrome's dev tools, I could see the action the form was setting was fusion_form_submit_form_to_url.
So ended up with this:
add_action( 'wp_ajax_fusion_form_submit_form_to_url', 'my_function' );
function my_function(){
//do stuff
}
You can see that the url you enter in the Form Submission URL field gets passed to admin-ajax as fusionAction. Whether the Avada theme does something additional with that - I don't know but you could use it to control the logic that gets executed in my_function. I suspect there's an action in the Avada form that works similar to the wp_ajax_ WordPress action but by the time I got this far I realized this wasn't going to work so I pivoted to the actual solution, below.
All of that worked okay but you can't redirect out of a call to admin-ajax.php unless you do it on the client side and I didn't want to dive into that.
What I was able to make work was configuring the Avada form to do a traditional HTTP POST. I added a hidden input element on the Avada form with a name of formName and the value set to the name of the form I wanted to handle.
In my plugin code, I hooked into the WordPress init action as in the code sample below, and then customized the logic to be executed based on which formName was sent in.
add_action('init', 'callback_function');
function callback_function()
{
if (isset($_POST['formName'])) {
$form = $_POST['formName']; //from the hidden input element "formName"
//there is a call to wp_redirect in each case
switch ($form) {
case 'form1':
process_form_1();
break;
case 'form2':
process_form_1();
break;
default:
# code...
break;
}
//without this "exit" you will get errors similar to "headers already sent"
exit;
}
}
This allowed me to run the code I needed to run based on what form was submitted, and redirect to the correct place afterward.

Wordpress errors from shortcodes being executed on edit page

I am writing a wordpress plugin.
I have noticed in my debug log that i get a lot of PHP errors thrown because my shortcodes are being executed on the admin edit pages and therefore the relevant data is not available because the shortcode is loading dynamic data based upon the user front end. For example i have a function:
function myFunction_availability() {
if (is_admin()) return; // tried adding this but still get the issue
$product = $this->myFunction_get_current_product();
return "<div class='product-availability'>{$product->availability}</div>";
}
Works fine from the front end, but whenever i load the edit page from admin area i get in my log:
PHP Warning: Attempt to read property "availability" on null in /home/vagrant/yodahwp/wp-content/plugins/yodah/class.yodah.php on line 1602
As you can see from my code, i tried adding is_admin() to exit out of the function if viewing an admin page (i.e. the edit post page) but this does not seem to work.
Do any wordpress whizzes have an answer for this? I am a bit surprised that shortcodes are executed on the admin edit pages, or am I missing something?!
Thanks
This is an old question. Usually, this happens when using visual builders.
One solution is to write a condition to check if the product exists.
If using woocommerce you can try:
$product = wc_get_product( get_the_ID() );
if($product){
//continue
}
In your case, you should edit your myFunction_get_current_product() method and verify there if the product exists.

Should I use wp_reset_postdata() or just save the global $post variable myself?

I have a Wordpress 4.3 site that uses Yoast for SEO. I have a custom post type and a shortcode that can be used to generate a list of posts of that type. The shortcode function uses what I believe to be the recommended approach in Wordpress for generating a list of posts of a certain type:
$query = new WP_Query(...);
while ($query->have_posts())
{
$query->the_post();
// Now I can call methods like the_ID(), the_permalink(), etc
// I can also access details of the post directly, because at
// this point it is stored in the global $post variable.
}
wp_reset_postdata(); // To restore original copy of global $post variable
When viewing the actual page that contains the shortcode, everything works fine because the global $wp_query variable stashes a copy of the global $post variable before the shortcode function gets called, which enables wp_reset_postdata() to successfully restore the state of the global $post variable.
However, I recently discovered a problem when editing the page and although I have fixed the issue, I would like to know if my solution is correct practice in the Wordpress world.
The problem was that whenever I edited the page, several fields would get changed without me having actually touched any of the settings. Further investigation revealed that the reason for this was that the HTML for the edit page, specifically the contents of some form fields, had already been altered by the time they reached my browser. Compounding this problem was the fact that the permalink field, which is highly visible, was not being altered, but a hidden field called slug was being altered, and so when the page was submitted, Wordpress was updating the permalink with the value of this now corrupted, hidden slug field. My permalink wasn't so perma after all!
The only clue I had about what was causing the problem was that the permalink that was being set belonged to another post; in fact, one of the posts that comes up when the shortcode function gets executed.
After a day and a half of debugging, I figured out the precise reason why the form fields were being trashed:
When preparing the edit page for a post, Wordpress calls all the related plugins in case they need to add any additional information or controls to the sidebar.
One such plugin is Yoast, which reports an SEO Status. In order to calculate this status, Yoast silently renders the post so that it can then analyse the contents of the page, taking into account the focus keywords, etc.
In order for Yoast to silently render a page, all of the shortcode functions that contribute output to that page must also be executed.
When my shortcode function gets executed as part of Yoast's silent page rendering, it does what I beleive to be the right thing by calling wp_reset_postdata() at the end to restore the contents of the global $post variable.
However, the problem was that wp_reset_postdata() was not, in fact, restoring the global $post variable, because the global $wp_query variable did not have a copy. I would have expected wp_reset_postdata() or WP_Query->reset_postdata() to throw an error at that point, but they don't.
So every form field in the edit page that was generated after Yoast did its work ended up with values from the wrong post, because the global $post variable had been left with the wrong contents.
I have resolved the problem by adding the following defensive/unobtrusive code to the top of my shortcode function:
global $wp_query;
if ( $wp_query->post == null )
{
return '';
}
This means my shortcode function will only execute "the loop" when there is a guarantee that it will be able to restore the global $post variable using wp_reset_postdata().
Should I stick to this solution or take it one step further and simply save a copy of the global $post variable myself and just ignore wp_reset_postdata() altogether?

Custom action on user_register hook in WordPress

I try to implement a custom function/action after a new user profile has been created in WordPress. To test the code I try to write a text in a file as proof of function execution.
Here is the code that I have inserted at the end of the active theme's functions.php file
if ( ! function_exists( 'register_for_cmsa' ) ) :
function register_for_cmsa($user_id) {
// write in an external file
// writeLogWP($msg) is a function from a file I have included in index.php
writeLogWP("A new user is: " . $user_id);
}
add_action('user_register', 'register_for_cmsa');
endif;
Therefore, I added a new user through the admin panel. As soon as I validate the standard WP add user form (wp-admin/user-new.php) I get a blank page, meaning that the above code is in trouble. But the user is added in the database (it is visible in the users' list if I comment my function). The trouble here is when executing the writeLogWP("A new user is: " . $user_id) statement inside the register_for_cmsa() function.
I tried to see if the statement works outside of the function, while always inside the functions.php file. And I noticed that it writes the message to the external file when I navigate in the WP site, BUT it publishes blank page as soon as I get into the admin dashboard section.
My code is accepted in 'site' side but it is in error in the 'admin' one.
The code is however not executed in the 'site' side because the hook is not triggered. It is triggered only if I go to the 'wp-admin/user-new.php' but ... I can' test it, as per the above reason.
I am really confused, glad to have your comments and, why not, solution.
Thanks
The index.php is not loaded when accessing the WordPress admin, hence the writeLogWP function is not being called in that case. Moving it to functions.php should solve the issue.

Hook into the WordPress Theme Customizer save action

I am facing the following issue :
I used to keep all the styling in a theme options page. When the user clicked the save button, i had a backend script that generated a css file with the changes so that they will not be output inline in each page. This has a lot of benefits, amongst them caching.
I have switched to the Theme Customizer, and everything is fine except i can't find a way to hook into the the "save" button. I would like to trigger a function that updates the content of the css file when that button is clicked in the backend.
Is this even possible ?
Thanks !
Since WordPress 3.6.0 you can now call customize_save_after.
<?php
function emailAdmin(){
mail('your#email', 'Woza!', 'You won\'t believe this but someone has updated the theme customizations!!');
}
add_action( 'customize_save_after', 'emailAdmin' );
?>
More info: http://developer.wordpress.org/reference/hooks/customize_save_after/
I'm facing the same situation. The customize_save works BEFORE the options are saved, so that's out. I've emailed Otto (ottodestruct.com) about it.
The solution I have right now is as follows:
add_action('customize_save', 'regenCSS', 100);
function regenCSS( $wp_customize ) {
checkCSSRegen(); // Checks if I need to regen and does so
set_theme_mod('regen-css', time()+3); // Waits 3 seconds until everything is saved
}
function checkCSSRegen() {
if (get_theme_mod('regen-css') != "" && get_theme_mod('regen-css') < time()) {
makecss();
remove_theme_mod('regen-css');
}
}
I also add an extra checkCSSRegen(); to my customize_controls_init function.
Again, this is a little bit of a hack. Unfortunately, it's the best I can find to do at the time.
Another option would be to use a ajax response that just pings a php file. That feels even more of a hack than this.
Another quick hack would be to do a javascript action that when the save button is clicked, it sets a timer to delay a call to a PHP file that runs the compile. That is VERY hacky to me.
The only fallback of the above, is unless the customizer is reloaded or another value saved, you may not get all the values you want.
Anyone else have a better idea?
** Update **
Just added the following request to the Wordpress team. Hopefully we'll get it squeezed in there.
http://wordpress.org/ideas/topic/do-customize_save-action-hook-after-the-settings-are-saved?replies=3#post-24853
* Update 2 *
Looks like it will be in the 3.6 release as customize_save_after. Guess a few tweets and example code can make stuff happen even with the Wordpress team. ;)
As describe by #Dovy already you can hook customize_save_after to do this now:
do_action('customize_save_after', 'savesettings', 99);
When savesettings save settings to a file it will be bad practice to do this with native php file functions (like file_put_contents()) as described here: http://ottopress.com/2011/tutorial-using-the-wp_filesystem/ by #otto.
Solution for file saving will be to use wp_filesystem. To use wp_filesystem you will need the file credentials (ftp) of the user.
customize_save_after will be called in a AJAX request and the result won't be visible. Cause of the AJAX handle you can't ask the user for the file credentials which requires a form submit.
Solution can be found by saving the file credentials to wp-config.php and add them ( temporary ) to the database. Doing this savesettings can read the credentials from the database and use them to save the file by using credentials. (this solution is described in more detail here: https://wordpress.stackexchange.com/a/126631/31759)
Not tested, but there is the action hook customize_save in /wp-includes/class-wp-customize-manager.php.
It's inside the save() function:
/**
* Switch the theme and trigger the save action of each setting.
*
* #since 3.4.0
*/
There are some other interesting action hooks (do_action) in this file that may be worth check.

Resources