MetalAPI
XAU3 997,89−1,54 %XAG53,936−1,51 %XPT1 554,47−0,83 %XPD1 047,03−0,44 %XCU6,5080+2,29 %WTI103,27+3,82 %BRENT111,70−1,30 %EUR1,120400−0,01 %GBP1,337500−0,01 %JPY0,0063761+0,14 %CHF1,213445−0,25 %TRY0,020125−0,12 %BTC80 679,98−0,12 %ETH2 351,16−0,20 %
Все статьи
ЗолотоPHPWordPressТуториал

API цен на золото на PHP: cURL, Guzzle и шорткод для WordPress

API цен на золото на PHP через cURL или Guzzle, кэшируемый шорткод [gold_price] для WordPress на transients и WP-Cron или виджет, для которого не нужен код.

Автор: MetalAPI Team··7 мин чтения

API цен на золото на PHP: основы

API цен на золото передаёт вашему коду на PHP текущую цену золота в формате JSON — для цен товаров, строки с ценой в теме оформления или ежедневного отчёта. В этом туториале рассмотрены обычный PHP с cURL, HTTP-клиент Guzzle и WordPress, где кэшируемый шорткод [gold_price], который обновляет WP-Cron, выводит цену в любой записи или на любой странице. Мы используем MetalAPI — JSON REST API для драгоценных и промышленных металлов, энергоносителей, валют и криптовалют.

Вам понадобится ключ API из личного кабинета MetalAPI. Ключи начинаются с mk_live_, а тариф Free включает 100 запросов в месяц с ежедневным обновлением цен и не требует банковской карты. Не храните ключ в коде: для обычного PHP поместите его в переменную окружения, а для WordPress — в wp-config.php.

Каждый эндпоинт — это запрос GET к адресу внутри https://metalapi.com/api/v1. Передавайте ключ в заголовке X-API-Key (или как Authorization: Bearer), а не в параметре запроса api_key, чтобы он не попадал в журналы доступа. Ответ /latest с примерными значениями из документации:

GET /api/v1/latest?base=USD&currencies=XAU,EUR
{
  "success": true,
  "timestamp": 1792834892,
  "date": "2026-10-24",
  "base": "USD",
  "rates": {
    "XAU": 0.0002501319,
    "USDXAU": 3997.89,
    "EUR": 0.8925,
    "USDEUR": 1.1204
  },
  "rate_limit": { "...": "..." }
}

rates.USDXAU — цена одной тройской унции золота в долларах; rates.XAU — обратная величина, количество унций за один доллар, поэтому никогда не показывайте её как цену. rates.USDEUR — цена одного евро в долларах; её плагин для WordPress использует для пересчёта. timestamp — время ценовых данных в секундах Unix.

Как получить цену золота на PHP с помощью cURL

Расширение cURL входит почти в любую установку PHP. Эта функция передаёт ключ в заголовке, задаёт тайм-ауты и превращает сетевые сбои и ошибки API в исключения:

gold.php
<?php
// PHP 8+ с расширением curl. Запуск: METALAPI_KEY=mk_live_... php gold.php
function metalapi(string $path, array $params = []): array
{
    $ch = curl_init('https://metalapi.com/api/v1/' . $path . '?' . http_build_query($params));
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_TIMEOUT        => 10,
        CURLOPT_HTTPHEADER     => ['X-API-Key: ' . getenv('METALAPI_KEY')],
    ]);
    $body = curl_exec($ch);
    if ($body === false) {
        throw new RuntimeException('Network error: ' . curl_error($ch));
    }
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    $data = json_decode($body, true);
    if (empty($data['success'])) {
        $code = $data['error']['code'] ?? $status;
        $info = $data['error']['info'] ?? "HTTP $status";
        throw new RuntimeException("MetalAPI $code: $info", $code);
    }
    return $data;
}

$data = metalapi('latest', ['base' => 'USD', 'currencies' => 'XAU']);
printf("Gold: %.2f USD per troy oz\n", $data['rates']['USDXAU']);
printf("Time: %s UTC\n", gmdate('Y-m-d H:i', $data['timestamp']));

