Fix code standards in orders code, and check payment method name instead of title on get order totals (#30468)

* Fix code standards errors in class-wc-meta-box-orrder-data.php

- Sanitize all input
- Escape all output
- Verify nonce on save
- Verify that all required POST parameters are present on save
- Minor fixes (periods at end of comments, function docs, Yodas...)

* Check payment method name, not title, on add_order_item_totals_payment_method_row

* Remove unnecessary nonce verification in "save" for orders.

Also move comment to new line for readability.

* Remove unnecessary nonce check in WC_Meta_Box_Order_Data::save

 The check is already performed in the code that invokes "save".

* Add transaction id to payment method string if URL doesn't exist

* Minor fix

Co-authored-by: Jorge A. Torres <jorge.torres@automattic.com>
This commit is contained in:
Néstor Soriano 2022-07-22 19:54:51 +02:00 committed by GitHub
parent 383c96f0ca
commit 7d2a992746
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 37 deletions

View File

@ -4,14 +4,12 @@
* *
* Functions for displaying the order data meta box. * Functions for displaying the order data meta box.
* *
* @author WooThemes
* @category Admin
* @package WooCommerce\Admin\Meta Boxes * @package WooCommerce\Admin\Meta Boxes
* @version 2.2.0 * @version 2.2.0
*/ */
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly exit; // Exit if accessed directly.
} }
/** /**
@ -143,7 +141,7 @@ class WC_Meta_Box_Order_Data {
/** /**
* Output the metabox. * Output the metabox.
* *
* @param WP_Post $post * @param WP_Post $post The post to output the metabox for.
*/ */
public static function output( $post ) { public static function output( $post ) {
global $theorder; global $theorder;
@ -171,14 +169,14 @@ class WC_Meta_Box_Order_Data {
#post-body-content, #titlediv { display:none } #post-body-content, #titlediv { display:none }
</style> </style>
<div class="panel-wrap woocommerce"> <div class="panel-wrap woocommerce">
<input name="post_title" type="hidden" value="<?php echo empty( $post->post_title ) ? __( 'Order', 'woocommerce' ) : esc_attr( $post->post_title ); ?>" /> <input name="post_title" type="hidden" value="<?php echo empty( $post->post_title ) ? esc_attr__( 'Order', 'woocommerce' ) : esc_attr( $post->post_title ); ?>" />
<input name="post_status" type="hidden" value="<?php echo esc_attr( $post->post_status ); ?>" /> <input name="post_status" type="hidden" value="<?php echo esc_attr( $post->post_status ); ?>" />
<div id="order_data" class="panel woocommerce-order-data"> <div id="order_data" class="panel woocommerce-order-data">
<h2 class="woocommerce-order-data__heading"> <h2 class="woocommerce-order-data__heading">
<?php <?php
/* translators: 1: order type 2: order number */
printf( printf(
/* translators: 1: order type 2: order number */
esc_html__( '%1$s #%2$s details', 'woocommerce' ), esc_html__( '%1$s #%2$s details', 'woocommerce' ),
esc_html( $order_type_object->labels->singular_name ), esc_html( $order_type_object->labels->singular_name ),
esc_html( $order->get_order_number() ) esc_html( $order->get_order_number() )
@ -192,35 +190,42 @@ class WC_Meta_Box_Order_Data {
$meta_list = array(); $meta_list = array();
if ( $payment_method && 'other' !== $payment_method ) { if ( $payment_method && 'other' !== $payment_method ) {
/* translators: %s: payment method */
$payment_method_string = sprintf( $payment_method_string = sprintf(
/* translators: %s: payment method */
__( 'Payment via %s', 'woocommerce' ), __( 'Payment via %s', 'woocommerce' ),
esc_html( isset( $payment_gateways[ $payment_method ] ) ? $payment_gateways[ $payment_method ]->get_title() : $payment_method ) esc_html( isset( $payment_gateways[ $payment_method ] ) ? $payment_gateways[ $payment_method ]->get_title() : $payment_method )
); );
if ( $transaction_id = $order->get_transaction_id() ) { $transaction_id = $order->get_transaction_id();
if ( isset( $payment_gateways[ $payment_method ] ) && ( $url = $payment_gateways[ $payment_method ]->get_transaction_url( $order ) ) ) { if ( $transaction_id ) {
$payment_method_string .= ' (<a href="' . esc_url( $url ) . '" target="_blank">' . esc_html( $transaction_id ) . '</a>)'; $to_add = null;
} else { if ( isset( $payment_gateways[ $payment_method ] ) ) {
$payment_method_string .= ' (' . esc_html( $transaction_id ) . ')'; $url = $payment_gateways[ $payment_method ]->get_transaction_url( $order );
if ( $url ) {
$to_add .= ' (<a href="' . esc_url( $url ) . '" target="_blank">' . esc_html( $transaction_id ) . '</a>)';
}
} }
$to_add = $to_add ?? ' (' . esc_html( $transaction_id ) . ')';
$payment_method_string .= $to_add;
} }
$meta_list[] = $payment_method_string; $meta_list[] = $payment_method_string;
} }
if ( $order->get_date_paid() ) { if ( $order->get_date_paid() ) {
/* translators: 1: date 2: time */
$meta_list[] = sprintf( $meta_list[] = sprintf(
/* translators: 1: date 2: time */
__( 'Paid on %1$s @ %2$s', 'woocommerce' ), __( 'Paid on %1$s @ %2$s', 'woocommerce' ),
wc_format_datetime( $order->get_date_paid() ), wc_format_datetime( $order->get_date_paid() ),
wc_format_datetime( $order->get_date_paid(), get_option( 'time_format' ) ) wc_format_datetime( $order->get_date_paid(), get_option( 'time_format' ) )
); );
} }
if ( $ip_address = $order->get_customer_ip_address() ) { $ip_address = $order->get_customer_ip_address();
/* translators: %s: IP address */ if ( $ip_address ) {
$meta_list[] = sprintf( $meta_list[] = sprintf(
/* translators: %s: IP address */
__( 'Customer IP: %s', 'woocommerce' ), __( 'Customer IP: %s', 'woocommerce' ),
'<span class="woocommerce-Order-customerIP">' . esc_html( $ip_address ) . '</span>' '<span class="woocommerce-Order-customerIP">' . esc_html( $ip_address ) . '</span>'
); );
@ -235,7 +240,7 @@ class WC_Meta_Box_Order_Data {
<h3><?php esc_html_e( 'General', 'woocommerce' ); ?></h3> <h3><?php esc_html_e( 'General', 'woocommerce' ); ?></h3>
<p class="form-field form-field-wide"> <p class="form-field form-field-wide">
<label for="order_date"><?php _e( 'Date created:', 'woocommerce' ); ?></label> <label for="order_date"><?php esc_html_e( 'Date created:', 'woocommerce' ); ?></label>
<input type="text" class="date-picker" name="order_date" maxlength="10" value="<?php echo esc_attr( date_i18n( 'Y-m-d', strtotime( $post->post_date ) ) ); ?>" pattern="<?php echo esc_attr( apply_filters( 'woocommerce_date_input_html_pattern', '[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])' ) ); ?>" />@ <input type="text" class="date-picker" name="order_date" maxlength="10" value="<?php echo esc_attr( date_i18n( 'Y-m-d', strtotime( $post->post_date ) ) ); ?>" pattern="<?php echo esc_attr( apply_filters( 'woocommerce_date_input_html_pattern', '[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])' ) ); ?>" />@
&lrm; &lrm;
<input type="number" class="hour" placeholder="<?php esc_attr_e( 'h', 'woocommerce' ); ?>" name="order_date_hour" min="0" max="23" step="1" value="<?php echo esc_attr( date_i18n( 'H', strtotime( $post->post_date ) ) ); ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />: <input type="number" class="hour" placeholder="<?php esc_attr_e( 'h', 'woocommerce' ); ?>" name="order_date_hour" min="0" max="23" step="1" value="<?php echo esc_attr( date_i18n( 'H', strtotime( $post->post_date ) ) ); ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:
@ -246,12 +251,12 @@ class WC_Meta_Box_Order_Data {
<p class="form-field form-field-wide wc-order-status"> <p class="form-field form-field-wide wc-order-status">
<label for="order_status"> <label for="order_status">
<?php <?php
_e( 'Status:', 'woocommerce' ); esc_html_e( 'Status:', 'woocommerce' );
if ( $order->needs_payment() ) { if ( $order->needs_payment() ) {
printf( printf(
'<a href="%s">%s</a>', '<a href="%s">%s</a>',
esc_url( $order->get_checkout_payment_url() ), esc_url( $order->get_checkout_payment_url() ),
__( 'Customer payment page &rarr;', 'woocommerce' ) esc_html__( 'Customer payment page &rarr;', 'woocommerce' )
); );
} }
?> ?>
@ -270,7 +275,7 @@ class WC_Meta_Box_Order_Data {
<!--email_off--> <!-- Disable CloudFlare email obfuscation --> <!--email_off--> <!-- Disable CloudFlare email obfuscation -->
<label for="customer_user"> <label for="customer_user">
<?php <?php
_e( 'Customer:', 'woocommerce' ); esc_html_e( 'Customer:', 'woocommerce' );
if ( $order->get_user_id( 'edit' ) ) { if ( $order->get_user_id( 'edit' ) ) {
$args = array( $args = array(
'post_status' => 'all', 'post_status' => 'all',
@ -280,12 +285,12 @@ class WC_Meta_Box_Order_Data {
printf( printf(
'<a href="%s">%s</a>', '<a href="%s">%s</a>',
esc_url( add_query_arg( $args, admin_url( 'edit.php' ) ) ), esc_url( add_query_arg( $args, admin_url( 'edit.php' ) ) ),
' ' . __( 'View other orders &rarr;', 'woocommerce' ) ' ' . esc_html__( 'View other orders &rarr;', 'woocommerce' )
); );
printf( printf(
'<a href="%s">%s</a>', '<a href="%s">%s</a>',
esc_url( add_query_arg( 'user_id', $order->get_user_id( 'edit' ), admin_url( 'user-edit.php' ) ) ), esc_url( add_query_arg( 'user_id', $order->get_user_id( 'edit' ), admin_url( 'user-edit.php' ) ) ),
' ' . __( 'Profile &rarr;', 'woocommerce' ) ' ' . esc_html__( 'Profile &rarr;', 'woocommerce' )
); );
} }
?> ?>
@ -294,10 +299,10 @@ class WC_Meta_Box_Order_Data {
$user_string = ''; $user_string = '';
$user_id = ''; $user_id = '';
if ( $order->get_user_id() ) { if ( $order->get_user_id() ) {
$user_id = absint( $order->get_user_id() ); $user_id = absint( $order->get_user_id() );
$user = get_user_by( 'id', $user_id ); $user = get_user_by( 'id', $user_id );
/* translators: 1: user display name 2: user ID 3: user email */
$user_string = sprintf( $user_string = sprintf(
/* translators: 1: user display name 2: user ID 3: user email */
esc_html__( '%1$s (#%2$s &ndash; %3$s)', 'woocommerce' ), esc_html__( '%1$s (#%2$s &ndash; %3$s)', 'woocommerce' ),
$user->display_name, $user->display_name,
absint( $user->ID ), absint( $user->ID ),
@ -306,7 +311,12 @@ class WC_Meta_Box_Order_Data {
} }
?> ?>
<select class="wc-customer-search" id="customer_user" name="customer_user" data-placeholder="<?php esc_attr_e( 'Guest', 'woocommerce' ); ?>" data-allow_clear="true"> <select class="wc-customer-search" id="customer_user" name="customer_user" data-placeholder="<?php esc_attr_e( 'Guest', 'woocommerce' ); ?>" data-allow_clear="true">
<option value="<?php echo esc_attr( $user_id ); ?>" selected="selected"><?php echo htmlspecialchars( wp_kses_post( $user_string ) ); // htmlspecialchars to prevent XSS when rendered by selectWoo. ?></option> <option value="<?php echo esc_attr( $user_id ); ?>" selected="selected">
<?php
// htmlspecialchars to prevent XSS when rendered by selectWoo.
echo esc_html( htmlspecialchars( wp_kses_post( $user_string ) ) );
?>
</option>
</select> </select>
<!--/email_off--> <!--/email_off-->
</p> </p>
@ -327,7 +337,7 @@ class WC_Meta_Box_Order_Data {
if ( $order->get_formatted_billing_address() ) { if ( $order->get_formatted_billing_address() ) {
echo '<p>' . wp_kses( $order->get_formatted_billing_address(), array( 'br' => array() ) ) . '</p>'; echo '<p>' . wp_kses( $order->get_formatted_billing_address(), array( 'br' => array() ) ) . '</p>';
} else { } else {
echo '<p class="none_set"><strong>' . __( 'Address:', 'woocommerce' ) . '</strong> ' . __( 'No billing address set.', 'woocommerce' ) . '</p>'; echo '<p class="none_set"><strong>' . esc_html__( 'Address:', 'woocommerce' ) . '</strong> ' . esc_html__( 'No billing address set.', 'woocommerce' ) . '</p>';
} }
foreach ( self::$billing_fields as $key => $field ) { foreach ( self::$billing_fields as $key => $field ) {
@ -402,7 +412,7 @@ class WC_Meta_Box_Order_Data {
foreach ( $payment_gateways as $gateway ) { foreach ( $payment_gateways as $gateway ) {
if ( 'yes' === $gateway->enabled ) { if ( 'yes' === $gateway->enabled ) {
echo '<option value="' . esc_attr( $gateway->id ) . '" ' . selected( $payment_method, $gateway->id, false ) . '>' . esc_html( $gateway->get_title() ) . '</option>'; echo '<option value="' . esc_attr( $gateway->id ) . '" ' . selected( $payment_method, $gateway->id, false ) . '>' . esc_html( $gateway->get_title() ) . '</option>';
if ( $payment_method == $gateway->id ) { if ( $payment_method === $gateway->id ) {
$found_method = true; $found_method = true;
} }
} }
@ -446,7 +456,7 @@ class WC_Meta_Box_Order_Data {
if ( $order->get_formatted_shipping_address() ) { if ( $order->get_formatted_shipping_address() ) {
echo '<p>' . wp_kses( $order->get_formatted_shipping_address(), array( 'br' => array() ) ) . '</p>'; echo '<p>' . wp_kses( $order->get_formatted_shipping_address(), array( 'br' => array() ) ) . '</p>';
} else { } else {
echo '<p class="none_set"><strong>' . __( 'Address:', 'woocommerce' ) . '</strong> ' . __( 'No shipping address set.', 'woocommerce' ) . '</p>'; echo '<p class="none_set"><strong>' . esc_html__( 'Address:', 'woocommerce' ) . '</strong> ' . esc_html__( 'No shipping address set.', 'woocommerce' ) . '</p>';
} }
if ( ! empty( self::$shipping_fields ) ) { if ( ! empty( self::$shipping_fields ) ) {
@ -473,8 +483,8 @@ class WC_Meta_Box_Order_Data {
} }
} }
if ( apply_filters( 'woocommerce_enable_order_notes_field', 'yes' == get_option( 'woocommerce_enable_order_comments', 'yes' ) ) && $post->post_excerpt ) { if ( apply_filters( 'woocommerce_enable_order_notes_field', 'yes' === get_option( 'woocommerce_enable_order_comments', 'yes' ) ) && $post->post_excerpt ) {
echo '<p class="order_note"><strong>' . __( 'Customer provided note:', 'woocommerce' ) . '</strong> ' . nl2br( esc_html( $post->post_excerpt ) ) . '</p>'; echo '<p class="order_note"><strong>' . esc_html__( 'Customer provided note:', 'woocommerce' ) . '</strong> ' . nl2br( esc_html( $post->post_excerpt ) ) . '</p>';
} }
?> ?>
</div> </div>
@ -510,10 +520,10 @@ class WC_Meta_Box_Order_Data {
} }
} }
if ( apply_filters( 'woocommerce_enable_order_notes_field', 'yes' == get_option( 'woocommerce_enable_order_comments', 'yes' ) ) ) : if ( apply_filters( 'woocommerce_enable_order_notes_field', 'yes' === get_option( 'woocommerce_enable_order_comments', 'yes' ) ) ) :
?> ?>
<p class="form-field form-field-wide"> <p class="form-field form-field-wide">
<label for="excerpt"><?php _e( 'Customer provided note', 'woocommerce' ); ?>:</label> <label for="excerpt"><?php esc_html_e( 'Customer provided note', 'woocommerce' ); ?>:</label>
<textarea rows="1" cols="40" name="excerpt" tabindex="6" id="excerpt" placeholder="<?php esc_attr_e( 'Customer notes about the order', 'woocommerce' ); ?>"><?php echo wp_kses_post( $post->post_excerpt ); ?></textarea> <textarea rows="1" cols="40" name="excerpt" tabindex="6" id="excerpt" placeholder="<?php esc_attr_e( 'Customer notes about the order', 'woocommerce' ); ?>"><?php echo wp_kses_post( $post->post_excerpt ); ?></textarea>
</p> </p>
<?php endif; ?> <?php endif; ?>
@ -532,8 +542,19 @@ class WC_Meta_Box_Order_Data {
* Save meta box data. * Save meta box data.
* *
* @param int $order_id Order ID. * @param int $order_id Order ID.
* @throws Exception Required request data is missing.
*/ */
public static function save( $order_id ) { public static function save( $order_id ) {
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( ! isset( $_POST['order_status'] ) ) {
throw new Exception( __( 'Order status is missing.', 'woocommerce' ), 400 );
}
if ( ! isset( $_POST['_payment_method'] ) ) {
throw new Exception( __( 'Payment method is missing.', 'woocommerce' ), 400 );
}
self::init_address_fields(); self::init_address_fields();
// Ensure gateways are loaded in case they need to insert data into the emails. // Ensure gateways are loaded in case they need to insert data into the emails.
@ -598,7 +619,7 @@ class WC_Meta_Box_Order_Data {
} }
// Payment method handling. // Payment method handling.
if ( $order->get_payment_method() !== wp_unslash( $_POST['_payment_method'] ) ) { if ( $order->get_payment_method() !== wc_clean( wp_unslash( $_POST['_payment_method'] ) ) ) {
$methods = WC()->payment_gateways->payment_gateways(); $methods = WC()->payment_gateways->payment_gateways();
$payment_method = wc_clean( wp_unslash( $_POST['_payment_method'] ) ); $payment_method = wc_clean( wp_unslash( $_POST['_payment_method'] ) );
$payment_method_title = $payment_method; $payment_method_title = $payment_method;
@ -607,10 +628,10 @@ class WC_Meta_Box_Order_Data {
$payment_method_title = $methods[ $payment_method ]->get_title(); $payment_method_title = $methods[ $payment_method ]->get_title();
} }
if ( $payment_method == 'other') { if ( 'other' === $payment_method ) {
$payment_method_title = esc_html__( 'Other', 'woocommerce' ); $payment_method_title = esc_html__( 'Other', 'woocommerce' );
} }
$props['payment_method'] = $payment_method; $props['payment_method'] = $payment_method;
$props['payment_method_title'] = $payment_method_title; $props['payment_method_title'] = $payment_method_title;
} }
@ -619,13 +640,17 @@ class WC_Meta_Box_Order_Data {
if ( empty( $_POST['order_date'] ) ) { if ( empty( $_POST['order_date'] ) ) {
$date = time(); $date = time();
} else { } else {
if ( ! isset( $_POST['order_date_hour'] ) || ! isset( $_POST['order_date_minute'] ) || ! isset( $_POST['order_date_second'] ) ) {
throw new Exception( __( 'Order date, hour, minute and/or second are missing.', 'woocommerce' ), 400 );
}
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput
$date = gmdate( 'Y-m-d H:i:s', strtotime( $_POST['order_date'] . ' ' . (int) $_POST['order_date_hour'] . ':' . (int) $_POST['order_date_minute'] . ':' . (int) $_POST['order_date_second'] ) ); $date = gmdate( 'Y-m-d H:i:s', strtotime( $_POST['order_date'] . ' ' . (int) $_POST['order_date_hour'] . ':' . (int) $_POST['order_date_minute'] . ':' . (int) $_POST['order_date_second'] ) );
} }
$props['date_created'] = $date; $props['date_created'] = $date;
// Set created via prop if new post. // Set created via prop if new post.
if ( isset( $_POST['original_post_status'] ) && $_POST['original_post_status'] === 'auto-draft' ) { if ( isset( $_POST['original_post_status'] ) && 'auto-draft' === $_POST['original_post_status'] ) {
$props['created_via'] = 'admin'; $props['created_via'] = 'admin';
} }
@ -633,5 +658,7 @@ class WC_Meta_Box_Order_Data {
$order->set_props( $props ); $order->set_props( $props );
$order->set_status( wc_clean( wp_unslash( $_POST['order_status'] ) ), '', true ); $order->set_status( wc_clean( wp_unslash( $_POST['order_status'] ) ), '', true );
$order->save(); $order->save();
// phpcs:enable WordPress.Security.NonceVerification.Missing
} }
} }

View File

@ -2053,7 +2053,7 @@ class WC_Order extends WC_Abstract_Order {
* @param string $tax_display Tax to display. * @param string $tax_display Tax to display.
*/ */
protected function add_order_item_totals_payment_method_row( &$total_rows, $tax_display ) { protected function add_order_item_totals_payment_method_row( &$total_rows, $tax_display ) {
if ( $this->get_total() > 0 && $this->get_payment_method_title() && 'other' !== $this->get_payment_method_title() ) { if ( $this->get_total() > 0 && $this->get_payment_method_title() && 'other' !== $this->get_payment_method() ) {
$total_rows['payment_method'] = array( $total_rows['payment_method'] = array(
'label' => __( 'Payment method:', 'woocommerce' ), 'label' => __( 'Payment method:', 'woocommerce' ),
'value' => $this->get_payment_method_title(), 'value' => $this->get_payment_method_title(),