I'm attempting to save a simple text input to the WooCommerce session. The session is created when a user adds something to their cart.
My input field exists in custom page template that will be placed in the user flow after the cart but before the checkout: cart > my template > checkout.
So far
Simple form to capture data (custom template file)
<form name="group" method="post" class="checkout woocommerce-checkout" action="http://localhost:/site.dev/my-template">
<div class="group-order">
<p class="form-row form-row woocommerce-validated" id="create_new_group_field">
<label for="create_new_group" class="">Join an existing group</label>
<input type="text" class="input-text " name="create_new_group" id="create_new_group">
</p>
</div>
</form>
Receiving and setting data (I'm having trouble figuring out when/how to run this. in my custom page)
UPDATE
I've added the code below to the top of my page template so the page processes itself and then re-directs to the checkout.
function set_and_save_input_to_session() {
if( !is_admin( ) ) {
// User input
if( ! empty( $_POST['create_new_group'] ) ) {
$group_input_value = $_POST['create_new_group'];
// Set session and save data
WC()->session->set( 'group_order_data', $group_input_value );
wp_redirect( 'http://localhost:28/site.dev/checkout' );
exit();
}
}
get_header();
add_action('woocommerce_checkout_process', 'set_and_save_input_to_session');
Retrieving and saving data
function retrieve_and_save_group_input_value_to_order_meta() {
$retrived_group_input_value = WC()->session->get( 'group_order_data' );
update_post_meta( $order_id, '_create_new_group', $retrived_group_input_value );
}
add_action('woocommerce_checkout_update_order_meta', 'retrieve_and_save_group_input_value_to_order_meta');
I'm currently working my way through what are to me, more complex solutions and therefore I'd appreciate if anyone could point out any major flaws with my process so far.
UPDATE
I can confirm that the form is receiving data and that the WC()->session->set is setting data. (Thanks to #Firefog for suggesting the use the $_SESSION global)
After further investigation and finding the right place to var_dump the session data I found that the data was being set to the session with my original method.
The data is set, but I can't see why the data won't save to the order.
It's more saying Thank you for solving my problem. But here is an answer, too:
The post meta could not been updated because there is no $order_id parameter in your callback function. This should do the trick:
function retrieve_and_save_group_input_value_to_order_meta( $order_id ) {
$retrived_group_input_value = WC()->session->get( 'group_order_data' );
update_post_meta( $order_id, '_create_new_group', $retrived_group_input_value );
}
add_action('woocommerce_checkout_update_order_meta', 'retrieve_and_save_group_input_value_to_order_meta');
Here is another approach.
1st page:
session_start();//place this at the top of all code
$data = $_POST['create_new_group'];
$_SESSION['custom_create_new_group']=$data;
Now in another page write the following to receive the value:
session_start(); //optional
$retrive_price = $_SESSION['custom_create_new_group'];
Related
I have a site with over 20,000 users. Occasionally I need to update the author of a post. However, the sheer amount of users makes the "Author" metabox on the edit post screen unusable. I'm trying to make a custom box where I can input the desired author's ID and change the post author to that ID. Ideally, I would like to do this within the box itself, rather than by way of saving/updating the post.
Here's my custom meta box code:
//Get the post data
$id = get_the_ID();
$author_id= $post->post_author;
<div class="update-author">
<p><strong>Current Author ID:</strong> <?php echo $author_id;?></p>
<p><strong>CHANGE AUTHOR ID TO:</strong></p>
<form id="update-author-form" method="post" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" >
<input type="hidden" name="action" value="update_author_form">
<input type="hidden" name="post-id" value="<?php echo $id; ?>">
<input type="number" id="update-author-id" name="update-author-id" value="" />
<button id="update-author-button" class="button button-primary button-large">Update Author ID</button>
</form>
</div>
Next, I have my form function built as follows:
function handle_update_author_form() {
$post_id = $_POST['post-id'];
$update_id = $_POST['update-author-id'];
$my_post = array(
'ID' => $post_id,
'post_author' => $update)_id,
);
wp_update_post( $my_post );
}
At this stage, my form button does nothing but refresh the page and send it to the posts screen (I know, I need to change the redirect URL).
Like in comments - I would go for a another approach of removing the original meta_box and replacing it with a new one - or alternatively just use a JS to turn the dropdown list into a searchable field ( for example the excellent select2 plugins - but have others - and also pure JS is quite easy - see example below )
Anyhow - in your code that you posted you are missing the hook where you can apply and invoke your code, for example:
'add_action( 'save_post', 'handle_update_author_form', 10, 1 ); '
Have a look at wp filters and actions.
The suggested (simple) JS solution :
Now, for the simple approach of just using JS to pseudo-search inside the dropdown and therefor there is no real need to interfere with the query or post injections.....
myPlugin.php / myTHeme,php
function admin_enqueue_scripts_callback(){
// We are using select2.js from CDN here ..
//This will add Select2 CSS
wp_enqueue_style( 'select2-css', 'https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/css/select2.min.css', array(), '4.1.0-rc.0');
////This will add Select2 JS
wp_enqueue_script( 'select2-js', 'https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/js/select2.min.js', 'jquery', '4.1.0-rc.0');
// Now we need a JavaScript file to initialize the Select2 elements
// here it is staged as a plugin - but a theme would be the same .
wp_enqueue_script( 'select2-init', '/wp-content/plugins/select2-init.js', 'jquery', '4.1.0-rc.0');
}
add_action( 'admin_enqueue_scripts', 'admin_enqueue_scripts_callback' );
select2-init.js
// initialize select2 on author dropdown field with jQuery
jQuery(document).ready(function($) {
$('#post_author_override').select2();
});
voilà !
At this point you will have the pseudo-search implemented that would resolve your problem in a practical way without any new ->queries or $objects and with minimum coding.
Possible / potential caveats
I am not sure what would be the efficiency of filtering 20,000 items.
It would be interesting to know how the select2 JS would perform with such a long list...
But if it is already loaded to the DOM i guess it would be ok ( might take a few seconds to react though )
Please let me know how it performing if you implement the solution.
I have a created a new template inside theme's folder named Pre-Checkout Customer Details where there is a form. and the page looks like:
<?php /* Template Name: Pre-Checkout Customer Details */ ?>
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
get_header(); ?>
<form action="/checkout/?">
<input type="name" name="name">
<input type="date" name="start_date">
<input type="submit" name="Next">
</form>
<?php get_footer(); ?>
Along with that, this page's URL will always contain some parameters such as
?add-to-cart=608&subscribe='weight_loss_plan'
which will look somewhat:
https://challengecenter-q8.com/pre-checkout-customer-details/?add-to-cart=608&subscribe=%D8%A8%D9%86%D8%A7%D8%A1%20%D8%B9%D8%B6%D9%84%20%D8%A3%D8%B4%D8%AA%D8%B1%D8%A7%D9%83%20%D8%A7%D8%B3%D8%A8%D9%88%D8%B9%D9%8A%D9%86%20%D9%88%D8%AC%D8%A8%D8%AA%D9%8A%D9%86
Now when I am clicking on submit, it is showing page not found instead of moving to the cart page. Also, I want the form details to show on the checkout page like: https://challengecenter-q8.com/checkout/?name='value 1'&date='04-04-2021'
How can I achieve that?
Thank you in advance!
Note: “Enable AJAX add to cart buttons on archives” is enabled and “Redirect to the cart page after successful addition”. is disabled.
I would look into using actions to accomplish what you're trying to do. You can use the template_redirect action to check for your URL parameter and programmatically add that item to the cart then redirect to which ever page you would like.
You can simply create an anchor link for the page you're currently on that has the parameter you're needing (in my case 'atc').
Here's a piece of code I use to do this.
add_action('template_redirect', 'mks_add_to_cart');
function mks_add_to_cart(){
$pid = filter_input( INPUT_GET, 'atc', FILTER_VALIDATE_INT );
if( !empty( $pid ) ) {
global $woocommerce;
$woocommerce->cart->add_to_cart( $pid );
wp_redirect( site_url() . '/cart' );
exit;
}}
Use another action for your second part to display on the checkout page. I use Business Bloomer Visual Hook Guide often to reference where I want information to show.
I want to save an information to the variation data without defining an explicit field in my backend.
I already create the information in my functions.php for each variation. But I do not want an explicit field (e.g. described here) because it is a dynamic value (delivery time) which is calculated on runtime when user enters the product page. I just want to save the information in the variation data, so I can access and display it via variation.php by this code:
<div class="woocommerce-variation-cmpzDeliveryTime">
{{{ data.variation.variation_cmpzDeliveryTime}}}
</div>
But unfortunately, I am not finding a solution. :(
Is this possible after all? Could anybody help me please?
/UPDATE: I found a solution, here is my code:
add_filter( 'woocommerce_available_variation', 'cmpz_load_variation_products_fields' );
function cmpz_load_variation_products_fields( $variations ) {
$variations['variation_cmpzDeliveryTime'] = cmpzGetBBDateForVariation( $variations[ 'variation_id' ] ) ;
return $variations;
}
function cmpzGetBBDateForVariation ( $variation_id ) {
//DO SOME CODING
return $cmpzDeliveryTime;
}
And this comes in variation.php:
<div class="woocommerce-variation-cmpzDeliveryTime">{{{ data.variation.variation_cmpzDeliveryTime}}}</div>
I'm building an online store and I have a private page where admins can scan a QR code and it displays the order details of the order assigned to that QR code. Admins can also set the status of the order on that page. I managed to display order notes in that page too. I also would like to add a form (textarea + submit button) to add a order note to the order, because our online store is about services, and I want to be able to put a note when the order is partially redeemed, so we don't have to go to the desktop -> orders -> the order and add the note. Could somebody help me? I would need a code to directly add it where I want it, I mean, not in functions.php, a code for the custom template of the page (page-scanqr.php). Any help would be appreciated!
EDIT: I saw this and I thought that maybe it could help me somehow, but I don't know how to apply it so it runs after pressing the submit button and sends the textarea text as a new order note: https://stackoverflow.com/a/49508808/12459095
As I say, I want to apply somehow this function. But I want to run it after pressing the button "submit" and I want it to pick the text from the text area and send it to wordpress as a new order note.
function add_redeeming_notes( $order_id ) {
$order = new WC_Order( $order_id );
// The text for the note
$note = __("I WANT THIS TO PICK THE TEXT FROM THE TEXTAREA");
// Add the note
$order->add_order_note( $note );
EDIT 2: I also show you the code that allows me to display the orders note, in case it could be helpful.
<?php
$order_notes = get_private_order_notes( $order_id );
foreach($order_notes as $note){
$note_id = $note['note_id'];
$note_date = $note['note_date'];
$note_author = $note['note_author'];
$note_content = $note['note_content'];
// Outputting each note content for the order
echo '<p>'.$note_date.' - '.$note_content.'</p>';
} ?>
Add the follows codes snippet in your custom page template. or you can replace follows code in your template form structure -
<?php
if ( isset( $_POST['order_note_nonce_field'] ) && wp_verify_nonce( $_POST['order_note_nonce_field'], 'order_note_action' ) ) {
$order_id = ( isset( $_POST['order_id'] ) && $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : '';
$order_note = ( isset( $_POST['order_note'] ) && $_POST['order_note'] ) ? sanitize_textarea_field( $_POST['order_note'] ) : '';
$order = wc_get_order( $order_id );
if( $order && $order_note ) {
// Add the note
$order->add_order_note( $order_note );
}
}
?>
<form action="" method="post">
<?php wp_nonce_field( 'order_note_action', 'order_note_nonce_field' ); ?>
<input type="hidden" name="order_id" value="21" /> <!-- dont forgot to replace the value with your current order id -->
<div class="form-field">
<textarea name="order_note"></textarea>
</div>
<div class="form-field">
<input type="submit" value="Add Note" />
</div>
</form>
Here is some psuedo code from my comment above:
if (isset($_POST['your_submit_action)) {
update_post_meta($id_of_product, 'your_text_key', $_POST['your_text_field'];
}
That right there will store it. To get it, do this:
$text = get_post_meta($id_of_product, 'your_text_key', TRUE);
Hope that helps.
EDIT:*
WC stores the order notes in the 'comments' table. The orders are post types themselves of 'shop_order'. Simply insert shop_order notes into the comments table as necessary using the order ID set to the 'comment_post_ID' field in the 'comments' table. Done and done.
I have input fields with names like: child1, child[2], child[3] and so on. A user can add as many fields as he wants, its handled with jquery and dynamically ads an input field with [n] in the end of the name.
Now I need to store this data to database in WordPress plugin I work on. And later retrieve this data to display it on the website, and of cause add those field out fields in admin page, where user edits data.
I know how to store one field for example child to the database in WordPress, it would be something like that:
<?php $child = get_post_meta( $post->ID, 'child', true ); ?>
<?php
function save_child_data( $post_id ) {
// Check if exists
if(! isset($_POST['child'])){return;}
// Sanitize
$child_data = sanitize_text_field( $_POST['child'] );
// Store data
update_post_meta( $post_id, 'child', $child_data);
}
add_action( 'save_post', 'save_child_data' );
?>
<!-- Field in admin -->
<input type="text" name="child" id="child" value="<?php echo esc_attr($child); ?>">
<!-- Front office -->
<div>Child: <?php echo get_post_meta( $post->ID, 'child', true ); ?></div>
So my question is how do I handle this array like child[n]?
Or another question maybe it is better to just use child1, child2, child3 and handle it as regular input fields?
So you understand what I mean by dynamically added block here is a jsfiddle link: http://jsfiddle.net/alexchizhov/LC2K6/
Store it as an JSON or serialized string in one field.
http://ch1.php.net/manual/en/function.json-encode.php
http://ch1.php.net/manual/en/function.serialize.php