PHP Function that executes a JS - Woocommerce - javascript

I have a JS function that I am trying to execute via my functions.php from within my child theme. This is my first time utilizing PHP so I apologize if my code is poor.
My goal is to try to change the page_title to what has been selected in a dropdown filter. After this is working I then plan to add the category_name to the end of the .innerHTML. This will only occur in the event that a drop down has been selected. In the event it hasn't been then just the category will display via how woocommerce handles it natively.
var machineEl = document.getElementsByClassName('woof_select_pa_machine').firstChild;
var machineValue = machineEl.value;
machineEl.addEventListener('change', function dynamic_page_title() {
if (machineValue != 'Product Machine') {
document.getElementsByClassName('woocommerce-products-header__title').innerHTML = machineValue;
}
});
This is the first script I try to execute in the function.php.
<?php
echo '<script type="text/javascript">',
'dynamic_page_title_js();',
'</script>';
?>
Alternatively I was trying to use the following to accomplish the same thing but with the intention to limiting to only certain pages. Though not sure if I will need this in the end. I used this set of code per another thread I found.
<?php
add_action ( 'wp_enqueue_scripts', 'dynamic_page_title_php');
function dynamic_page_title_php() {
//$wp_query->get_queried_object()->cat_name;
global $page_title;
if( is_page() || is_single() )
{
switch($page_title->title_name ) // post_name is the post slug which is more consistent for matching to here
{
case 'shop':
wp_enqueue_script('shop', get_template_directory_uri() . '/js/dynamic_page_title_js.js', array('jquery'), '', false);
break;
}
}
}
?>
Here is the html of the class I am trying to overwrite.
<h1 class="woocommerce-products-header__title page-title">Sample Page</h1>

I decided to take this a different route and break the issue apart. I used a js function to update page_title on filter select. Then I used code provided in another thread (Woocommerce: How to show Product Attribute name on title when in a category page and "filtering" products via '?pa_attribute=' on address bar) to handle the attribute portion from within my function.php file. The php function handles the page on load replacing shop with the attribute name, in this case the machine type. The js updates this attribute and adds the category on filter select.
There is still some work to be done on the functions.php to add the category name to the page_title when the user navigates to a category via the nav bar. I have posted a new question on how to resolve this last part (Woocommerce: How to show Product Attribute name and Category name on title) but by utilizing both these independently it is more or less accomplishing what I intended.
Also, the JS I am currently executing within the woof-woocommerece-product-filter plugin. It is written within the JS after Ajax is done section. But I do plan to move this in to its own file and call the function only from a organizational aspect.
PHP
add_filter( 'woocommerce_page_title', 'custom_woocommerce_page_title', 15, 2 );
function custom_woocommerce_page_title( $page_title ) {
if ( is_archive() ) {
$exists_attr = false;
foreach ( $_GET as $index => $value ) {
if ( substr( $index, 0, 3 ) === 'pa_' ) {
$attr_id = wc_attribute_taxonomy_id_by_name( $index );
if ( $attr_id === 0 && $cat_id ) {
continue;
}
if ( ! $exists_attr /* && ! $exists_cat */) {
$exists_attr = true;
$page_title .= ' ';
} else {
$page_title .= ' ';
}
$term = get_term_by( 'slug', esc_html( $value ), $index );
$page_title = $term->name;
}
}
}
return $page_title;
}
JS
(function() {
var machineEl = document.getElementsByClassName('woof_select woof_select_pa_machine')[0];
var processEl = document.getElementsByClassName('woof_select woof_select_pa_processing')[0];
var optionMachine = machineEl.querySelector("option[selected='selected']");
var optionProcess = processEl.querySelector("option[selected='selected']");
var machineValue = optionMachine.innerHTML;
var processValue = optionProcess.innerHTML;
var result = document.getElementsByClassName('woocommerce-products-header__title page-title')[0];
if (machineValue != 'Product Machine' && processValue != 'Product Processing') {
result.innerHTML = machineValue + " " + processValue;
}
else if (machineValue != 'Product Machine') {
result.innerHTML = machineValue;
}
else if (processValue != 'Product Processing') {
result.innerHTML = processValue;
}
})()
Once I have the category posting the to page_title I will update this answer.

Related

How to get post id in Ajax callback in Wordpress

