Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom order fields drop-down to custom fields metabox under HPOS #44739

Merged
merged 15 commits into from Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions plugins/woocommerce/changelog/fix-44029
@@ -0,0 +1,4 @@
Significance: patch
Type: add

Add used meta keys dropdown in HPOS custom fields metabox.
11 changes: 11 additions & 0 deletions plugins/woocommerce/client/legacy/css/admin.scss
Expand Up @@ -2786,6 +2786,17 @@ ul.wc_coupon_list_block {
}
}

#order_custom #postcustomstuff {
.add-custom-field {
padding: 12px 8px 8px;
}

.submit {
border: 0 none;
float: none;
}
}

#side-sortables #woocommerce-order-downloads {
.buttons,
.select2-container {
Expand Down
@@ -1,12 +1,12 @@
<?php

Check notice on line 1 in plugins/woocommerce/src/Internal/Admin/Orders/MetaBoxes/CustomMetaBox.php

View workflow job for this annotation

GitHub Actions / Analyze Branch Changes

new filter found - postmeta_form_limit

\'postmeta_form_limit\' introduced in 8.8.0
/**
* Meta box to edit and add custom meta values for an order.
*/

namespace Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes;

use WC_Data_Store;
use WC_Meta_Data;
use Automattic\WooCommerce\Internal\DataStores\CustomMetaDataStore;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStoreMeta;
use WC_Order;
use WP_Ajax_Response;

Expand Down Expand Up @@ -92,16 +92,44 @@
* Compute keys to display in autofill when adding new meta key entry in custom meta box.
* Currently, returns empty keys, will be implemented after caching is merged.
*
* @param array|null $keys Keys to display in autofill.
* @param \WP_Post|\WC_Order $order Order object.
* @param mixed $deprecated Unused argument. For backwards compatibility.
* @param \WP_Post|\WC_Order $order Order object.
*
* @return array|mixed Array of keys to display in autofill.
* @return array Array of keys to display in autofill.
*/
public function order_meta_keys_autofill( $keys, $order ) {
if ( is_a( $order, \WC_Order::class ) ) {
public function order_meta_keys_autofill( $deprecated, $order ) {
if ( ! is_a( $order, \WC_Order::class ) ) {
return array();
}

/**
* Filters values for the meta key dropdown in the Custom Fields meta box.
*
* Compatibility filter for `postmeta_form_keys` filter.
*
* @since 6.9.0
*
* @param array|null $keys Pre-defined meta keys to be used in place of a postmeta query. Default null.
* @param \WC_Order $order The current post object.
*/
$keys = apply_filters( 'postmeta_form_keys', null, $order );
if ( null === $keys || ! is_array( $keys ) ) {
/**
* Compatibility filter for 'postmeta_form_limit', which filters the number of custom fields to retrieve
* for the drop-down in the Custom Fields meta box.
*
* @since 8.8.0
*
* @param int $limit Number of custom fields to retrieve. Default 30.
*/
$limit = apply_filters( 'postmeta_form_limit', 30 );
$keys = wc_get_container()->get( OrdersTableDataStoreMeta::class )->get_meta_keys( $limit );
}

if ( $keys ) {
natcasesort( $keys );
}

return $keys;
}

Expand All @@ -116,17 +144,6 @@
$meta_key_input_id = 'metakeyselect';

$keys = $this->order_meta_keys_autofill( null, $order );
/**
* Filters values for the meta key dropdown in the Custom Fields meta box.
*
* Compatibility filter for `postmeta_form_keys` filter.
*
* @since 6.9.0
*
* @param array|null $keys Pre-defined meta keys to be used in place of a postmeta query. Default null.
* @param \WC_Order $order The current post object.
*/
$keys = apply_filters( 'postmeta_form_keys', $keys, $order );
?>
<p><strong><?php esc_html_e( 'Add New Custom Field:', 'woocommerce' ); ?></strong></p>
<table id="newmeta">
Expand All @@ -145,43 +162,42 @@
<option value="#NONE#"><?php esc_html_e( '&mdash; Select &mdash;', 'woocommerce' ); ?></option>
<?php
foreach ( $keys as $key ) {
if ( is_protected_meta( $key, 'post' ) || ! current_user_can( 'edit_others_shop_order', $order->get_id() ) ) {
if ( is_protected_meta( $key, 'post' ) || ! current_user_can( 'edit_others_shop_orders' ) ) {
continue;
}
echo "\n<option value='" . esc_attr( $key ) . "'>" . esc_html( $key ) . '</option>';
}
?>
</select>
<input class="hide-if-js" type="text" id="metakeyinput" name="metakeyinput" value="" />
<a href="#postcustomstuff" class="hide-if-no-js" onclick="jQuery('#metakeyinput, #metakeyselect, #enternew, #cancelnew').toggle();return false;">
<span id="enternew"><?php esc_html_e( 'Enter new', 'woocommerce' ); ?></span>
<span id="cancelnew" class="hidden"><?php esc_html_e( 'Cancel', 'woocommerce' ); ?></span></a>
<input class="hidden" type="text" id="metakeyinput" name="metakeyinput" value="" aria-label="<?php esc_attr_e( 'New custom field name', 'woocommerce' ); ?>" />
<button type="button" id="newmeta-button" class="button button-small hide-if-no-js" onclick="jQuery('#metakeyinput, #metakeyselect, #enternew, #cancelnew').toggleClass('hidden');jQuery('#metakeyinput, #metakeyselect').filter(':visible').trigger('focus');">
<span id="enternew"><?php esc_html_e( 'Enter new', 'woocommerce' ); ?></span>
<span id="cancelnew" class="hidden"><?php esc_html_e( 'Cancel', 'woocommerce' ); ?></span>
<?php } else { ?>
<input type="text" id="metakeyinput" name="metakeyinput" value="" />
<?php } ?>
</td>
<td><textarea id="metavalue" name="metavalue" rows="2" cols="25"></textarea></td>
<td><textarea id="metavalue" name="metavalue" rows="2" cols="25"></textarea>
<?php wp_nonce_field( 'add-meta', '_ajax_nonce-add-meta', false ); ?>
</td>
</tr>

<tr><td colspan="2">
<div class="submit">
<?php
submit_button(
__( 'Add Custom Field', 'woocommerce' ),
'',
'addmeta',
false,
array(
'id' => 'newmeta-submit',
'data-wp-lists' => 'add:the-list:newmeta',
)
);
?>
</div>
<?php wp_nonce_field( 'add-meta', '_ajax_nonce-add-meta', false ); ?>
</td></tr>
</tbody>
</table>

<div class="submit add-custom-field">
<?php
submit_button(
__( 'Add Custom Field', 'woocommerce' ),
'',
'addmeta',
false,
array(
'id' => 'newmeta-submit',
'data-wp-lists' => 'add:the-list:newmeta',
)
);
?>
</div>
<?php
}

Expand Down Expand Up @@ -218,17 +234,20 @@
$order_id = (int) $_POST['order_id'] ?? 0;
$order = $this->verify_order_edit_permission_for_ajax( $order_id );

if ( isset( $_POST['metakeyselect'] ) && '#NONE#' === $_POST['metakeyselect'] && empty( $_POST['metakeyinput'] ) ) {
$select_meta_key = trim( sanitize_text_field( wp_unslash( $_POST['metakeyselect'] ?? '' ) ) );
$input_meta_key = trim( sanitize_text_field( wp_unslash( $_POST['metakeyinput'] ?? '' ) ) );

if ( empty( $_POST['meta'] ) && in_array( $select_meta_key, array( '', '#NONE#' ), true ) && ! $input_meta_key ) {
wp_die( 1 );
}

if ( isset( $_POST['metakeyinput'] ) ) { // add meta.
$meta_key = sanitize_text_field( wp_unslash( $_POST['metakeyinput'] ) );
if ( ! empty( $_POST['meta'] ) ) { // update.
$meta = wp_unslash( $_POST['meta'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitization done below in array_walk.
$this->handle_update_meta( $order, $meta );
} else { // add meta.
$meta_value = sanitize_text_field( wp_unslash( $_POST['metavalue'] ?? '' ) );
$meta_key = $input_meta_key ? $input_meta_key : $select_meta_key;
$this->handle_add_meta( $order, $meta_key, $meta_value );
} else { // update.
$meta = wp_unslash( $_POST['meta'] ?? array() ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitization done below in array_walk.
$this->handle_update_meta( $order, $meta );
}
}

Expand Down
Expand Up @@ -232,4 +232,35 @@ public function get_metadata_by_key( &$object, string $meta_key ) {
return $meta;
}

/**
* Returns distinct meta keys in use.
*
* @since 8.8.0
*
* @param int $limit Maximum number of meta keys to return. Defaults to 100.
* @param string $order Order to use for the results. Either 'ASC' or 'DESC'. Defaults to 'ASC'.
* @param bool $include_private Whether to include private meta keys in the results. Defaults to FALSE.
* @return string[]
*/
public function get_meta_keys( $limit = 100, $order = 'ASC', $include_private = false ) {
global $wpdb;

$db_info = $this->get_db_info();

$query = "SELECT DISTINCT meta_key FROM {$db_info['table']} ";

if ( ! $include_private ) {
$query .= $wpdb->prepare( 'WHERE meta_key NOT LIKE %s ', $wpdb->esc_like( '_' ) . '%' );
}

$order = in_array( strtoupper( $order ), array( 'ASC', 'DESC' ), true ) ? $order : 'ASC';
$query .= 'ORDER BY meta_key ' . $order . ' ';

if ( $limit ) {
$query .= $wpdb->prepare( 'LIMIT %d ', $limit );
}

return $wpdb->get_col( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $query is prepared.
coreymckrill marked this conversation as resolved.
Show resolved Hide resolved
}

}