Sedifex Developers

Build websites, automations, and integrations that pay.

Sedifex Docs

Sedifex Sync

Source file: wordpress-plugin/sedifex-sync.php

wordpress-plugin/sedifex-sync.php
php
<?php
/**
 * Plugin Name: Sedifex Sync (MVP)
 * Description: Store settings, shortcode renderer, and sync health for Sedifex product catalog.
 * Version: 0.1.0
 */

if (!defined('ABSPATH')) {
  exit;
}

const SEDIFEX_SYNC_OPTION = 'sedifex_sync_settings';
const SEDIFEX_SYNC_HEALTH_OPTION = 'sedifex_sync_health';

function sedifex_sync_register_settings() {
  register_setting('sedifex_sync', SEDIFEX_SYNC_OPTION);

  add_options_page(
    'Sedifex Sync',
    'Sedifex Sync',
    'manage_options',
    'sedifex-sync',
    'sedifex_sync_render_settings_page'
  );
}
add_action('admin_menu', 'sedifex_sync_register_settings');

function sedifex_sync_render_settings_page() {
  $settings = get_option(SEDIFEX_SYNC_OPTION, [
    'api_base_url' => '',
    'store_id' => '',
    'integration_key' => '',
    'cache_ttl' => 60,
  ]);
  ?>
  <div class="wrap">
    <h1>Sedifex Sync</h1>
    <form method="post" action="options.php">
      <?php settings_fields('sedifex_sync'); ?>
      <table class="form-table" role="presentation">
        <tr>
          <th scope="row"><label for="api_base_url">API base URL</label></th>
          <td><input name="<?php echo esc_attr(SEDIFEX_SYNC_OPTION); ?>[api_base_url]" id="api_base_url" value="<?php echo esc_attr($settings['api_base_url']); ?>" class="regular-text" /></td>
        </tr>
        <tr>
          <th scope="row"><label for="store_id">Store ID</label></th>
          <td><input name="<?php echo esc_attr(SEDIFEX_SYNC_OPTION); ?>[store_id]" id="store_id" value="<?php echo esc_attr($settings['store_id']); ?>" class="regular-text" /></td>
        </tr>
        <tr>
          <th scope="row"><label for="integration_key">Integration API key</label></th>
          <td><input name="<?php echo esc_attr(SEDIFEX_SYNC_OPTION); ?>[integration_key]" id="integration_key" value="<?php echo esc_attr($settings['integration_key']); ?>" class="regular-text" /></td>
        </tr>
        <tr>
          <th scope="row"><label for="cache_ttl">Cache TTL (seconds)</label></th>
          <td><input type="number" min="30" max="300" name="<?php echo esc_attr(SEDIFEX_SYNC_OPTION); ?>[cache_ttl]" id="cache_ttl" value="<?php echo esc_attr($settings['cache_ttl']); ?>" /></td>
        </tr>
      </table>
      <?php submit_button('Save settings'); ?>
    </form>
    <?php sedifex_sync_render_health(); ?>
  </div>
  <?php
}

function sedifex_sync_render_health() {
  $health = get_option(SEDIFEX_SYNC_HEALTH_OPTION, [
    'last_success_at' => null,
    'last_failure_at' => null,
    'last_error' => null,
    'item_count' => 0,
  ]);

  echo '<h2>Sync health</h2>';
  echo '<p><strong>Last success:</strong> ' . esc_html($health['last_success_at'] ?: 'Never') . '</p>';
  echo '<p><strong>Last failure:</strong> ' . esc_html($health['last_failure_at'] ?: 'Never') . '</p>';
  echo '<p><strong>Items synced:</strong> ' . esc_html((string) $health['item_count']) . '</p>';

  if (!empty($health['last_error'])) {
    echo '<p><strong>Last error:</strong> ' . esc_html($health['last_error']) . '</p>';
  }
}