I use the Add to cart Ajax callback, but I miss how I can get the post Id there.
MY GOAL: I want to use the add_filter only on a specific page.
PHP in functions.php
add_filter( 'woocommerce_add_cart_item_data', 'iconic_add_engraving_text_to_cart_item' , 10, 3 );
function iconic_add_engraving_text_to_cart_item( $cart_item_data, $product_id, $variation_id ) {
global $post;
if ( $post->ID === 54214 ) {
$engraving_text = 'test';
$cart_item_data['iconic-engraving'] = $engraving_text;
return $cart_item_data;
} else {
return $cart_item_data;
}
}
This is NOT WORKING because $post is NULL (because of the Ajax woocommerce_add_cart_item_data hook).
So I tried the following code in the JS to get the post id in JS (working).
function get_current_page_id() {
var page_body = $('body.page');
var id = 0;
if(page_body) {
var classList = page_body.attr('class').split(/\s+/);
$.each(classList, function(index, item) {
if (item.indexOf('page-id') >= 0) {
var item_arr = item.split('-');
id = item_arr[item_arr.length -1];
return false;
}
});
}
return id;
}
Now, how can I handover the id to my Ajax Callback to work with it?
Any advice?
EDIT:
I forgot to tell that I am planning to use the add to cart action on other pages but not a single product page.
For that, I am using a third party plugin which gives me the button for my desired product, so I am not using default $product or $post Object (like in single product pages).
I have finally found a solution for this "simple" problem. I can work with a session:
add_action( 'wp_head', 'set_session' );
add_filter( 'woocommerce_add_cart_item_data', 'iconic_add_engraving_text_to_cart_item' , 10, 3 );
function set_session() {
session_start();
// add post id
global $post;
$post_id = $post->ID;
$_SESSION['post_id'] = $post_id;
}
function iconic_add_engraving_text_to_cart_item( $cart_item_data, $product_id, $variation_id ) {
session_start();
if( $_SESSION['post_id'] == 54214 ) {
$engraving_text = 'test';
$cart_item_data['iconic-engraving'] = $engraving_text;
return $cart_item_data;
} else {
return $cart_item_data;
}
}

How to dynamically pass an array of values to a <select> field in Contact Form 7?

According to the official Contact Form 7 docs, it is possible to pass a a default value to CF7 from the shortcode, in this way:
// field in CF7 in Wordpress admin area
[email* destination-email default:shortcode_attr]
// shortcode in a Wordpress php template
[contact-form-7 id="123" title="Contact Form" destination-email="xxxxxx#example.com"]
// function in functions.php
add_filter( 'shortcode_atts_wpcf7', 'custom_shortcode_atts_wpcf7_filter', 10, 3 );
function custom_shortcode_atts_wpcf7_filter( $out, $pairs, $atts ) {
$my_attr = 'destination-email';
if ( isset( $atts[$my_attr] ) ) {
$out[$my_attr] = $atts[$my_attr];
}
return $out;
}
This works for a simple text field, but I need to pass an array of values to a <select> field and use them as <option>s inside it; I've tried to modify a bit this code, but apparently it isn't working, or at least I've not been able to.
Is it possible to use the shortcode to send dynamic data to CF7 even if not a single plain text like this?
If not, I'm open to every other kind of solution, even if it involves another method, or some additional plugin; is there some other way to dynamically send an array of values to <select> fields in Contact Form 7?
These values are data queried from the database (such as post names, custom fields, and so on), so they need to come from php first even if there is a solution that involves javascript.
Here's an example of a form tag I've used for getting US States. This is a <select> generated from an array. This is probably more along the lines of what you want to do.
You can see that I also use the usermeta billing_state to pre-select the choice.
With that said, you should also be able to use this same method to create a select tag that performs any WP_Query and puts the results into an option tag.
<?php
add_action('wpcf7_init', function (){
wpcf7_add_form_tag( array('dd_states', 'dd_states*'), 'cf7_state_dropdown' , true );
});
function cf7_state_dropdown($tag) {
$tag = new WPCF7_FormTag( $tag );
$atts = array();
$validation_error = wpcf7_get_validation_error( $tag->type );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts['class'] = $tag->get_class_option( $class );
$atts['aria-required'] = 'true';
$atts['aria-invalid'] = $validation_error ? 'true' : 'false';
$atts = wpcf7_format_atts( $atts );
// Get User ID and Billing State from DB
$userid = get_current_user_id();
$user_state = get_user_meta($userid, 'billing_state', true);
$states = array ( 'FL'=>'Florida','AL'=>'Alabama','AK'=>'Alaska','AZ'=>'Arizona','AR'=>'Arkansas','CA'=>'California','CO'=>'Colorado','CT'=>'Connecticut','DE'=>'Delaware','DC'=>'District of Columbia','GA'=>'Georgia','HI'=>'Hawaii','ID'=>'Idaho','IL'=>'Illinois','IN'=>'Indiana','IA'=>'Iowa','KS'=>'Kansas','KY'=>'Kentucky','LA'=>'Louisiana','ME'=>'Maine','MD'=>'Maryland','MA'=>'Massachusetts','MI'=>'Michigan','MN'=>'Minnesota','MS'=>'Mississippi','MO'=>'Missouri','MT'=>'Montana','NE'=>'Nebraska','NV'=>'Nevada','NH'=>'New Hampshire','NJ'=>'New Jersey','NM'=>'New Mexico','NY'=>'New York','NC'=>'North Carolina','ND'=>'North Dakota','OH'=>'Ohio','OK'=>'Oklahoma','OR'=>'Oregon','PA'=>'Pennsylvania','RI'=>'Rhode Island','SC'=>'South Carolina','SD'=>'South Dakota','TN'=>'Tennessee','TX'=>'Texas','UT'=>'Utah','VT'=>'Vermont','VA'=>'Virginia','WA'=>'Washington','WV'=>'West Virginia','WI'=>'Wisconsin','WY'=>'Wyoming');
$output = '<span class="wpcf7-form-control-wrap '.sanitize_html_class( $tag->name ).'"><select name="state" id="state" '.$atts.'>';
$output .= "<option value=\"\"> - - Choose State - - </option>";
foreach ($states as $abbrev=>$state){
$selected = ($user_state == $abbrev) ? ' selected="selected"' : '';
$output .= '<option value="'.$abbrev.'"'. $selected .'>'.$state.'</option>';
}
$output .= "</select></span>";
$output .= $validation_error;
return $output;
}