С примерными значениями скрипт выводит Gold: 3997.89 USD per troy oz. Код исключения — это код ошибки MetalAPI: повторяйте 104 (поминутный лимит) через указанное в Retry-After число секунд, а 500 или 503 — с нарастающей задержкой, но для кодов вроде 102 (недействительный ключ), 105 (месячная квота исчерпана) или 106 (эндпоинт не входит в ваш тариф) устраняйте причину. Все коды перечислены в руководстве по обработке ошибок.

Guzzle вместо cURL

В проекте на Composer то же самое делает Guzzle, и строк получается меньше. Оставьте завершающий слеш в base_uri и запрашивайте относительные пути, например latest, потому что /latest Guzzle разрешает относительно корня домена. Кроме того, отключите http_errors, чтобы ответы с ошибками возвращали JSON-тело MetalAPI, а не выбрасывали исключение:

gold-guzzle.php
<?php
// composer require guzzlehttp/guzzle
require __DIR__ . '/vendor/autoload.php';

$client = new GuzzleHttp\Client([
    'base_uri'    => 'https://metalapi.com/api/v1/',
    'timeout'     => 10,
    'http_errors' => false,
    'headers'     => ['X-API-Key' => (string) getenv('METALAPI_KEY')],
]);

$res  = $client->get('latest', ['query' => ['base' => 'EUR', 'currencies' => 'XAU', 'unit' => 'gram']]);
$data = json_decode((string) $res->getBody(), true);

if (empty($data['success'])) {
    $code = $data['error']['code'] ?? $res->getStatusCode();
    throw new RuntimeException("MetalAPI $code: " . ($data['error']['info'] ?? $res->getReasonPhrase()), $code);
}
printf("Gold: %.2f EUR per gram\n", $data['rates']['EURXAU']);

Тайм-ауты и другие сетевые сбои по-прежнему выбрасывают ConnectException, поэтому перехватывайте его там, где сбой не должен ломать страницу.

Цена золота в WordPress: кэшируемый шорткод [gold_price]

Внутри WordPress используйте вместо этого wp_remote_get() из встроенного HTTP API. Два правила проектирования делают шорткод быстрым и экономным:

  • Не вызывайте API во время отрисовки страницы. Плагин хранит цены в transient, который WP-Cron обновляет в фоне. Посетители инициируют запрос, только когда transient отсутствует, например сразу после активации.
  • Запрашивайте все валюты одним вызовом. При базе USD и currencies=XAU,EUR,GBP ответ содержит долларовую цену золота и каждой валюты из одного снимка, поэтому золото в евро — это USDXAU ÷ USDEUR, а цена за грамм получается из 31,1034768 грамма в тройской унции. Один запрос на обновление покрывает все валюты и единицы.

Transients могут исчезнуть до истечения срока, например когда их вытесняет постоянный объектный кэш, поэтому плагин также хранит последние удачные цены в опции. Если обновление не удалось, он записывает ошибку в журнал и отдаёт эту копию в течение пяти минут. Сначала добавьте ключ в wp-config.php — над строкой, которая призывает прекратить редактирование:

wp-config.php
define( 'METALAPI_KEY', 'mk_live_your_key_here' );

Затем сохраните плагин как wp-content/plugins/metalapi-gold-price/metalapi-gold-price.php и активируйте его в разделе Плагины (Plugins):

metalapi-gold-price.php
<?php
/**
 * Plugin Name:  MetalAPI Gold Price
 * Description:  [gold_price] shortcode, cached in a transient and refreshed by WP-Cron.
 * Requires PHP: 8.0
 */
defined( 'ABSPATH' ) || exit;

const MGP_INTERVAL   = 600;              // секунды. Standard: 600, Lite: 3600, Free: 86400
const MGP_CURRENCIES = [ 'EUR', 'GBP' ]; // кроме USD — все валюты, которые используют ваши шорткоды
const MGP_GRAMS      = [ 'troy_oz' => 31.1034768, 'gram' => 1, 'kilogram' => 1000 ];

