How to debug save_post actions in WordPress? - php

I have some custom post meta being generated and am ready to add to a post's meta. I know how to do this. However, save_post causes a redirection after POST data has been sent. This means I am redirected to the dashboard and lose access to my POST data - therefore I cannot debug easily.
Currently I am using something like:
add_action('save_post', 'something_process');
function something_process() {
if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
return;
print_r($_POST);
}
Is there a way to easily debug this?

The best approach for me has been to use a function to log the values to wp-content/debug.log, lifted from http://fuelyourcoding.com/simple-debugging-with-wordpress:
if(!function_exists('log_it')){
function log_it( $message ) {
if( WP_DEBUG === true ){
if( is_array( $message ) || is_object( $message ) ){
error_log( print_r( $message, true ) );
} else {
error_log( $message );
}
}
}
}
Then use the function like this in your save_post hook:
log_it($_POST);
log_it('The value for ' . $custom_field . ' is ' . $_POST[$custom_field]);
Make sure that wp-content/debug.log is writable, and that you have debugging enabled in wp-config.php:
#ini_set('display_errors',0);
define( 'WP_DEBUG', true ); // Turn debugging ON
define( 'WP_DEBUG_DISPLAY', false ); // Turn forced display OFF
define( 'WP_DEBUG_LOG', true ); // Turn logging to wp-content/debug.log ON
define( 'WP_POST_REVISIONS', false); // Disables revision functionality

Method 1:
if (isset($_POST)) die(print_r($_POST)); //answer by Tumas
Method 2:
create log file (my_logs.txt) in a folder, where you use this code:
add_action('save_post', 'something_process',11,11);
function something_process()
{
print_r($_POST);
$tmp = fopen(dirname(__file__).'/my_logs.txt', "a+"); fwrite($tmp,"\r\n\r\n".ob_get_contents());fclose($tmp);
}

The best solution I've found so far is storing the $_POST in a session var for access later.

First Approach:
die(print_r($post_id));
Second Approach:
var_dump($post_id);
Third Approach:
<?php
echo <pre>{whatever you want to echo goes here}</pre>
?>
Or take any browser add-ons for console logging
may one of three help..Good Luck

You could also save your debug messages in a WordPress option and show it as an admin message after the redirect.
// display all notices after saving post
add_action( 'admin_notices', 'show_admin_notices', 0 );
// your custom save_post aciton
add_action( 'save_post', 'custom_save_post' );
function custom_save_post() {
store_error_in_notices_option( 'my debug message' );
}
function store_error_in_notices_option( $m ) {
if ( ! empty( $m ) ) {
// store error notice in option array
$notices = get_option( 'my_error_notices' );
$notices[] = $m;
update_option( 'my_error_notices', $notices );
}
}
function show_admin_notices() {
$notices = get_option( 'my_error_notices' );
if ( empty( $notices ) ) {
return;
}
// print all messages
foreach ( $notices as $key => $m ) {
echo '<div class="error"><p>' . $m . '</p></div>';
}
delete_option( 'my_error_notices' );
}

I use this for a quick formatted output :
die( '<pre>' . print_r( $_POST, true ) . '</pre>');

Related

How to inspect variables inside "register_activation_hook" in WordPress

I'm new to WordPress/PHP and I'm trying to create a WP plugin. I want to be able to inspect some code inside the register_activation_hook. This is the code that's being executed inside the register_activation_hook:
$data_store = \WC_Data_Store::load('webhook');
$all_hooks = $data_store->search_webhooks(
array(
'limit' => 10,
)
);
$_items = array_map('wc_get_webhook', $all_hooks->webhooks);
foreach ($_items as $webhook) {
$name = $webhook->get_name();
echo $name; // trying to inspect the name here
if ($name === "Test Hook") {
$webhook->set_status('active');
$webhook->save();
}
}
When I install and then activate the plugin, I don't get any output anywhere, even if I use alert instead of echo.
I saw some people saying that you shouldn't output anything inside the register_activation_hook. If that's the case, how can we inspect the values inside this hook?
I tried using a debugging plugin called Query Monitor, but it's also not capturing anything.
You can't pass output to the register_activation_hooksince it will return a Headers already sent error, you should catch the values you need with a transient and pass it to the admin_notices action, similar to this:
register_activation_hook( __FILE__, 'initiate_webhooks' );
function initiate_webhooks(){
$data_store = \WC_Data_Store::load( 'webhook' );
$all_hooks = $data_store->search_webhooks(
array(
'limit' => 10,
)
);
$_items = array_map( 'wc_get_webhook', $all_hooks->webhooks );
set_transient( 'active_webhooks', wp_json_encode( $_items ) , 60 );
foreach ( $_items as $webhook ) {
$name = $webhook->get_name();
if ( $name === "Test Hook" ) {
$webhook->set_status( 'active' );
$webhook->save();
}
}
}
add_action( 'admin_notices', function() {
$webhooks = get_transient( 'active_webhooks' );
if ( false !== $webhooks ) {
?>
<div class="notice notice-success is-dismissible">
<?php
$webhooks = json_decode( $webhooks );
foreach( $webhooks as $webhook ) {
echo $webhook;
}
?>
</div>
<?php
}
});
Don't forget to delete the transient.
https://developer.wordpress.org/apis/transients/