How to add a link for a popup window when user selects a particular variation

I'm using PopupMaker plugin for wordpress to create the popup up. This works by using a click trigger on a css selector of your choosing.
With this line of code I can output the variations for the particular product when I'm on its single product page.
add_action( 'woocommerce_before_add_to_cart_quantity', 'dump_attributes' );
function dump_attributes() {
global $product;
var_dump($product->get_attribute('size'));
}
I need to output a click-able link only when the customer selects a certain variation from the drop down.
The problem I have is generating that link only when a user selects the variation 'Drum'.
I was able to give this a little more thought. First, we need to give the variation data that Woo sends via JSON a little extra value. I'm checking for a "black" color attribute:
if( 'black' === strtolower($variation->get_attribute('color')) ){
But you will want to change to suit your size attribute.
Next, I define the link as
$kia_data['custom_link'] = sprintf( '%s', __( 'Your Link', 'your-textdomain' ) );
This is just a link to google and so you'll need to change that.
Next, we add an empty <div> placeholder. And finally we load some scripts on variable products and listen for the found_variation event. When we get it, we get the variation from the JSON data and we can check for the custom_link we defined earlier and dump it into the empty holder <div>.
That's probably clear as mud, but here's the full code snippet:
/**
* Add data to json encoded variation form.
*
* #param array $data - this is the variation's json data
* #param object $product
* #param object $variation
* #return array
*/
function kia_available_variation( $data, $product, $variation ){
if( 'black' === strtolower($variation->get_attribute('color')) ){
$kia_data['custom_link'] = sprintf( '%s', __( 'Your Link', 'your-textdomain' ) );
} else {
$kia_data['custom_link'] = false;
}
return array_merge( $data, $kia_data );
}
add_filter( 'woocommerce_available_variation', 'kia_available_variation', 10, 3 );
/**
* holder for display link
*/
function kia_custom_varition_link() {
echo '<div class="woocommerce-variation-link"></div>';
}
add_action( 'woocommerce_single_variation', 'kia_custom_varition_link', 5 );
/**
* Add scripts to variable products.
*/
function kia_on_found_template_for_variable_add_to_cart() {
add_action( 'wp_print_footer_scripts', 'kia_variable_footer_scripts' );
}
add_action( 'woocommerce_variable_add_to_cart', 'kia_on_found_template_for_variable_add_to_cart', 30 );
function kia_variable_footer_scripts() {
?>
<script type="text/javascript">
jQuery( document ).ready(function($) {
$('form.cart')
.on('found_variation', function( event, variation ) {
if ( variation.custom_link ) {
$link_html = variation.custom_link;
$(this).find( '.woocommerce-variation-link' ).html( $link_html ).show();
} else {
$(this).find( '.woocommerce-variation-link' ).html('').hide();
}
}).on('reset_variation', function( event, variation ) {
$(this).find( '.woocommerce-variation-link' ).html('').hide();
});
});
</script>
<?php
}
Here is the result:
Figured out one way to solve it using jQuery and getting the ID of the selection drop down (there were two different ID's named after the attribute slug #size & #pa_size).
add_action( 'woocommerce_before_add_to_cart_quantity', 'add_link_on_selection' );
function add_link_on_selection() {
?>
<script>
jQuery(document).ready(function ($) {
$('#size, #pa_size').change(function(){
if($('#add').length) {
$('#add').remove();
return;
} else {
$selection = $(this).val().toLowerCase();
console.log($selection);
$(this).after(
'<div>' +
($selection == 'drum' ? '<div id="add">Freight Restrictions</div>' : '') +
'</div>'
);
}
})
});
</script>
<?php
}

(populate dropdown in contact form 7 getting this error - Warning: array_keys() expects parameter 1 to be array, null given in

Ok where to start, I will try and explain as much as I can.
I am using wordpress with contact form 7 and I am trying to populate 3 dropdown items on the contact form, I found some code that I was able to use with no problem but the problem with this was that it was getting the information from a excel file, the file is now to big and will not run on my website anymore so I would like to get the information from my database now.
I have made a table in my database "vehicle_information" with 3 columns "vehicle_type", "vehicle_make", vehicle_model"
I have code in my functions.php and code in my footer to be able to use the cf7 shortcodes.
Code from funtions.php
function ajax_cf7_populate_values() {
//MySQLi information
$db_host = '***';
$db_username = '***';
$db_password = '***';
$vehicles_makes_models = array();
//connect to mysqli database (Host/Username/Password)
$connection = mysqli_connect($db_host, $db_username, $db_password) or die('Error ' . mysqli_error());
//select MySQLi dabatase table
$vehicles_makes_models = mysqli_select_db($connection, 'vehicle_information') or die('Error ' . mysqli_error());
$sql = mysqli_query($connection, 'SELECT * FROM vehicle_type');
while($row = mysqli_fetch_array($sql)) {
$vehicles_makes_models[$row[0]][$row[1]][] = $row[2]; }
}
// setup the initial array that will be returned to the the client side script as a JSON object.
$return_array = array(
'vehicles' => array_keys($vehicles_makes_models),
'makes' => array(),
'models' => array(),
'current_vehicle' => false,
'current_make' => false
);
// collect the posted values from the submitted form
$vehicle = key_exists('vehicle', $_POST) ? $_POST['vehicle'] : false;
$make = key_exists('make', $_POST) ? $_POST['make'] : false;
$model = key_exists('model', $_POST) ? $_POST['model'] : false;
// populate the $return_array with the necessary values
if ($vehicle) {
$return_array['current_vehicle'] = $vehicle;
$return_array['makes'] = array_keys($vehicles_makes_models[$vehicle]);
if ($make) {
$return_array['current_make'] = $make;
$return_array['models'] = $vehicles_makes_models[$vehicle][$make];
if ($model) {
$return_array['current_model'] = $model;
}
}
}
// encode the $return_array as a JSON object and echo it
echo json_encode($return_array);
wp_die();
// These action hooks are needed to tell WordPress that the cf7_populate_values() function needs to be called
// if a script is POSTing the action : 'cf7_populate_values'
add_action( 'wp_ajax_cf7_populate_values', 'ajax_cf7_populate_values' );
add_action( 'wp_ajax_nopriv_cf7_populate_values', 'ajax_cf7_populate_values' );
Code from my footer
<script>
(function($) {
// create references to the 3 dropdown fields for later use.
var $vehicles_dd = $('[name="vehicles"]');
var $makes_dd = $('[name="makes"]');
var $models_dd = $('[name="models"]');
// run the populate_fields function, and additionally run it every time a value changes
populate_fields();
$('select').change(function() {
populate_fields();
});
function populate_fields() {
var data = {
// action needs to match the action hook part after wp_ajax_nopriv_ and wp_ajax_ in the server side script.
'action' : 'cf7_populate_values',
// pass all the currently selected values to the server side script.
'vehicle' : $vehicles_dd.val(),
'make' : $makes_dd.val(),
'model' : $models_dd.val()
};
// call the server side script, and on completion, update all dropdown lists with the received values.
$.post('<?php echo admin_url( 'admin-ajax.php' ) ?>', data, function(response) {
all_values = response;
$vehicles_dd.html('').append($('<option>').text(' -- choose vehicle -- '));
$makes_dd.html('').append($('<option>').text(' -- choose make -- '));
$models_dd.html('').append($('<option>').text(' -- choose model -- '));
$.each(all_values.vehicles, function() {
$option = $("<option>").text(this).val(this);
if (all_values.current_vehicle == this) {
$option.attr('selected','selected');
}
$vehicles_dd.append($option);
});
$.each(all_values.makes, function() {
$option = $("<option>").text(this).val(this);
if (all_values.current_make == this) {
$option.attr('selected','selected');
}
$makes_dd.append($option);
});
$.each(all_values.models, function() {
$option = $("<option>").text(this).val(this);
if (all_values.current_model == this) {
$option.attr('selected','selected');
}
$models_dd.append($option);
});
},'json');
}
})( jQuery );
The problem is I am still learning and this is the first time I have had to use this funtion.
and I am getting an error on my website
Warning: array_keys() expects parameter 1 to be array, null given in /customers/4/0/0/motobid.co.uk/httpd.www/wp-content/themes/storevilla-child/functions.php on line 38 {"vehicles":null,"makes":[],"models":[],"current_vehicle":false,"current_make":false}
any help would be very greatful.
Just like to say code was supplied by BDMW.
Where you use the method array_keys(), instead of:
$return_array['makes'] = array_keys($vehicles_makes_models[$vehicle]);
Try this:
$return_array['makes'] = ! empty($vehicles_makes_models[$vehicle]) ? array_keys($vehicles_makes_models[$vehicle]) : [];
From what I've read, the array_keys() has been an issue depending on php versions. Hope this helps!

Create a redirect based on applied coupon in WooCommerce order received page

Here is the flow:
Customer adds product to cart.
Customer adds coupon "smile" at checkout.
When customer places order the function will run before the Order
Details page loads. Function will check for "smile" coupon and if it
has been applied it redirects to a new page where they will be
offered additional products for free. If not, then it continues on
as normal.
I have been referencing two solutions I found through a Google search similar to parts of my problem. Individually I get them to work but together I cannot seem to get them to work correctly.
Here is my code:
add_action( 'woocommerce_thankyou' , 'sq_checkout_custom_redirect' );
function sq_checkout_custom_redirect($order_id) {
global $woocommerce;
$order = new WC_Order( $order_id );
$coupon_id = 'smile';
$applied_coupon = $woocommerce->cart->applied_coupons;
$url = 'https://site.mysite.org/score-you-win/';
if( $applied_coupon[0] === $coupon_id ) {
echo "<script type=\"text/javascript\">window.location.replace('".$url."');</script>";
} else {
echo '<h3 style="font-size:200px; z-index:30000; color:#000 !important;">Coupon not applied</h3>';
}
}
No matter what coupon I apply I get the message "Coupon not applied." and no redirect happens.
The two solutions that I am referencing are:
Find applied coupon_id in cart
Redirect with JS
This code runs successfully:
add_action( 'woocommerce_thankyou', function ($order_id){
$order = new WC_Order( $order_id );
$coupon_id = "smile";
$url = 'https://site.mysite.org/score-you-win/';
if ($order->status != 'failed') {
echo "<script type=\"text/javascript\">window.location.replace('".$url."');</script>";
}
});
And this runs successfully:
function product_checkout_custom_content() {
global $woocommerce;
$coupon_id = 'smile';
$applied_coupon = $woocommerce->cart->applied_coupons;
if( $applied_coupon[0] === $coupon_id ) {
echo '<span style="font-size:200px; z-index:30000; color:#red !important;">We are happy you bought this product =)</span> ';
} else {
echo '<h3 style="font-size:200px; z-index:30000; color:#000 !important;">Coupon not applied</h3>';
}
}
add_action( 'woocommerce_thankyou' , 'sq_checkout_custom_redirect' );
Updated: In woocommerce "Order Received" page (thankyou), there is no more WC_Cart object available. Instead you need to target the WC_Order object this way:
add_action( 'woocommerce_thankyou', 'thankyou_custom_redirect', 20, 1 );
function thankyou_custom_redirect( $order_id ) {
// Your settings below:
$coupon_id = 'smile';
$url = 'https://site.mysite.org/score-you-win/';
// Get an instance of the WC_order object
$order = wc_get_order($order_id);
$found = false;
// Loop through the order coupon items
foreach( $order->get_items('coupon') as $coupon_item ){
if( $coupon_item->get_code() == strtolower($coupon_id) ){
$found = true; // Coupon is found
break; // We stop the loop
}
}
if( $found )
echo "<script type=\"text/javascript\">window.location.replace('".$url."');</script>";
else
echo '<h3 style="font-size:200px; z-index:30000; color:#000 !important;">Coupon not applied</h3>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Categories