diff --git a/CHANGELOG.md b/CHANGELOG.md
index edd11f4..2b50ab3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.3.0] - 2026-03-01
+
+### Added
+
+- **Include Non-Public Products**: New option to include draft and private products in composable product selections
+ - Global setting under WooCommerce > Settings > Composable Products
+ - Per-product override in the Composable Options tab (Use global default / Yes / No)
+ - Useful when products should only be sold as part of a composition, not individually
+- Translations for the new setting in all 6 locales (de_DE, de_CH, fr_CH, it_CH + informal variants)
+
## [1.2.1] - 2026-03-01
### Changed
diff --git a/includes/Admin/Product_Data.php b/includes/Admin/Product_Data.php
index 79b7d0c..d0f5d24 100644
--- a/includes/Admin/Product_Data.php
+++ b/includes/Admin/Product_Data.php
@@ -95,6 +95,19 @@ class Product_Data {
'_composable_include_unpublished',
+ 'label' => __('Include Non-Public Products', 'wc-composable-product'),
+ 'description' => __('Allow draft and private products in the selection. Useful when products should only be sold as part of a composition.', 'wc-composable-product'),
+ 'desc_tip' => true,
+ 'options' => [
+ '' => __('Use global default', 'wc-composable-product'),
+ 'yes' => __('Yes', 'wc-composable-product'),
+ 'no' => __('No', 'wc-composable-product'),
+ ],
+ 'value' => get_post_meta($post->ID, '_composable_include_unpublished', true) ?: '',
+ ]);
+
woocommerce_wp_select([
'id' => '_composable_criteria_type',
'label' => __('Selection Criteria', 'wc-composable-product'),
@@ -181,6 +194,10 @@ class Product_Data {
$pricing_mode = isset($_POST['_composable_pricing_mode']) ? sanitize_text_field($_POST['_composable_pricing_mode']) : '';
update_post_meta($post_id, '_composable_pricing_mode', $pricing_mode);
+ // Save include unpublished
+ $include_unpublished = isset($_POST['_composable_include_unpublished']) ? sanitize_text_field($_POST['_composable_include_unpublished']) : '';
+ update_post_meta($post_id, '_composable_include_unpublished', $include_unpublished);
+
// Save criteria type
$criteria_type = isset($_POST['_composable_criteria_type']) ? sanitize_text_field($_POST['_composable_criteria_type']) : 'category';
update_post_meta($post_id, '_composable_criteria_type', $criteria_type);
diff --git a/includes/Admin/Settings.php b/includes/Admin/Settings.php
index fd56f4d..5f9bd12 100644
--- a/includes/Admin/Settings.php
+++ b/includes/Admin/Settings.php
@@ -60,6 +60,13 @@ class Settings extends \WC_Settings_Page {
],
'desc_tip' => true,
],
+ [
+ 'title' => __('Include Non-Public Products', 'wc-composable-product'),
+ 'desc' => __('Allow draft and private products to appear in composable product selections. Useful when products should only be sold as part of a composition, not individually.', 'wc-composable-product'),
+ 'id' => 'wc_composable_include_unpublished',
+ 'type' => 'checkbox',
+ 'default' => 'no',
+ ],
[
'title' => __('Show Product Images', 'wc-composable-product'),
'desc' => __('Display product images in the selection interface.', 'wc-composable-product'),
diff --git a/includes/Product_Type.php b/includes/Product_Type.php
index bbba38d..49b8dc6 100644
--- a/includes/Product_Type.php
+++ b/includes/Product_Type.php
@@ -97,6 +97,22 @@ class Product_Type extends \WC_Product {
return true;
}
+ /**
+ * Check if non-public products should be included
+ *
+ * @return bool
+ */
+ public function should_include_unpublished() {
+ $per_product = $this->get_meta('_composable_include_unpublished', true);
+ if ($per_product === 'yes') {
+ return true;
+ }
+ if ($per_product === 'no') {
+ return false;
+ }
+ return get_option('wc_composable_include_unpublished', 'no') === 'yes';
+ }
+
/**
* Get available products based on criteria
*
@@ -104,10 +120,11 @@ class Product_Type extends \WC_Product {
*/
public function get_available_products() {
$criteria = $this->get_selection_criteria();
+ $include_unpublished = $this->should_include_unpublished();
$args = [
'post_type' => 'product',
'posts_per_page' => -1,
- 'post_status' => 'publish',
+ 'post_status' => $include_unpublished ? ['publish', 'draft', 'private'] : 'publish',
'orderby' => 'title',
'order' => 'ASC',
];
@@ -177,11 +194,11 @@ class Product_Type extends \WC_Product {
$variation_ids = $product->get_children();
foreach ($variation_ids as $variation_id) {
$variation = wc_get_product($variation_id);
- if ($variation && $variation->is_purchasable()) {
+ if ($variation && ($include_unpublished || $variation->is_purchasable())) {
$products[] = $variation;
}
}
- } elseif ($product->is_purchasable()) {
+ } elseif ($include_unpublished || $product->is_purchasable()) {
$products[] = $product;
}
}
diff --git a/languages/wc-composable-product-de_CH.po b/languages/wc-composable-product-de_CH.po
index 99e6605..9c7befe 100755
--- a/languages/wc-composable-product-de_CH.po
+++ b/languages/wc-composable-product-de_CH.po
@@ -242,3 +242,23 @@ msgstr "An Lager"
#: templates/product-selector.twig
msgid "No products available for selection. Please configure the product criteria in the admin panel."
msgstr "Keine Produkte zur Auswahl verfügbar. Bitte konfigurieren Sie die Produktkriterien im Admin-Bereich."
+
+#: includes/Admin/Settings.php, includes/Admin/Product_Data.php
+msgid "Include Non-Public Products"
+msgstr "Nicht-öffentliche Produkte einbeziehen"
+
+#: includes/Admin/Settings.php
+msgid "Allow draft and private products to appear in composable product selections. Useful when products should only be sold as part of a composition, not individually."
+msgstr "Entwürfe und private Produkte in der Auswahl zusammenstellbarer Produkte anzeigen. Nützlich, wenn Produkte nur als Teil einer Zusammenstellung verkauft werden sollen, nicht einzeln."
+
+#: includes/Admin/Product_Data.php
+msgid "Allow draft and private products in the selection. Useful when products should only be sold as part of a composition."
+msgstr "Entwürfe und private Produkte in der Auswahl zulassen. Nützlich, wenn Produkte nur als Teil einer Zusammenstellung verkauft werden sollen."
+
+#: includes/Admin/Product_Data.php
+msgid "Yes"
+msgstr "Ja"
+
+#: includes/Admin/Product_Data.php
+msgid "No"
+msgstr "Nein"
diff --git a/languages/wc-composable-product-de_CH_informal.po b/languages/wc-composable-product-de_CH_informal.po
index f699bee..e53baa5 100755
--- a/languages/wc-composable-product-de_CH_informal.po
+++ b/languages/wc-composable-product-de_CH_informal.po
@@ -242,3 +242,23 @@ msgstr "An Lager"
#: templates/product-selector.twig
msgid "No products available for selection. Please configure the product criteria in the admin panel."
msgstr "Keine Produkte zur Auswahl verfügbar. Bitte konfiguriere die Produktkriterien im Admin-Bereich."
+
+#: includes/Admin/Settings.php, includes/Admin/Product_Data.php
+msgid "Include Non-Public Products"
+msgstr "Nicht-öffentliche Produkte einbeziehen"
+
+#: includes/Admin/Settings.php
+msgid "Allow draft and private products to appear in composable product selections. Useful when products should only be sold as part of a composition, not individually."
+msgstr "Entwürfe und private Produkte in der Auswahl zusammenstellbarer Produkte anzeigen. Nützlich, wenn Produkte nur als Teil einer Zusammenstellung verkauft werden sollen, nicht einzeln."
+
+#: includes/Admin/Product_Data.php
+msgid "Allow draft and private products in the selection. Useful when products should only be sold as part of a composition."
+msgstr "Entwürfe und private Produkte in der Auswahl zulassen. Nützlich, wenn Produkte nur als Teil einer Zusammenstellung verkauft werden sollen."
+
+#: includes/Admin/Product_Data.php
+msgid "Yes"
+msgstr "Ja"
+
+#: includes/Admin/Product_Data.php
+msgid "No"
+msgstr "Nein"
diff --git a/languages/wc-composable-product-de_DE.po b/languages/wc-composable-product-de_DE.po
index e5f45e0..3e34c44 100755
--- a/languages/wc-composable-product-de_DE.po
+++ b/languages/wc-composable-product-de_DE.po
@@ -242,3 +242,23 @@ msgstr "Auf Lager"
#: templates/product-selector.twig
msgid "No products available for selection. Please configure the product criteria in the admin panel."
msgstr "Keine Produkte zur Auswahl verfügbar. Bitte konfigurieren Sie die Produktkriterien im Admin-Bereich."
+
+#: includes/Admin/Settings.php, includes/Admin/Product_Data.php
+msgid "Include Non-Public Products"
+msgstr "Nicht-öffentliche Produkte einbeziehen"
+
+#: includes/Admin/Settings.php
+msgid "Allow draft and private products to appear in composable product selections. Useful when products should only be sold as part of a composition, not individually."
+msgstr "Entwürfe und private Produkte in der Auswahl zusammenstellbarer Produkte anzeigen. Nützlich, wenn Produkte nur als Teil einer Zusammenstellung verkauft werden sollen, nicht einzeln."
+
+#: includes/Admin/Product_Data.php
+msgid "Allow draft and private products in the selection. Useful when products should only be sold as part of a composition."
+msgstr "Entwürfe und private Produkte in der Auswahl zulassen. Nützlich, wenn Produkte nur als Teil einer Zusammenstellung verkauft werden sollen."
+
+#: includes/Admin/Product_Data.php
+msgid "Yes"
+msgstr "Ja"
+
+#: includes/Admin/Product_Data.php
+msgid "No"
+msgstr "Nein"
diff --git a/languages/wc-composable-product-de_DE_informal.po b/languages/wc-composable-product-de_DE_informal.po
index f69ed90..279047f 100755
--- a/languages/wc-composable-product-de_DE_informal.po
+++ b/languages/wc-composable-product-de_DE_informal.po
@@ -242,3 +242,23 @@ msgstr "Auf Lager"
#: templates/product-selector.twig
msgid "No products available for selection. Please configure the product criteria in the admin panel."
msgstr "Keine Produkte zur Auswahl verfügbar. Bitte konfiguriere die Produktkriterien im Admin-Bereich."
+
+#: includes/Admin/Settings.php, includes/Admin/Product_Data.php
+msgid "Include Non-Public Products"
+msgstr "Nicht-öffentliche Produkte einbeziehen"
+
+#: includes/Admin/Settings.php
+msgid "Allow draft and private products to appear in composable product selections. Useful when products should only be sold as part of a composition, not individually."
+msgstr "Entwürfe und private Produkte in der Auswahl zusammenstellbarer Produkte anzeigen. Nützlich, wenn Produkte nur als Teil einer Zusammenstellung verkauft werden sollen, nicht einzeln."
+
+#: includes/Admin/Product_Data.php
+msgid "Allow draft and private products in the selection. Useful when products should only be sold as part of a composition."
+msgstr "Entwürfe und private Produkte in der Auswahl zulassen. Nützlich, wenn Produkte nur als Teil einer Zusammenstellung verkauft werden sollen."
+
+#: includes/Admin/Product_Data.php
+msgid "Yes"
+msgstr "Ja"
+
+#: includes/Admin/Product_Data.php
+msgid "No"
+msgstr "Nein"
diff --git a/languages/wc-composable-product-fr_CH.po b/languages/wc-composable-product-fr_CH.po
index 37843e3..096c692 100755
--- a/languages/wc-composable-product-fr_CH.po
+++ b/languages/wc-composable-product-fr_CH.po
@@ -242,3 +242,23 @@ msgstr "En stock"
#: templates/product-selector.twig
msgid "No products available for selection. Please configure the product criteria in the admin panel."
msgstr "Aucun produit disponible pour la sélection. Veuillez configurer les critères de produit dans le panneau d'administration."
+
+#: includes/Admin/Settings.php, includes/Admin/Product_Data.php
+msgid "Include Non-Public Products"
+msgstr "Inclure les produits non publics"
+
+#: includes/Admin/Settings.php
+msgid "Allow draft and private products to appear in composable product selections. Useful when products should only be sold as part of a composition, not individually."
+msgstr "Autoriser les brouillons et les produits privés dans les sélections de produits composables. Utile lorsque les produits ne doivent être vendus que dans le cadre d'une composition, pas individuellement."
+
+#: includes/Admin/Product_Data.php
+msgid "Allow draft and private products in the selection. Useful when products should only be sold as part of a composition."
+msgstr "Autoriser les brouillons et les produits privés dans la sélection. Utile lorsque les produits ne doivent être vendus que dans le cadre d'une composition."
+
+#: includes/Admin/Product_Data.php
+msgid "Yes"
+msgstr "Oui"
+
+#: includes/Admin/Product_Data.php
+msgid "No"
+msgstr "Non"
diff --git a/languages/wc-composable-product-it_CH.po b/languages/wc-composable-product-it_CH.po
index cab8eb3..64feaec 100755
--- a/languages/wc-composable-product-it_CH.po
+++ b/languages/wc-composable-product-it_CH.po
@@ -242,3 +242,23 @@ msgstr "Disponibile"
#: templates/product-selector.twig
msgid "No products available for selection. Please configure the product criteria in the admin panel."
msgstr "Nessun prodotto disponibile per la selezione. Si prega di configurare i criteri del prodotto nel pannello di amministrazione."
+
+#: includes/Admin/Settings.php, includes/Admin/Product_Data.php
+msgid "Include Non-Public Products"
+msgstr "Includi prodotti non pubblici"
+
+#: includes/Admin/Settings.php
+msgid "Allow draft and private products to appear in composable product selections. Useful when products should only be sold as part of a composition, not individually."
+msgstr "Consenti la visualizzazione di bozze e prodotti privati nelle selezioni dei prodotti componibili. Utile quando i prodotti devono essere venduti solo come parte di una composizione, non singolarmente."
+
+#: includes/Admin/Product_Data.php
+msgid "Allow draft and private products in the selection. Useful when products should only be sold as part of a composition."
+msgstr "Consenti bozze e prodotti privati nella selezione. Utile quando i prodotti devono essere venduti solo come parte di una composizione."
+
+#: includes/Admin/Product_Data.php
+msgid "Yes"
+msgstr "Sì"
+
+#: includes/Admin/Product_Data.php
+msgid "No"
+msgstr "No"
diff --git a/languages/wc-composable-product.pot b/languages/wc-composable-product.pot
index 602318d..18a6321 100755
--- a/languages/wc-composable-product.pot
+++ b/languages/wc-composable-product.pot
@@ -241,3 +241,23 @@ msgstr ""
#: templates/product-selector.twig
msgid "No products available for selection. Please configure the product criteria in the admin panel."
msgstr ""
+
+#: includes/Admin/Settings.php, includes/Admin/Product_Data.php
+msgid "Include Non-Public Products"
+msgstr ""
+
+#: includes/Admin/Settings.php
+msgid "Allow draft and private products to appear in composable product selections. Useful when products should only be sold as part of a composition, not individually."
+msgstr ""
+
+#: includes/Admin/Product_Data.php
+msgid "Allow draft and private products in the selection. Useful when products should only be sold as part of a composition."
+msgstr ""
+
+#: includes/Admin/Product_Data.php
+msgid "Yes"
+msgstr ""
+
+#: includes/Admin/Product_Data.php
+msgid "No"
+msgstr ""
diff --git a/wc-composable-product.php b/wc-composable-product.php
index 596f9b7..c626461 100644
--- a/wc-composable-product.php
+++ b/wc-composable-product.php
@@ -4,7 +4,7 @@
* Plugin Name: WooCommerce Composable Products
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wc-composable-product
* Description: Create composable products where customers select a limited number of items from a configurable set
- * Version: 1.2.1
+ * Version: 1.3.0
* Author: Marco Graetsch
* Author URI: https://src.bundespruefstelle.ch/magdev
* License: GPL v3 or later
@@ -20,7 +20,7 @@
defined('ABSPATH') || exit;
// Define plugin constants
-define('WC_COMPOSABLE_PRODUCT_VERSION', '1.2.1');
+define('WC_COMPOSABLE_PRODUCT_VERSION', '1.3.0');
define('WC_COMPOSABLE_PRODUCT_FILE', __FILE__);
define('WC_COMPOSABLE_PRODUCT_PATH', plugin_dir_path(__FILE__));
define('WC_COMPOSABLE_PRODUCT_URL', plugin_dir_url(__FILE__));