function mgp_refresh(): ?array {
    if ( ! defined( 'METALAPI_KEY' ) ) {
        return null;
    }
    $url  = add_query_arg(
        [ 'base' => 'USD', 'currencies' => implode( ',', [ 'XAU', ...MGP_CURRENCIES ] ) ],
        'https://metalapi.com/api/v1/latest'
    );
    $res  = wp_remote_get( $url, [ 'timeout' => 8, 'headers' => [ 'X-API-Key' => METALAPI_KEY ] ] );
    $data = is_wp_error( $res ) ? null : json_decode( wp_remote_retrieve_body( $res ), true );

    if ( empty( $data['success'] ) ) {
        error_log( 'MetalAPI refresh failed: ' . ( is_wp_error( $res ) ? $res->get_error_message() : wp_remote_retrieve_body( $res ) ) );
        $last = get_option( 'mgp_prices_last' );
        if ( $last ) {
            set_transient( 'mgp_prices', $last, 5 * MINUTE_IN_SECONDS ); // пауза, сохраняем последние удачные цены
        }
        return $last ?: null;
    }

    $per_oz = [ 'USD' => $data['rates']['USDXAU'] ];
    foreach ( MGP_CURRENCIES as $cur ) {
        if ( ! empty( $data['rates'][ "USD$cur" ] ) ) {
            $per_oz[ $cur ] = $data['rates']['USDXAU'] / $data['rates'][ "USD$cur" ];
        }
    }
    $prices = [ 'per_oz' => $per_oz, 'time' => $data['timestamp'] ];
    set_transient( 'mgp_prices', $prices, 2 * MGP_INTERVAL ); // переживёт один запоздавший запуск cron
    update_option( 'mgp_prices_last', $prices, false );       // запасной вариант, если transient вытеснен
    return $prices;
}

function mgp_prices(): ?array {
    return get_transient( 'mgp_prices' ) ?: mgp_refresh();
}

add_shortcode( 'gold_price', function ( $atts ): string {
    $a    = shortcode_atts( [ 'currency' => 'USD', 'unit' => 'troy_oz', 'decimals' => 2 ], $atts, 'gold_price' );
    $cur  = strtoupper( $a['currency'] );
    $unit = strtolower( $a['unit'] );
    $p    = mgp_prices();
    if ( ! $p || ! isset( $p['per_oz'][ $cur ] ) || ! array_key_exists( $unit, MGP_GRAMS ) ) {
        return '';
    }
    $price = $p['per_oz'][ $cur ] / MGP_GRAMS['troy_oz'] * MGP_GRAMS[ $unit ];
    return sprintf(
        '<span class="gold-price">%s %s / %s</span> <small>%s</small>',
        esc_html( number_format_i18n( $price, absint( $a['decimals'] ) ) ),
        esc_html( $cur ),
        esc_html( str_replace( '_', ' ', $unit ) ),
        esc_html( wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $p['time'] ) )
    );
} );

// WP-Cron: фоновое обновление один раз за интервал.
add_filter( 'cron_schedules', function ( array $schedules ): array {
    $schedules['mgp_interval'] = [ 'interval' => MGP_INTERVAL, 'display' => 'MetalAPI refresh' ];
    return $schedules;
} );
add_action( 'mgp_refresh_event', 'mgp_refresh' );

register_activation_hook( __FILE__, function (): void {
    if ( ! wp_next_scheduled( 'mgp_refresh_event' ) ) {
        wp_schedule_event( time(), 'mgp_interval', 'mgp_refresh_event' );
    }
} );
register_deactivation_hook( __FILE__, function (): void {
    wp_clear_scheduled_hook( 'mgp_refresh_event' );
} );

Используйте его в любой записи, на любой странице или в блоке «Шорткод» (Shortcode) как [gold_price] или [gold_price currency="EUR" unit="gram"]. С примерными курсами второй вариант выводит 114,72 EUR / gram: 3 997,89 ÷ 1,1204 даёт 3 568,27 евро за тройскую унцию, а деление на 31,1034768 даёт цену грамма. Для валюты, которой нет в MGP_CURRENCIES, ничего не выводится, поэтому перечислите там все валюты, которые используют ваши шорткоды.

Обновление цен на золото через WP-Cron

Хук активации планирует обновление с собственным интервалом, зарегистрированным через cron_schedules, а деактивация удаляет его. Установите MGP_INTERVAL равным интервалу обновления вашего тарифа или больше, если этого требует квота:

ТарифMGP_INTERVALЗапросов за месяц из 31 дняМесячная квота
Free (обновление раз в день)8640031100
Lite (обновление каждые 30 минут)36007441 000
Standard (обновление каждые 10 минут)6004 46410 000

