You've already forked wc-composable-product
Upgrade to PHPUnit 10, add PHPCS with WPCS compliance, add phpcs CI job
All checks were successful
All checks were successful
- Upgrade PHPUnit 9.6 → 10, update phpunit.xml.dist schema - Add PHPCS 3.13 with WordPress-Extra + PHPCompatibilityWP standards - PHPCBF auto-fix + manual fixes for full WPCS compliance - Add phpcs job to release workflow (parallel with lint) - Pin composer platform to PHP 8.3 to prevent incompatible dep locks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace Magdev\WcComposableProduct;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Stock Manager Class
|
||||
@@ -20,15 +20,15 @@ class StockManager {
|
||||
*/
|
||||
public function __construct() {
|
||||
// Hook into order completion to reduce stock
|
||||
add_action('woocommerce_order_status_completed', [$this, 'reduce_stock_on_order_complete'], 10, 1);
|
||||
add_action('woocommerce_order_status_processing', [$this, 'reduce_stock_on_order_complete'], 10, 1);
|
||||
add_action( 'woocommerce_order_status_completed', array( $this, 'reduce_stock_on_order_complete' ), 10, 1 );
|
||||
add_action( 'woocommerce_order_status_processing', array( $this, 'reduce_stock_on_order_complete' ), 10, 1 );
|
||||
|
||||
// Hook into order cancellation/refund to restore stock
|
||||
add_action('woocommerce_order_status_cancelled', [$this, 'restore_stock_on_order_cancel'], 10, 1);
|
||||
add_action('woocommerce_order_status_refunded', [$this, 'restore_stock_on_order_cancel'], 10, 1);
|
||||
add_action( 'woocommerce_order_status_cancelled', array( $this, 'restore_stock_on_order_cancel' ), 10, 1 );
|
||||
add_action( 'woocommerce_order_status_refunded', array( $this, 'restore_stock_on_order_cancel' ), 10, 1 );
|
||||
|
||||
// Prevent double stock reduction
|
||||
add_filter('woocommerce_can_reduce_order_stock', [$this, 'prevent_composable_stock_reduction'], 10, 2);
|
||||
add_filter( 'woocommerce_can_reduce_order_stock', array( $this, 'prevent_composable_stock_reduction' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,42 +38,42 @@ class StockManager {
|
||||
* @param int $quantity Quantity of composable product being added
|
||||
* @return bool|string True if in stock, error message otherwise
|
||||
*/
|
||||
public function validate_stock_availability($selected_product_ids, $quantity = 1) {
|
||||
foreach ($selected_product_ids as $product_id) {
|
||||
$product = wc_get_product($product_id);
|
||||
public function validate_stock_availability( $selected_product_ids, $quantity = 1 ) {
|
||||
foreach ( $selected_product_ids as $product_id ) {
|
||||
$product = wc_get_product( $product_id );
|
||||
|
||||
if (!$product) {
|
||||
if ( ! $product ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip stock check if stock management is disabled for this product
|
||||
if (!$product->managing_stock()) {
|
||||
if ( ! $product->managing_stock() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stock_quantity = $product->get_stock_quantity();
|
||||
|
||||
// Check if product is in stock
|
||||
if (!$product->is_in_stock()) {
|
||||
if ( ! $product->is_in_stock() ) {
|
||||
return sprintf(
|
||||
/* translators: %s: product name */
|
||||
__('"%s" is out of stock and cannot be selected.', 'wc-composable-product'),
|
||||
__( '"%s" is out of stock and cannot be selected.', 'wc-composable-product' ),
|
||||
$product->get_name()
|
||||
);
|
||||
}
|
||||
|
||||
// Check if enough stock is available
|
||||
if ($stock_quantity !== null && $stock_quantity < $quantity) {
|
||||
if ( null !== $stock_quantity && $stock_quantity < $quantity ) {
|
||||
return sprintf(
|
||||
/* translators: 1: product name, 2: stock quantity */
|
||||
__('Only %2$d of "%1$s" are available in stock.', 'wc-composable-product'),
|
||||
__( 'Only %2$d of "%1$s" are available in stock.', 'wc-composable-product' ),
|
||||
$product->get_name(),
|
||||
$stock_quantity
|
||||
);
|
||||
}
|
||||
|
||||
// Check for backorders
|
||||
if ($product->backorders_allowed()) {
|
||||
if ( $product->backorders_allowed() ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -88,29 +88,29 @@ class StockManager {
|
||||
* @param int $required_quantity Required quantity
|
||||
* @return array Stock information [in_stock, stock_quantity, backorders_allowed]
|
||||
*/
|
||||
public function get_product_stock_info($product_id, $required_quantity = 1) {
|
||||
$product = wc_get_product($product_id);
|
||||
public function get_product_stock_info( $product_id, $required_quantity = 1 ) {
|
||||
$product = wc_get_product( $product_id );
|
||||
|
||||
if (!$product) {
|
||||
return [
|
||||
'in_stock' => false,
|
||||
'stock_quantity' => 0,
|
||||
if ( ! $product ) {
|
||||
return array(
|
||||
'in_stock' => false,
|
||||
'stock_quantity' => 0,
|
||||
'backorders_allowed' => false,
|
||||
'stock_status' => 'outofstock',
|
||||
];
|
||||
'stock_status' => 'outofstock',
|
||||
);
|
||||
}
|
||||
|
||||
$stock_quantity = $product->get_stock_quantity();
|
||||
$managing_stock = $product->managing_stock();
|
||||
|
||||
return [
|
||||
'in_stock' => $product->is_in_stock(),
|
||||
'stock_quantity' => $stock_quantity,
|
||||
return array(
|
||||
'in_stock' => $product->is_in_stock(),
|
||||
'stock_quantity' => $stock_quantity,
|
||||
'backorders_allowed' => $product->backorders_allowed(),
|
||||
'stock_status' => $product->get_stock_status(),
|
||||
'managing_stock' => $managing_stock,
|
||||
'has_enough_stock' => !$managing_stock || $stock_quantity === null || $stock_quantity >= $required_quantity,
|
||||
];
|
||||
'stock_status' => $product->get_stock_status(),
|
||||
'managing_stock' => $managing_stock,
|
||||
'has_enough_stock' => ! $managing_stock || null === $stock_quantity || $stock_quantity >= $required_quantity,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,54 +118,54 @@ class StockManager {
|
||||
*
|
||||
* @param int $order_id Order ID
|
||||
*/
|
||||
public function reduce_stock_on_order_complete($order_id) {
|
||||
$order = wc_get_order($order_id);
|
||||
public function reduce_stock_on_order_complete( $order_id ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if (!$order) {
|
||||
if ( ! $order ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if stock has already been reduced
|
||||
if ($order->get_meta('_composable_stock_reduced', true)) {
|
||||
if ( $order->get_meta( '_composable_stock_reduced', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($order->get_items() as $item) {
|
||||
foreach ( $order->get_items() as $item ) {
|
||||
$product = $item->get_product();
|
||||
|
||||
if (!$product || $product->get_type() !== 'composable') {
|
||||
if ( ! $product || $product->get_type() !== 'composable' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get selected products from order item meta
|
||||
$selected_products = $item->get_meta('_composable_products', true);
|
||||
$selected_products = $item->get_meta( '_composable_products', true );
|
||||
|
||||
if (empty($selected_products) || !is_array($selected_products)) {
|
||||
if ( empty( $selected_products ) || ! is_array( $selected_products ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$quantity = $item->get_quantity();
|
||||
|
||||
// Reduce stock for each selected product
|
||||
foreach ($selected_products as $product_id) {
|
||||
$selected_product = wc_get_product($product_id);
|
||||
foreach ( $selected_products as $product_id ) {
|
||||
$selected_product = wc_get_product( $product_id );
|
||||
|
||||
if (!$selected_product || !$selected_product->managing_stock()) {
|
||||
if ( ! $selected_product || ! $selected_product->managing_stock() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stock_quantity = $selected_product->get_stock_quantity();
|
||||
|
||||
if ($stock_quantity !== null) {
|
||||
if ( null !== $stock_quantity ) {
|
||||
$new_stock = $stock_quantity - $quantity;
|
||||
$selected_product->set_stock_quantity($new_stock);
|
||||
$selected_product->set_stock_quantity( $new_stock );
|
||||
$selected_product->save();
|
||||
|
||||
// Add order note
|
||||
$order->add_order_note(
|
||||
sprintf(
|
||||
/* translators: 1: product name, 2: quantity, 3: remaining stock */
|
||||
__('Stock reduced for "%1$s": -%2$d (remaining: %3$d)', 'wc-composable-product'),
|
||||
__( 'Stock reduced for "%1$s": -%2$d (remaining: %3$d)', 'wc-composable-product' ),
|
||||
$selected_product->get_name(),
|
||||
$quantity,
|
||||
$new_stock
|
||||
@@ -176,7 +176,7 @@ class StockManager {
|
||||
}
|
||||
|
||||
// Mark stock as reduced
|
||||
$order->update_meta_data('_composable_stock_reduced', true);
|
||||
$order->update_meta_data( '_composable_stock_reduced', true );
|
||||
$order->save();
|
||||
}
|
||||
|
||||
@@ -185,54 +185,54 @@ class StockManager {
|
||||
*
|
||||
* @param int $order_id Order ID
|
||||
*/
|
||||
public function restore_stock_on_order_cancel($order_id) {
|
||||
$order = wc_get_order($order_id);
|
||||
public function restore_stock_on_order_cancel( $order_id ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if (!$order) {
|
||||
if ( ! $order ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if stock was reduced
|
||||
if (!$order->get_meta('_composable_stock_reduced', true)) {
|
||||
if ( ! $order->get_meta( '_composable_stock_reduced', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($order->get_items() as $item) {
|
||||
foreach ( $order->get_items() as $item ) {
|
||||
$product = $item->get_product();
|
||||
|
||||
if (!$product || $product->get_type() !== 'composable') {
|
||||
if ( ! $product || $product->get_type() !== 'composable' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get selected products from order item meta
|
||||
$selected_products = $item->get_meta('_composable_products', true);
|
||||
$selected_products = $item->get_meta( '_composable_products', true );
|
||||
|
||||
if (empty($selected_products) || !is_array($selected_products)) {
|
||||
if ( empty( $selected_products ) || ! is_array( $selected_products ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$quantity = $item->get_quantity();
|
||||
|
||||
// Restore stock for each selected product
|
||||
foreach ($selected_products as $product_id) {
|
||||
$selected_product = wc_get_product($product_id);
|
||||
foreach ( $selected_products as $product_id ) {
|
||||
$selected_product = wc_get_product( $product_id );
|
||||
|
||||
if (!$selected_product || !$selected_product->managing_stock()) {
|
||||
if ( ! $selected_product || ! $selected_product->managing_stock() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stock_quantity = $selected_product->get_stock_quantity();
|
||||
|
||||
if ($stock_quantity !== null) {
|
||||
if ( null !== $stock_quantity ) {
|
||||
$new_stock = $stock_quantity + $quantity;
|
||||
$selected_product->set_stock_quantity($new_stock);
|
||||
$selected_product->set_stock_quantity( $new_stock );
|
||||
$selected_product->save();
|
||||
|
||||
// Add order note
|
||||
$order->add_order_note(
|
||||
sprintf(
|
||||
/* translators: 1: product name, 2: quantity, 3: new stock */
|
||||
__('Stock restored for "%1$s": +%2$d (total: %3$d)', 'wc-composable-product'),
|
||||
__( 'Stock restored for "%1$s": +%2$d (total: %3$d)', 'wc-composable-product' ),
|
||||
$selected_product->get_name(),
|
||||
$quantity,
|
||||
$new_stock
|
||||
@@ -243,7 +243,7 @@ class StockManager {
|
||||
}
|
||||
|
||||
// Mark stock as restored
|
||||
$order->update_meta_data('_composable_stock_reduced', false);
|
||||
$order->update_meta_data( '_composable_stock_reduced', false );
|
||||
$order->save();
|
||||
}
|
||||
|
||||
@@ -255,11 +255,11 @@ class StockManager {
|
||||
* @param \WC_Order $order Order object
|
||||
* @return bool
|
||||
*/
|
||||
public function prevent_composable_stock_reduction($reduce_stock, $order) {
|
||||
foreach ($order->get_items() as $item) {
|
||||
public function prevent_composable_stock_reduction( $reduce_stock, $order ) {
|
||||
foreach ( $order->get_items() as $item ) {
|
||||
$product = $item->get_product();
|
||||
|
||||
if ($product && $product->get_type() === 'composable') {
|
||||
if ( $product && $product->get_type() === 'composable' ) {
|
||||
// We'll handle stock reduction manually
|
||||
return false;
|
||||
}
|
||||
@@ -275,9 +275,9 @@ class StockManager {
|
||||
* @param string $cart_item_key Cart item key
|
||||
* @param array $values Cart item values
|
||||
*/
|
||||
public function store_selected_products_in_order($item, $cart_item_key, $values) {
|
||||
if (isset($values['composable_products']) && !empty($values['composable_products'])) {
|
||||
$item->add_meta_data('_composable_products', $values['composable_products'], true);
|
||||
public function store_selected_products_in_order( $item, $cart_item_key, $values ) {
|
||||
if ( isset( $values['composable_products'] ) && ! empty( $values['composable_products'] ) ) {
|
||||
$item->add_meta_data( '_composable_products', $values['composable_products'], true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user