{\rtf1\ansi\ansicpg1252\cocoartf2822 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \f0\fs24 \cf0 /i', "\\n", $s);\ $s = wp_strip_all_tags($s);\ return $s;\ \}\ private function rephrase_title($src_title) \{\ $t = $this->normalize_space($this->strip_html($src_title));\ $t = preg_replace('/\\bNEW\\b/i', 'New', $t);\ $t = preg_replace('/\\bMINT\\b/i', 'Mint', $t);\ $patterns = [\ '%s \'96 stage-ready, great condition',\ 'Excellent %s \'96 set up & ready to play',\ '%s | clean setup, great action',\ '%s \'95 classic tone, dependable player',\ ];\ $choice = $patterns[array_rand($patterns)];\ $out = sprintf($choice, $t);\ return mb_substr($out, 0, 140);\ \}\ private function rephrase_description($src_desc) \{\ $desc = $this->strip_html($src_desc);\ $desc = $this->normalize_space($desc);\ $pairs = [\ '/\\bexcellent condition\\b/i' => 'in excellent shape',\ '/\\bvery good condition\\b/i' => 'in very good shape',\ '/\\bplays great\\b/i' => 'plays beautifully',\ '/\\bsetup\\b/i' => 'professional setup',\ '/\\bno issues\\b/i' => 'no functional issues',\ '/\\bcrack(-|\\s)?free\\b/i' => 'crack-free',\ '/\\bcosmetic wear\\b/i' => 'light cosmetic wear',\ '/\\bcollector(s)?\\b/i' => 'collectors',\ '/\\brare\\b/i' => 'hard to find',\ ];\ foreach ($pairs as $pat => $rep) $desc = preg_replace($pat, $rep, $desc);\ $bullets = "Highlights:\\n\'95 Professionally set up for smooth playability\\n\'95 Honest condition with detailed photos\\n\'95 Packed securely for shipping\\n\\n";\ $out = $bullets . $desc . "\\n\\nNotes: Please review photos and feel free to ask for close-ups or additional info.";\ return mb_substr($out, 0, 15000);\ \}\ private function compute_price($amount, $divider, $bump_pct = 30.0, $decimals = 2) \{\ $amount = floatval($amount);\ $divider = floatval($divider);\ $bump_pct = floatval($bump_pct);\ if ($divider <= 0) throw new Exception("Divider must be > 0.");\ $new = ($amount / $divider) * (1.0 + $bump_pct / 100.0);\ return round($new, $decimals);\ \}\ private function reverb_headers($token) \{\ return [\ 'Authorization' => 'Bearer ' . $token,\ 'Accept' => 'application/hal+json',\ 'Accept-Version' => '3.0',\ 'Content-Type' => 'application/hal+json',\ ];\ \}\ private function reverb_get_listing($token, $listing_id) \{\ $url = "https://api.reverb.com/api/listings/" . rawurlencode($listing_id);\ $res = wp_remote_get($url, [\ 'headers' => $this->reverb_headers($token),\ 'timeout' => 30,\ ]);\ if (is_wp_error($res)) throw new Exception($res->get_error_message());\ $code = wp_remote_retrieve_response_code($res);\ $body = wp_remote_retrieve_body($res);\ if ($code < 200 || $code >= 300) throw new Exception("GET failed ($code): " . $body);\ $json = json_decode($body, true);\ if (!is_array($json)) throw new Exception("Invalid JSON from Reverb.");\ return $json;\ \}\ private function reverb_update_listing($token, $listing_id, $payload) \{\ $url = "https://api.reverb.com/api/listings/" . rawurlencode($listing_id);\ $args = [\ 'headers' => $this->reverb_headers($token),\ 'timeout' => 60,\ 'method' => 'PUT',\ 'body' => wp_json_encode($payload),\ ];\ $res = wp_remote_request($url, $args);\ $code = wp_remote_retrieve_response_code($res);\ if ($code == 405 || $code == 501) \{\ // Fallback to PATCH\ $args['method'] = 'PATCH';\ $res = wp_remote_request($url, $args);\ $code = wp_remote_retrieve_response_code($res);\ \}\ $body = wp_remote_retrieve_body($res);\ if ($code < 200 || $code >= 300) return [false, $code, $body];\ return [true, $code, $body];\ \}\ \ /* -------------------- Page -------------------- */\ public function render_page() \{\ if (!current_user_can('manage_options')) return;\ \ $error = null; $preview = null; $result = null;\ \ if ($_SERVER['REQUEST_METHOD'] === 'POST' && check_admin_referer('rde_nonce_action','rde_nonce_field')) \{\ $token = isset($_POST['rde_token']) ? trim(wp_unslash($_POST['rde_token'])) : '';\ $src_id = isset($_POST['rde_src']) ? trim(wp_unslash($_POST['rde_src'])) : '';\ $target_id = isset($_POST['rde_target']) ? trim(wp_unslash($_POST['rde_target'])) : '';\ $divider = isset($_POST['rde_divider']) ? floatval($_POST['rde_divider']) : 1.0;\ $bump = isset($_POST['rde_bump']) ? floatval($_POST['rde_bump']) : 30.0;\ $keep_title = !empty($_POST['rde_keep_title']);\ $keep_desc = !empty($_POST['rde_keep_desc']);\ $do_update = !empty($_POST['rde_update']);\ \ try \{\ if (!$token || !$src_id || !$target_id)\ throw new Exception("Token, Source Listing ID, and Target Draft ID are required.");\ \ $src = $this->reverb_get_listing($token, $src_id);\ $src_price = isset($src['price']['amount']) ? floatval($src['price']['amount']) : 0.0;\ if ($src_price <= 0) throw new Exception("Source listing has no valid price.amount");\ \ $new_price = $this->compute_price($src_price, $divider, $bump, 2);\ \ $currency = isset($src['price']['currency']) ? $src['price']['currency'] : 'USD';\ $title = $keep_title ? null : $this->rephrase_title(isset($src['title']) ? $src['title'] : '');\ $desc = $keep_desc ? null : $this->rephrase_description(isset($src['description']) ? $src['description'] : '');\ \ $payload = [\ 'price' => ['amount' => (string)$new_price, 'currency' => $currency],\ 'draft' => true, // never publish\ ];\ if (isset($src['condition'])) $payload['condition'] = $src['condition'];\ if (array_key_exists('make',$src)) $payload['make'] = $src['make'];\ if (array_key_exists('model',$src)) $payload['model'] = $src['model'];\ if (array_key_exists('year',$src)) $payload['year'] = $src['year'];\ if (array_key_exists('sku',$src)) $payload['sku'] = $src['sku'];\ if (isset($src['category']) && is_array($src['category'])) \{\ $payload['category'] = array_intersect_key($src['category'], array_flip(['slug','uuid','id']));\ \}\ if ($title !== null) $payload['title'] = $title;\ if ($desc !== null) $payload['description'] = $desc;\ \ // Try reuse image URLs (per-account capability)\ if (isset($src['_links']['images']) && is_array($src['_links']['images'])) \{\ $urls = [];\ foreach ($src['_links']['images'] as $img) \{\ if (is_array($img) && !empty($img['href'])) $urls[] = $img['href'];\ \}\ if (!empty($urls)) $payload['photo_urls'] = $urls;\ \}\ \ // Always show preview\ $preview = [\ 'source_listing_id' => $src_id,\ 'target_draft_id' => $target_id,\ 'source_price' => $src_price,\ 'divider' => $divider,\ 'bump_pct' => $bump,\ 'computed_new_price'=> $new_price,\ 'payload' => $payload,\ ];\ \ if ($do_update) \{\ list($ok, $code, $body) = $this->reverb_update_listing($token, $target_id, $payload);\ $decoded = json_decode($body, true);\ $result = [\ 'ok' => $ok,\ 'code' => $code,\ 'body' => $decoded ? $decoded : $body,\ ];\ \}\ \ \} catch (Exception $e) \{\ $error = $e->getMessage();\ \}\ \}\ \ echo '
Update an existing draft by pulling fields from a source listing, adjusting price (divider + bump%), and optionally rephrasing title/description. Shipping is not modified.
';\ \ if ($error) \{\ echo 'Error: '.esc_html($error).'
Preview (no write unless you click Update Draft):
';\ echo '';\ echo esc_html(json_encode($preview, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));\ echo '
API Response ('.intval($result['code']).'):
';\ echo '';\ echo esc_html(is_string($result['body']) ? $result['body'] : json_encode($result['body'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));\ echo '