Merge pull request #12123 from woocommerce/product-crud-grouped
[Product CRUD] Grouped products
This commit is contained in:
commit
05b0b34c96
|
@ -1386,7 +1386,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
|
|||
* @return bool
|
||||
*/
|
||||
public function has_child() {
|
||||
return false;
|
||||
return 0 < count( $this->get_children() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,15 +9,38 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
* Grouped products cannot be purchased - they are wrappers for other products.
|
||||
*
|
||||
* @class WC_Product_Grouped
|
||||
* @version 2.3.0
|
||||
* @version 2.7.0
|
||||
* @package WooCommerce/Classes/Products
|
||||
* @category Class
|
||||
* @author WooThemes
|
||||
*/
|
||||
class WC_Product_Grouped extends WC_Product {
|
||||
|
||||
/** @public array Array of child products/posts/variations. */
|
||||
public $children;
|
||||
/**
|
||||
* Stores product data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $extra_data = array(
|
||||
'children' => array(),
|
||||
);
|
||||
|
||||
/**
|
||||
* Merges grouped product data into the parent object.
|
||||
* @param int|WC_Product|object $product Product to init.
|
||||
*/
|
||||
public function __construct( $product = 0 ) {
|
||||
$this->data = array_merge( $this->data, $this->extra_data );
|
||||
parent::__construct( $product );
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Getters
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Methods for getting data from the product object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get internal type.
|
||||
|
@ -28,6 +50,15 @@ class WC_Product_Grouped extends WC_Product {
|
|||
return 'grouped';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the children of this product.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_children() {
|
||||
return $this->data['children'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the add to cart button text.
|
||||
*
|
||||
|
@ -38,79 +69,20 @@ class WC_Product_Grouped extends WC_Product {
|
|||
return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'View products', 'woocommerce' ), $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the products children posts.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function get_children() {
|
||||
if ( ! is_array( $this->children ) || empty( $this->children ) ) {
|
||||
$transient_name = 'wc_product_children_' . $this->id;
|
||||
$this->children = array_filter( array_map( 'absint', (array) get_transient( $transient_name ) ) );
|
||||
|
||||
if ( empty( $this->children ) ) {
|
||||
|
||||
$args = apply_filters( 'woocommerce_grouped_children_args', array(
|
||||
'post_parent' => $this->id,
|
||||
'post_type' => 'product',
|
||||
'orderby' => 'menu_order',
|
||||
'order' => 'ASC',
|
||||
'fields' => 'ids',
|
||||
'post_status' => 'publish',
|
||||
'numberposts' => -1,
|
||||
) );
|
||||
|
||||
$this->children = get_posts( $args );
|
||||
|
||||
set_transient( $transient_name, $this->children, DAY_IN_SECONDS * 30 );
|
||||
}
|
||||
}
|
||||
return (array) $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the product has any child product.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function has_child() {
|
||||
return sizeof( $this->get_children() ) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the product is on sale.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function is_on_sale() {
|
||||
$is_on_sale = false;
|
||||
|
||||
if ( $this->has_child() ) {
|
||||
|
||||
foreach ( $this->get_children() as $child_id ) {
|
||||
$sale_price = get_post_meta( $child_id, '_sale_price', true );
|
||||
if ( '' !== $sale_price && $sale_price >= 0 ) {
|
||||
$is_on_sale = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if ( $this->sale_price && $this->sale_price == $this->price ) {
|
||||
$is_on_sale = true;
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_product_is_on_sale', $is_on_sale, $this );
|
||||
global $wpdb;
|
||||
$on_sale = 1 === $wpdb->get_var( "SELECT 1 FROM $wpdb->postmeta WHERE meta_key = '_sale_price' AND meta_value > 0 AND post_id IN (" . implode( ',', array_map( 'esc_sql', $this->get_children() ) ) . ");" );
|
||||
return apply_filters( 'woocommerce_product_is_on_sale', $on_sale, $this );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns false if the product cannot be bought.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function is_purchasable() {
|
||||
|
@ -118,7 +90,7 @@ class WC_Product_Grouped extends WC_Product {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the price in html format.
|
||||
* Returns the price in html format. @todo consider moving to template function
|
||||
*
|
||||
* @access public
|
||||
* @param string $price (default: '')
|
||||
|
@ -129,7 +101,7 @@ class WC_Product_Grouped extends WC_Product {
|
|||
$child_prices = array();
|
||||
|
||||
foreach ( $this->get_children() as $child_id ) {
|
||||
$child = wc_get_product( $child_id );
|
||||
$child = wc_get_product( $child_id );
|
||||
if ( '' !== $child->get_price() ) {
|
||||
$child_prices[] = 'incl' === $tax_display_mode ? $child->get_price_including_tax() : $child->get_price_excluding_tax();
|
||||
}
|
||||
|
@ -158,4 +130,51 @@ class WC_Product_Grouped extends WC_Product {
|
|||
|
||||
return apply_filters( 'woocommerce_get_price_html', $price, $this );
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Setters
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Methods for getting data from the product object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return the children of this product.
|
||||
*
|
||||
* @param array $children
|
||||
*/
|
||||
public function set_children( $children ) {
|
||||
$this->data['children'] = array_filter( wp_parse_id_list( (array) $children ) );
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| CRUD methods
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reads a product from the database and sets its data to the class.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @param int $id Product ID.
|
||||
*/
|
||||
public function read( $id ) {
|
||||
parent::read( $id );
|
||||
|
||||
$this->set_props( array(
|
||||
'children' => wp_parse_id_list( get_post_meta( $id, '_children', true ) ),
|
||||
) );
|
||||
do_action( 'woocommerce_product_loaded', $this );
|
||||
do_action( 'woocommerce_product_' . $this->get_type() . '_loaded', $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that updates all the post meta for a grouped product.
|
||||
*/
|
||||
protected function update_post_meta() {
|
||||
parent::update_post_meta();
|
||||
update_post_meta( $this->get_id(), '_children', $this->get_children() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,33 @@ class WC_Helper_Product {
|
|||
return new WC_Product_Simple( $product );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create grouped product.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @return WC_Product_Grouped
|
||||
*/
|
||||
public static function create_grouped_product() {
|
||||
// Create the product
|
||||
$product = wp_insert_post( array(
|
||||
'post_title' => 'Dummy Grouped Product',
|
||||
'post_type' => 'product',
|
||||
'post_status' => 'publish',
|
||||
) );
|
||||
$simple_product_1 = self::create_simple_product( $product );
|
||||
$simple_product_2 = self::create_simple_product( $product );
|
||||
update_post_meta( $product, '_children', array( $simple_product_1->id, $simple_product_2->id ) );
|
||||
update_post_meta( $product, '_sku', 'DUMMY GROUPED SKU' );
|
||||
update_post_meta( $product, '_manage_stock', 'no' );
|
||||
update_post_meta( $product, '_tax_status', 'taxable' );
|
||||
update_post_meta( $product, '_downloadable', 'no' );
|
||||
update_post_meta( $product, '_virtual', 'no' );
|
||||
update_post_meta( $product, '_visibility', 'visible' );
|
||||
update_post_meta( $product, '_stock_status', 'instock' );
|
||||
return new WC_Product_Grouped( $product );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create external product.
|
||||
*
|
||||
|
@ -72,16 +99,8 @@ class WC_Helper_Product {
|
|||
update_post_meta( $product, '_regular_price', '10' );
|
||||
update_post_meta( $product, '_sale_price', '' );
|
||||
update_post_meta( $product, '_sku', 'DUMMY EXTERNAL SKU' );
|
||||
update_post_meta( $product, '_manage_stock', 'no' );
|
||||
update_post_meta( $product, '_tax_status', 'taxable' );
|
||||
update_post_meta( $product, '_downloadable', 'no' );
|
||||
update_post_meta( $product, '_virtual', 'no' );
|
||||
update_post_meta( $product, '_visibility', 'visible' );
|
||||
update_post_meta( $product, '_stock_status', 'instock' );
|
||||
|
||||
update_post_meta( $product, '_product_url', 'http://woocommerce.com' );
|
||||
update_post_meta( $product, '_button_text', 'Buy external product' );
|
||||
|
||||
return new WC_Product_External( $product );
|
||||
}
|
||||
|
||||
|
@ -287,12 +306,12 @@ class WC_Helper_Product {
|
|||
public static function create_product_review( $product_id, $review_content = 'Review content here' ) {
|
||||
$data = array(
|
||||
'comment_post_ID' => $product_id,
|
||||
'comment_author' => 'admin',
|
||||
'comment_author_email' => 'woo@woo.local',
|
||||
'comment_author_url' => '',
|
||||
'comment_author' => 'admin',
|
||||
'comment_author_email' => 'woo@woo.local',
|
||||
'comment_author_url' => '',
|
||||
'comment_date' => '2016-01-01T11:11:11',
|
||||
'comment_content' => $review_content,
|
||||
'comment_approved' => 1,
|
||||
'comment_content' => $review_content,
|
||||
'comment_approved' => 1,
|
||||
'comment_type' => 'review',
|
||||
);
|
||||
|
||||
|
|
|
@ -104,23 +104,86 @@ class WC_Tests_Product_CRUD extends WC_Unit_Test_Case {
|
|||
'purchase_note' => 'A note',
|
||||
'menu_order' => 2,
|
||||
);
|
||||
$product = new WC_Product;
|
||||
foreach ( $getters_and_setters as $function => $value ) {
|
||||
$product->{"set_{$function}"}( $value );
|
||||
}
|
||||
$product->create();
|
||||
$product = new WC_Product_Simple( $product->get_id() );
|
||||
foreach ( $getters_and_setters as $function => $value ) {
|
||||
$product = new WC_Product;
|
||||
foreach ( $getters_and_setters as $function => $value ) {
|
||||
$product->{"set_{$function}"}( $value );
|
||||
}
|
||||
$product->create();
|
||||
$product = new WC_Product_Simple( $product->get_id() );
|
||||
foreach ( $getters_and_setters as $function => $value ) {
|
||||
$this->assertEquals( $value, $product->{"get_{$function}"}(), $function );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Test creating a new grouped product.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function test_grouped_product_create() {
|
||||
$simple_product = WC_Helper_Product::create_simple_product();
|
||||
$product = new WC_Product_Grouped;
|
||||
$product->set_children( array( $simple_product->get_id() ) );
|
||||
$product->set_name( 'My Grouped Product' );
|
||||
$product->create();
|
||||
$read_product = new WC_Product_Grouped( $product->get_id() );
|
||||
$this->assertEquals( 'My Grouped Product', $read_product->get_name() );
|
||||
$this->assertEquals( array( $simple_product->get_id() ), $read_product->get_children() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting / reading an grouped product.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function test_grouped_product_read() {
|
||||
$product = WC_Helper_Product::create_grouped_product();
|
||||
$read_product = new WC_Product_Grouped( $product->get_id() );
|
||||
$this->assertEquals( 'Dummy Grouped Product', $read_product->get_name() );
|
||||
$this->assertEquals( 2, count( $read_product->get_children() ) );
|
||||
}
|
||||
/**
|
||||
* Test updating an grouped product.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function test_grouped_product_update() {
|
||||
$product = WC_Helper_Product::create_grouped_product();
|
||||
$simple_product = WC_Helper_Product::create_simple_product();
|
||||
$this->assertEquals( 'Dummy Grouped Product', $product->get_name() );
|
||||
$this->assertEquals( 2, count( $product->get_children() ) );
|
||||
$children = $product->get_children();
|
||||
$children[] = $simple_product->get_id();
|
||||
$product->set_children( $children );
|
||||
$product->set_name( 'Dummy Grouped Product 2' );
|
||||
$product->save();
|
||||
// Reread from database
|
||||
$product = new WC_Product_Grouped( $product->get_id() );
|
||||
$this->assertEquals( 3, count( $product->get_children() ) );
|
||||
$this->assertEquals( 'Dummy Grouped Product 2', $product->get_name() );
|
||||
}
|
||||
/**
|
||||
* Test grouped product setters and getters
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function test_grouped_product_getters_and_setters() {
|
||||
$getters_and_setters = array(
|
||||
'children' => array( 1, 2, 3 ),
|
||||
);
|
||||
$product = new WC_Product_Grouped;
|
||||
foreach ( $getters_and_setters as $function => $value ) {
|
||||
$product->{"set_{$function}"}( $value );
|
||||
$this->assertEquals( $value, $product->{"get_{$function}"}(), $function );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creating a new external product.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function test_external_product_create() {
|
||||
function test_external_product_create() {
|
||||
$product = new WC_Product_External;
|
||||
$product->set_regular_price( 42 );
|
||||
$product->set_button_text( 'Test CRUD' );
|
||||
|
|
Loading…
Reference in New Issue