I'm trying to add validation to some checkout fields when editing an order from admin panel, but I haven't found the hook for that. I want to prevent saving post if validation fails and also show a notice. I've tried woocommerce_process_shop_order_meta hook but post is always saved and notices are not shown.
This is the code I used in my functions.php file:
$meta_box_errors[] = array();
add_action( 'woocommerce_process_shop_order_meta', 'save_order_custom_field_meta_data', 12, 2 );
public function save_order_custom_field_meta_data( $post_id, $post ){
$field_name = 'billing_nif';
$nif_value = '';
if( isset( $_POST[ '_' . $field_name ] ) && !empty($_POST[ '_' . $field_name ]) ) {
$nif_value = sanitize_text_field( $_POST[ '_' . $field_name ] );
if (!empty ($nif_value)) {
if (! validate_nif( $nif_value )) {
$meta_box_errors["invalid_nif"] = 'Invalid NIF';
}
} else {
$meta_box_errors["empty_nif"] = 'Empty NIF';
}
} else {
$meta_box_errors["empty_nif"] = 'Empty NIF';
}
if( ! empty( $this->meta_box_errors ) ) {
add_action( 'admin_notices', 'output_errors' );
}
}
public function validate_nif( $nif ){
$nif = strtoupper($nif);
if (strlen($nif) != 9) {
return false;
}
$nifExp = "^((\d{8})([A-Z]{1}))$^";
return preg_match($nifExp, $nif));
}
public function output_errors() {
echo '<div id="woocommerce_errors" class="error notice is-dismissible">';
foreach ( $meta_box_errors as $error ) {
echo '<p>' . wp_kses_post( $error ) . '</p>';
}
echo '</div>';
unset($meta_box_errors);
}
Related
I rephrase my question in this new post to which I have not had any answer. These two functions create a page on the user's account endpoint. A table is published on this page. I would like this table to be published in a new page / post of the site accessible to all. Any suggestions? Thank you
1 add_action( 'init', array(__CLASS__, 'wsc_add_my_account_endpoint') );
2 public static function wsc_add_my_account_endpoint() { add_rewrite_endpoint( 'wsc-share-cart', EP_ROOT | EP_PAGES ); }
3 The content that I would to print in a wordpress page:
if ( !isset($_GET['wc-wsc']) || !isset($_GET['nounce']) ) {
return;
}
if ( ! wp_verify_nonce( wc_clean($_GET['nounce']), 'wsc_save_share_cart' ) ) {
return;
}
$posted_fields = wc_clean($_POST);
$fields = get_option('wsc_form_fields');
$errors = array();
$form_submission = array();
$form_submission_html = '';
$customer_email = '';
if ( !empty($fields) ) {
$form_submission_html .= '<table>';
foreach ( $fields as $key => $field ) {
if ( true == $field['required'] && empty($posted_fields['wsc_form_field_' . esc_attr($key)]) ) {
$errors['wsc_form_field_' . esc_attr($key)] = wp_sprintf( '%s %s', esc_html__($field['label'], 'wc-wsc'), esc_html__('is required.', 'wc-wsc') );
}
$label = !empty($field['label']) ? $field['label'] : 'wsc_form_field_' . esc_attr($key);
$field_value = wc_clean($posted_fields['wsc_form_field_' . esc_attr($key)]);
if ( 'email' == $field['type'] ) {
if ( !is_email($field_value) ) {
$errors['wsc_form_field_' . esc_attr($key)] = wp_sprintf( '%s %s', esc_html__($field['label'], 'wc-wsc'), esc_html__('must be an email.', 'wc-wsc') );
}
$customer_email = $field_value;
}
if ( isset($posted_fields['wsc_form_field_' . esc_attr($key)]) ) {
$form_submission[$label] = $field_value;
}
$form_submission_html .= '<tr><th>' . esc_html($label) . '</th><td>' . esc_html($field_value) . '</td></tr>';
}
$form_submission_html .= '</table>';
} ```
I'm using WooCommerce with a child theme of Storefront.
I have a secondary menu named "Desktop secondary top right EN" where there's a link to "my account".
My question is: how to change the "my account" item wording if the customer is logged in ?
I'd like to do this without having to create another menu in the back office and without installing a plugin of course.
I should be able to use something similar to:
function menu_add_admin_buttons( $items, $args ) {
if( 'secondary' == $args['theme_location'] ) {
$btn_format = '<li>%s</li>';
if ( is_user_logged_in() ) {
$btn = sprintf($btn_format, admin_url('profile.php'), __('Your Profile') );
} else {
$btn = sprintf($btn_format, wp_login_url(), __('Log In') );
}
return $items . $btn;
}
}
$menu_filter = 'wp_nav_menu_' . sanitize_title("Desktop secondary top right EN") . '_items';
add_filter($menu_filter, 'menu_add_admin_buttons', 20, 2);
but it has to be customized to my needs. How can I do this?
You can try another wordpress hook wp_nav_menu_items:
function menu_add_admin_buttons( $items, $args ) {
$btn = '';
if ( $args->theme_location === 'secondary' ) {
$btn_format = '<li>%s</li>';
if ( is_user_logged_in() ) {
$btn = sprintf($btn_format, admin_url( 'profile.php' ), __( 'Your Profile' ) );
} else {
$btn = sprintf($btn_format, wp_login_url(), __('Log In') );
}
}
return sprintf( '%s%s', $items, $btn );
}
add_filter( 'wp_nav_menu_items','menu_add_admin_buttons', 10, 2 );
Could you please to check the documentation.
I did this instead, and it seems to work fine.
I use the standard hook : wp_setup_nav_menu_item to filter the menu items.
I check if it's not the back office (admin mode) and if woocommerce is active.
Then, if the url is the url of the "my account" menu, I make the change according to the current language.
add_filter( 'wp_setup_nav_menu_item','my_account_setup' );
function my_account_setup( $item ) {
if ( ! is_admin() && class_exists( 'woocommerce' ) ) {
if ( $item->url == esc_url( wp_login_url() ) || strpos($item->url, '/my-account-2-2/') !== false ){
if ( is_user_logged_in() ) {
if(get_locale() == 'fr_FR') {
$item->title = 'MON COMPTE';
} else {
$item->title = 'MY ACCOUNT';
}
} else {
if(get_locale() == 'fr_FR') {
$item->title = 'LOGIN';
} else {
$item->title = 'LOGIN';
}
}
}
}
return $item;
}
I added a custom <select> field to each product in cart page to be able to update variation, but when I change it's value and click "Update Cart", nothing updates unless quantity field has also been changed.
Is there a way to avoid this?
My code:
functions.php file:
add_filter( 'woocommerce_update_cart_action_cart_updated', 'on_action_cart_updated', 20, 1 );
function on_action_cart_updated( $cart_updated ){
if ($cart_updated) {
$cart_content = WC()->cart->get_cart_contents();
$update_cart = false;
$cart_totals = isset( $_POST['cart'] ) ? wp_unslash( $_POST['cart'] ) : '';
if ( ! empty( $cart_content ) && is_array( $cart_totals ) ) {
foreach ($cart_content as $key => $item) {
$lease_period = $cart_totals[$key]['lease'];
if ( ! empty( $lease_period )) {
$cart_content[$key]['variation']['attribute_pa_lease-period'] = $lease_period;
$update_cart = true;
}
}
if ($update_cart) {
WC()->cart->set_cart_contents($cart_content);
}
}
}
}
cart.php file:
<td class="product-lease-period" data-title="<?php esc_attr_e( 'Lease Period', 'woocommerce' ); ?>">
<div class="product-lease-period-select">
<select name="cart[<?php echo $cart_item_key ?>][lease]">
<?php
$lease_periods = ['6-months'=> '6 Months',
'12-months' => '12 Months',
'18-months' => '18 Months',
'24-months' => '24 Months'];
foreach ($lease_periods as $key => $period) {
$selected = '';
if ($cart_item['variation']['attribute_pa_lease-period'] == $key) {
$selected = 'selected="selected"';
}
echo "<option value=" . $key . " $selected>" . $period . "</option>";
}
?>
</select>
</div>
</td>
My conclusions so far:
I believe it's because of these pieces of code inside the class-wc-form-handler.php :
// Skip product if no updated quantity was posted.
if ( ! isset( $cart_totals[ $cart_item_key ] ) || ! isset( $cart_totals[ $cart_item_key ]['qty'] ) ) {
continue;
}
and a bit below:
if ( '' === $quantity || $quantity === $values['quantity'] ) {
continue;
}
I extended the WC_Form_Handler class in my functions.php file, copied a method I needed and edited it, and gave it higher hook priority in my extended class than it's in the original class:
class WC_Form_Handler_Ext extends WC_Form_Handler {
/**
* Hook in method.
*/
public static function init() {
add_action( 'wp_loaded', array( __CLASS__, 'update_cart_action' ), 30 );
}
/**
* Remove from cart/update.
*/
public static function update_cart_action() {
// method content edited
}
}
WC_Form_Handler_Ext::init();
UPDATE:
To make price change after variation value in cart is updated, this function needs to be added to the functions.php
function find_matching_product_variation_id($product_id, $attributes)
{
return (new WC_Product_Data_Store_CPT())->find_matching_product_variation(
new WC_Product($product_id),
$attributes
);
}
And it should be called from the loop in functions.php I mentioned in my question this way:
$attributes = $cart_content[$key]['variation'];
$variation_id = find_matching_product_variation_id($product_id, $attributes);
$price = get_post_meta($variation_id, '_price', true);
$item['data']->set_price($price);
i'm searching for a way to display the modified date of a custom field / meta box. until now, i only know how to echo
the_modified_date('l, j.n.Y');
but this one only works with the entire post.
i'am using a meta_box for additional pdf files uploading, code:
<?php class PDF_Metabox_id1 {
function __construct() {
add_action( 'post_mime_types', array( $this, 'pdf_mime_type_id1' ) );
add_action( 'add_meta_boxes', array( $this, 'admin_scripts_id1' ), 5 );
add_action( 'add_meta_boxes', array( $this, 'metabox_add_id1' ) );
add_action( 'save_post', array( $this, 'pdf_save_postdata_id1') );
add_action( 'wp_ajax_refresh_pdf', array( $this, 'refresh_pdf_id1' ) ); }
function pdf_mime_type_id1() {
$post_mime_types['application/pdf'] = array( __( 'PDFs' ), __( 'Manage PDFs' ), _n_noop( 'PDF <span class="count">(%s)</span>', 'PDFs <span class="count">(%s)</span>' ) );
return $post_mime_types;
}
function admin_scripts_id1() {
wp_register_script( 'pdf_metabox_js', get_stylesheet_directory_uri() . '/js/pdf_metabox.js' );
}
function metabox_add_id1() {
$post_types = array( 'myposttype','anotherposttype' );
$context = 'normal'; $priority = 'low';
foreach( $post_types as $post_type ) {
add_meta_box( 'pdf_metabox_id1', __( 'PDF Box 1', 'pdf_metabox_id1' ), array( $this, 'pdf_metabox_id1' ), $post_type, $context, $priority );
wp_enqueue_media();
wp_enqueue_script( 'pdf_metabox_js' );
}
}
function pdf_metabox_id1( $post ) {
$original_post = $post; echo $this->pdf_metabox_html_id1( $post->ID ); $post = $original_post;
}
function pdf_item_id1( $id ) {
if(!$id) return; $pdf_url = esc_url_raw(wp_get_attachment_url($id)); $pdf = $pdf_url; return $pdf;
}
function pdf_metabox_html_id1( $post_id ) {
$current_value = ''; $post_meta = get_post_custom($post_id);
if( isset($post_meta['pdf_id_id1'][0] ) ) $current_value = $post_meta['pdf_id_id1'][0];
$return = ''; wp_nonce_field( plugin_basename( __FILE__ ), 'pdf_noncename' );
$return .= '<p>';
$return .= '<a title="'.__( 'PDF', 'pdf_metabox_id1' ).'" class="button button-primary insert-pdf-button" id="insert_pdf_button_id1" href="#" style="float:left">'.__( 'Upload / editiere PDF', 'pdf_metabox_id1' ).'</a><span id="pdf_spinner_id1" class="spinner" style="float:left"></span></p>';
$return .= '<div style="clear:both"></div>';
$return .= '<input type="hidden" name="pdf_id_id1" id="pdf_id_id1" value="'.$current_value.'">';
$return .= '<div style="clear:both"></div>';
$return .= '<div id="pdf_wrapper_id1">';
$pdf = $this->pdf_item_id1( $current_value ); if( empty( $pdf ) ) {
$return .= '<p>Diesem Feld ist kein PDF hinterlegt.</p>'; } else {
$return .= '<br />URL des PDF:<br /> ';
$return .= $pdf; }
$return .= '</div>';
return $return;
}
function pdf_save_postdata_id1($post_id){
if ( isset($_POST['post_type']) && 'post' == $_POST['post_type'] ) {
if ( !current_user_can( 'edit_post', $post_id ) ) return; } if ( !isset( $_POST['pdf_noncename'] ) || ! wp_verify_nonce( $_POST['pdf_noncename'], plugin_basename( __FILE__ ) ) ) return;
if(isset($_POST['pdf_id_id1']) ): update_post_meta($post_id, 'pdf_id_id1', sanitize_text_field( $_POST['pdf_id_id1'] ) );
else: if (isset($post_id)) {
delete_post_meta($post_id, 'pdf_id_id1'); }
endif;
}
function refresh_pdf_id1() {
if(isset($_POST['id'])){
$item = $_POST['id'];
if($item != '' && $item !=0){
$pdf = $this->pdf_item_id1( $item );
$ret = array();
if( !empty( $pdf ) ) {$ret['success'] = true;
$ret['pdf'] = $pdf; } else {
$ret['success'] = false; } } else {
$ret['success'] = true; $ret['pdf'] = ''; } } else {
$ret['success'] = false; } echo json_encode( $ret ); die();
}
}
$PDF_Metabox_id1 = new PDF_Metabox_id1();
in my theme i'm using:
$post_meta_id1 = get_post_custom(get_the_ID());
$pdf_id_id1 = $post_meta_id1['pdf_id_id1'][0];
$pdf_url_id1 = wp_get_attachment_url($pdf_id_id1);
...and now i want to display the modified date of this field. any ideas?
As per the comment
how do i save the modified date of this custom field and how do i get it?
You may need to check every custom field in loop one by one if any of custom fields doesnot matched with the current post data then save a new custom field to post_meta. then retrieve in your template/page.
Just an idea:
<?php
function attributes_save_postdata( $post_id ) {
$postcustom = get_post_custom( $post_id );
$is_modified = false;
foreach ( $postcustom as $key => $val ) {
var_dump( $val );
// check your post custom values and
$getpostmeta = get_post_meta( $post_id, 'your_meta_key', true );
// if database value ($getpostmeta) not equal to current post value($_POST['your_meta_key'])
if ( $getpostmeta != $_POST['your_meta_key'] ) {
$is_modified = true;
// if found any custom field updated set $modified = true
}
}
// if found any custom field updated add or update new date and time
if ( $is_modified ) {
$date = date( 'Y-m-d h:i:s' ); // example : 2016-02-02 12:00:00 current date and time
update_post_meta( $post_id, '_modifieddate', $date );
}
}
add_action( 'save_post', 'attributes_save_postdata' );
Then in your theme. get modified date.
$post_id = get_the_ID();
$getpostmeta = get_post_meta( $post_id, 'your_meta_key', true );
I think that wordpress built-in function about this would help you out even for the custom fields.
<p>Last modified: <?php the_modified_time(); ?></p>
I am getting an out of the box error for a plugin and I am wondering if there is a quick fix.
I have googled the issue and checked the creator of the plugin's website. No help.
The plugin needs:
<?php do_shortcode('[print_wp_footer]'); ?>
Added to Footer.php for the theme.
WordPress then gives an error of:
Warning: Invalid argument supplied for foreach() in /.../wp-content/plugins/wp-footer-menu/main.php on line 192
Here is the line by itself
foreach ($values as $attr=>$val) {
Here is the section of code with line "192" with arrows.
<?php
}
function wp_footer_menu_confirm_delete ($delete) {
$base_uri = wp_footer_menu_base_uri();
// Find out about this menu item.
$menu_items = get_option ( 'footer_menu_links' );
$item_to_delete = explode( ',', $menu_items[$delete] );
$item_title = $item_to_delete[0];
$item_address = $item_to_delete[1];
// Create form for user to confirm option.
echo '<h3>Confirm Delete</h3>';
echo '<p>Are you sure you want to delete this menu item?</p>';
echo '<p>Title: ' . $item_title . '</p>' ;
echo '<p>Address: ' . $item_address . '</p>';
echo '<form method="post" action="' . $base_uri . '">';
echo '<input type="hidden" name="delete_key" value="' . $delete . '" />';
echo wp_nonce_field( 'confirm_delete', 'delete' );
echo '<input type="submit" class="button-primary" value="Delete item" />';
echo '</form>';
}
function wp_footer_menu_process() {
if ( isset( $_GET[ 'delete' ] ) ) {
$nonce = $_GET ['nonce'];
if ( wp_verify_nonce( $nonce, 'footer_delete' ) ) {
wp_footer_menu_confirm_delete ( $_GET[ 'delete' ] );
}
return 0;
} else if ( isset( $_POST[ 'delete_key' ] ) && check_admin_referer ( 'confirm_delete', 'delete' ) ) {
$menu_items = get_option ( 'footer_menu_links' );
$key = $_POST['delete_key'];
unset ( $menu_items[$key] );
update_option ( 'footer_menu_links', $menu_items );
}
if ( isset( $_POST[ 'link_title' ] ) && check_admin_referer( 'footer_menu', 'add' ) ) {
$link_title = $_POST ['link_title'];
$link_address = $_POST ['link_address'];
$link_order = $_POST ['link_order'];
$new_link = $link_title . ',' . $link_address . ',' . $link_order;
$footer_links = get_option( 'footer_menu_links' );
if ($footer_links == '') {
$footer_links = array();
}
$new_links = array_push( $footer_links, $new_link );
update_option ( 'footer_menu_links', $footer_links );
}
if ( isset( $_POST[ 'font-size' ] ) && check_admin_referer( 'footer_menu', 'save' ) ) {
if (empty($_POST['auto-footer'])) {
$_POST['auto-footer'] = 'no';
}
if (empty($_POST['auto-sticky'])) {
$_POST['auto-sticky'] = 'no';
}
update_option('wp_footer_values', $_POST);
echo '<div class="wp_footer_info" style="margin:0 auto;margin-top:5px;text-align:center;">Customizations Saved</div>';
}
return 1;
}
function wp_footer_print_menu() {
$menu = wp_footer_get_menu();
$values = get_option('wp_footer_values');
--192--> foreach ($values as $attr=>$val) {
$menu = str_replace('%' . $attr . '%', stripslashes($val), $menu);
}
echo $menu;
if ($values['auto-sticky'] == 'yes') {
?>
<style type="text/css">
.wp_footer_sticky {
position:fixed;
bottom: 0;
width: 100%;
}
</style>
<script type="text/javascript">
jQuery(document).ready(function($) {
$('#wp_footer_menu').addClass('wp_footer_sticky');
});
</script>
<?php
It seems to depend to returned value of the following code :
$values = get_option('wp_footer_values');
Depending on the WordPress codex, if the option does not exist it return a boolean FALSE. To you will need to verify if that the $values variable is not empty. Check with the following code.
function wp_footer_print_menu() {
$menu = wp_footer_get_menu();
$values = get_option('wp_footer_values');
if (!empty($values)) { // <-- verify it's not empty
foreach ($values as $attr=>$val) {
$menu = str_replace('%' . $attr . '%', stripslashes($val), $menu);
}
echo $menu;
// [...}
} // <-- don't forget to close the if statement just after the end of the foreach statement
Hope that help.
Source : get_option()