I am adding a custom payment gateway to WP Woocommerce.
I want to get the current user order_id for the cart created.
I can get the cart total :
global $woocommerce;
$total= $woocommerce->cart->total ;
or with :
WC()->cart->get_total() ;
How can I call the function :
process_payment($order_id)
when I don't have the $order_id yet and I have only the cart ?
(wrong question: there is no order_id yet)
The answer to the question asked initially is:
you don't have a Order ID yet in the cart.
Only after checkout is complete the Order ID exists.
The answers are not inline with the question, which probably needs to be asked again or edited.
add_action('woocommerce_payment_complete', 'custom_process_order', 10, 1);
function custom_process_order($order_id) {
$order = new WC_Order( $order_id );
$myuser_id = (int)$order->user_id;
$user_info = get_userdata($myuser_id);
$items = $order->get_items();
foreach ($items as $item) {
if ($item['product_id']==24) {
// Do something clever
}
}
return $order_id;
}
This will hook into WooCommerce to Trigger custom_process_order After an Order is Placed
how do you create custom payment gateway?
did you create class that extends WC_Payment_Gateway,
you don't need to direct call the the process_payment() function.
you just need to create class that extends WC_Payment_Gateway and add that function on your class, it will automatically called from checkout process
see woocommerce/includes/class-wc-checkout.php line 777
the process_payment() function should return an array with key results and redirect_url
example :
public function process_payment( $order_id ) {
$order = wc_get_order( $order_id );
// Set order status
$order->update_status( 'processing', __( 'Payment created from custom gateway' ) );
// Reduce stock levels
wc_reduce_stock_levels( $order_id );
// Remove cart
WC()->cart->empty_cart();
// Return thankyou redirect
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $order ),
);
}
I have a plugin created with the file custom payment.php
containing a form to connect with the payment provider:
/*
Plugin Name: Clic To Pay Payment Gateway
Description: Custom payment gateway example
Author:
Author URI:
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* Custom Payment Gateway.
*
* Provides a Custom Payment Gateway, mainly for testing purposes.
*/
add_action('plugins_loaded', 'init_custom_gateway_class');
function init_custom_gateway_class(){
class WC_Gateway_Custom extends WC_Payment_Gateway {
public $domain;
/**
* Constructor for the gateway.
*/
public function __construct() {
$this->domain = 'custom_payment';
$this->id = 'ClictoPay';
$this->icon = apply_filters('woocommerce_custom_gateway_icon', '');
$this->has_fields = false;
$this->method_title = __( 'ClictoPay', $this->domain );
$this->method_description = __( 'Allows payments with custom gateway.', $this->domain );
// Load the settings.
$this->init_form_fields();
$this->init_settings();
// Define user set variables
$this->title = $this->get_option( 'title' );
$this->description = $this->get_option( 'description' );
$this->instructions = $this->get_option( 'instructions', $this->description );
$this->order_status = $this->get_option( 'order_status', 'completed' );
// Actions
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
add_action( 'woocommerce_thankyou_custom', array( $this, 'thankyou_page' ) );
// Customer Emails
add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
}
/**
* Initialise Gateway Settings Form Fields.
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', $this->domain ),
'type' => 'checkbox',
'label' => __( 'Enable Clic To Pay Payment', $this->domain ),
'default' => 'yes'
),
'title' => array(
'title' => __( 'Title', $this->domain ),
'type' => 'text',
'description' => __( 'This controls the title which the user sees during checkout.', $this->domain ),
// 'default' => __( 'Clic to pay Payment', $this->domain ),
'desc_tip' => false,
),
'order_status' => array(
'title' => __( 'Order Status', $this->domain ),
'type' => 'select',
'class' => 'wc-enhanced-select',
'description' => __( 'Choose whether status you wish after checkout.', $this->domain ),
'default' => 'wc-completed',
'desc_tip' => true,
'options' => wc_get_order_statuses()
),
'description' => array(
'title' => __( 'Description', $this->domain ),
'type' => 'textarea',
'description' => __( 'Payment method description that the customer will see on your checkout.', $this->domain ),
'default' => __('Payment Information', $this->domain),
'desc_tip' => true,
),
'instructions' => array(
'title' => __( 'Instructions', $this->domain ),
'type' => 'textarea',
'description' => __( 'Instructions that will be added to the thank you page and emails.', $this->domain ),
'default' => '',
'desc_tip' => true,
),
);
}
/**
* Output for the order received page.
*/
public function thankyou_page() {
if ( $this->instructions )
echo wpautop( wptexturize( $this->instructions ) );
}
/**
* Add content to the WC emails.
*
* #access public
* #param WC_Order $order
* #param bool $sent_to_admin
* #param bool $plain_text
*/
public function email_instructions( $order, $sent_to_admin, $plain_text = false ) {
if ( $this->instructions && ! $sent_to_admin && 'custom' === $order->payment_method && $order->has_status( 'on-hold' ) ) {
echo wpautop( wptexturize( $this->instructions ) ) . PHP_EOL;
}
}
public function payment_fields(){
if ( $description = $this->get_description() ) {
// echo wpautop( wptexturize( $description ) );
}
?>
<form action="https://clictopay.monetiquetunisie.com/clicktopay/" method="post" name="form">
<?php $loguserid = session_id();
/***/
global $woocommerce,$amount ,$connectdb ;
// se connecter la base
$connectdb=mysqli_connect(DB_HOST,DB_USER,DB_PASSWORD,DB_DATABASE)or die("error 01");
$amount =number_format ( $woocommerce->cart->total, 3 , ',' ,'');
/**/
/* $order = wc_get_order( $order_id ); , etat='".$order_id."' */
$querye=mysqli_query($connectdb," Update nauto set amount='".$amount."', session='".$loguserid ."' ")or die(mysqli_error .' erreur');
/***/
$refc='cd'.date('ymdHis');
//$amount =number_format ( $woocommerce->cart->total, 3 , ',' ,'');
echo '<input type="hidden" name="sid" value="'.$loguserid.'">
<input name="Reference" type="hidden" value="'.$refc.'">
<input name="Montant" type="hidden" value='.$amount.' > '; ?>
<input name="Devise" type="hidden" value="TND" />
<input type="hidden" name="affilie" value="0870172012">
<input type="hidden" name="lg" value="en">
<table border="0">
<tr><td ><input style="margin-right:105px; border: none;
background: no-repeat url('https://saharagift.com/wp-content/uploads/2017/05/payyy.png') 0 0;width:250px;height:46px;
" name="Submit" type="submit" value="" id="clictop" onmouseover='if ( (document.getElementById("billing_first_name").value.length <2) || (document.getElementById("billing_last_name_field").value.length <2) || (document.getElementById("billing_email").value.length <5) || (document.getElementById("billing_address_1").value.length <5) || (document.getElementById("billing_city").value.length <2) || (document.getElementById("billing_postcode").value.length <2) || ( ! document.getElementById("billing_email").value.includes("#")) || ( ! document.getElementById("billing_email").value.includes(".")) )
{alert("Please check billing details !");
document.getElementById("clictop").disabled = true;
}
else{
document.getElementById("clictop").disabled = false;
}' /></td></tr>
<tr><td><img style="float:left;margin-left:10px;" src="https://saharagift.com/wp-content/uploads/2017/05/pmm.png" /></td></tr>
</table>
</form>
<?php
}
/**
* Process the payment and return the result.
*
* #param int $order_id
* #return array
*/
public function process_payment( $order_id ) {
$order = wc_get_order( $order_id );
$status = 'wc-' === substr( $this->order_status, 0, 3 ) ? substr( $this->order_status, 3 ) : $this->order_status;
// Set order status
$order->update_status( $status, __( 'Checkout with custom payment. ', $this->domain ) );
// Reduce stock levels
$order->reduce_order_stock();
// Remove cart
WC()->cart->empty_cart();
// Return thankyou redirect
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $order )
);
}
}
}
add_filter( 'woocommerce_payment_gateways', 'add_custom_gateway_class' );
function add_custom_gateway_class( $methods ) {
$methods[] = 'WC_Gateway_Custom';
return $methods;
}
add_action('woocommerce_checkout_process', 'process_custom_payment');
function process_custom_payment(){
if($_POST['payment_method'] != 'custom')
return;
if( !isset($_POST['mobile']) || empty($_POST['mobile']) )
wc_add_notice( __( 'Please add your mobile number', $this->domain ), 'error' );
if( !isset($_POST['transaction']) || empty($_POST['transaction']) )
wc_add_notice( __( 'Please add your transaction ID', $this->domain ), 'error' );
}
/**
* Update the order meta with field value
*/
add_action( 'woocommerce_checkout_update_order_meta', 'custom_payment_update_order_meta' );
function custom_payment_update_order_meta( $order_id ) {
if($_POST['payment_method'] != 'custom')
return;
// echo "<pre>";
// print_r($_POST);
// echo "</pre>";
// exit();
/// update_post_meta( $order_id, 'mobile', $_POST['mobile'] );
/// update_post_meta( $order_id, 'transaction', $_POST['transaction'] );
}
/**
* Display field value on the order edit page
*/
add_action( 'woocommerce_admin_order_data_after_billing_address', 'custom_checkout_field_display_admin_order_meta', 10, 1 );
function custom_checkout_field_display_admin_order_meta($order){
$method = get_post_meta( $order->id, '_payment_method', true );
if($method != 'custom')
return;
/* $mobile = get_post_meta( $order->id, 'mobile', true );
$transaction = get_post_meta( $order->id, 'transaction', true );
echo '<p><strong>'.__( 'Mobile Number' ).':</strong> ' . $mobile . '</p>';
echo '<p><strong>'.__( 'Transaction ID').':</strong> ' . $transaction . '</p>';*/
}
?>
the payment provider communicate with the file notfication.php (anwser detail than answer accord in case of successful payment) :
<?
$ref = $_GET['Reference'];
$act = $_GET['Action'];
$par = $_GET['Param'];
define("DB_HOST", "****");
define("DB_USER", "****");
define("DB_PASSWORD", "****");
define("DB_DATABASE", "****");
// se connecter la base
include '/wp-content/plugins/woocommerce/woocommerce.php';
include '/wp-content/plugins/CustomPayment.php';
global $connectdb, $woocommerce,$amount;
$connectdb=mysqli_connect(DB_HOST,DB_USER,DB_PASSWORD,DB_DATABASE)or die("error 01");
$loguserid = session_id();
/* */
$query=mysqli_query ($connectdb,"SELECT * FROM nauto ;");
/** recupertaion amount*/
while($col = mysqli_fetch_object($query)){
$amount=$col->amount ;
}
$querye=mysqli_query($connectdb," Update nauto set amount='".$amount."' , ref='".$ref."' ")or die(mysqli_error .' erreur');
switch ($act) {
case "DETAIL":
// accéder à la base et récuperer le montant
echo "Reference=".$ref. "&Action=".$act."&Reponse=".$amount;
break;
case "ERREUR":
// accéder à la base et mettre à jour l’état de la transaction
$queryerr=mysqli_query($connectdb," Update nauto set num=".$par.", etat=".$act." ")or die(mysqli_error .' erreur');
echo "Reference=".$ref. "&Action=".$act. "&Reponse=OK";
break;
case "ACCORD":
// accéder à la base, enregistrer le numéro d’autorisation (dans param)
$query=mysqli_query($connectdb," INSERT INTO nauto (num,ref,session,etat,amount) values (".$par.",".$ref.",".$loguserid.",".$etat.",".$amount.")" )or die(mysqli_error .' here');
echo "Reference=".$ref. "&Action=".$act. "&Reponse=OK";
///echo "Reference=".$ref. "Action=".$act. "Reponse=ANNULATION"."Param=".$par;
break;
case "REFUS":
// accéder à la base et mettre à jour l’état de la transaction
$queryref=mysqli_query($connectdb," Update nauto set num=".$par.", etat=".$act." ")or die(mysqli_error .' refus');
echo "Reference=".$ref. "&Action=".$act. "&Reponse=OK";
break;
case "ANNULATION":
// accéder à la base et mettre à jour l’état de la transaction
$queryann=mysqli_query($connectdb," Update nauto set num=".$par.", etat=".$act." ")or die(mysqli_error .' annulation');
echo "Reference=".$ref. "&Action=".$act. "&Reponse=OK";
break;
}
?>
How can I create the order after I receive the payment (case ACCORD in notification.php ) ???
If you user tried a payment and it failed, you might like to check $order_id = WC()->session->get( 'order_awaiting_payment' );
Related
I have created a custom checkout select field with validation. I was able to show this field in the order in the backend and in the confirmation email. I added it with this code:
/*** ADD DOCKING STATION FIELD # WC CHECKOUT ***/
add_action( 'woocommerce_after_checkout_billing_form', 'bbloomer_add_custom_checkout_field' );
function bbloomer_add_custom_checkout_field( $checkout ) {
$current_user = wp_get_current_user();
$saved_docking_station = $current_user->docking_station;
woocommerce_form_field( 'docking_station', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'label' => 'Do you have a docking station/ loading dock on-site?',
'required' => true,
'default' => $saved_docking_station,
'options' => array(
'' => __( 'Choose an option' ),
'No' => __( 'No' ),
'Yes' => __( 'Yes' ),
)
), $checkout->get_value( 'docking_station' ) );
}
/* Validate this field */
add_action( 'woocommerce_checkout_process', 'bbloomer_validate_new_checkout_field' );
function bbloomer_validate_new_checkout_field() {
if ( ! $_POST['docking_station'] ) {
wc_add_notice( '<strong>Docking station</strong> is a required field.', 'error' );
}
}
/* Save & show this field # WC orders & emails */
add_action( 'woocommerce_checkout_update_order_meta', 'bbloomer_save_new_checkout_field' );
function bbloomer_save_new_checkout_field( $order_id ) {
if ( $_POST['docking_station'] ) update_post_meta( $order_id, '_docking_station', esc_attr( $_POST['docking_station'] ) );
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'bbloomer_show_new_checkout_field_order', 10, 1 );
function bbloomer_show_new_checkout_field_order( $order ) {
$order_id = $order->get_id();
if ( get_post_meta( $order_id, '_docking_station', true ) ) echo '<p><strong>Docking station:</strong> ' . get_post_meta( $order_id, '_docking_station', true ) . '</p>';
}
add_action( 'woocommerce_email_after_order_table', 'bbloomer_show_new_checkout_field_emails', 20, 4 );
function bbloomer_show_new_checkout_field_emails( $order, $sent_to_admin, $plain_text, $email ) {
if ( get_post_meta( $order->get_id(), '_docking_station', true ) ) echo '<p><strong>Docking station:</strong> ' . get_post_meta( $order->get_id(), '_docking_station', true ) . '</p>';
}
I also want to show this field on the account page; in the tab Account details (/my-account/edit-account). It would be perfect if the value of the docking field is visible on the account page and that the users can change this value on the account page for future orders.
I wonder if it's even possible to show the exact same field on the account page? I can imagine that this is not possible because checkout fields and account (user) fields are different type of fields and therefore you can't use the same field for both purposes. However, I hope it's possible.
How to add custom field in shipping method using woocommerce wordpress
Please see my screenshot
Please try this code.
if ( ! function_exists( 'dimative_shipping_instance_form_fields_filters' ) ) {
/**
* Shipping Instance form add extra fields.
*
* #param array $settings Settings.
* #return array
*/
function dimative_shipping_instance_form_add_extra_fields( $settings ) {
$settings['shipping_extra_field_title'] = array(
'title' => esc_html__( 'Shipping method title', 'zincheco' ),
'type' => 'text',
'placeholder' => esc_html__( 'Please add shipping method title', 'zincheco' ),
'description' => '',
);
$settings['shipping_extra_field_description'] = array(
'title' => esc_html__( 'Shipping method description', 'zincheco' ),
'type' => 'textarea',
'placeholder' => esc_html__( 'Please add your shipping method description', 'zincheco' ),
'description' => '',
);
return $settings;
}
/**
* Shipping instance form fields.
*/
function dimative_shipping_instance_form_fields_filters() {
$shipping_methods = WC()->shipping->get_shipping_methods();
foreach ( $shipping_methods as $shipping_method ) {
add_filter( 'woocommerce_shipping_instance_form_fields_' . $shipping_method->id, 'dimative_shipping_instance_form_add_extra_fields' );
}
}
add_action( 'woocommerce_init', 'dimative_shipping_instance_form_fields_filters' );
}
In case if someone is looking how to get the value using #Өлзийбат-Нансалцог code example. I was able to retrieve it this way:
//Get Shipping rate object
//$method->id is the ID of the shipping method.
//In my case I used that in cart-shipping.php template
$WC_Shipping_Rate = new WC_Shipping_Rate($method->id);
// Returned value is flat_rate:1
$shipping_rate_id = $WC_Shipping_Rate->get_id();
//Replacing : with underscore to have the id in format of flat_rate_1
$shipping_rate_id = str_replace(':', '_', $shipping_rate_id);
//Get the description field value
//Since the value is stored inside options table use get_option() method
get_option('woocommerce_'.$shipping_rate_id.'_settings')['shipping_extra_field_description']
Here is the code for getting the value.
if ( ! function_exists( 'dimative_shipping_method_description' ) ) {
/**
* Function will print shipping method description.
*
* #param object $method Shipping method object.
* #param int $index Shipping method index.
* #return void
*/
function dimative_shipping_method_description( $method, $index ) {
$dimative_method_fields = get_option( 'woocommerce_' . $method->method_id . '_' . $method->instance_id . '_settings' );
$dimative_method_allowed_html = array(
'p' => array(
'class' => array(),
),
'strong' => array(),
'b' => array(),
'a' => array(
'href' => array(),
),
'span' => array(
'class' => array(),
),
);
// Shipping method custom description.
if ( $dimative_method_fields['shipping_extra_field_description'] ) {
?>
<div class="method-description"><?php echo wp_kses( $dimative_method_fields['shipping_extra_field_description'], $dimative_method_allowed_html ); ?></div>
<?php
}
}
add_action( 'woocommerce_after_shipping_rate', 'dimative_shipping_method_description', 1, 2 );
}
I am trying to display the "billing_gender" custom field I have added to my checkout form to the customer new account notification email.
The field is correctly saved to the database but it is shown empty in the new account email.
Other user meta fields (phone, ...) work but not my custom checkout field.
I guess it is saved to late in the user meta information but I really can't figure it out :
Here is my code :
functions.php
add_filter( 'woocommerce_checkout_fields' , 'divi_override_checkout_fields' );
function divi_override_checkout_fields( $fields ) {
unset($fields['billing']['billing_company']);
unset($fields['billing']['billing_address_1']);
unset($fields['billing']['billing_address_2']);
unset($fields['billing']['billing_city']);
unset($fields['billing']['billing_postcode']);
unset($fields['billing']['billing_state']);
unset($fields['billing']['billing_country']);
// Custom gender field
$fields['billing']['billing_gender'] = array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'label' => __( 'Title', 'divi-ultimate'),
'required' => true,
'priority' => 3,
'options' => array(
'' => __( 'Select title', 'divi-ultimate' ),
'male' => __( 'Mr', 'divi-ultimate' ),
'female' => __( 'Mrs', 'divi-ultimate' )
),
);
return $fields;
}
// Gender select default value
add_filter( 'default_checkout_billing_gender', 'checkout_billing_gender',10,2 );
function checkout_billing_gender($value) {
if ( is_user_logged_in()){
$current_user = wp_get_current_user();
$value = get_user_meta( $current_user->ID, 'billing_gender', true );
}
return $value;
}
//* Update the order meta with fields values
add_action('woocommerce_checkout_update_order_meta', 'divi_select_checkout_field_update_order_meta', 10, 2);
function divi_select_checkout_field_update_order_meta( $order_id ) {
if ($_POST['delivery-shop']) update_post_meta( $order_id, 'delivery-shop', esc_attr($_POST['delivery-shop']));
if ($_POST['billing_gender']) update_post_meta( $order_id, 'billing_gender', esc_attr($_POST['billing_gender']));
}
//* Update the user meta with gender value
add_action( 'woocommerce_checkout_update_user_meta', 'divi_save_extra_user_fields', 10, 2 );
function divi_save_extra_user_fields($customer_id) {
if (isset($_POST['billing_gender'])) {
update_user_meta( $customer_id, 'billing_gender', esc_attr($_POST['billing_gender']) );
}
}
What am I doing wrong ?
Cheers.
Here is the customer-new-account.php file :
$user = get_user_by('login', $user_login );
if (!empty($user)) {
$gender = get_user_meta($user->ID, 'billing_gender', true);
$lastname = $user->last_name;
$user_email = $user->user_email;
}
if( !empty($gender) && !empty($lastname) ) {
printf( esc_html__( 'Dear ' . $gender . ' %s,', 'woocommerce' ), esc_html( $lastname ) );
}
else {
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $email ) );
} ?>
Hello I'm trying to display the custom checkout field in the admin order details page. My Custom field is Delivery Option and it allows the user to pick the to pick a value from checkbox. I use the code below following the similar topics about this, but it seems something is wrong with my code.
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_additional_field', 20 );
function checkout_shipping_additional_field()
{
$domain = 'wocommerce';
$default = 'option 1';
echo '<tr class="additional-shipping-fields"><th>' . __('Delivery Time', $domain) . '</th><td>';
// Add a custom checkbox field
woocommerce_form_field( 'custom_radio_field', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'options' => array(
'option 1' => __('10:04 : 13:04 ', $domain),
),
'default' => $default,
), $default );
echo '</td></tr>';
}
//update order meta
add_action('woocommerce_checkout_update_order_meta', 'gon_update_order_meta_business_address');
function gon_update_order_meta_business_address( $order_id ) {
if ($_POST['custom_radio_field']) update_post_meta( $order_id, 'Business Address?',
esc_attr($_POST['custom_radio_field']));
}
// Display field value on the admin order edit page
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'custom_checkout_field_display_admin_order_meta', 10, 1 );
function custom_checkout_field_display_admin_order_meta( $order ){
$delivery_time = get_post_meta( $order->get_id(), 'Delivery Time', true );
if( ! empty( $delivery_time ) )
echo '<p><strong>'.__('Delivery Time', 'woocommerce').': </strong> ' . $delivery_time . '</p>';
}
There is some mistakes, so I have revisited your code. I have also replaced some hooks. Try the following:
// HERE set your the options array for your select field.
function delivery_time_options(){
$domain = 'woocommerce';
return array(
'1' => __('10:04 : 13:04 ', $domain),
'2' => __('14:04 : 16:04 ', $domain), // <== Added for testing
);
}
// Display a custom select field after shipping total line
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_additional_field', 20 );
function checkout_shipping_additional_field(){
$domain = 'woocommerce';
echo '<tr class="additional-shipping-fields"><th>' . __('Delivery Time', $domain) . '</th><td>';
// Add a custom select field
woocommerce_form_field( 'delivery_time', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'options' => delivery_time_options(),
), '' );
echo '</td></tr>';
}
// Save custom field as order meta data
add_action('woocommerce_checkout_create_order', 'save_custom_field_order_meta', 22, 2 );
function save_custom_field_order_meta( $order, $data ) {
if ( isset($_POST['delivery_time']) ) {
$options = delivery_time_options(); // Get select options array
$option_key = esc_attr($_POST['delivery_time']); // The selected key
$order->update_meta_data( '_delivery_time', $options[$option_key] ); // Save
}
}
// Display a custom field value on the admin order edit page
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_custom_meta_data_in_backend_orders', 10, 1 );
function display_custom_meta_data_in_backend_orders( $order ){
$domain = 'woocommerce';
$delivery_time = $order->get_meta('_delivery_time');
if( ! empty( $delivery_time ) )
echo '<p><strong>'.__('Delivery Time', $domain).': </strong> ' . $delivery_time . '</p>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Based on #LoicTheAztec answer, if you want multiple fields without re-writing the functions for every field (DRY), you can use this class (by adding it to your functions.php):
/**
* Add a custom field to the woocommerce checkout page
* https://stackoverflow.com/q/52098807/
*/
class WOO_Add_Checkout_Field
{
public function __construct($options)
{
$this->field_name = $options['field_name'];
$this->label = $options['label'];
$this->placeholder = $options['placeholder'];
$this->required = $options['required'];
if ($this->field_name && $this->label && $this->placeholder) {
add_action('woocommerce_after_order_notes', [$this, 'customise_checkout_field']);
add_action('woocommerce_checkout_update_order_meta', [$this, 'custom_checkout_field_update_order_meta'], 10, 1);
add_action('woocommerce_admin_order_data_after_billing_address', [$this, 'display_custom_field_on_order_edit_pages'], 10, 1);
} else {
die("Error in WOO_Add_Checkout_Field \$options: \n\n" . var_dump($options));
}
}
public function customise_checkout_field($checkout)
{
echo '<div id="customise_checkout_field">';
// echo '<h2>' . __('Heading') . '</h2>';
woocommerce_form_field($this->field_name, array(
'type' => 'text',
'class' => array(
'my-field-class form-row-wide'
),
'label' => $this->label,
'placeholder' => $this->placeholder,
'required' => $this->required,
), $checkout->get_value($this->field_name));
echo '</div>';
}
public function custom_checkout_field_update_order_meta($order_id)
{
if (!empty($_POST[$this->field_name]))
update_post_meta($order_id, $this->field_name, $_POST[$this->field_name]);
else
update_post_meta($order_id, $this->field_name, 0);
}
public function display_custom_field_on_order_edit_pages($order)
{
$field = $order->get_meta($this->field_name);
if (!empty($field)) {
echo '<p><strong style="display:block" title="' . $this->placeholder . '">' . $this->label . ': </strong><span>';
echo $field;
echo '</span></p>';
}
}
}
And use it as many times as you'd like:
$my_custom_field_1 = new WOO_Add_Checkout_Field([
'field_name' => 'my_custom_field_1',
'label' => __('My First Field'),
'placeholder' => __('Please write something in field 1...'),
'required' => false,
]);
$my_custom_field_2 = new WOO_Add_Checkout_Field([
'field_name' => 'my_custom_field_2',
'label' => __('My Second Field'),
'placeholder' => __('Please write something in field 2...'),
'required' => false,
]);
$my_custom_field_3 = new WOO_Add_Checkout_Field([
'field_name' => 'my_custom_field_3',
'label' => __('My Third Field'),
'placeholder' => __('Please write something in field 3...'),
'required' => false,
]);
// and so on...
Please note:
The custom field will show up in admin area ONLY if it was not sent empty
You can customize this code how you like
I am using the example from the CMB2 snippets library to add a theme options page in WordPress
/**
* Hook in and register a metabox to handle a theme options page and adds a menu item.
*/
function yourprefix_register_main_options_metabox() {
/**
* Registers main options page menu item and form.
*/
$args = array(
'id' => 'yourprefix_main_options_page',
'title' => 'Main Options',
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_main_options',
'tab_group' => 'yourprefix_main_options',
'tab_title' => 'Main',
);
// 'tab_group' property is supported in > 2.4.0.
if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
$args['display_cb'] = 'yourprefix_options_display_with_tabs';
}
$main_options = new_cmb2_box( $args );
/**
* Options fields ids only need
* to be unique within this box.
* Prefix is not needed.
*/
$main_options->add_field( array(
'name' => 'Site Background Color',
'desc' => 'field description (optional)',
'id' => 'bg_color',
'type' => 'colorpicker',
'default' => '#ffffff',
) );
/**
* Registers secondary options page, and set main item as parent.
*/
$args = array(
'id' => 'yourprefix_secondary_options_page',
'menu_title' => 'Secondary Options', // Use menu title, & not title to hide main h2.
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_secondary_options',
'parent_slug' => 'yourprefix_main_options',
'tab_group' => 'yourprefix_main_options',
'tab_title' => 'Secondary',
);
// 'tab_group' property is supported in > 2.4.0.
if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
$args['display_cb'] = 'yourprefix_options_display_with_tabs';
}
$secondary_options = new_cmb2_box( $args );
$secondary_options->add_field( array(
'name' => 'Test Radio',
'desc' => 'field description (optional)',
'id' => 'radio',
'type' => 'radio',
'options' => array(
'option1' => 'Option One',
'option2' => 'Option Two',
'option3' => 'Option Three',
),
) );
/**
* Registers tertiary options page, and set main item as parent.
*/
$args = array(
'id' => 'yourprefix_tertiary_options_page',
'menu_title' => 'Tertiary Options', // Use menu title, & not title to hide main h2.
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_tertiary_options',
'parent_slug' => 'yourprefix_main_options',
'tab_group' => 'yourprefix_main_options',
'tab_title' => 'Tertiary',
);
// 'tab_group' property is supported in > 2.4.0.
if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
$args['display_cb'] = 'yourprefix_options_display_with_tabs';
}
$tertiary_options = new_cmb2_box( $args );
$tertiary_options->add_field( array(
'name' => 'Test Text Area for Code',
'desc' => 'field description (optional)',
'id' => 'textarea_code',
'type' => 'textarea_code',
) );
}
add_action( 'cmb2_admin_init', 'yourprefix_register_main_options_metabox' );
/**
* A CMB2 options-page display callback override which adds tab navigation among
* CMB2 options pages which share this same display callback.
*
* #param CMB2_Options_Hookup $cmb_options The CMB2_Options_Hookup object.
*/
function yourprefix_options_display_with_tabs( $cmb_options ) {
$tabs = yourprefix_options_page_tabs( $cmb_options );
?>
<div class="wrap cmb2-options-page option-<?php echo $cmb_options->option_key; ?>">
<?php if ( get_admin_page_title() ) : ?>
<h2><?php echo wp_kses_post( get_admin_page_title() ); ?></h2>
<?php endif; ?>
<h2 class="nav-tab-wrapper">
<?php foreach ( $tabs as $option_key => $tab_title ) : ?>
<a class="nav-tab<?php if ( isset( $_GET['page'] ) && $option_key === $_GET['page'] ) : ?> nav-tab-active<?php endif; ?>" href="<?php menu_page_url( $option_key ); ?>"><?php echo wp_kses_post( $tab_title ); ?></a>
<?php endforeach; ?>
</h2>
<form class="cmb-form" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="POST" id="<?php echo $cmb_options->cmb->cmb_id; ?>" enctype="multipart/form-data" encoding="multipart/form-data">
<input type="hidden" name="action" value="<?php echo esc_attr( $cmb_options->option_key ); ?>">
<?php $cmb_options->options_page_metabox(); ?>
<?php submit_button( esc_attr( $cmb_options->cmb->prop( 'save_button' ) ), 'primary', 'submit-cmb' ); ?>
</form>
</div>
<?php
}
/**
* Gets navigation tabs array for CMB2 options pages which share the given
* display_cb param.
*
* #param CMB2_Options_Hookup $cmb_options The CMB2_Options_Hookup object.
*
* #return array Array of tab information.
*/
function yourprefix_options_page_tabs( $cmb_options ) {
$tab_group = $cmb_options->cmb->prop( 'tab_group' );
$tabs = array();
foreach ( CMB2_Boxes::get_all() as $cmb_id => $cmb ) {
if ( $tab_group === $cmb->prop( 'tab_group' ) ) {
$tabs[ $cmb->options_page_keys()[0] ] = $cmb->prop( 'tab_title' )
? $cmb->prop( 'tab_title' )
: $cmb->prop( 'title' );
}
}
return $tabs;
}
This works great, but I can't figure out how to actually get one of these values and display it in a theme. Anyone have an example?
You can use cmb2_get_option()
It takes 3 parameters: cmb2_get_option( $option_key, $field_id, $default );
So in your case:
$option_key = yourprefix_main_options,
$field_id = bg_color,
$default = the default value (in case you set it).
It should look like this:
cmb2_get_option( 'yourprefix_main_options', 'bg_color' );
cmb2_get_option( 'yourprefix_secondary_options', 'radio' );
and so on ..
Also, You can use your own function with Fallback:
/**
* Wrapper function around cmb2_get_option
* #since 0.1.0
* #param string $key Options array key
* #param mixed $default Optional default value
* #return mixed Option value
*/
function myprefix_get_option( $key = '', $default = false ) {
if ( function_exists( 'cmb2_get_option' ) ) {
// Use cmb2_get_option as it passes through some key filters.
return cmb2_get_option( 'yourprefix_main_options', $key, $default );
}
// Fallback to get_option if CMB2 is not loaded yet.
$opts = get_option( 'yourprefix_main_options', $default );
$val = $default;
if ( 'all' == $key ) {
$val = $opts;
} elseif ( is_array( $opts ) && array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
$val = $opts[ $key ];
}
return $val;
}
Use it like this:
myprefix_get_option( bg_color )
Please use the following code :
get_option("<your id>");
Like :
get_option('bg_color');
Hope this will work for you.
You can try using array system with get_option() function.
First time you need to use get_option('your-option-key');
like your option-key is "yourprefix_main_options" so you need to use get_option('yourprefix_main_options');
then you can keep your value on variable. like
$main_option_data = get_option('yourprefix_main_options');
then you can use $main_option_data and your filed id as a array. like your one filed id is bg_color so you can use $main_option_data['bg_color'];
You can check my one previous work, I think it will be help you.
// Theme Options
add_action( 'cmb2_admin_init', 'mosc_panel_theme_options_metabox' );
/**
* Hook in and register a metabox to handle a theme options page and adds a menu item.
*/
function mosc_panel_theme_options_metabox() {
/**
* Registers options page menu item and form.
*/
$mos_option_panel = new_cmb2_box( array(
'id' => 'mosc_theme_options_page',
'title' => esc_html__( 'Theme Options', 'cmb2' ),
'parent_slug' => 'themes.php', // Make options page a submenu item of the themes menu.
'object_types' => array( 'options-page' ),
'option_key' => 'mosc_theme_options', // The option key and admin menu page slug.
'icon_url' => 'dashicons-palmtree', // Menu icon. Only applicable if 'parent_slug' is left empty.
) );
// Regular text field
$mos_option_panel->add_field( array(
'name' => __( 'Contact Form Heading', 'mosc' ),
'id' => 'mosc-contact-form-heading',
'type' => 'text',
'default' => __('Feel free to drop me a line', 'mosc'),
) );
}
then I've used this code for show my field value.
$mosc_contact_heading = get_option('mosc_theme_options');
if(!empty($mosc_contact_heading['mosc-contact-form-heading'])) {
echo esc_html($mosc_contact_heading['mosc-contact-form-heading']);
}
I've used this code to show my field value and working perfectly:
echo cmb2_get_option( '_key_options', 'text_text');