I try to change a class, which is stored in a variable without making any changes in the plugin file. I'm not sure how to target the variable inside the function.
This is the function: function learndash_mark_complete( $post, $atts = array() ) { Inside this function, there is a variable called $button_class.
if ( isset( $atts['button']['class'] ) ) {
$button_class = ' class="learndash_mark_complete_button ' . esc_attr( $atts['button']['class'] ) . '" ';
} else {
$button_class = ' class="learndash_mark_complete_button" ';
}
Is there a simple way to change the code to..
if ( isset( $atts['button']['class'] ) ) {
$button_class = ' class="myclass' . esc_attr( $atts['button']['class'] ) . '" ';
} else {
$button_class = ' class="myclass" ';
}
without change the plugin file. Maybe to create a function in functions.php or in a seperate (new) plugin?
I saw articles on the internet about add_filter, but I'm not sure how to target the part I need without wipe the whole function.
I know I could change the class with jQuery or something, and maybe it should be a lot easier, but I like to learn new things.
If plugin does not provide filter hook to change the class name then you can not you filter value.
But, if you are writing your own plugin then you can use this type of logic to change the value without touching original source.
This code should be in the plugin file,
$arrayToFilter = array(
'class_name' => 'learndash_mark_complete_button',
'key1' => 'value1', // So on
);
$value = apply_filters( 'change_class', $arrayToFilter );
if ( isset( $atts['button']['class'] ) ) {
$button_class = ' class="'.$value['class_name'].'' . esc_attr( $atts['button']['class'] ) . '" ';
} else {
$button_class = ' class="'.$value['class_name'].'" ';
}
And add this filter into theme functions.php file to modify change_class hook's value
function example_callback($args) {
// Here you can get $arrayToFilter as $args
$args['class_name'] = 'myclass';
return $args;
}
add_filter( 'change_class', 'example_callback',10 , 1 ); // Where $priority is 10, $accepted_args is 1.
I hope you got basic idea of add_filter().
Related
I have constructed the below function to work in conjunction with a button displayed on the edit product page. It is designed to generate some description text based on the title and SKU of the product. The code works perfectly for 'simple' products, but I am struggling to get it to work for 'variable' products too.
What exactly do I need to do to get it to work correctly for both simple and variable products?
The current behaviour is:
When triggered on a simple product, it adds the new description or updates the old one to the new one.
When triggered on a variable product, it updates the main description, but deletes all variations which were previously set up on the product.
add_action('woocommerce_process_product_meta', 'update_and_save_utapd');
function update_and_save_utapd() {
if(isset($_POST['button_new_update_description'])){
$product_id = wc_get_product(get_the_ID());
$wcProduct = new WC_Product($product_id);
$get_title = $wcProduct->get_name();
$get_mpn = $wcProduct->get_meta('sp_wc_barcode_field');
$get_description = $wcProduct->get_description();
$output = '';
if(!empty($get_title)){
$output .= "<p>The " . $get_title;
}if(!empty($get_mpn)){
$output .= " (MPN: " . $get_mpn . ").";
}if(!empty($get_description)){
$wcProduct->set_description($output);
$wcProduct->save();
return "<div>SUCCESS: YOU HAVE UPDATED YOUR DESCRIPTION.</div>";
}elseif(empty($get_description)){
$wcProduct->set_description($output);
$wcProduct->save();
return "<div>SUCCESS: YOU HAVE GENERATED A NEW DESCRIPTION.</div>";
}
}
}
First when using action hooks in backend that save product data, you can't return a string (a text) as you are trying to do and anyway, it will never be displayed
Now since WooCommerce 3 you can use woocommerce_admin_process_product_object much better hook that include the WC_Product Object as function argument and there is no need to use save() method at the end of your code as once this hook is triggered the save() method is auto applied.
So we can simplify your code:
add_action('woocommerce_admin_process_product_object', 'update_and_save_utapd');
function update_and_save_utapd( $product ) {
if( isset($_POST['button_new_update_description']) ){
$name = $product->get_name();
$barcode = $product->get_meta('sp_wc_barcode_field');
$output = '';
if ( ! empty($name) ) {
$output .= "<p>The " . $name;
}
if ( ! empty($barcode) ) {
$output .= " (MPN: " . $barcode . ").";
}
$product->set_description( $output );
}
}
Code goes in functions.php file of the active child theme (or active theme). It should better work now, without throwing errors.
With the woocommerce_process_product_meta hook you already have the product id and the product object available. Here you will find more information.
To verify that the button has been clicked you must also check its value, in addition to the isset() function.
Replace value_button with the value of the element's value
attribute
add_action('woocommerce_process_product_meta', 'update_and_save_utapd', 10, 2 );
function update_and_save_utapd( $product_id, $product ) {
// replace "value_button" with the value of the element's "value" attribute
if ( isset( $_POST['button_new_update_description'] ) && $_POST['button_new_update_description'] == 'value_button' ) {
if ( $product->is_type('simple') || $product->is_type('variable') ) {
$title = $product->get_name();
$mpn = $product->get_meta('sp_wc_barcode_field');
$description = $product->get_description();
$output = '';
if ( ! empty($title) ) {
$output .= "<p>The " . $title;
}
if ( ! empty($mpn) ) {
$output .= " (MPN: " . $mpn . ").";
}
if ( ! empty($get_description) ) {
$product->set_description($output);
$product->save();
return "<div>SUCCESS: YOU HAVE UPDATED YOUR DESCRIPTION.</div>";
} else {
$product->set_description($output);
$product->save();
return "<div>SUCCESS: YOU HAVE GENERATED A NEW DESCRIPTION.</div>";
}
}
}
}
I'm working in a woocommerce site (Real Estate) and I don't get to show product custom attributes on my front shop page (Eg. Square meters, Rooms, Toilets, etc). I'm trying to use the code below but I can make it work. With the code I have I'm just able to show product ID but when it comes to attributes it only shows the word "Array" or just "Nothing" when I put the attributes IDs in the code.
The is the code I have:
add_action('woocommerce_after_shop_loop_item_title', 'cstm_display_product_category', 5);
function cstm_display_product_category()
{
global $product;
$productAttribute = $product->get_id();
//if(isset($productAttribute)){
echo '<div class="items" style="color: #fff;"><p>Output: ' . $productAttribute . '</p></div>';
//}
}
You can see the output live here
Whatever help or guide you can give me to be able to achieve this, will be so much appreciated. I'm a noob in this matters.
P.D. I'm inserting this code in my functions.php file.
Wordpress is up to date.
Woocommerce is up to date.
Update 3
With product attributes (custom or not), you can use the WC_Product method get_attribute() where you can input an attribute name, slug or taxonomy. So in your code:
add_action('woocommerce_after_shop_loop_item_title', 'display_custom_product_attributes_on_loop', 5 );
function display_custom_product_attributes_on_loop() {
global $product;
$value1 = $product->get_attribute('Square meters');
$value2 = $product->get_attribute('Rooms');
$value3 = $product->get_attribute('Toilets');
if ( ! empty($value1) || ! empty($value2) || ! empty($value3) ) {
echo '<div class="items" style="color: red;"><p>';
$attributes = array(); // Initializing
if ( ! empty($value1) ) {
$attributes[] = __("Square meters:") . ' ' . $value1;
}
if ( ! empty($value2) ) {
$attributes[] = __("Rooms:") . ' ' . $value2;
}
if ( ! empty($value3) ) {
$attributes[] = __("Toilets:") . ' ' . $value3;
}
echo implode( '<br>', $attributes ) . '</p></div>';
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Automate the code from a simple array of product attribute names:
The code below will gives the same output, but it's compacted, optimized and requires just an array of your desired product attributes:
add_action('woocommerce_after_shop_loop_item_title', 'display_custom_product_attributes_on_loop', 5 );
function display_custom_product_attributes_on_loop() {
global $product;
// Settings: Here below set your product attribute label names
$attributes_names = array('Square meters', 'Rooms', 'Toilets');
$attributes_data = array(); // Initializing
// Loop through product attribute settings array
foreach ( $attributes_names as $attribute_name ) {
if ( $value = $product->get_attribute($attribute_name) ) {
$attributes_data[] = $attribute_name . ': ' . $value;
}
}
if ( ! empty($attributes_data) ) {
echo '<div class="items" style="color: red;"><p>' . implode( '<br>', $attributes_data ) . '</p></div>';
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
I have following code in a plugin:
public static function addFooterScript() {
add_action( 'wp_footer', function () {
$primary = has_action( 'spx_color_primary' ) ? do_action( 'spx_color_primary' ) : 'teal';
$secondary = has_action( 'spx_color_secondary' ) ? do_action( 'spx_color_secondary' ) : 'pink';
echo '
<spx-section-settings
color-primary="' . $primary . '"
color-secondary="' . $secondary . '">
</spx-section-settings>
<script
id="spx-footer">
' . file_get_contents( SPX_DIR . '/assets/js/footer.js' ) . '
</script>';
} );
}
And in my theme, I am calling it like that:
add_action( 'spx_color_primary', function () {
echo 'blue';
} );
However, the return value from the action is appearing before the element:
I am clueless, why is that happening?
You need to use a filter instead of an action. Change the action to filter by the below code the default value will be teal. And the filter will change it to blue.
$primary = apply_filters( 'spx_color_primary', 'teal');
Use this in your functions.php
function example_callback_to_change_color( $string ) {
$string = 'blue';
return $string;
}
add_filter( 'spx_color_primary', 'example_callback_to_change_color', 10, 1 );
To understand more about action and filters Difference Between Filter and Action Hooks?
I'm trying to pass Custom CSS in global variable to use it in another function then to pass it to wp_enqueue_scripts via wp_add_inline_style but the global variable whenever I use it as global it doesn't return anything only if i use add_action('wp_footer', 'my_function') below i'll show you my code and functions
I've tried many methods but still the same problem!
I use cru_generate_custom_style in many files to generate custom css for custom elements and based on WordPress you canβt run wp_add_inline_style anywhere else except wp_enqueue_scripts this is to eliminate errors on W3C and add inline style to wp_head
global $cru_bottom_styles;
$cru_bottom_styles = array();
function cru_generate_custom_style( $selector = '', $props = '', $media = '', $footer = true ) {
global $cru_bottom_styles;
$css = '';
// Selector Start
$css .= $selector . ' {' . PHP_EOL;
// Selector Properties
$css .= str_replace( ';', ';' . PHP_EOL, $props );
$css .= PHP_EOL . '}';
// Selector End
// Media Wrap
if ( trim( $media ) ) {
$css = "#media {$media} { {$css} }";
}
if ( ! $footer || defined( 'DOING_AJAX' ) ) {
echo "<style>{$css}</style>";
return;
}
$cru_bottom_styles[] = $css;
}
function cru_parse_header_styles() {
global $cru_bottom_styles;
print_r($cru_bottom_styles);
wp_add_inline_style( 'main', implode( PHP_EOL . PHP_EOL, $cru_bottom_styles ) );
}
add_action( 'wp_enqueue_scripts', 'cru_parse_header_styles' );
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.