How to make arguments compulsory in WP CLI command

I want to use WP CLI to delete the WooCommerce orders.
I have 3 arguments ( product_id,start_date,end_date ). How do I check all 3 arguments are passed in command or not ?
How do I do something like this ?
if ( ! empty( ALL THE ARGS ) ) {
WP_CLI::success( "Success" );
} else {
WP_CLI::error( "args missing" );
}
Below is my code.
$delete_woo_orders = function( $args,$assoc_args ) {
WP_CLI::line( $assoc_args['product_id'] );
WP_CLI::line( $assoc_args['start_date'] );
WP_CLI::line( $assoc_args['end_date'] );
};
WP_CLI::add_command( 'delete_woo_orders', $delete_woo_orders );
Here is my command : wp delete_woo_orders --product_id=1 --start_date="some_date" end_date="some_date"
You can try below code :-
if( defined( 'WP_CLI' ) && WP_CLI ) {
function delete_order ( $args, $assoc_args ) {
global $wpdb;
if( $assoc_args['product_id'] && $assoc_args['start_date'] &&
$assoc_args['end_date'] ){
WP_CLI::success( "all args passed" ); // Success Message
}else{
WP_CLI::error( "args missing" ); // Failed Message
}
}
WP_CLI::add_command( 'delete_woo_orders', 'delete_order' );
}
I have little bit modified your code and checked the $assoc_args have value or not and showing a success and error message.

How to print to console from a php file in wordpress

I have a php file which is part of a wordpress plugin. I need to debug an issue we are having. I want to find out what a variable's value is. How can I print the variable's value to console? echo or chrome or firefox extensions have been suggested. I couldn't get echo to output to console (echo “$variablename";) and neither using the firephp extension for firefox.
To answer your question, you can do this:
echo '<script>console.log("PHP error: ' . $error . '")</script>';
but I would recommend doing one of the things #Ishas suggested instead. Make sure $error doesn't contain anything that can mess up your script.
If you are thinking about the javascript console, you can not do this from PHP.
You have a few options you could choose from:
echo
var_dump
create a log file
xdebug
For a quick check for a variables value I would use var_dump, it will also show you the data type of the variable. This will be output to the browser when you request the page.
Logging to the DevTools console from PHP in WordPress
Here you can see my solution for the problem in action while debugging coupon logic in WooCommerce. This solution is meant for debug purposes, only. (Note: Screenshot not up to date, it will also expose private members.)
Features
Allow printing before and after rendering has started
Works in front-end and back-end
Print any amount of variables
Encode arrays and objects
Expose private and protected members of objects
Also log to the log file
Safely and easily opt-out in the production environment (in case you keep the calls)
Print the caller class, function and hook (quality of life improvement)
Solution
wp-debug.php
function console_log(): string {
list( , $caller ) = debug_backtrace( false );
$action = current_action();
$encoded_args = [];
foreach ( func_get_args() as $arg ) try {
if ( is_object( $arg ) ) {
$extract_props = function( $obj ) use ( &$extract_props ): array {
$members = [];
$class = get_class( $obj );
foreach ( ( new ReflectionClass( $class ) )->getProperties() as $prop ) {
$prop->setAccessible( true );
$name = $prop->getName();
if ( isset( $obj->{$name} ) ) {
$value = $prop->getValue( $obj );
if ( is_array( $value ) ) {
$members[$name] = [];
foreach ( $value as $item ) {
if ( is_object( $item ) ) {
$itemArray = $extract_props( $item );
$members[$name][] = $itemArray;
} else {
$members[$name][] = $item;
}
}
} else if ( is_object( $value ) ) {
$members[$name] = $extract_props( $value );
} else $members[$name] = $value;
}
}
return $members;
};
$encoded_args[] = json_encode( $extract_props( $arg ) );
} else {
$encoded_args[] = json_encode( $arg );
}
} catch ( Exception $ex ) {
$encoded_args[] = '`' . print_r( $arg, true ) . '`';
}
$msg = '`📜`, `'
. ( array_key_exists( 'class', $caller ) ? $caller['class'] : "\x3croot\x3e" )
. '\\\\'
. $caller['function'] . '()`, '
. ( strlen( $action ) > 0 ? '`🪝`, `' . $action . '`, ' : '' )
. '` ➡️ `, ' . implode( ', ', $encoded_args );
$html = '<script type="text/javascript">console.log(' . $msg . ')</script>';
add_action( 'wp_enqueue_scripts', function() use ( $html ) {
echo $html;
} );
add_action( 'admin_enqueue_scripts', function() use ( $html ) {
echo $html;
} );
error_log( $msg );
return $html;
}
wp-config.php (partially)
// ...
define( 'WP_DEBUG', true );
// ...
/** Include WP debug helper */
if ( defined( 'WP_DEBUG' ) && WP_DEBUG && file_exists( ABSPATH . 'wp-debug.php' ) ) {
include_once ABSPATH . 'wp-debug.php';
}
if ( ! function_exists( 'console_log' ) ) {
function console_log() {
}
}
/** Sets up WordPress vars and included files. */
require_once( ABSPATH . 'wp-settings.php' );
Usage
Before the HTML <head> is rendered:
console_log( $myObj, $myArray, 123, "test" );
After the HTML <head> is rendered (in templates, etc. / use when the above does not work):
echo console_log( $myObj, $myArray, 123, "test" );
Output format
📜 <caller class>\<caller function>() 🪝 <caller action/hook> ➡️ <variables ...>
Special thanks to
Andre Medeiros for the property extraction method
You can write a utility function like this:
function prefix_console_log_message( $message ) {
$message = htmlspecialchars( stripslashes( $message ) );
//Replacing Quotes, so that it does not mess up the script
$message = str_replace( '"', "-", $message );
$message = str_replace( "'", "-", $message );
return "<script>console.log('{$message}')</script>";
}
The you may call the function like this:
echo prefix_console_log_message( "Error Message: This is really a 'unique' problem!" );
and this will output to console like this:
Error Message: This is really a -unique- problem!
Notice the quotes replaced with "-". It is done so that message does not mess up your script as pointed by #Josef-Engelfrost
You may also go one step further and do something like this:
function prefix_console_log_message( $message, $type = "log" ) {
$message_types = array( 'log', 'error', 'warn', 'info' );
$type = ( in_array( strtolower( $type ), $message_types ) ) ? strtolower( $type ) : $message_types[0];
$message = htmlspecialchars( stripslashes( $message ) );
//Replacing Quotes, so that it does not mess up the script
$message = str_replace( '"', "-", $message );
$message = str_replace( "'", "-", $message );
return "<script>console.{$type}('{$message}')</script>";
}
and call the function like this:
echo prefix_console_log_message( "Error Message: This is really a 'unique' problem!" , 'error');
It will output error in console.

