object = $object; // error_log('Wrapping ' . get_class( $object ) ); } public static function wrap($object, $use_pool = true) { _deprecated_function('WJECF_Wrap::wrap', '3.0.0'); if ($use_pool) { // Prevent a huge amount of wrappers to be initiated; one wrapper per object instance should do the trick foreach (static::$wrappers as $wrapper) { if ($wrapper->holds($object)) { return $wrapper; } } } if (is_numeric($object)) { $post_type = get_post_type($object); if ('shop_coupon' == $post_type) { $object = WJECF_WC()->get_coupon($object); } elseif ('product' == $post_type) { $object = new WC_Product($object); } } if (is_string($object)) { $object = WJECF_WC()->get_coupon($object); } if ($object instanceof WC_Coupon) { return static::$wrappers[] = new WJECF_Wrap_Coupon($object); } if ($object instanceof WC_Customer) { return static::$wrappers[] = new WJECF_Wrap_Customer($object); } if ($object instanceof WC_Product) { return static::$wrappers[] = new WJECF_Wrap_Product($object); } throw new Exception('Cannot wrap '.get_class($object)); } public function get_id() { // Since WC 2.7 if ($this->use_wc27 && is_callable([$this->object, 'get_id'])) { return $this->object->get_id(); } return $this->object->id; } public function holds($object) { return $object === $this->object; } /** * Get Meta Data by Key. * * If no value found: * If $single is true, an empty string is returned. * If $single is false, an empty array is returned. * * @since 2.4.0 * * @param bool $single return first found meta, or all * @param mixed $meta_key * * @return mixed */ final public function get_meta($meta_key, $single = true) { if ($this->use_wc27 && is_callable([$this->object, 'get_meta'])) { return $this->get_meta_wc27($meta_key, $single); } return $this->get_meta_legacy($meta_key, $single); } /** * Update single meta data item by meta key. * Call save() if the values must to be persisted. * * @since 2.4.0 * * @param string $meta_key * @param mixed $value The value; use null to clear */ final public function set_meta($meta_key, $value) { if ($this->use_wc27 && is_callable([$this->object, 'update_meta_data'])) { if (null === $value) { $this->object->delete_meta_data($meta_key); } else { $this->object->update_meta_data($meta_key, $value); } return; } $this->set_meta_legacy($meta_key, $value); } protected function get_meta_wc27($meta_key, $single = true) { $values = $this->object->get_meta($meta_key, $single); if ($single) { return $values; // it's just one, dispite the plural in the name! } if ('' === $values) { return []; // get_meta returns empty string if meta does not exist } return wp_list_pluck(array_values($values), 'value'); // when not using array_values; the index might not start with 0 } protected function get_meta_legacy($meta_key, $single = true) { throw new Exception(sprintf('%s::get_meta_legacy not implemented', get_class($this))); } protected function set_meta_legacy($meta_key, $value) { throw new Exception(sprintf('%s::set_meta_legacy not implemented', get_class($this))); } } /** * Wrap a data object ( Coupons and products were converted to WC_Data since WC 2.7.0 ). */ class WJECF_Wrap_Coupon extends WJECF_Wrap { protected $legacy_custom_fields; // [ 'meta_key' => [ array_of_values ] ] protected $legacy_unsaved_keys = []; public function exists() { return $this->get_id() > 0; } public function get_code() { if ($this->use_wc27 && is_callable([$this->object, 'get_code'])) { return $this->object->get_code(); } return $this->object->code; } public function get_description() { if ($this->use_wc27 && is_callable([$this->object, 'get_description'])) { return $this->object->get_description(); } $post = get_post($this->get_id()); return $post->post_excerpt; } public function get_amount() { if ($this->use_wc27 && is_callable([$this->object, 'get_amount'])) { return $this->object->get_amount(); } return $this->object->coupon_amount; } public function get_individual_use() { if ($this->use_wc27 && is_callable([$this->object, 'get_individual_use'])) { return $this->object->get_individual_use(); } return 'yes' == $this->object->individual_use; } public function get_limit_usage_to_x_items() { if ($this->use_wc27 && is_callable([$this->object, 'get_limit_usage_to_x_items'])) { return $this->object->get_limit_usage_to_x_items(); } return $this->object->limit_usage_to_x_items; } public function set_limit_usage_to_x_items($limit_usage_to_x_items) { if ($this->use_wc27 && is_callable([$this->object, 'set_limit_usage_to_x_items'])) { $this->object->set_limit_usage_to_x_items($limit_usage_to_x_items); } else { $this->object->limit_usage_to_x_items = $limit_usage_to_x_items; } } public function get_discount_type() { if ($this->use_wc27 && is_callable([$this->object, 'get_discount_type'])) { return $this->object->get_discount_type(); } return $this->object->discount_type; } public function set_discount_type($discount_type) { if ($this->use_wc27 && is_callable([$this->object, 'set_discount_type'])) { $this->object->set_discount_type($discount_type); } else { $this->object->discount_type = $discount_type; $this->object->type = $discount_type; } } public function get_email_restrictions() { if ($this->use_wc27 && is_callable([$this->object, 'get_email_restrictions'])) { return $this->object->get_email_restrictions(); } return $this->object->customer_email; } public function get_product_ids() { if ($this->use_wc27 && is_callable([$this->object, 'get_product_ids'])) { return $this->object->get_product_ids(); } return $this->object->product_ids; } public function get_free_shipping() { if ($this->use_wc27 && is_callable([$this->object, 'get_free_shipping'])) { return $this->object->get_free_shipping(); } return $this->object->enable_free_shipping(); } public function get_product_categories() { if ($this->use_wc27 && is_callable([$this->object, 'get_product_categories'])) { return $this->object->get_product_categories(); } return $this->object->product_categories; } public function get_minimum_amount() { if ($this->use_wc27 && is_callable([$this->object, 'get_minimum_amount'])) { return $this->object->get_minimum_amount(); } return $this->object->minimum_amount; } /** * Set the product IDs this coupon cannot be used with. * * @since 2.4.2 (For WC3.0) * * @param array $excluded_product_ids * * @throws WC_Data_Exception */ public function set_excluded_product_ids($excluded_product_ids) { if ($this->use_wc27 && is_callable([$this->object, 'set_excluded_product_ids'])) { $this->object->set_excluded_product_ids($excluded_product_ids); } else { // NOTE: Prior to WC2.7 it was called exclude_ instead of excluded_ $this->object->exclude_product_ids = $excluded_product_ids; } } /** * Set the product category IDs this coupon cannot be used with. * * @since 2.4.2 (For WC3.0) * * @param array $excluded_product_categories * * @throws WC_Data_Exception */ public function set_excluded_product_categories($excluded_product_categories) { if ($this->use_wc27 && is_callable([$this->object, 'set_excluded_product_categories'])) { $this->object->set_excluded_product_categories($excluded_product_categories); } else { // NOTE: Prior to WC2.7 it was called exclude_ instead of excluded_ $this->object->exclude_product_categories = $excluded_product_categories; } } /** * Set if this coupon should excluded sale items or not. * * @since 2.4.2 (For WC3.0) * * @param bool $exclude_sale_items * * @throws WC_Data_Exception */ public function set_exclude_sale_items($exclude_sale_items) { if ($this->use_wc27 && is_callable([$this->object, 'set_exclude_sale_items'])) { $this->object->set_exclude_sale_items($exclude_sale_items); } else { // NOTE: Prior to WC2.7 it was yes/no instead of boolean $this->object->exclude_sale_items = $exclude_sale_items ? 'yes' : 'no'; } } /** * Check the type of the coupon. * * @param array|string $type The type(s) we want to check for * * @return bool True if the coupon is of the type */ public function is_type($type) { // Backwards compatibility 2.2.11 if (method_exists($this->object, 'is_type')) { return $this->object->is_type($type); } return ($this->object->discount_type == $type || (is_array($type) && in_array($this->object->discount_type, $type))) ? true : false; } /** * Save the metadata. * * @return id of this object */ public function save() { // WJECF()->log('debug', 'Saving ' . $this->get_id() ); if ($this->use_wc27 && is_callable([$this->object, 'save'])) { return $this->object->save(); } // Save the unsaved... foreach ($this->legacy_unsaved_keys as $meta_key) { // WJECF()->log('debug', '...saving legacy meta ' . $meta_key ); $value = reset($this->legacy_custom_fields[$meta_key]); if (null === $value) { delete_post_meta($this->get_id(), $meta_key); } else { update_post_meta($this->get_id(), $meta_key, $value); } } $this->legacy_unsaved_keys = []; return $this->get_id(); } protected function set_meta_legacy($meta_key, $value) { $this->maybe_get_custom_fields(); // WJECF()->log('debug', '...setting legacy meta ' . $meta_key ); $this->legacy_custom_fields[$meta_key] = [$value]; $this->legacy_unsaved_keys[] = $meta_key; } protected function maybe_get_custom_fields() { // Read custom fields if not yet done if (is_null($this->legacy_custom_fields)) { $this->legacy_custom_fields = $this->object->coupon_custom_fields; } } protected function get_meta_legacy($meta_key, $single = true) { // Read custom fields if not yet done $this->maybe_get_custom_fields(); if (isset($this->legacy_custom_fields[$meta_key])) { $values = $this->legacy_custom_fields[$meta_key]; // WP_CLI::log( "LEGACY:" . print_r( $values, true )); if ($single) { return maybe_unserialize(reset($values)); // reset yields the first } return array_map('maybe_unserialize', $values); } return $single ? '' : []; } } class WJECF_Wrap_Product extends WJECF_Wrap { protected $legacy_custom_fields; // [ 'meta_key' => [ array_of_values ] ] protected $legacy_unsaved_keys = []; public function set_meta_legacy($meta_key, $value) { $this->legacy_custom_fields[$meta_key] = [0 => $value]; $this->legacy_unsaved_keys[] = $meta_key; } /** * Combines get_meta or get_prop (in legacy WC those were the same thing, in WC3.0+ there is a difference). * * @param string $field_name * @param bool $single */ public function get_field($field_name, $single = true) { if ($this->use_wc27) { $values = $this->get_meta($field_name, $single); if (!empty($values)) { return $values; } if (is_callable([$this->object, 'get_prop'])) { $value = $this->object->get_prop($field_name); if (!empty($value)) { return $single ? $value : [$value]; } } } return get_post_meta($this->get_product_or_variation_id(), $field_name, $single); } /** * Retrieve the id of the product or the variation id if it's a variant. * * (2.4.0: Moved from WJECF_Controller to WJECF_WC) * * @return bool|int The variation or product id. False if not a valid product */ public function get_product_or_variation_id() { if ($this->is_variation()) { return $this->get_variation_id(); } if ($this->object instanceof WC_Product) { return $this->get_id(); } return false; } /** * Retrieve the id of the parent product if it's a variation; otherwise retrieve this products id. * * (2.4.0: Moved from WJECF_Controller to WJECF_WC) * * @return bool|int The product id. False if this product is not a variation */ public function get_variable_product_id() { if (!$this->is_variation()) { return false; } if ($this->use_wc27 && is_callable([$this->object, 'get_parent_id'])) { return $this->object->get_parent_id(); } return wp_get_post_parent_id($this->object->variation_id); } public function get_name() { if ($this->use_wc27 && is_callable([$this->object, 'get_name'])) { return $this->object->get_name(); } return $this->object->post->post_title; } public function get_description() { if ($this->use_wc27 && is_callable([$this->object, 'get_description'])) { return $this->object->get_description(); } return $this->object->post->post_content; } public function get_short_description() { if ($this->use_wc27 && is_callable([$this->object, 'get_short_description'])) { return $this->object->get_short_description(); } return $this->object->post->post_excerpt; } public function get_status() { if ($this->use_wc27 && is_callable([$this->object, 'get_status'])) { return $this->object->get_status(); } return $this->object->post->post_status; } public function get_tag_ids() { if ($this->use_wc27 && is_callable([$this->object, 'get_tag_ids'])) { return $this->object->get_tag_ids(); } return $this->legacy_get_term_ids('product_tag'); } /** * If set, get the default attributes for a variable product. * * @param string $attribute_name * * @return string */ public function get_variation_default_attribute($attribute_name) { if ($this->use_wc27 && is_callable([$this->object, 'get_variation_default_attribute'])) { return $this->object->get_variation_default_attribute($attribute_name); } return ''; } protected function get_meta_legacy($meta_key, $single = true) { if (isset($this->legacy_custom_fields[$meta_key])) { $values = $this->legacy_custom_fields[$meta_key]; // WP_CLI::log( "LEGACY:" . print_r( $values, true )); if ($single) { return maybe_unserialize(reset($values)); // reset yields the first } return array_map('maybe_unserialize', $values); } return get_post_meta($this->get_product_or_variation_id(), $meta_key, $single); } /** * Get current variation id. * * @return bool|int False if this is not a variation */ protected function get_variation_id() { if (!$this->is_variation()) { return false; } if ($this->use_wc27 && is_callable([$this->object, 'get_id'])) { return $this->object->get_id(); } if ($this->use_wc27 && is_callable([$this->object, 'get_variation_id'])) { return $this->object->get_variation_id(); } return $this->object->variation_id; } protected function legacy_get_term_ids($taxonomy) { $terms = get_the_terms($this->get_id(), $taxonomy); if (false === $terms || is_wp_error($terms)) { return []; } return wp_list_pluck($terms, 'term_id'); } private function is_variation() { return $this->object instanceof WC_Product_Variation; } } class WJECF_Wrap_Customer extends WJECF_Wrap {}