Upgrade to PHPUnit 10, add PHPCS with WPCS compliance, add phpcs CI job
All checks were successful
Create Release Package / PHP Lint (push) Successful in 48s
Create Release Package / PHP CodeSniffer (push) Successful in 52s
Create Release Package / PHP Unit (push) Successful in 53s
Create Release Package / build-release (push) Successful in 59s

- 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:
2026-03-01 13:25:02 +01:00
parent a7d6a57f01
commit dea1b055b2
16 changed files with 2006 additions and 1365 deletions

View File

@@ -7,7 +7,7 @@
namespace Magdev\WcComposableProduct;
defined('ABSPATH') || exit;
defined( 'ABSPATH' ) || exit;
/**
* Product Selector Class
@@ -15,63 +15,64 @@ defined('ABSPATH') || exit;
* Handles rendering the product selection interface
*/
class ProductSelector {
/**
* Render product selector
*
* @param ProductType $product Composable product
*/
public static function render($product) {
if (!$product || $product->get_type() !== 'composable') {
return;
}
/**
* Render product selector
*
* @param ProductType $product Composable product
*/
public static function render( $product ) {
if ( ! $product || $product->get_type() !== 'composable' ) {
return;
}
$available_products = $product->get_available_products();
$selection_limit = $product->get_selection_limit();
$pricing_mode = $product->get_pricing_mode();
$available_products = $product->get_available_products();
$selection_limit = $product->get_selection_limit();
$pricing_mode = $product->get_pricing_mode();
$show_images = get_option('wc_composable_show_images', 'yes') === 'yes';
$show_prices = get_option('wc_composable_show_prices', 'yes') === 'yes';
$show_total = get_option('wc_composable_show_total', 'yes') === 'yes';
$show_images = get_option( 'wc_composable_show_images', 'yes' ) === 'yes';
$show_prices = get_option( 'wc_composable_show_prices', 'yes' ) === 'yes';
$show_total = get_option( 'wc_composable_show_total', 'yes' ) === 'yes';
// Get stock manager for stock information
$stock_manager = new StockManager();
// Get stock manager for stock information
$stock_manager = new StockManager();
// Prepare product data for template
$products_data = [];
foreach ($available_products as $available_product) {
$stock_info = $stock_manager->get_product_stock_info($available_product->get_id());
// Prepare product data for template
$products_data = array();
foreach ( $available_products as $available_product ) {
$stock_info = $stock_manager->get_product_stock_info( $available_product->get_id() );
$products_data[] = [
'id' => $available_product->get_id(),
'name' => $available_product->get_name(),
'price' => $available_product->get_price(),
'price_html' => $available_product->get_price_html(),
'image_url' => wp_get_attachment_image_url($available_product->get_image_id(), 'thumbnail'),
'permalink' => $available_product->get_permalink(),
'stock_status' => $stock_info['stock_status'],
'in_stock' => $stock_info['in_stock'],
'stock_quantity' => $stock_info['stock_quantity'],
'managing_stock' => $stock_info['managing_stock'],
'backorders_allowed' => $stock_info['backorders_allowed'],
];
}
$products_data[] = array(
'id' => $available_product->get_id(),
'name' => $available_product->get_name(),
'price' => $available_product->get_price(),
'price_html' => $available_product->get_price_html(),
'image_url' => wp_get_attachment_image_url( $available_product->get_image_id(), 'thumbnail' ),
'permalink' => $available_product->get_permalink(),
'stock_status' => $stock_info['stock_status'],
'in_stock' => $stock_info['in_stock'],
'stock_quantity' => $stock_info['stock_quantity'],
'managing_stock' => $stock_info['managing_stock'],
'backorders_allowed' => $stock_info['backorders_allowed'],
);
}
$context = [
'product_id' => $product->get_id(),
'products' => $products_data,
'selection_limit' => $selection_limit,
'pricing_mode' => $pricing_mode,
'show_images' => $show_images,
'show_prices' => $show_prices,
'show_total' => $show_total,
'fixed_price' => $product->get_price(),
'fixed_price_html' => wc_price($product->get_price()),
'zero_price_html' => wc_price(0),
'currency_symbol' => get_woocommerce_currency_symbol(),
];
$context = array(
'product_id' => $product->get_id(),
'products' => $products_data,
'selection_limit' => $selection_limit,
'pricing_mode' => $pricing_mode,
'show_images' => $show_images,
'show_prices' => $show_prices,
'show_total' => $show_total,
'fixed_price' => $product->get_price(),
'fixed_price_html' => wc_price( $product->get_price() ),
'zero_price_html' => wc_price( 0 ),
'currency_symbol' => get_woocommerce_currency_symbol(),
);
// Render template
$plugin = Plugin::instance();
echo $plugin->render_template('product-selector.twig', $context);
}
// Render template — Twig handles escaping via registered esc_html/esc_attr/esc_url functions.
$plugin = Plugin::instance();
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped by Twig template.
echo $plugin->render_template( 'product-selector.twig', $context );
}
}