prefix . 'usedkit_prices';
}
/** The price-history table; created on activation and whenever its version changes. */
function usedkit_prices_install() {
global $wpdb;
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta('CREATE TABLE ' . usedkit_prices_table() . ' (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
product_id bigint(20) unsigned NOT NULL,
price decimal(19,4) NOT NULL,
recorded_at datetime NOT NULL,
PRIMARY KEY (id),
KEY product_time (product_id, recorded_at)
) ' . $wpdb->get_charset_collate() . ';');
update_option('usedkit_prices_version', USEDKIT_PRICES_VERSION);
}
add_action('admin_init', function () {
if ((int) get_option('usedkit_prices_version') !== USEDKIT_PRICES_VERSION) {
usedkit_prices_install();
}
});
add_filter('usedkit_default_settings', function ($d) {
return $d + array('omnibus' => 'no', 'omnibus_days' => 30);
});
add_filter('usedkit_save_settings', function ($out, $post) {
return $out + array('omnibus' => !empty($post['omnibus']) ? 'yes' : 'no',
'omnibus_days' => max(1, min(90, absint($post['omnibus_days'] ?? 30))));
}, 10, 2);
add_action('usedkit_settings_rows', function ($s) { ?>
is_type('variable') || $product->is_type('grouped')) {
return;
}
$price = $product->get_price();
if ($price === '' || $price === null) {
return;
}
global $wpdb;
$table = usedkit_prices_table();
$last = $wpdb->get_var($wpdb->prepare(
"SELECT price FROM %i WHERE product_id = %d ORDER BY recorded_at DESC, id DESC LIMIT 1",
$table, $product->get_id()));
if ($last !== null && abs((float) $last - (float) $price) < 0.00001) {
return;
}
$wpdb->insert($table, array('product_id' => $product->get_id(), 'price' => (float) $price,
'recorded_at' => current_time('mysql', true)));
}
add_action('woocommerce_after_product_object_save', 'usedkit_record_price');
/**
* The lowest price in the `$days` before the current price took effect, or null with no
* history from before it. `$history` is [[unix time, price], ...] oldest first.
*
* The price in force when the window opened counts -- a price set 40 days ago and held
* until the discount was applied throughout the window.
*/
function usedkit_lowest_before($history, $current, $days = 30) {
$n = count($history);
if ($n === 0) {
return null;
}
// When did the current price begin? Walk back over the run of records at it.
$i = $n - 1;
if (abs($history[$i][1] - $current) > 0.00001) {
return null; // the history has not caught up with this price
}
while ($i > 0 && abs($history[$i - 1][1] - $current) < 0.00001) {
$i--;
}
if ($i === 0) {
return null; // nothing before the current price
}
$start = $history[$i][0];
$from = $start - $days * DAY_IN_SECONDS;
$lowest = null;
for ($k = 0; $k < $i; $k++) {
list($t, $p) = $history[$k];
$next = $history[$k + 1][0];
if ($next <= $from) {
continue; // replaced before the window opened
}
$lowest = $lowest === null ? $p : min($lowest, $p);
}
return $lowest;
}
function usedkit_price_history($product_id) {
global $wpdb;
$table = usedkit_prices_table();
$rows = $wpdb->get_results($wpdb->prepare(
"SELECT UNIX_TIMESTAMP(recorded_at) AS t, price FROM %i WHERE product_id = %d "
. "ORDER BY recorded_at, id", $table, $product_id), ARRAY_N);
return array_map(function ($r) { return array((int) $r[0], (float) $r[1]); }, $rows ?: array());
}
add_filter('woocommerce_get_price_html', function ($html, $product) {
$s = usedkit_settings();
if ($s['omnibus'] !== 'yes' || !$product->is_on_sale() || $product->is_type('variable')
|| $product->is_type('grouped') || is_admin()) {
return $html;
}
$lowest = usedkit_lowest_before(usedkit_price_history($product->get_id()),
(float) $product->get_price(), (int) $s['omnibus_days']);
if ($lowest === null) {
// No history from before the discount: the regular price was the price.
$lowest = (float) $product->get_regular_price();
}
if (!$lowest) {
return $html;
}
return $html . wp_kses(sprintf('%s %s',
/* translators: %d: number of days, 30 by default */
esc_html(sprintf(__('Lowest price in the %d days before the discount:', 'usedkit'), (int) $s['omnibus_days'])),
wp_kses_post(wc_price(wc_get_price_to_display($product, array('price' => $lowest))))), usedkit_allowed_html());
}, 20, 2);