function sedifex_sync_fetch_products($force = false) {
  $settings = get_option(SEDIFEX_SYNC_OPTION, []);
  $cache_key = 'sedifex_sync_products';
  $cache_ttl = max(30, min(300, intval($settings['cache_ttl'] ?? 60)));

  if (!$force) {
    $cached = get_transient($cache_key);
    if ($cached !== false) {
      return $cached;
    }
  }

  $url = trailingslashit($settings['api_base_url'] ?? '') . 'integrationProducts?storeId=' . urlencode($settings['store_id'] ?? '');
  $response = wp_remote_get($url, [
    'timeout' => 15,
    'headers' => [
      'x-api-key' => ($settings['integration_key'] ?? ''),
      'Accept' => 'application/json',
    ],
  ]);

  if (is_wp_error($response)) {
    update_option(SEDIFEX_SYNC_HEALTH_OPTION, [
      'last_success_at' => get_option(SEDIFEX_SYNC_HEALTH_OPTION)['last_success_at'] ?? null,
      'last_failure_at' => gmdate(DATE_ATOM),
      'last_error' => $response->get_error_message(),
      'item_count' => 0,
    ]);
    return [];
  }

  $status = wp_remote_retrieve_response_code($response);
  $body = wp_remote_retrieve_body($response);
  $payload = json_decode($body, true);

  if ($status < 200 || $status >= 300 || !is_array($payload)) {
    update_option(SEDIFEX_SYNC_HEALTH_OPTION, [
      'last_success_at' => get_option(SEDIFEX_SYNC_HEALTH_OPTION)['last_success_at'] ?? null,
      'last_failure_at' => gmdate(DATE_ATOM),
      'last_error' => 'Non-success response: ' . $status,
      'item_count' => 0,
    ]);
    return [];
  }

  $products = is_array($payload['products'] ?? null) ? $payload['products'] : [];
  set_transient($cache_key, $products, $cache_ttl);

  update_option(SEDIFEX_SYNC_HEALTH_OPTION, [
    'last_success_at' => gmdate(DATE_ATOM),
    'last_failure_at' => null,
    'last_error' => null,
    'item_count' => count($products),
  ]);

  return $products;
}

function sedifex_sync_shortcode() {
  $products = sedifex_sync_fetch_products();
  if (!$products) {
    return '<p>No products available right now.</p>';
  }

  ob_start();
  echo '<div class="sedifex-products">';
  foreach ($products as $product) {
    $name_raw = $product['name'] ?? 'Untitled product';
    $name = esc_html($name_raw);
    $price = esc_html((string) ($product['price'] ?? '0'));
    $image_urls = [];

    if (isset($product['imageUrls']) && is_array($product['imageUrls'])) {
      foreach ($product['imageUrls'] as $url) {
        if (is_string($url) && trim($url) !== '') {
          $image_urls[] = trim($url);
        }
      }
    }

    if (empty($image_urls) && isset($product['imageUrl']) && is_string($product['imageUrl']) && trim($product['imageUrl']) !== '') {
      $image_urls[] = trim($product['imageUrl']);
    }

    $image_urls = array_slice(array_values(array_unique($image_urls)), 0, 3);
    $image_alt_raw = isset($product['imageAlt']) && is_string($product['imageAlt']) && trim($product['imageAlt']) !== ''
      ? trim($product['imageAlt'])
      : $name_raw;
    $image_alt = esc_attr($image_alt_raw);

    echo '<article class="sedifex-product">';
    if (!empty($image_urls)) {
      echo '<div class="sedifex-product-gallery">';
      foreach ($image_urls as $url) {
        echo '<img src="' . esc_url($url) . '" alt="' . $image_alt . '" loading="lazy" />';
      }
      echo '</div>';
    }
    echo '<h3>' . $name . '</h3>';
    echo '<p>Price: ' . $price . '</p>';
    echo '</article>';
  }
  echo '</div>';

  return (string) ob_get_clean();
}
add_shortcode('sedifex_products', 'sedifex_sync_shortcode');

function sedifex_sync_register_block() {
  if (!function_exists('register_block_type')) {
    return;
  }

  register_block_type('sedifex/products', [
    'render_callback' => 'sedifex_sync_shortcode',
  ]);
}
add_action('init', 'sedifex_sync_register_block');