mirror of
https://github.com/pronamic/woocommerce-subscriptions.git
synced 2025-10-07 10:04:03 +00:00
557 lines
21 KiB
PHP
557 lines
21 KiB
PHP
<?php
|
|
/**
|
|
* Woocommerce Subscriptions Data Copier
|
|
*/
|
|
|
|
defined( 'ABSPATH' ) || exit;
|
|
|
|
class WC_Subscriptions_Data_Copier {
|
|
|
|
/**
|
|
* The default copy type.
|
|
*/
|
|
const DEFAULT_COPY_TYPE = 'subscription';
|
|
|
|
/**
|
|
* The default data keys that are excluded from the copy.
|
|
*
|
|
* @var string[]
|
|
*/
|
|
const DEFAULT_EXCLUDED_META_KEYS = [
|
|
'_paid_date',
|
|
'_date_paid',
|
|
'_completed_date',
|
|
'_date_completed',
|
|
'_edit_last',
|
|
'_subscription_switch_data',
|
|
'_order_key',
|
|
'_edit_lock',
|
|
'_wc_points_earned',
|
|
'_transaction_id',
|
|
'_billing_interval',
|
|
'_billing_period',
|
|
'_subscription_resubscribe',
|
|
'_subscription_renewal',
|
|
'_subscription_switch',
|
|
'_payment_method',
|
|
'_payment_method_title',
|
|
'_suspension_count',
|
|
'_requires_manual_renewal',
|
|
'_cancelled_email_sent',
|
|
'_last_order_date_created',
|
|
'_trial_period',
|
|
'_created_via',
|
|
'_order_stock_reduced',
|
|
'id',
|
|
];
|
|
|
|
/**
|
|
* The subscription or order being copied.
|
|
*
|
|
* @var WC_Order
|
|
*/
|
|
private $from_object = null;
|
|
|
|
/**
|
|
* The subscription or order being copied to.
|
|
*
|
|
* @var WC_Order
|
|
*/
|
|
private $to_object = null;
|
|
|
|
/**
|
|
* The type of copy. Can be 'subscription' or 'renewal'.
|
|
*
|
|
* Used in dynamic filters to allow third parties to target specific meta keys in different copying contexts.
|
|
*
|
|
* @var string
|
|
*/
|
|
private $copy_type = '';
|
|
|
|
/**
|
|
* Copies data from one object to another.
|
|
*
|
|
* This function acts as a publicly accessible wrapper for obtaining an instance of the copier and completing the copy.
|
|
*
|
|
* @param WC_Order $from_object The object to copy data from.
|
|
* @param WC_Order $to_object The object to copy data to.
|
|
* @param string $copy_type Optional. The type of copy. Can be 'subscription', 'parent', 'renewal_order' or 'resubscribe_order'. Default is 'subscription'.
|
|
*/
|
|
public static function copy( $from_object, $to_object, $copy_type = self::DEFAULT_COPY_TYPE ) {
|
|
$instance = new self( $from_object, $to_object, $copy_type );
|
|
$instance->copy_data();
|
|
}
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param WC_Order $from_object The object to copy data from.
|
|
* @param WC_Order $to_object The object to copy data to.
|
|
* @param string $copy_type Optional. The type of copy. Can be 'subscription', 'parent', 'renewal_order' or 'resubscribe_order'. Default is 'subscription'.
|
|
*/
|
|
public function __construct( $from_object, $to_object, $copy_type = self::DEFAULT_COPY_TYPE ) {
|
|
$this->from_object = $from_object;
|
|
$this->to_object = $to_object;
|
|
$this->copy_type = $copy_type;
|
|
}
|
|
|
|
/**
|
|
* Copies the data from the "from" object to the "to" object.
|
|
*/
|
|
public function copy_data() {
|
|
|
|
if ( ! wcs_is_custom_order_tables_usage_enabled() ) {
|
|
$data_array = $GLOBALS['wpdb']->get_results( $this->get_deprecated_meta_query(), ARRAY_A );
|
|
$data = wp_list_pluck( $data_array, 'meta_value', 'meta_key' );
|
|
} else {
|
|
$data = $this->get_meta_data();
|
|
$data += $this->get_order_data();
|
|
$data += $this->get_operational_data();
|
|
$data += $this->get_address_data();
|
|
|
|
// Payment token meta isn't accounted from in the above methods, so we need to add it separately.
|
|
if ( ! isset( $data['_payment_tokens'] ) ) {
|
|
$tokens = $this->from_object->get_payment_tokens();
|
|
|
|
if ( ! empty( $tokens ) ) {
|
|
$data['_payment_tokens'] = $tokens;
|
|
}
|
|
}
|
|
|
|
// Remove any excluded meta keys.
|
|
$data = $this->filter_excluded_meta_keys_via_query( $data );
|
|
}
|
|
|
|
$data = $this->apply_deprecated_filter( $data );
|
|
|
|
/**
|
|
* Filters the data to be copied from one object to another.
|
|
*
|
|
* This filter name contains a dynamic part, $this->copy_type. The full set of hooks include:
|
|
* - wc_subscriptions_subscription_data
|
|
* - wc_subscriptions_parent_data
|
|
* - wc_subscriptions_renewal_order_data
|
|
* - wc_subscriptions_resubscribe_order_data
|
|
*
|
|
* @since subscriptions-core 2.5.0
|
|
*
|
|
* @param array $data {
|
|
* The data to be copied to the "to" object. Each value is keyed by the meta key. Example format [ '_meta_key' => 'meta_value' ].
|
|
*
|
|
* @type mixed $meta_value The meta value to be copied.
|
|
* }
|
|
* @param WC_Order $from_object The object to copy data from.
|
|
* @param WC_Order $to_object The object to copy data to.
|
|
*/
|
|
$data = apply_filters( "wc_subscriptions_{$this->copy_type}_data", $data, $this->to_object, $this->from_object );
|
|
|
|
/**
|
|
* Filters the data to be copied from one object to another.
|
|
*
|
|
* @since subscriptions-core 2.5.0
|
|
*
|
|
* @param array $data {
|
|
* The data to be copied to the "to" object. Each value is keyed by the meta key. Example format [ '_meta_key' => 'meta_value' ].
|
|
*
|
|
* @type mixed $meta_value The meta value to be copied.
|
|
* }
|
|
* @param WC_Order $from_object The object to copy data from.
|
|
* @param WC_Order $to_object The object to copy data to.
|
|
* @param string $copy_type The type of copy. Can be 'subscription', 'parent', 'renewal_order' or 'resubscribe_order'.
|
|
*/
|
|
$data = apply_filters( 'wc_subscriptions_object_data', $data, $this->to_object, $this->from_object, $this->copy_type );
|
|
|
|
foreach ( $data as $key => $value ) {
|
|
$this->set_data( $key, maybe_unserialize( $value ) );
|
|
}
|
|
|
|
$this->to_object->save();
|
|
}
|
|
|
|
/**
|
|
* Sets a piece of data on the "to" object.
|
|
*
|
|
* This function uses a setter where appropriate, otherwise it sets the data directly.
|
|
* Values which are stored as a bool in memory are converted before being set. eg 'no' -> false, 'yes' -> true.
|
|
*
|
|
* @param string $key The data key to set.
|
|
* @param mixed $value The value to set.
|
|
*/
|
|
private function set_data( $key, $value ) {
|
|
|
|
// WC will automatically set/update these keys when a shipping/billing address attribute changes so we can ignore these keys.
|
|
if ( in_array( $key, [ '_shipping_address_index', '_billing_address_index' ], true ) ) {
|
|
return;
|
|
}
|
|
|
|
// The WC_Order setter for these keys will expect an array of values, return early if the value is not an array.
|
|
if (
|
|
in_array( $key, [ '_shipping_address', '_shipping', '_billing_address', '_billing' ], true )
|
|
&& ! is_array( $value )
|
|
) {
|
|
return;
|
|
}
|
|
|
|
// Special cases where properties with setters don't map nicely to their function names.
|
|
$setter_map = [
|
|
'_cart_discount' => 'set_discount_total',
|
|
'_cart_discount_tax' => 'set_discount_tax',
|
|
'_customer_user' => 'set_customer_id',
|
|
'_order_tax' => 'set_cart_tax',
|
|
'_order_shipping' => 'set_shipping_total',
|
|
'_order_currency' => 'set_currency',
|
|
'_order_shipping_tax' => 'set_shipping_tax',
|
|
'_order_total' => 'set_total',
|
|
'_order_version' => 'set_version',
|
|
];
|
|
|
|
$setter = isset( $setter_map[ $key ] ) ? $setter_map[ $key ] : 'set_' . ltrim( $key, '_' );
|
|
|
|
if ( is_callable( [ $this->to_object, $setter ] ) ) {
|
|
// Re-bool the value before setting it. Setters like `set_prices_include_tax()` expect a bool.
|
|
if ( is_string( $value ) && in_array( $value, [ 'yes', 'no' ], true ) ) {
|
|
$value = 'yes' === $value;
|
|
}
|
|
|
|
$this->to_object->{$setter}( $value );
|
|
} elseif ( '_payment_tokens' === $key ) {
|
|
// Payment tokens don't have a setter and cannot be set via metadata so we need to set them via the datastore.
|
|
$this->to_object->get_data_store()->update_payment_token_ids( $this->to_object, $value );
|
|
} else {
|
|
$this->to_object->update_meta_data( $key, $value );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines if there are callbacks attached to the deprecated "wcs_{$this->copy_type}_meta_query" filter.
|
|
*
|
|
* @return bool True if there are callbacks attached to the deprecated "wcs_{$this->copy_type}_meta_query" filter. False otherwise.
|
|
*/
|
|
private function has_filter_on_meta_query_hook() {
|
|
return has_filter( "wcs_{$this->copy_type}_meta_query" );
|
|
}
|
|
|
|
/**
|
|
* Gets the "from" object's meta data.
|
|
*
|
|
* @return string[] The meta data.
|
|
*/
|
|
private function get_meta_data() {
|
|
$meta_data = [];
|
|
|
|
foreach ( $this->from_object->get_meta_data() as $meta ) {
|
|
$meta_data[ $meta->key ] = $meta->value;
|
|
}
|
|
|
|
return $meta_data;
|
|
}
|
|
|
|
/**
|
|
* Gets the "from" object's operational data that was previously stored in wp post meta.
|
|
*
|
|
* @return string[] The operational data with the legacy meta key.
|
|
*/
|
|
private function get_operational_data() {
|
|
return [
|
|
'_created_via' => $this->from_object->get_created_via( 'edit' ),
|
|
'_order_version' => $this->from_object->get_version( 'edit' ),
|
|
'_prices_include_tax' => wc_bool_to_string( $this->from_object->get_prices_include_tax( 'edit' ) ),
|
|
'_recorded_coupon_usage_counts' => wc_bool_to_string( $this->from_object->get_recorded_coupon_usage_counts( 'edit' ) ),
|
|
'_download_permissions_granted' => wc_bool_to_string( $this->from_object->get_download_permissions_granted( 'edit' ) ),
|
|
'_cart_hash' => $this->from_object->get_cart_hash( 'edit' ),
|
|
'_new_order_email_sent' => wc_bool_to_string( $this->from_object->get_new_order_email_sent( 'edit' ) ),
|
|
'_order_key' => $this->from_object->get_order_key( 'edit' ),
|
|
'_order_stock_reduced' => $this->from_object->get_order_stock_reduced( 'edit' ),
|
|
'_date_paid' => $this->from_object->get_date_paid( 'edit' ),
|
|
'_date_completed' => $this->from_object->get_date_completed( 'edit' ),
|
|
'_order_shipping_tax' => $this->from_object->get_shipping_tax( 'edit' ),
|
|
'_order_shipping' => $this->from_object->get_shipping_total( 'edit' ),
|
|
'_cart_discount_tax' => $this->from_object->get_discount_tax( 'edit' ),
|
|
'_cart_discount' => $this->from_object->get_discount_total( 'edit' ),
|
|
'_recorded_sales' => wc_bool_to_string( $this->from_object->get_recorded_sales( 'edit' ) ),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Gets the "from" object's core data that was previously stored in wp post meta.
|
|
*
|
|
* @return string[] The core data with the legacy meta keys.
|
|
*/
|
|
private function get_order_data() {
|
|
return [
|
|
'_order_currency' => $this->from_object->get_currency( 'edit' ),
|
|
'_order_tax' => $this->from_object->get_cart_tax( 'edit' ),
|
|
'_order_total' => $this->from_object->get_total( 'edit' ),
|
|
'_customer_user' => $this->from_object->get_customer_id( 'edit' ),
|
|
'_billing_email' => $this->from_object->get_billing_email( 'edit' ),
|
|
'_payment_method' => $this->from_object->get_payment_method( 'edit' ),
|
|
'_payment_method_title' => $this->from_object->get_payment_method_title( 'edit' ),
|
|
'_customer_ip_address' => $this->from_object->get_customer_ip_address( 'edit' ),
|
|
'_customer_user_agent' => $this->from_object->get_customer_user_agent( 'edit' ),
|
|
'_transaction_id' => $this->from_object->get_transaction_id( 'edit' ),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Gets the "from" object's address data that was previously stored in wp post meta.
|
|
*
|
|
* @return string[] The address data with the legacy meta keys.
|
|
*/
|
|
private function get_address_data() {
|
|
return array_filter(
|
|
[
|
|
'_billing_first_name' => $this->from_object->get_billing_first_name( 'edit' ),
|
|
'_billing_last_name' => $this->from_object->get_billing_last_name( 'edit' ),
|
|
'_billing_company' => $this->from_object->get_billing_company( 'edit' ),
|
|
'_billing_address_1' => $this->from_object->get_billing_address_1( 'edit' ),
|
|
'_billing_address_2' => $this->from_object->get_billing_address_2( 'edit' ),
|
|
'_billing_city' => $this->from_object->get_billing_city( 'edit' ),
|
|
'_billing_state' => $this->from_object->get_billing_state( 'edit' ),
|
|
'_billing_postcode' => $this->from_object->get_billing_postcode( 'edit' ),
|
|
'_billing_country' => $this->from_object->get_billing_country( 'edit' ),
|
|
'_billing_email' => $this->from_object->get_billing_email( 'edit' ),
|
|
'_billing_phone' => $this->from_object->get_billing_phone( 'edit' ),
|
|
'_shipping_first_name' => $this->from_object->get_shipping_first_name( 'edit' ),
|
|
'_shipping_last_name' => $this->from_object->get_shipping_last_name( 'edit' ),
|
|
'_shipping_company' => $this->from_object->get_shipping_company( 'edit' ),
|
|
'_shipping_address_1' => $this->from_object->get_shipping_address_1( 'edit' ),
|
|
'_shipping_address_2' => $this->from_object->get_shipping_address_2( 'edit' ),
|
|
'_shipping_city' => $this->from_object->get_shipping_city( 'edit' ),
|
|
'_shipping_state' => $this->from_object->get_shipping_state( 'edit' ),
|
|
'_shipping_postcode' => $this->from_object->get_shipping_postcode( 'edit' ),
|
|
'_shipping_country' => $this->from_object->get_shipping_country( 'edit' ),
|
|
'_shipping_phone' => $this->from_object->get_shipping_phone( 'edit' ),
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Removes the meta keys excluded via the deprecated from the set of data to be copied.
|
|
*
|
|
* @param array $data The data to be copied.
|
|
* @return array The data to be copied with the excluded keys removed.
|
|
*/
|
|
public function filter_excluded_meta_keys_via_query( $data ) {
|
|
$excluded_keys = $this->get_excluded_data_keys();
|
|
|
|
foreach ( $data as $meta_key => $meta_value ) {
|
|
if ( isset( $excluded_keys['in'] ) && in_array( $meta_key, $excluded_keys['in'], true ) ) {
|
|
unset( $data[ $meta_key ] );
|
|
} elseif ( isset( $excluded_keys['regex'] ) ) {
|
|
foreach ( $excluded_keys['regex'] as $regex ) {
|
|
if ( preg_match( $regex, $meta_key ) ) {
|
|
unset( $data[ $meta_key ] );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Returns the deprecated meta database query that returns the "from" objects meta data.
|
|
*
|
|
* Triggers a deprecation notice if the deprecated "wcs_{$this->copy_type}_meta_query" filter is in use by at least 1 third-party.
|
|
*
|
|
* @return string SQL SELECT query.
|
|
*/
|
|
private function get_deprecated_meta_query() {
|
|
global $wpdb;
|
|
|
|
$meta_query = sprintf(
|
|
"SELECT `meta_key`, `meta_value`
|
|
FROM %s
|
|
WHERE `post_id` = %d
|
|
AND `meta_key` NOT LIKE '%s'
|
|
AND `meta_key` NOT IN ('%s')",
|
|
$wpdb->postmeta,
|
|
$this->from_object->get_id(),
|
|
'_schedule_%',
|
|
implode( "', '", self::DEFAULT_EXCLUDED_META_KEYS )
|
|
);
|
|
|
|
if ( in_array( $this->copy_type, [ 'renewal_order', 'parent' ], true ) ) {
|
|
$meta_query .= " AND `meta_key` NOT LIKE '_download_permissions_granted' ";
|
|
}
|
|
|
|
if ( $this->has_filter_on_meta_query_hook() ) {
|
|
$data_copier_to_object = $this->to_object;
|
|
$data_copier_from_object = $this->from_object;
|
|
|
|
/**
|
|
* Filters the data to be copied from one object to another.
|
|
*
|
|
* This filter name contains a dynamic part, $this->copy_type. The full set of hooks include:
|
|
* - wcs_subscription_meta_query
|
|
* - wcs_parent_meta_query
|
|
* - wcs_renewal_order_meta_query
|
|
* - wcs_resubscribe_order_meta_query
|
|
*
|
|
* @deprecated subscriptions-core 2.5.0
|
|
*
|
|
* @param string $meta_query The SQL query to fetch the meta data to be copied.
|
|
* @param WC_Order $data_copier_to_object The object to copy data to.
|
|
* @param WC_Order $data_copier_from_object The object to copy data from.
|
|
*/
|
|
$meta_query = apply_filters( "wcs_{$this->copy_type}_meta_query", $meta_query, $data_copier_to_object, $data_copier_from_object );
|
|
wcs_deprecated_hook( "wcs_{$this->copy_type}_meta_query", 'subscriptions-core 2.5.0', "wc_subscriptions_{$this->copy_type}_data" );
|
|
}
|
|
|
|
return $meta_query;
|
|
}
|
|
|
|
/**
|
|
* Applies the deprecated "wcs_{$this->copy_type}_meta filter.
|
|
*
|
|
* Triggers a deprecation notice if the deprecated "wcs_{$this->copy_type}_meta" filter is in use by at least 1 third-party.
|
|
*
|
|
* @param array $data The data to copy.
|
|
* @return array The filtered set of data to copy.
|
|
*/
|
|
private function apply_deprecated_filter( $data ) {
|
|
// Only continue if the filter is use.
|
|
if ( ! has_filter( "wcs_{$this->copy_type}_meta" ) ) {
|
|
return $data;
|
|
}
|
|
|
|
// Convert the data into the backwards compatible format ready for filtering - wpdb's ARRAY_A format.
|
|
$data_array = [];
|
|
|
|
foreach ( $data as $key => $value ) {
|
|
$data_array[] = [
|
|
'meta_key' => $key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- This is a meta key, not a query.
|
|
'meta_value' => $value, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- This is a meta value, not a query.
|
|
];
|
|
}
|
|
|
|
wcs_deprecated_hook( "wcs_{$this->copy_type}_meta", 'wcs-core 2.5.0', "wc_subscriptions_{$this->copy_type}_data" );
|
|
|
|
$data_copier_to_object = $this->to_object;
|
|
$data_copier_from_object = $this->from_object;
|
|
|
|
/**
|
|
* Filters the data to be copied from one object to another.
|
|
*
|
|
* This filter name contains a dynamic part, $this->copy_type. The full set of hooks include:
|
|
* - wcs_subscription_meta
|
|
* - wcs_parent_meta
|
|
* - wcs_renewal_order_meta
|
|
* - wcs_resubscribe_order_meta
|
|
*
|
|
* @deprecated subscriptions-core 2.5.0
|
|
*
|
|
* @param array[] $data_array {
|
|
* The metadata to be copied to the "to" object.
|
|
*
|
|
* @type array $meta_data {
|
|
* The metadata to be copied.
|
|
*
|
|
* @type string $meta_key The meta key to be copied.
|
|
* @type mixed $meta_value The meta value to be copied.
|
|
* }
|
|
* }
|
|
* @param WC_Order $data_copier_to_object The object to copy data to.
|
|
* @param WC_Order $data_copier_from_object The object to copy data from.
|
|
*/
|
|
$data_array = apply_filters( "wcs_{$this->copy_type}_meta", $data_array, $data_copier_to_object, $data_copier_from_object );
|
|
|
|
// Return the data to a key => value format.
|
|
return wp_list_pluck( $data_array, 'meta_value', 'meta_key' );
|
|
}
|
|
|
|
/**
|
|
* Gets a list of meta keys to exclude from the copy.
|
|
*
|
|
* If third-parties are hooked onto the "wcs_{$this->copy_type}_meta_query" filter, this function will attempt
|
|
* to pluck the excluded meta keys from the filtered SQL query. There is no guarantee that this will work for all
|
|
* queries, however it should work under most standard circumstances.
|
|
*
|
|
* If no third-parties are hooked onto the "wcs_{$this->copy_type}_meta_query" filter, this function will simply return
|
|
* the default list of excluded meta keys.
|
|
*
|
|
* @return string[][] An array of excluded meta keys. The array has two keys: 'in' and 'regex'. The 'in' key contains an array of meta keys to exclude. The 'regex' key contains an array of regular expressions to exclude.
|
|
*/
|
|
private function get_excluded_data_keys() {
|
|
$excluded_keys = [];
|
|
|
|
// If there are no third-parties hooked into the deprecated filter, there is no need to parse the query.
|
|
if ( ! $this->has_filter_on_meta_query_hook() ) {
|
|
$excluded_keys['in'] = self::DEFAULT_EXCLUDED_META_KEYS;
|
|
|
|
if ( in_array( $this->copy_type, [ 'renewal_order', 'parent' ], true ) ) {
|
|
$excluded_keys['regex'][] = $this->get_keys_from_like_clause( '_download_permissions_granted' );
|
|
}
|
|
|
|
return $excluded_keys;
|
|
}
|
|
|
|
// Get the deprecated meta query and attempt to pull the excluded keys from it.
|
|
$meta_query = $this->get_deprecated_meta_query();
|
|
|
|
// Normalize the query.
|
|
$meta_query = str_replace( [ "\r", "\n", "\t" ], ' ', $meta_query ); // Remove line breaks, tabs, etc.
|
|
$meta_query = preg_replace( '/\s+/', ' ', $meta_query ); // Remove duplicate whitespace.
|
|
$meta_query = str_replace( '`', '', $meta_query ); // Remove backticks.
|
|
$meta_query = str_replace( '"', "'", $meta_query ); // Replace double quotes with single quotes.
|
|
|
|
// Handle all the NOT LIKE clauses.
|
|
preg_match_all( "/meta_key NOT LIKE '(.*?)'/", $meta_query, $not_like_clauses );
|
|
|
|
if ( ! empty( $not_like_clauses[1] ) ) {
|
|
foreach ( $not_like_clauses[1] as $not_like_clause ) {
|
|
$excluded_keys['regex'][] = $this->get_keys_from_like_clause( $not_like_clause );
|
|
}
|
|
}
|
|
|
|
// Handle all the NOT IN clauses.
|
|
preg_match_all( '/meta_key NOT IN \((.*?)\)/', $meta_query, $not_in_clauses );
|
|
|
|
if ( ! empty( $not_in_clauses[1] ) ) {
|
|
$excluded_keys['in'] = [];
|
|
foreach ( $not_in_clauses[1] as $not_in_clause ) {
|
|
$excluded_keys['in'] = array_merge( $excluded_keys['in'], $this->get_keys_from_in_clause( $not_in_clause ) );
|
|
}
|
|
}
|
|
|
|
return $excluded_keys;
|
|
}
|
|
|
|
/**
|
|
* Gets a list of meta keys from a SQL IN clause.
|
|
*
|
|
* @param string $in_clause The concatenated string of meta keys from the IN clause. eg: '_paid_date', '_date_paid', '_completed_date' ...
|
|
* @return string[] The meta keys from the IN clause. eg: [ '_paid_date', '_date_paid', '_completed_date' ]
|
|
*/
|
|
private function get_keys_from_in_clause( $in_clause ) {
|
|
// Remove single quotes.
|
|
$in_keys = str_replace( "'", '', $in_clause );
|
|
|
|
// Split into an array.
|
|
$in_keys = explode( ',', $in_keys );
|
|
|
|
// Trim whitespace from each key.
|
|
$in_keys = array_map( 'trim', $in_keys );
|
|
|
|
return $in_keys;
|
|
}
|
|
|
|
/**
|
|
* Formats a LIKE clause into a regex pattern.
|
|
*
|
|
* @param string $like_clause A SQL LIKE clause. eg: '_schedule_%%'
|
|
* @return string A regex pattern. eg: '/^_schedule_.*$/'
|
|
*/
|
|
private function get_keys_from_like_clause( $like_clause ) {
|
|
// Remove the surrounding quotes.
|
|
$like_clause = str_replace( "'", '', $like_clause );
|
|
|
|
// Replace the wildcard with a regex wildcard.
|
|
$like_clause = str_replace( '%', '.*?', $like_clause );
|
|
|
|
// Add the regex wildcard to the beginning and end of the string.
|
|
return '^' . trim( $like_clause ) . '$^';
|
|
}
|
|
}
|