You've already forked wc-composable-product
Implemented custom WooCommerce product type allowing customers to build their own product bundles by selecting from predefined sets of products. Features: - Custom "Composable Product" type with admin interface - Product selection by category, tag, or SKU - Configurable selection limits (global and per-product) - Dual pricing modes: fixed price or sum of selected products - Modern responsive frontend with Twig templates - AJAX add-to-cart functionality - Full internationalization support (.pot file) - WooCommerce settings integration - Comprehensive documentation Technical implementation: - PHP 8.3+ with PSR-4 autoloading - Twig 3.0 templating engine via Composer - Vanilla JavaScript with jQuery for frontend interactions - WordPress and WooCommerce hooks for seamless integration - Security: input sanitization, validation, and output escaping - Translation-ready with text domain 'wc-composable-product' Documentation: - README.md: Project overview and features - INSTALL.md: Installation and usage guide - IMPLEMENTATION.md: Technical architecture - CHANGELOG.md: Version history 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
217 lines
6.2 KiB
PHP
217 lines
6.2 KiB
PHP
<?php
|
|
/**
|
|
* Main Plugin Class
|
|
*
|
|
* @package WC_Composable_Product
|
|
*/
|
|
|
|
namespace WC_Composable_Product;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
/**
|
|
* Main plugin class - Singleton pattern
|
|
*/
|
|
class Plugin {
|
|
/**
|
|
* The single instance of the class
|
|
*
|
|
* @var Plugin
|
|
*/
|
|
protected static $instance = null;
|
|
|
|
/**
|
|
* Twig environment
|
|
*
|
|
* @var \Twig\Environment
|
|
*/
|
|
private $twig = null;
|
|
|
|
/**
|
|
* Main Plugin Instance
|
|
*
|
|
* Ensures only one instance is loaded or can be loaded.
|
|
*
|
|
* @return Plugin
|
|
*/
|
|
public static function instance() {
|
|
if (is_null(self::$instance)) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
private function __construct() {
|
|
$this->init_hooks();
|
|
$this->init_twig();
|
|
$this->includes();
|
|
}
|
|
|
|
/**
|
|
* Hook into WordPress and WooCommerce
|
|
*/
|
|
private function init_hooks() {
|
|
// Register product type
|
|
add_filter('product_type_selector', [$this, 'add_product_type']);
|
|
add_filter('woocommerce_product_class', [$this, 'product_class'], 10, 2);
|
|
|
|
// Enqueue scripts and styles
|
|
add_action('wp_enqueue_scripts', [$this, 'enqueue_frontend_scripts']);
|
|
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts']);
|
|
|
|
// Admin settings
|
|
add_filter('woocommerce_get_settings_pages', [$this, 'add_settings_page']);
|
|
}
|
|
|
|
/**
|
|
* Initialize Twig template engine
|
|
*/
|
|
private function init_twig() {
|
|
$loader = new \Twig\Loader\FilesystemLoader(WC_COMPOSABLE_PRODUCT_PATH . 'templates');
|
|
$this->twig = new \Twig\Environment($loader, [
|
|
'cache' => WC_COMPOSABLE_PRODUCT_PATH . 'cache',
|
|
'auto_reload' => true,
|
|
'debug' => defined('WP_DEBUG') && WP_DEBUG,
|
|
]);
|
|
|
|
// Add WordPress functions to Twig
|
|
$this->twig->addFunction(new \Twig\TwigFunction('__', function($text) {
|
|
return __($text, 'wc-composable-product');
|
|
}));
|
|
$this->twig->addFunction(new \Twig\TwigFunction('esc_html', 'esc_html'));
|
|
$this->twig->addFunction(new \Twig\TwigFunction('esc_attr', 'esc_attr'));
|
|
$this->twig->addFunction(new \Twig\TwigFunction('esc_url', 'esc_url'));
|
|
}
|
|
|
|
/**
|
|
* Include required files
|
|
*/
|
|
private function includes() {
|
|
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Admin/Settings.php';
|
|
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Admin/Product_Data.php';
|
|
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Product_Type.php';
|
|
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Cart_Handler.php';
|
|
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Product_Selector.php';
|
|
|
|
// Initialize components
|
|
new Admin\Product_Data();
|
|
new Cart_Handler();
|
|
}
|
|
|
|
/**
|
|
* Add composable product type to selector
|
|
*
|
|
* @param array $types Product types
|
|
* @return array
|
|
*/
|
|
public function add_product_type($types) {
|
|
$types['composable'] = __('Composable product', 'wc-composable-product');
|
|
return $types;
|
|
}
|
|
|
|
/**
|
|
* Use custom product class for composable products
|
|
*
|
|
* @param string $classname Product class name
|
|
* @param string $product_type Product type
|
|
* @return string
|
|
*/
|
|
public function product_class($classname, $product_type) {
|
|
if ($product_type === 'composable') {
|
|
$classname = 'WC_Composable_Product\Product_Type';
|
|
}
|
|
return $classname;
|
|
}
|
|
|
|
/**
|
|
* Enqueue frontend scripts and styles
|
|
*/
|
|
public function enqueue_frontend_scripts() {
|
|
if (is_product()) {
|
|
wp_enqueue_style(
|
|
'wc-composable-product',
|
|
WC_COMPOSABLE_PRODUCT_URL . 'assets/css/frontend.css',
|
|
[],
|
|
WC_COMPOSABLE_PRODUCT_VERSION
|
|
);
|
|
|
|
wp_enqueue_script(
|
|
'wc-composable-product',
|
|
WC_COMPOSABLE_PRODUCT_URL . 'assets/js/frontend.js',
|
|
['jquery'],
|
|
WC_COMPOSABLE_PRODUCT_VERSION,
|
|
true
|
|
);
|
|
|
|
wp_localize_script('wc-composable-product', 'wcComposableProduct', [
|
|
'ajax_url' => admin_url('admin-ajax.php'),
|
|
'nonce' => wp_create_nonce('wc_composable_product_nonce'),
|
|
'i18n' => [
|
|
'select_items' => __('Please select items', 'wc-composable-product'),
|
|
'max_items' => __('Maximum items selected', 'wc-composable-product'),
|
|
'min_items' => __('Please select at least one item', 'wc-composable-product'),
|
|
],
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enqueue admin scripts and styles
|
|
*/
|
|
public function enqueue_admin_scripts($hook) {
|
|
if ('post.php' === $hook || 'post-new.php' === $hook) {
|
|
global $post_type;
|
|
if ('product' === $post_type) {
|
|
wp_enqueue_style(
|
|
'wc-composable-product-admin',
|
|
WC_COMPOSABLE_PRODUCT_URL . 'assets/css/admin.css',
|
|
[],
|
|
WC_COMPOSABLE_PRODUCT_VERSION
|
|
);
|
|
|
|
wp_enqueue_script(
|
|
'wc-composable-product-admin',
|
|
WC_COMPOSABLE_PRODUCT_URL . 'assets/js/admin.js',
|
|
['jquery', 'wc-admin-product-meta-boxes'],
|
|
WC_COMPOSABLE_PRODUCT_VERSION,
|
|
true
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add settings page to WooCommerce
|
|
*
|
|
* @param array $settings WooCommerce settings pages
|
|
* @return array
|
|
*/
|
|
public function add_settings_page($settings) {
|
|
$settings[] = new Admin\Settings();
|
|
return $settings;
|
|
}
|
|
|
|
/**
|
|
* Get Twig environment
|
|
*
|
|
* @return \Twig\Environment
|
|
*/
|
|
public function get_twig() {
|
|
return $this->twig;
|
|
}
|
|
|
|
/**
|
|
* Render a Twig template
|
|
*
|
|
* @param string $template Template name
|
|
* @param array $context Template variables
|
|
* @return string
|
|
*/
|
|
public function render_template($template, $context = []) {
|
|
return $this->twig->render($template, $context);
|
|
}
|
|
}
|