04
WP Plugin - Quick Price Manager
A custom WordPress admin plugin for bulk price management of ASIC miners. Inline editing, CSV import/export, badge management, and stale price alerts - all on one page.
WordPressPHPACFMySQL
"Update prices for 100 devices without opening a single product page."
4
hashrate variants per device (H1-H4)
AJAX
save without page reload
CSV
bulk import + export with hashrate columns
7 days
stale price threshold with color alerts
How it works
Admin page render→
Inline price input→
CSV import → fill fields→
AJAX POST → PHP handler→
update_post_meta + ACF→
_price_updated_at timestamp
Project Structure
inc/price-manager.phpadmin page render, AJAX handlers, ACF hook, stale price noticems2026_save_prices_ajax()validates nonce, updates h1_price-h4_price via post_meta + ACF, stamps _price_updated_atms2026_update_badge_ajax()validates badge value against ACF choices whitelist before savingms2026_acf_track_price_update()ACF save_post hook - compares old vs new prices, only updates timestamp on real changems2026_outdated_prices_notice()WP_Query finds products where _price_updated_at is older than 7 days - admin notice with linkNotable detail
CSV import runs entirely client-side - the file is parsed in the browser, matching rows to product blocks by model name, and highlighting changed fields in yellow before any data is sent to the server.
Code
// CSV import - client-side, no server round-trip
importBtn.addEventListener('click', function () {
var reader = new FileReader();
reader.onload = function (e) {
var rows = e.target.result.split(/\r?\n/);
// Auto-detect separator: ; or ,
var sep = rows[0].indexOf(';') !== -1 ? ';' : ',';
// New format: model_name;h1_th;h2_th;h3_th;h4_th;h1_price
// Old format: model_name;h1_price;h2_price
var priceStart = rows[0].toLowerCase().includes('h1_th') ? 5 : 1;
rows.slice(1).forEach(function (row) {
var cols = row.split(sep).map(c => c.trim().replace(/^"|"$/g, ''));
var modelName = cols[0];
document.querySelectorAll('.ms2026-price-block').forEach(function (block) {
if (block.dataset.model.toLowerCase() === modelName.toLowerCase()) {
block.querySelectorAll('.ms2026-price-input').forEach(function (inp, j) {
var newPrice = cols[priceStart + j] || '';
if (newPrice) {
inp.value = newPrice;
inp.style.backgroundColor = '#fcf3cf'; // highlight changed
}
});
}
});
});
};
reader.readAsText(fileInput.files[0], 'UTF-8');
});
// AJAX save - only sends fields that were actually changed
saveBtn.addEventListener('click', function () {
var data = {};
document.querySelectorAll('.ms2026-price-input').forEach(function (inp) {
if (!inp.value.trim()) return; // skip unchanged
var match = inp.name.match(/prices\[(\d+)\]\[(h\d+_price)\]/);
if (match) {
if (!data[match[1]]) data[match[1]] = {};
data[match[1]][match[2]] = inp.value.trim();
}
});
// POST to wp_ajax_ms2026_save_prices
});Screenshots

Features
- •Single admin page lists all miner products with all hashrate variants inline
- •Inline price editing - type new price, click Save - AJAX saves without reload
- •CSV import: upload file - fields auto-fill highlighted in yellow - review - save
- •CSV export: downloads current prices with hashrate columns (model_name; h1_th-h4_th; h1_price-h4_price)
- •Badge management per product - dropdown updates via separate AJAX call instantly
- •Filter by brand and algorithm - URL-based, no JS required
- •Stale price indicator: green < 3 days - yellow 3-7 days - red > 7 days
- •Admin notice on product list: "N products with outdated prices - Update prices"
- •Prices saved via update_post_meta + update_field (ACF) simultaneously for full compatibility
- •ACF hook tracks price changes - _price_updated_at only updates when value actually changes