diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml
index 587109b..8bb67e7 100644
--- a/.gitea/workflows/release.yml
+++ b/.gitea/workflows/release.yml
@@ -9,7 +9,7 @@ on:
push:
branches: [ main ]
paths:
- - 'master-file.php'
+ - 'siti-delivery-time-notices.php'
- 'includes/**'
- 'assets/**'
- 'languages/**'
@@ -18,8 +18,8 @@ jobs:
release:
uses: roberto/ci-workflows/.gitea/workflows/wp-plugin-release.yml@c6393ed47258d6f040ceeed3994b17b7faa3ef23
with:
- main_file: master-file.php
- slug: siti-plugin-template
+ main_file: siti-delivery-time-notices.php
+ slug: siti-delivery-time-notices
release_body: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_notes || '' }}
secrets:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
\ No newline at end of file
diff --git a/assets/js/levertijden.js b/assets/js/levertijden.js
new file mode 100644
index 0000000..937b11d
--- /dev/null
+++ b/assets/js/levertijden.js
@@ -0,0 +1,41 @@
+(function ($) {
+ $(function () {
+ var $card = $('.lb-levertijd-card');
+ if (!$card.length) {
+ return;
+ }
+
+ var $text = $card.find('.lb-levertijd-text');
+ var defaultText = $card.data('defaultText') || '';
+ var $form = $('.variations_form');
+
+ function updateCard(text) {
+ if (!text) {
+ $card.toggleClass('lb-levertijd-hidden', true).hide();
+ return;
+ }
+
+ $text.text(text);
+ $card.toggleClass('lb-levertijd-hidden', false).show();
+ }
+
+ if (!$form.length) {
+ updateCard(defaultText);
+ return;
+ }
+
+ updateCard(defaultText);
+
+ $form.on('found_variation', function (event, variation) {
+ if (variation && variation.lb_levertijd) {
+ updateCard(variation.lb_levertijd);
+ } else {
+ updateCard(defaultText);
+ }
+ });
+
+ $form.on('reset_data hide_variation', function () {
+ updateCard(defaultText);
+ });
+ });
+}(jQuery));
diff --git a/includes/SitiDeliveryTimeNotice.php b/includes/SitiDeliveryTimeNotice.php
new file mode 100644
index 0000000..2772cb2
--- /dev/null
+++ b/includes/SitiDeliveryTimeNotice.php
@@ -0,0 +1,581 @@
+
+ [
+ 'min' => 1,
+ 'max' => 2,
+ ],
+ 'suppliers' => [],
+ ];
+
+ $options = get_option(self::OPTION_KEY, []);
+ if (!is_array($options)) {
+ $options = [];
+ }
+
+ $options = wp_parse_args($options, $defaults);
+ $options['default_range'] = self::sanitize_range($options['default_range']);
+
+ if (!is_array($options['suppliers'])) {
+ $options['suppliers'] = [];
+ } else {
+ foreach ($options['suppliers'] as $key => $range) {
+ $options['suppliers'][$key] = self::sanitize_range($range);
+ }
+ }
+
+ $options['suppliers'] = self::ensure_known_suppliers($options['suppliers'], $options['default_range']);
+
+ return $options;
+ }
+
+ public static function register_settings_page(): void {
+ add_submenu_page(
+ 'woocommerce',
+ __('Levertijden', SITI_DELIVERY_TIME_NOTICES_SLUG),
+ __('Levertijden', SITI_DELIVERY_TIME_NOTICES_SLUG),
+ 'manage_woocommerce',
+ 'lb-levertijden',
+ [__CLASS__, 'render_settings_page']
+ );
+ }
+
+ public static function maybe_save_settings(): void {
+ if (!isset($_POST['lb_levertijden_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['lb_levertijden_nonce'])), 'lb_save_levertijden')) {
+ return;
+ }
+
+ if (!current_user_can('manage_woocommerce')) {
+ return;
+ }
+
+ $default_min = isset($_POST['lb_default_min']) ? absint($_POST['lb_default_min']) : 1;
+ $default_max = isset($_POST['lb_default_max']) ? absint($_POST['lb_default_max']) : $default_min;
+
+ $default_range = self::sanitize_range([
+ 'min' => $default_min,
+ 'max' => $default_max,
+ ]);
+
+ $suppliers = [];
+ if (!empty($_POST['lb_suppliers']) && is_array($_POST['lb_suppliers'])) {
+ $data = wp_unslash($_POST['lb_suppliers']);
+ $keys = $data['key'] ?? [];
+ $labels = $data['label'] ?? [];
+ $mins = $data['min'] ?? [];
+ $maxes = $data['max'] ?? [];
+ $count = max(count($keys), count($labels), count($mins), count($maxes));
+
+ for ($i = 0; $i < $count; $i++) {
+ $key = sanitize_key($keys[$i] ?? '');
+ $label = sanitize_text_field($labels[$i] ?? '');
+ $min = absint($mins[$i] ?? 0);
+ $max = absint($maxes[$i] ?? 0);
+
+ if ($key === '' || $label === '') {
+ continue;
+ }
+
+ $range = self::sanitize_range([
+ 'min' => $min,
+ 'max' => $max,
+ 'label' => $label,
+ ]);
+
+ $range['label'] = $label;
+ $suppliers[$key] = $range;
+ }
+ }
+
+ update_option(
+ self::OPTION_KEY,
+ [
+ 'default_range' => $default_range,
+ 'suppliers' => $suppliers,
+ ]
+ );
+
+ add_settings_error('lb_levertijden', 'lb_levertijden_saved', __('Levertijden opgeslagen.', SITI_DELIVERY_TIME_NOTICES_SLUG), 'updated');
+ }
+
+ public static function render_settings_page(): void {
+ $settings = self::get_settings();
+ $suppliers = $settings['suppliers'];
+ $select_options = self::get_supplier_dropdown_options(array_keys($suppliers));
+ settings_errors('lb_levertijden');
+ ?>
+
+
+
+
+ $label, 'min' => $range['min'], 'max' => $range['max']], $select_options); ?>
+
+
+ |
+ |
+ |
+ |
+ |
+ '',
+ 'min' => $default_range['min'] ?? 1,
+ 'max' => $default_range['max'] ?? 1,
+ ], $select_options);
+
+ return $content;
+ }
+
+ private static function sanitize_range(array $range): array {
+ $min = isset($range['min']) ? absint($range['min']) : 0;
+ $max = isset($range['max']) ? absint($range['max']) : 0;
+
+ if ($min === 0 && $max === 0) {
+ $min = 1;
+ $max = 1;
+ }
+
+ if ($max === 0) {
+ $max = $min;
+ }
+
+ if ($min === 0) {
+ $min = $max;
+ }
+
+ if ($max < $min) {
+ $temp = $min;
+ $min = $max;
+ $max = $temp;
+ }
+
+ return [
+ 'min' => max(1, $min),
+ 'max' => max(1, $max),
+ 'label' => $range['label'] ?? '',
+ ];
+ }
+
+ private static function ensure_known_suppliers(array $current, array $default_range): array {
+ $known = self::get_distinct_supplier_sources();
+ foreach ($known as $key => $label) {
+ if (!isset($current[$key])) {
+ $current[$key] = [
+ 'min' => $default_range['min'],
+ 'max' => $default_range['max'],
+ 'label' => $label ?: $key,
+ ];
+ continue;
+ }
+
+ if (empty($current[$key]['label']) && $label) {
+ $current[$key]['label'] = $label;
+ }
+ }
+
+ ksort($current);
+
+ return $current;
+ }
+
+ private static function get_supplier_dropdown_options(array $current_keys = []): array {
+ $options = [
+ '' => __('Selecteer leverancier', SITI_DELIVERY_TIME_NOTICES_SLUG),
+ ];
+
+ foreach (self::get_distinct_supplier_sources() as $key => $label) {
+ $options[$key] = $label ?: $key;
+ }
+
+ foreach ($current_keys as $key) {
+ if ($key !== '' && !isset($options[$key])) {
+ $options[$key] = $key;
+ }
+ }
+
+ return $options;
+ }
+
+ private static function render_supplier_select(string $selected, array $options): string {
+ if ($selected !== '' && !array_key_exists($selected, $options)) {
+ $options[$selected] = $selected;
+ }
+
+ $html = '';
+
+ return $html;
+ }
+
+ private static function get_distinct_supplier_sources(): array {
+ static $cache = null;
+ if ($cache !== null) {
+ return $cache;
+ }
+
+ global $wpdb;
+ $table = $wpdb->postmeta;
+ $rows = $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT DISTINCT meta_value FROM {$table} WHERE meta_key = %s AND meta_value <> ''",
+ '_wpci_supplier'
+ )
+ );
+
+ $cache = [];
+ if ($rows) {
+ foreach ($rows as $raw) {
+ foreach (self::normalize_supplier_values($raw) as $value) {
+ $key = sanitize_key($value);
+ if ($key === '' || isset($cache[$key])) {
+ continue;
+ }
+ $cache[$key] = $value;
+ }
+ }
+ }
+
+ return $cache;
+ }
+
+ private static function normalize_supplier_values($raw): array {
+ $result = [];
+ $value = maybe_unserialize($raw);
+
+ if (is_array($value)) {
+ array_walk_recursive($value, function ($item) use (&$result) {
+ if (is_scalar($item)) {
+ $item = trim((string) $item);
+ if ($item !== '') {
+ $result[] = $item;
+ }
+ }
+ });
+ } elseif (is_scalar($value)) {
+ $value = trim((string) $value);
+ if ($value !== '') {
+ $result[] = $value;
+ }
+ }
+
+ return $result;
+ }
+
+ public static function render_product_override_field(): void {
+ $settings = self::get_settings();
+ $choices = [
+ '' => __('Automatisch (voorraad / leverancier)', SITI_DELIVERY_TIME_NOTICES_SLUG),
+ 'default' => __('Altijd standaard levertijd', SITI_DELIVERY_TIME_NOTICES_SLUG),
+ ];
+
+ foreach ($settings['suppliers'] as $key => $range) {
+ $choices[$key] = sprintf(
+ '%s (%s)',
+ $range['label'] ?: $key,
+ self::format_range_text($range)
+ );
+ }
+
+ global $post;
+ $value = get_post_meta($post->ID, self::META_SUPPLIER_OVERRIDE, true);
+
+ echo '';
+ woocommerce_wp_select([
+ 'id' => self::META_SUPPLIER_OVERRIDE,
+ 'label' => __('Levertijd leverancier', SITI_DELIVERY_TIME_NOTICES_SLUG),
+ 'options' => $choices,
+ 'value' => $value,
+ 'desc_tip' => false,
+ 'description' => __('Kies een leverancier om de levertijd van dit product te forceren.', SITI_DELIVERY_TIME_NOTICES_SLUG),
+ ]);
+ echo '
';
+ }
+
+ public static function save_product_override_field(int $post_id): void {
+ if (!isset($_POST[self::META_SUPPLIER_OVERRIDE])) {
+ return;
+ }
+
+ $value = sanitize_text_field(wp_unslash($_POST[self::META_SUPPLIER_OVERRIDE]));
+ update_post_meta($post_id, self::META_SUPPLIER_OVERRIDE, $value);
+ }
+
+ public static function filter_availability_text(string $availability, WC_Product $product): string {
+ $text = self::get_levertijd_text($product, false);
+ if ($text) {
+ return sprintf(__('Verwachte levertijd: %s', SITI_DELIVERY_TIME_NOTICES_SLUG), $text);
+ }
+
+ return $availability;
+ }
+
+ public static function render_card_below_cart(): void {
+ if (!is_product()) {
+ return;
+ }
+
+ global $product;
+ if (!$product instanceof WC_Product) {
+ return;
+ }
+
+ if ($product->is_type('variable')) {
+ $text = '';
+ } else {
+ $text = self::get_levertijd_text($product);
+ if (!$text) {
+ return;
+ }
+ }
+
+ echo '';
+ echo '
' . esc_html($text) . '
';
+ echo '
';
+ }
+
+ public static function add_variation_levertijd_data($variation_data, $product = null, $variation = null) {
+ if ($variation instanceof WC_Product_Variation) {
+ $text = self::get_levertijd_text($variation);
+ $variation_data['lb_levertijd'] = $text;
+ }
+
+ return $variation_data;
+ }
+
+ private static function get_product_meta_with_parent(WC_Product $product, string $key, bool $allow_array = false) {
+ $value = get_post_meta($product->get_id(), $key, true);
+ if (($value === '' || ($allow_array && empty($value))) && $product->get_parent_id()) {
+ $value = get_post_meta($product->get_parent_id(), $key, true);
+ }
+
+ if (!$allow_array && is_array($value)) {
+ return '';
+ }
+
+ return $value;
+ }
+
+ private static function get_levertijd_text(WC_Product $product, bool $with_label = true): string {
+ $range = self::resolve_range_for_product($product);
+ if (!$range) {
+ return '';
+ }
+
+ $text = self::format_range_text($range);
+ if ($text === '') {
+ return '';
+ }
+
+ return $with_label ? sprintf(__('Verwachte levertijd: %s', SITI_DELIVERY_TIME_NOTICES_SLUG), $text) : $text;
+ }
+
+ private static function resolve_range_for_product(WC_Product $product): ?array {
+ $settings = self::get_settings();
+
+ $override = self::get_product_meta_with_parent($product, self::META_SUPPLIER_OVERRIDE);
+ if ($override && $override !== 'auto') {
+ if ($override === 'default') {
+ return $settings['default_range'];
+ }
+
+ if (isset($settings['suppliers'][$override])) {
+ return $settings['suppliers'][$override];
+ }
+ }
+
+ if (self::has_local_stock($product)) {
+ return $settings['default_range'];
+ }
+
+ $supplier = self::get_supplier_key($product);
+ if ($supplier && isset($settings['suppliers'][$supplier])) {
+ return $settings['suppliers'][$supplier];
+ }
+
+ return $settings['default_range'];
+ }
+
+ private static function has_local_stock(WC_Product $product): bool {
+ $explicit_stock = self::get_product_meta_with_parent($product, '_stock');
+ if ($explicit_stock !== '') {
+ $qty = function_exists('wc_stock_amount') ? wc_stock_amount($explicit_stock) : (int) $explicit_stock;
+ return $qty > 0;
+ }
+
+ if ($product->managing_stock()) {
+ $qty = $product->get_stock_quantity();
+ if ($qty !== null) {
+ return $qty > 0;
+ }
+ }
+
+ return $product->is_in_stock();
+ }
+
+ private static function get_supplier_key(WC_Product $product): string {
+ $supplier_meta = self::get_product_meta_with_parent($product, '_wpci_supplier', true);
+ if ($supplier_meta === '' || $supplier_meta === null) {
+ return '';
+ }
+
+ $supplier = $supplier_meta;
+ if (is_string($supplier) && is_serialized($supplier)) {
+ $maybe = maybe_unserialize($supplier);
+ if (is_array($maybe)) {
+ $supplier = $maybe;
+ }
+ }
+
+ if (is_array($supplier)) {
+ $supplier = reset($supplier);
+ }
+
+ return sanitize_key((string) $supplier);
+ }
+
+ private static function format_range_text(array $range): string {
+ $min = absint($range['min'] ?? 0);
+ $max = absint($range['max'] ?? 0);
+
+ if ($min === 0 && $max === 0) {
+ return '';
+ }
+
+ if ($max === 0) {
+ $max = $min;
+ }
+
+ if ($min === $max) {
+ $text = sprintf(_n('%d werkdag', '%d werkdagen', $min, SITI_DELIVERY_TIME_NOTICES_SLUG), $min);
+ } else {
+ $text = sprintf(__('van %d tot %d werkdagen', SITI_DELIVERY_TIME_NOTICES_SLUG), $min, $max);
+ }
+
+ return $text;
+ }
+}
diff --git a/master-file.php b/siti-delivery-time-notices.php
similarity index 64%
rename from master-file.php
rename to siti-delivery-time-notices.php
index ab2c274..6f5b973 100644
--- a/master-file.php
+++ b/siti-delivery-time-notices.php
@@ -1,6 +1,6 @@
set_owner( 'roberto' );
-$updater->set_repository( 'siti-plugin-template' );
-$updater->initialize();
\ No newline at end of file
+$updater->set_repository( SITI_DELIVERY_TIME_NOTICES_SLUG );
+$updater->initialize();
+
+SitiDeliveryTimeNotice::init();
\ No newline at end of file