[
'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;
}
}