'no', 'reserve_hours' => 24);
});
add_filter('usedkit_save_settings', function ($out, $post) {
return $out + array('reserve' => !empty($post['reserve']) ? 'yes' : 'no',
'reserve_hours' => max(1, min(168, absint($post['reserve_hours'] ?? 24))));
}, 10, 2);
add_action('usedkit_settings_rows', function ($s) { ?>
|
|
get_meta('_usedkit_reserved_until');
if ($until && $until <= time()) {
usedkit_release($product);
return 0;
}
return $until;
}
function usedkit_release($product) {
$product->delete_meta_data('_usedkit_reserved_until');
$product->delete_meta_data('_usedkit_reserved_by');
$product->save_meta_data();
wc_delete_product_transients($product->get_id());
}
/** Where the shop's mail goes: the trade-in address, else the site's. */
function usedkit_shop_email() {
$s = usedkit_settings();
return $s['trade_email'] ?: get_option('admin_email');
}
/** The store's address from WooCommerce's settings, one line. */
function usedkit_store_address() {
$parts = array(get_option('woocommerce_store_address'), get_option('woocommerce_store_address_2'),
trim(get_option('woocommerce_store_postcode') . ' ' . get_option('woocommerce_store_city')));
return implode(', ', array_filter(array_map('trim', $parts)));
}
add_filter('woocommerce_is_purchasable', function ($ok, $product) {
return $ok && !(usedkit_reserve_on() && usedkit_reserved_until($product));
}, 10, 2);
add_action('woocommerce_single_product_summary', function () {
global $product;
if (!$product || !usedkit_reserve_on() || !$product->is_in_stock() || !$product->is_type('simple')) {
return;
}
$msgs = array('reserved' => array('ok', __('Reserved for you. We have emailed you the details.', 'usedkit')),
'taken' => array('err', __('Someone reserved this a moment ago.', 'usedkit')),
'invalid' => array('err', __('Please fill in your name and a valid email address.', 'usedkit')),
'busy' => array('err', __('Too many requests. Please try again later.', 'usedkit')));
$state = usedkit_form_state($msgs);
$until = usedkit_reserved_until($product);
if ($until) {
$when = wp_date(get_option('date_format') . ' ' . get_option('time_format'), $until);
/* translators: %s: date and time */
$held = sprintf(__('Reserved until %s.', 'usedkit'), $when);
echo wp_kses('' . usedkit_icon('clock') . esc_html($held) . '
' . $state, usedkit_allowed_html());
return;
} ?>
>
is_in_stock() || $product->get_status() !== 'publish') {
$go('taken');
}
if ($name === '' || !is_email($email)) {
$go('invalid');
}
if (usedkit_reserved_until($product)) {
$go('taken');
}
if (!usedkit_rate_ok('reserve', 3)) {
$go('busy');
}
$until = time() + (int) usedkit_settings()['reserve_hours'] * HOUR_IN_SECONDS;
$product->update_meta_data('_usedkit_reserved_until', $until);
$product->update_meta_data('_usedkit_reserved_by', array('name' => $name, 'email' => $email, 'phone' => $phone, 'at' => time()));
$product->save_meta_data();
wc_delete_product_transients($id);
$when = wp_date(get_option('date_format') . ' ' . get_option('time_format'), $until);
$shop = get_bloginfo('name');
$address = usedkit_store_address();
/* translators: 1: item, 2: date and time */
wp_mail($email, sprintf(__('Reserved: %1$s until %2$s', 'usedkit'), $product->get_name(), $when),
/* translators: 1: customer's name, 2: item, 3: date and time, 4: shop name, 5: shop address */
sprintf(__("Hi %1\$s,\n\n%2\$s is reserved for you until %3\$s. Come and see it at %4\$s%5\$s.\n\nIf you change your mind, just reply to this email.", 'usedkit'),
$name, $product->get_name(), $when, $shop, $address ? ', ' . $address : ''),
array('Reply-To: ' . $shop . ' <' . usedkit_shop_email() . '>'));
wp_mail(usedkit_shop_email(),
/* translators: %s: item */
sprintf(__('Reservation: %s', 'usedkit'), $product->get_name()),
/* translators: 1: item, 2: date and time, 3: name, 4: email, 5: phone, 6: link to the product in the admin */
sprintf(__("%1\$s is reserved until %2\$s for:\n\n%3\$s\n%4\$s\n%5\$s\n\nRelease it or mark it sold: %6\$s", 'usedkit'),
$product->get_name(), $when, $name, $email, $phone, admin_url('post.php?action=edit&post=' . $id)),
array('Reply-To: ' . $name . ' <' . $email . '>'));
$go('reserved');
}
add_action('admin_post_usedkit_reserve', 'usedkit_handle_reserve');
add_action('admin_post_nopriv_usedkit_reserve', 'usedkit_handle_reserve');
/* On the item's edit screen: who holds it, and release or sold. */
add_action('add_meta_boxes', function () {
if (!usedkit_reserve_on()) {
return;
}
$product = wc_get_product(get_the_ID());
if (!$product || !usedkit_reserved_until($product)) {
return;
}
add_meta_box('usedkit_hold', __('Reserved', 'usedkit'), function ($post) {
$product = wc_get_product($post->ID);
$by = (array) $product->get_meta('_usedkit_reserved_by');
printf('%s
%s
%s
%s
', esc_html(sprintf(
/* translators: %s: date and time */
__('Until %s for', 'usedkit'), wp_date(get_option('date_format') . ' ' . get_option('time_format'), usedkit_reserved_until($product)))),
esc_html($by['name'] ?? ''), esc_html($by['email'] ?? ''), esc_html($by['phone'] ?? ''));
foreach (array('release' => __('Release', 'usedkit'), 'sold' => __('Sold in the shop', 'usedkit')) as $do => $label) {
printf('%s ', esc_url(wp_nonce_url(admin_url('admin-post.php?action=usedkit_hold&do=' . $do . '&product=' . $post->ID), 'usedkit_hold_' . $post->ID)), esc_html($label));
}
}, 'product', 'side', 'high');
});
add_action('admin_post_usedkit_hold', function () {
$id = absint($_GET['product'] ?? 0);
check_admin_referer('usedkit_hold_' . $id);
if (!current_user_can('edit_product', $id) || !($product = wc_get_product($id))) {
wp_die(esc_html__('Not allowed.', 'usedkit'));
}
usedkit_release($product);
if (sanitize_key($_GET['do'] ?? '') === 'sold') {
$product = wc_get_product($id);
if ($product->managing_stock()) {
$product->set_stock_quantity(0);
}
$product->set_stock_status('outofstock');
$product->save();
}
wp_safe_redirect(admin_url('post.php?action=edit&post=' . $id));
exit;
});
/* Held items in the product list. */
add_filter('woocommerce_admin_stock_html', function ($html, $product) {
if (usedkit_reserve_on() && ($until = usedkit_reserved_until($product))) {
/* translators: %s: date and time */
$html .= '
' . esc_html(sprintf(__('Reserved until %s', 'usedkit'), wp_date('j.n. H:i', $until))) . '';
}
return $html;
}, 10, 2);