direct users with set_transient

i wanna redirect users every 12hours to another page
and want use header(location:url) and set_transient
i use this codes
$transient = get_transient( 'name_my_transient' );
if ( empty( $transient ) ){
function redirect() {
$data = 'redirected';
return $data;
header('location: http://www.google.com');
}
add_action('wp_head', 'redirect');
set_transient('name_my_transient', $data, 60*60*12 );
}
if i remove return $data it always redirect users
Your reflexion is good but i think you had made some mistakes on your code organization, try with this :
<?php
// Call your function with a top priority
add_action( 'wp_head', 'redirect', 1 );
function redirect() {
// Get the transien
$transient = get_transient( 'name_my_transient' );
// If the data do not exist, set it and redirect user
if ( $transient === false ) {
// Set the transient for 12 hours
set_transient('name_my_transient', 'redirected', 12 * HOUR_IN_SECONDS );
// Redirect the user with wp_redirect
wp_redirect( 'http://www.google.com' ); exit;
}
}
?>

maintenance mode function for multiple users - php array not working?

I have created a maintenance mode function, but I can only get it to work for one username.
get_currentuserinfo();
global $current_user;
// MAINTAINANCE MODE
function website_site_maintenance() {
global $current_user;
if ( 'josh' != $current_user->user_login ) {
// vars
$logout_url = wp_login_url().'?mode=maintenance';
wp_logout();
wp_redirect( $logout_url, 302 );
}
}
add_action('get_header', 'website_site_maintenance');
add_action('admin_init', 'website_site_maintenance');
// CUSTOM LOGIN MESSAGES
function website_my_login_message() {
if( $_GET['mode'] == 'maintenance' ){
$message = '<p class="message"><b>Site undergoing maintenance.</b></p>';
return $message;
}
}
add_filter('login_message', 'website_my_login_message');
this above function works, but I want to add more maintenance users.
So i've tried this but it does not work...
// MAINTAINANCE MODE
function website_site_maintenance() {
global $current_user;
$maintenance_users = array('josh','george','bob');
if ( $maintenance_users != $current_user->user_login ) {
// vars
$logout_url = wp_login_url().'?mode=maintenance';
wp_logout();
wp_redirect( $logout_url, 302 );
}
}
I simply tried to add the users into an array.
$maintenance_users = array('josh','george','bob');
But this doesn't seem to work as it should.
Instead of using
if ( $maintenance_users != $current_user->user_login ) {
// vars
$logout_url = wp_login_url().'?mode=maintenance';
wp_logout();
wp_redirect( $logout_url, 302 );
}
use
if ( !in_array($current_user->user_login, $maintenance_users) ) {
// vars
$logout_url = wp_login_url().'?mode=maintenance';
wp_logout();
wp_redirect( $logout_url, 302 );
}
The problem you're having is that you're comparing an array to a string, and this is not going to work. In the "correct" version you'll be checking whether the username of the currently logged in user is in the array $maintenance_users you specified. Hope that helps.

Categories