WP-Cron — не настоящий планировщик: он выполняет назначенные события, когда кто-то заходит на сайт, поэтому на сайте с небольшим трафиком обновление может запаздывать; двойной срок жизни transient и сохранённая копия это компенсируют. Для точного расписания добавьте define( 'DISABLE_WP_CRON', true ); в wp-config.php и запускайте назначенные события из системного cron с помощью WP-CLI:

crontab
*/10 * * * * cd /var/www/html && wp cron event run --due-now > /dev/null 2>&1

Учитывайте и кэширование страниц: кэш целых страниц сохраняет вывод шорткода вместе со страницей, и посетители видят цену на момент кэширования. Срок жизни кэша для страниц с ценами не должен превышать интервал обновления.

Когда лучше выбрать виджет без кода

Шорткод подходит, когда цена должна быть частью вашего HTML или когда число нужно коду на PHP, например для переоценки товаров. Если нужно только показывать цены, виджет MetalAPI проще:

  • Ни ключа API, ни PHP. Вы создаёте виджет в личном кабинете и вставляете его код в блок Произвольный HTML (Custom HTML). Если позже вы измените символы или макет, править сайт не придётся.
  • Без расхода квоты. Просмотры страниц с виджетом не расходуют месячные запросы, а виджеты входят во все тарифы: 1 на Free, 3 на Lite и 10 на Standard.
  • Безопасно с кэшированием страниц. Цены загружаются внутри iframe, поэтому закэшированная страница никогда их не замораживает.
Код для встраивания виджета
<div id="metalapi-widget-w_abc123"></div>
<script src="https://metalapi.com/js/widget.js" data-widget="w_abc123" async></script>

Если ваш хостинг удаляет теги <script>, используйте вариант встраивания через iframe. Статья «Как добавить на сайт виджет с актуальной ценой золота» рассказывает о конструкторе, размещении в WordPress и ограничениях тарифов, а на странице виджетов показаны макеты.

Что дальше

Создайте бесплатный аккаунт, добавьте ключ в wp-config.php и установите плагин, задав MGP_INTERVAL равным 86400: ежедневное обновление расходует 31 из 100 месячных запросов тарифа Free. Когда понадобятся более свежие цены, установите интервал, равный интервалу обновления нового тарифа, и сравните тарифы на странице тарифов. Для бэкендов на Node.js статья «API цен на золото на JavaScript» показывает те же подходы с Express и Next.js.

Частые вопросы

Где хранить ключ API в WordPress?

В wp-config.php в виде константы или в переменной окружения, которая там читается. Никогда — в файлах темы, которые часто попадают в Git, и не в JavaScript, который может прочитать любой посетитель. Запросы из PHP не отправляют заголовков Origin и Referer, поэтому с сервера работает даже ключ с ограничением по доменам.

Почему шорткод показывает одну и ту же цену золота все выходные?

Спотовое золото не торгуется с 17:00 пятницы до 17:00 воскресенья по нью-йоркскому времени, поэтому API возвращает последнюю цену до открытия рынков. Кроме того, на тарифе Free цены меняются только раз в день.

Сколько запросов к API будет расходовать плагин?

Один на каждое обновление, сколько бы ни было посетителей, страниц или шорткодов, потому что один вызов возвращает все валюты, а единицы пересчитываются локально: около 4 500 в месяц при интервале 10 минут.

Можно ли использовать цену золота в ценах товаров WooCommerce?

Да. Вызовите mgp_prices() из PHP, например в фильтре woocommerce_product_get_price, и умножьте цену за грамм на массу и пробу изделия. Сохраняйте использованную цену золота вместе с каждым заказом, чтобы счета потом не менялись.

Нужны ли cURL или Guzzle в WordPress?

Нет. wp_remote_get() использует HTTP API WordPress, который сам выбирает доступный транспорт и учитывает настройки прокси. Оставьте cURL и Guzzle для обычного PHP и фреймворков вроде Laravel или Symfony.

Попробуйте на своих данных

Создайте бесплатный аккаунт и отправьте первый запрос меньше чем за две минуты. 100 запросов в месяц, без банковской карты.

Читайте также