int (seconds, default 15) * 'blocking' => bool (default true; false for fire-and-forget) * 'headers' => extra headers (merged; cannot override signing headers) * @return array|\WP_Error Same return shape as wp_remote_post. */ public static function post($url, $body_array, $opts = array()) { if (strpos($url, 'http') !== 0) { $url = rtrim(ADVOCATE_LOOP_API_URL, '/') . '/' . ltrim($url, '/'); } $api_key = get_option('advocate_loop_api_key'); $brand_id = get_option('advocate_loop_brand_id'); $secret = get_option('advocate_loop_ss'); $json = wp_json_encode($body_array); if ($json === false) { return new \WP_Error('al_json_encode_failed', 'Failed to encode request body'); } $headers = array( 'Content-Type' => 'application/json', 'X-API-Key' => $api_key, 'X-Brand-ID' => $brand_id, ); if (!empty($secret)) { $timestamp = time(); $path = wp_parse_url($url, PHP_URL_PATH); $body_hash = hash('sha256', $json); $canonical = $timestamp . "\n" . 'POST' . "\n" . $path . "\n" . $body_hash; $signature = hash_hmac('sha256', $canonical, $secret); $headers['X-AL-Signature'] = $signature; $headers['X-AL-Timestamp'] = (string) $timestamp; } if (!empty($opts['headers']) && is_array($opts['headers'])) { $headers = array_merge($opts['headers'], $headers); } $request_args = array( 'headers' => $headers, 'body' => $json, 'timeout' => isset($opts['timeout']) ? (int) $opts['timeout'] : 15, 'blocking' => isset($opts['blocking']) ? (bool) $opts['blocking'] : true, ); return wp_remote_post($url, $request_args); } /** * Given a decoded /api/v1/account response, silently persist the signing * secret if present. Called from the verify-connection handler. * Never echoes or returns the secret. * * @param array $account_response Decoded JSON from /api/v1/account * @return bool true if a secret was saved, false otherwise */ public static function maybe_store_secret($account_response) { if (!is_array($account_response)) { return false; } $secret = null; if (isset($account_response['signing_secret'])) { $secret = $account_response['signing_secret']; } elseif (isset($account_response['data']['signing_secret'])) { $secret = $account_response['data']['signing_secret']; } if (!empty($secret) && is_string($secret)) { update_option('advocate_loop_ss', $secret); return true; } return false; } }