03
WP Block - Hot Offers
A two-part WordPress feature: an infinite CSS marquee carousel of top-performing miners, and a Telegram webhook that automatically parses price lists from a channel and updates product prices in the catalog.
WordPressGutenbergReactTelegram APIPHP
"The manager posts a price list in Telegram. The catalog updates itself."
CSS
marquee - no JS animation, pure keyframes
webhook
Telegram - WordPress REST API - ACF update
2%
hashrate matching tolerance for price slot lookup
4
fallback states: updated - new hashrate - slots full - not found
How it works
Telegram channel post→
Webhook - /wp-json/ms/v1/tg-webhook→
Secret token validation→
Parse price lines (regex)→
Normalize model names→
Match - update_field()→
Report back to Telegram
Project Structure
parts/hot-deals.phpqueries miners, scores by daily income, selects top 4, triples array for CSS loopinc/tg-channel.phpREST webhook handler, price parser, normalizer, slot matcher, report senderPOST /wp-json/ms/v1/tg-webhookreceives Telegram channel_post, validates secret, routes: price message vs regular postGET /wp-json/ms/v1/tg-postsreturns last 5 channel posts from transient, falls back to scraping t.me/s/channelms2026_pending_prices optionstores unmatched price lines for manual review - new hashrate variants and unknown modelsNotable detail
When a price line cannot be matched - new hashrate variant or product not yet in catalog - it is stored in a pending_prices option for manual review. The manager gets an itemized Telegram report: what was updated, what needs attention, and which products have not had prices updated in 14+ days.
Code
// Price message detection + line parser
function ms2026_is_price_message(string $text): bool {
return mb_strpos($text, '🔵') === 0
&& mb_strpos($text, 'в наличии РФ') !== false;
}
// Each line: ModelName 100TH 1500 USDT
preg_match(
'/\s*(бу\s+)?(.+?)\s+([\d,\.]+)\s*(Mh|Th|TH|GH|kSol)\s*[-]\s*([\d\s,\.]+)\s*USDT/iu',
$line, $m
);
// Normalize model name for fuzzy matching
function ms2026_normalize_name(string $name): string {
$name = mb_strtolower(trim($name));
$name = preg_replace('/^бу\s+/u', '', $name);
$name = str_replace('+', 'plus', $name);
foreach (['hydro','pro','mini','home','plus'] as $suffix) {
$name = preg_replace('/\s*'.$suffix.'\s*/u', ' '.$suffix.' ', $name);
}
return trim(preg_replace('/\s+/', ' ', $name));
}
// Match hashrate with 2% tolerance across H1H4 slots
for ($i = 1; $i <= 4; $i++) {
$slot_th = get_field('h'.$i.'_th', $pid);
$diff = abs((float)$slot_th - $parsed['hashrate']);
if ($diff <= $parsed['hashrate'] * 0.02) {
update_field('h'.$i.'_price', $parsed['price'], $pid);
break;
}
}Features
- •Hot Deals carousel: selects top miners by daily income - up to 2 "Новинка" badges + top by ROI
- •Cards triplicated in PHP for seamless CSS loop - no JS cloning required
- •Animation speed calculated dynamically: card_count - (280px + 24px gap) - 60px/s
- •Pause on hover via CSS animation-play-state, respects prefers-reduced-motion
- •Telegram webhook receives channel_post events via REST API endpoint
- •Secret token validated with hash_equals() - constant-time comparison, timing-attack safe
- •Price message detection: starts with 🔵, contains "в наличии РФ"
- •Regex parser extracts model name, hashrate (TH/GH/kSol/MH normalized to TH), price in USDT
- •Model name normalization: lowercase, strip "бу", expand "+", add spaces before suffixes (pro/hydro/mini)
- •Hashrate slot matching with 2% tolerance - finds correct H1H4 slot per product
- •Unmatched prices stored in ms2026_pending_prices option for manual review
- •Report sent back to Telegram: updated / new hashrate variant / slots full / not found in catalog
- •Fallback: if webhook transient is empty, scrapes t.me/s/channel HTML for last 5 posts