'yes');
});
add_filter('usedkit_save_settings', function ($out, $post) {
return $out + array('reference' => !empty($post['reference']) ? 'yes' : 'no');
}, 10, 2);
add_action('usedkit_settings_rows', function ($s) { ?>
|
|
key]: stored ones while the title is unchanged, the
* rest asked of the service in one call and stored. When the service cannot be reached
* (or is not to be asked: a customer's page view does not wait on it) the title's words
* stand in, unstored, so it is asked again next time.
*/
function usedkit_model_keys($products, $ask_service = true) {
$out = array();
$ask = array();
foreach ($products as $p) {
$for = md5(USEDKIT_KEYS_VERSION . $p->get_name());
if ($p->get_meta('_usedkit_model_for') === $for && $p->get_meta('_usedkit_model') !== '') {
$out[$p->get_id()] = $p->get_meta('_usedkit_model');
} else {
$ask[$p->get_id()] = $p;
}
}
foreach (array_chunk($ask, 500, true) as $chunk) {
$res = $ask_service ? usedkit_call('/v1/keys', array('external_ids' => array_map('strval', array_keys($chunk))))
: new WP_Error('usedkit_not_asked', '');
$found = (!is_wp_error($res) && wp_remote_retrieve_response_code($res) === 200)
? (json_decode(wp_remote_retrieve_body($res), true)['products'] ?? array()) : null;
foreach ($chunk as $id => $p) {
$key = $found[(string) $id]['key'] ?? '';
$key = $key ?: usedkit_plain_key($p->get_name());
$out[$id] = $key;
if ($found !== null && $key !== '') {
update_post_meta($id, '_usedkit_model', $key);
update_post_meta($id, '_usedkit_model_for', md5(USEDKIT_KEYS_VERSION . $p->get_name()));
// The model's name as the service knows it, for its page (seo.php).
update_post_meta($id, '_usedkit_model_label', (string) ($found[(string) $id]['label'] ?? ''));
}
}
}
return $out;
}
/** The model key a customer's words name (the trade-in form). */
function usedkit_query_key($query) {
$res = usedkit_call('/v1/keys', array('queries' => array($query)));
$found = (!is_wp_error($res) && wp_remote_retrieve_response_code($res) === 200)
? (json_decode(wp_remote_retrieve_body($res), true)['queries'][$query]['key'] ?? '') : '';
return $found ?: usedkit_plain_key($query);
}
/** What a product sold for: the order's price where recorded, else its price. */
function usedkit_sold_price($product) {
$p = $product->get_meta('_usedkit_sold_price');
return $p !== '' ? (float) $p : (float) $product->get_price();
}
/** Every sale of the last years by model key, [key => [sale, ...]]; kept half a day,
* rebuilt when an item sells or comes back. */
function usedkit_sales_index() {
$index = get_transient('usedkit_sales_index');
if (is_array($index)) {
return $index;
}
$products = wc_get_products(array('limit' => 3000, 'stock_status' => 'outofstock', 'status' => array('publish', 'private'),
'meta_key' => '_usedkit_sold_at', 'meta_compare' => '>=',
'meta_value' => time() - USEDKIT_REFERENCE_YEARS * 365 * DAY_IN_SECONDS));
$keys = usedkit_model_keys($products);
$index = array();
foreach ($products as $p) {
$key = $keys[$p->get_id()] ?? '';
if ($key === '') {
continue;
}
$sold = (int) $p->get_meta('_usedkit_sold_at');
$listed = $p->get_date_created() ? $p->get_date_created()->getTimestamp() : null;
$index[$key][] = array('id' => $p->get_id(), 'price' => usedkit_sold_price($p), 'at' => $sold,
'days' => $listed ? max(0, (int) round(($sold - $listed) / DAY_IN_SECONDS)) : null,
'grade' => function_exists('usedkit_condition') ? usedkit_condition($p) : '');
}
set_transient('usedkit_sales_index', $index, 12 * HOUR_IN_SECONDS);
return $index;
}
function usedkit_sales_index_reset() {
delete_transient('usedkit_sales_index');
}
add_action('woocommerce_product_set_stock_status', 'usedkit_sales_index_reset');
add_action('usedkit_sold_price_recorded', 'usedkit_sales_index_reset');
/** The reference for a key, leaving one product out (the one being priced). */
function usedkit_reference($key, $except = 0) {
if ($key === '') {
return null;
}
$sales = array_filter(usedkit_sales_index()[$key] ?? array(), function ($s) use ($except) {
return $s['id'] !== $except;
});
return usedkit_reference_stats($sales);
}
function usedkit_product_reference($product) {
$keys = usedkit_model_keys(array($product));
return usedkit_reference($keys[$product->get_id()] ?? '', $product->get_id());
}
/** "4 sold: median 410 € (350–460 €), typically 12 days to sell." */
function usedkit_reference_text($r) {
$range = $r['count'] > 1 ? ' (' . usedkit_money($r['low']) . '–' . usedkit_money($r['high']) . ')' : '';
/* translators: 1: number sold, 2: median price, 3: price range in parentheses or nothing */
$text = sprintf(_n('%1$d sold: %2$s%3$s.', '%1$d sold: median %2$s%3$s.', $r['count'], 'usedkit'),
$r['count'], usedkit_money($r['median']), $range);
if ($r['days'] !== null) {
/* translators: %d: number of days */
$text .= ' ' . sprintf(_n('Typically %d day to sell.', 'Typically %d days to sell.', $r['days'], 'usedkit'), $r['days']);
}
return $text;
}
/* A box beside the price while editing an item. */
add_action('add_meta_boxes', function () {
if (!usedkit_reference_on()) {
return;
}
add_meta_box('usedkit_reference', __('Your sales of this model', 'usedkit'), function ($post) {
$product = wc_get_product($post->ID);
$r = $product && $product->get_name() !== '' ? usedkit_product_reference($product) : null;
if (!$r) {
echo '' . esc_html__('None sold yet: the first one sets the price.', 'usedkit') . '
';
return;
}
echo '' . esc_html(usedkit_reference_text($r)) . '
';
$grades = function_exists('usedkit_grade_names') ? usedkit_grade_names() : array();
foreach ($r['sales'] as $s) {
printf('- %s · %s%s
', esc_url(get_edit_post_link($s['id'])),
esc_html(wp_date(get_option('date_format'), $s['at'])), wp_kses_post(wc_price($s['price'])),
isset($grades[$s['grade']]) ? ' · ' . esc_html($grades[$s['grade']]) : '');
}
echo '
';
}, 'product', 'side', 'default');
});