الجمعة ٣١ / أكتوبر / ٢٠٢٥
من نحن اتصل بنا سياسة الخصوصية

دورة تعلم سيو الذكاء الاصطناعي المحاضرة 2 تفعيل Google Indexing API لتسريع الأرشفة - التفعيل على ووردبريس

دورة تعلم سيو الذكاء الاصطناعي المحاضرة 2 تفعيل Google Indexing API لتسريع الأرشفة - التفعيل على ووردبريس

دورة تعلم سيو الذكاء الاصطناعي - المحاضرة الثانية الاشتراك في Google Cloud Console وتفعيل Google Indexing API لتسريع الأرشفة- خطوات التفعيل على ووردبريس 

في المحاضرة الثانية من دورة تعلم السيو بالذكاء الاصطناعي والتي يقدمها المحاضر محمد الضبعان بالتعاون مع بوابة عالم واحد للإعلام والبرمجيات سنقوم بخطوات عملية لتنفيذ الاشتراك في Google Indexing API بهدف تسريع أرشفة مقالات موقعك في نتائج Google خلال دقائق بدل أيام أو أسابيع؟ وذلك من خلال خدمة Google Indexing API. 

الخدمة مجانية من Google تتيح لك إرسال روابط موقعك مباشرة لمحرك البحث ليقوم بأرشفتها فورًا دون انتظار الزحف التلقائي من Googlebot. 

في هذا الدليل، سنتعرف على: 

  • أهمية وفوائد استخدام Indexing API. 

  • الخطوات الكاملة للاشتراك في Google Cloud Console. 

  • طريقة تفعيل الخدمة ورفع مفاتيح الربط. 

  • وأخيرًا، طريقة الربط العملي مع WordPress أو PHP. 

أهمية الاشتراك في Google Indexing API 

 1. تسريع الأرشفة بشكل كبير 

بدلاً من انتظار Googlebot ليزحف تلقائيًا إلى موقعك، يمكنك إرسال الروابط فورًا، فتظهر المقالات في نتائج البحث خلال دقائق، وهي ميزة مهمة جدًا للمواقع الإخبارية والمدونات النشطة.  

2. تحسين الظهور في نتائج البحث (SEO Boost) 

عندما تتم أرشفة المقال الجديد أو التحديث الأخير فورًا، فإنك تضمن أن المحتوى الأحدث هو الذي يظهر أولاً في نتائج البحث، مما يمنح موقعك أفضلية تنافسية خاصة في الأخبار والترندات. 

3. إبلاغ جوجل بالتحديثات المهمة 

إذا عدّلت عنوان المقال أو وصفه أو أي جزء من المحتوى، يمكنك إرسال تحديث باستخدام الأمر URL_UPDATED لتقوم Google بتحديث النتيجة القديمة بسرعة. 

4. حذف الصفحات القديمة من الفهرس 

يمكنك استخدام URL_DELETED لإزالة الصفحات غير المتوفرة أو المحذوفة فورًا من الفهرس، مما يقلل أخطاء 404 ويحافظ على جودة الموقع في عيون Google. 

5. مثالي للمواقع الإخبارية والمدونات 

المواقع التي تنشر باستمرار — مثل الأخبار، الرياضة، أو الوظائف — تستفيد بشكل هائل، لأن الأرشفة السريعة تعني الظهور قبل المنافسين. 

6. تقليل الاعتماد على Googlebot العشوائي 

بدلاً من انتظار روبوت الزحف الذي قد يزور موقعك كل عدة أيام، تصبح أنت المتحكم في توقيت إرسال الروابط الجديدة أو المحدثة. 

7. تحسين تجربة المستخدم (UX) 

عندما تظهر المقالات الجديدة بسرعة في Google Discover ونتائج البحث، تزداد الزيارات العضوية ويشعر المستخدم أن موقعك نشط وحديث دائمًا. 

8. تكامل سهل مع WordPress وPHP 

يمكن ربط الخدمة بسهولة عبر إضافات WordPress أو أكواد PHP ترسل الرابط تلقائيًا عند النشر أو التحديث. 

️ 9. تعزيز الثقة في موقعك 

المواقع التي تستخدم Indexing API بانتظام تُعتبر أمام خوارزميات Google مواقع نشطة وموثوقة. 

10. مجاني تمامًا 

الخدمة مجانية 100٪ من Google، تحتاج فقط إلى إعدادها مرة واحدة داخل Google Cloud Console. 

 خطوات الاشتراك في Google Cloud Console وتفعيل Indexing API 

الخطوة 1: إنشاء مشروع جديد 

  1. سجّل الدخول بحساب Google. 

  1. من الأعلى اختر "Select Project" ثم "New Project". 

  1. اكتب اسم المشروع (مثلاًindexing-api-projectثم اضغط Create. 

 

الخطوة 2: تفعيل واجهة Indexing API 

  1. بعد إنشاء المشروع، اذهب إلىAPIs & Services → Library 

  1. في مربع البحث، اكتب Indexing API. 

  1. اضغط عليها ثم اختر Enable لتفعيلها. 

 

الخطوة 3: إنشاء Service Account وتحميل مفتاح JSON 

  1. من القائمة الجانبية اخترIAM & Admin → Service Accounts 

  1. اضغط Create Service Account. 

  1. أدخل اسمًا مثلindexing-api-service. 

  1. في الأذونات اختر Owner أو Editor. 

  1. بعد الإنشاء، اختر الحساب الجديد → Keys → Add Key → Create New Key. 

  1. اختر JSON، وسيتم تحميل ملف مثلindexing-api-key.json 

 
















الخطوة 4: إضافة البريد الإلكتروني إلى Google Search Console 

  1. اختر موقعك من القائمة. 

  1. من Settings → Users and Permissions. 

  1. اضغط Add User. 

  1. انسخ البريد الإلكتروني الموجود في ملف JSON (يبدو مثل service-account-name@project-id.iam.gserviceaccount.com). 

  1. أعطه صلاحية Full أو Owner. 

الآن أصبح الحساب المخصص مسموحًا له بإرسال روابط موقعك إلى Google مباشرة. 

ربط الخدمة مع WordPress عمليًا 

الطريقة الأولىعبر إضافة جاهزة 

أشهر إضافة مجانية: 

Instant Indexing for Google من فريق Rank Math. 

الخطوات: 

  1. من لوحة تحكم WordPress → إضافات → أضف جديد. 

  1. ابحث عن Instant Indexing for Google. 

  1. فعّل الإضافة. 

  1. من الإعدادات، ارفع ملف JSON الذي حصلت عليه من Google Cloud. 

  1. حدد متى يتم الإرسال: 

  1. عند نشر المقال. 

  1. عند تحديث المقال. 

  1. أو يدويًا. 

الإضافة ستقوم تلقائيًا بتحميل مكتبة Google API وإرسال الروابط فورًا إلى الخدمة. 

الطريقة الثانيةعبر كود PHP مخصص 

يمكنك إرسال أي رابط يدويًا باستخدام الكود التالي (بعد وضع ملف JSON في مجلد آمن داخل موقعك): 

 
require_once 'vendor/autoload.php'; 
 
use Google\Client; 
use Google\Service\Indexing; 
 
$client = new Client(); 
$client->setAuthConfig('indexing-api-key.json'); 
$client->addScope('https://www.googleapis.com/auth/indexing'); 
 
$service = new Indexing($client); 
 
$url = 'https://example.com/article-link'; 
$type = 'URL_UPDATED'; // أو URL_DELETED لحذف الرابط 
 
$batch = new Google\Service\Indexing\UrlNotification(); 
$batch->setUrl($url); 
$batch->setType($type); 
 
$response = $service->urlNotifications->publish($batch); 
 
echo 'تم إرسال الرابط بنجاح: ' . $response->getUrl(); 
?> 
 

الأسئلة الشائعة (FAQ) 

هل Indexing API مسموح للمقالات الإخبارية؟ 

رغم أن Google صممتها أساسًا لصفحات الوظائف (JobPosting) و**البث المباشر (BroadcastEvent)**، إلا أن العديد من المواقع الإخبارية تستخدمها لتسريع الأرشفة بنجاح، دون مشاكل، طالما لا يتم استخدامها بشكل مفرط أو مخالف لسياسات Google. 

هل يمكن استخدام Indexing API لمواقع كبيرة أو متعددة اللغات؟ 

نعم، يمكن استخدامها في المواقع الكبيرة بشرط إدارة الطلبات بمعدل معقول (حوالي 200 طلب يوميًا لكل حساب خدمة). ويمكنك إنشاء أكثر من مشروع Cloud إذا كنت تدير شبكة مواقع متعددة اللغات. 

هل الخدمة مجانية بالكامل؟ 

نعم Google Indexing API مجانية تمامًا، ولا يوجد أي رسوم على الاستخدام، فقط يلزمك إعداد المشروع في Google Cloud مرة واحدة. 

هل يمكن معرفة ما إذا تم قبول الرابط؟ 

نعمعند الإرسال، يعيد Google استجابة تحتوي على حالة الرابط (URL Notification Metadataويمكنك التحقق من آخر وقت تمت فيه الأرشفة أو التحديث. 


ملفات المشروع :

1 - ملف indexing-api

<?php
function sendToIndexingAPI($liveUrl) {
    $serviceAccount = json_decode(file_get_contents(__DIR__ . '/service-account.json'), true);

    $header = json_encode(['alg' => 'RS256','typ' => 'JWT']);
    $now = time();
    $claimSet = json_encode([
        'iss' => $serviceAccount['client_email'],
        'scope' => 'https://www.googleapis.com/auth/indexing',
        'aud' => $serviceAccount['token_uri'],
        'exp' => $now + 3600,
        'iat' => $now
    ]);

    function base64UrlEncode($data) {
        return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
    }

    $base64Header = base64UrlEncode($header);
    $base64ClaimSet = base64UrlEncode($claimSet);
    $signatureInput = "$base64Header.$base64ClaimSet";

    $privateKey = $serviceAccount['private_key'];
    openssl_sign($signatureInput, $signature, $privateKey, 'sha256');
    $jwt = "$signatureInput." . base64UrlEncode($signature);

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $serviceAccount['token_uri']);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
        'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        'assertion' => $jwt
    ]));
    $result = curl_exec($ch);
    curl_close($ch);

    $tokenData = json_decode($result, true);
    if(!isset($tokenData['access_token'])){
        return "خطأ في الحصول على التوكن: " . $result;
    }

    $accessToken = $tokenData['access_token'];

    $payload = json_encode([
        'url' => $liveUrl,
        'type' => 'URL_UPDATED'
    ]);

    $ch = curl_init('https://indexing.googleapis.com/v3/urlNotifications:publish');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $accessToken,
        'Content-Type: application/json'
    ]);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);

    $response = curl_exec($ch);
    curl_close($ch);

    return $response;
}
?>

2 - ملفات مجلد live

1 - ملف index

<?php
$dsn = "mysql:host=localhost;dbname=;charset=utf8mb4";
$user = "";
$pass = "";

try {
    $connect = new PDO($dsn, $user, $pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ]);
} catch (PDOException $e) {
    die("Database connection failed: " . $e->getMessage());
}

$stmt = $connect->query("SELECT * FROM live_broadcasts ORDER BY id DESC");
$broadcasts = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="ar">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>البث المباشر | عالم واحد للإعلام والبرمجيات</title>
  <meta name="description" content="شاهد جميع البثوث المباشرة السابقة والحالية على موقع عالم واحد للإعلام والبرمجيات.">
  <style>
    body { font-family: Arial, sans-serif; direction: rtl; text-align: right; background: #fff; color: #222; margin: 0; padding: 0; }
    header { background: #f2f2f2; padding: 15px; font-size: 26px; text-align: center; font-weight: bold; }
    main { max-width: 900px; margin: 30px auto; padding: 0 15px; }
    article { padding: 15px; border-bottom: 1px solid #ddd; }
    article h2 { font-size: 22px; margin: 0 0 10px; }
    article h2 a { color: #0077cc; text-decoration: none; }
    article h2 a:hover { text-decoration: underline; }
    .desc { color: #555; font-size: 16px; }
  </style>
</head>
<body>

<header>🎬 جميع البثوث المباشرة</header>

<main>
  <?php if (count($broadcasts) > 0): ?>
    <?php foreach ($broadcasts as $b): ?>
      <article>
        <h2>
<a href="/live/<?= urlencode($b['slug']) ?>">
  <?= htmlspecialchars($b['title']) ?>
</a>

        </h2>
        <p class="desc"><?= nl2br(htmlspecialchars(mb_substr($b['description'], 0, 120))) ?>...</p>
      </article>
    <?php endforeach; ?>
  <?php else: ?>
    <p>لا توجد بثوث حالياً.</p>
  <?php endif; ?>
</main>

</body>
</html>

2 - ملف liveNow
<?php
// -------------------------
// 1️⃣ إعدادات قاعدة البيانات
// -------------------------
$dsn = "mysql:host=localhost;dbname=;charset=utf8mb4";
$user = "";
$pass = "";

try {
    $connect = new PDO($dsn, $user, $pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ]);
} catch (PDOException $e) {
    die("Database connection failed: " . $e->getMessage());
}

// -------------------------
// 2️⃣ جلب slug من الرابط
// -------------------------
$slug = $_GET['slug'] ?? '';
if (!$slug) {
    http_response_code(404);
    die("<h2>❌ البث غير موجود</h2>");
}

// -------------------------
// 3️⃣ جلب بيانات البث من قاعدة البيانات
// -------------------------
$stmt = $connect->prepare("SELECT * FROM live_broadcasts WHERE slug = ?");
$stmt->execute([$slug]);
$broadcast = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$broadcast) {
    http_response_code(404);
    die("<h2>❌ لم يتم العثور على البث.</h2>");
}

// -------------------------
// 4️⃣ إرسال الرابط لجوجل تلقائيًا
// -------------------------
include __DIR__ . '/../inc/indexing-api.php';
$liveUrl = "https://awepai.com/live/" . urlencode($broadcast['slug']);
if(function_exists('sendToIndexingAPI')) {
    sendToIndexingAPI($liveUrl);
}

// -------------------------
// 5️⃣ تحويل التواريخ إلى صيغة ISO للـ JSON-LD
// -------------------------
function toIso($datetime) {
    return $datetime ? date('c', strtotime($datetime)) : null;
}

$start = toIso($broadcast['start']);
$end   = toIso($broadcast['end']);

// -------------------------
// 6️⃣ دالة عرض الفيديو حسب النوع
// -------------------------
function renderVideo($url) {
    $url = trim($url);

    // إذا كان iframe كامل بالفعل
    if (stripos($url, '<iframe') === 0) {
        return $url;
    }

    // YouTube
    if (strpos($url, 'youtube.com') !== false || strpos($url, 'youtu.be') !== false) {
        parse_str(parse_url($url, PHP_URL_QUERY), $query);
        $id = $query['v'] ?? '';
        if (!$id && strpos($url, 'youtu.be') !== false) {
            $parts = explode('/', $url);
            $id = end($parts);
        }
        return '<iframe src="https://www.youtube.com/embed/'.$id.'" frameborder="0" allowfullscreen></iframe>';
    }

    // Vimeo
    if (strpos($url, 'vimeo.com') !== false) {
        preg_match("/vimeo\.com\/(\d+)/", $url, $matches);
        $id = $matches[1] ?? '';
        return '<iframe src="https://player.vimeo.com/video/'.$id.'" frameborder="0" allowfullscreen></iframe>';
    }

    // Facebook
    if (strpos($url, 'facebook.com') !== false) {
        $fbUrlClean = preg_replace('/(\?|\&)t=\d+/', '', $url); // إزالة معامل t
        $fbUrl = urlencode($fbUrlClean);
        return '<iframe src="https://www.facebook.com/plugins/video.php?href='.$fbUrl.'&show_text=true&width=560" width="560" height="315" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowfullscreen="true" allow="autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share"></iframe>';
    }

    // رابط مباشر MP4
    return '<video controls style="width:100%;height:100%"><source src="'.htmlspecialchars($url).'"></video>';
}

?>

<!DOCTYPE html>
<html lang="ar">
<head>
  <meta charset="UTF-8">
  <title><?= htmlspecialchars($broadcast['title']) ?> | البث المباشر</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="description" content="<?= htmlspecialchars($broadcast['description']) ?>">

  <!-- Open Graph -->
  <meta property="og:title" content="<?= htmlspecialchars($broadcast['title']) ?>">
  <meta property="og:description" content="<?= htmlspecialchars($broadcast['description']) ?>">
  <meta property="og:type" content="video.other">
  <meta property="og:video:url" content="<?= htmlspecialchars($broadcast['video_url']) ?>">
  <meta property="og:video:secure_url" content="<?= htmlspecialchars($broadcast['video_url']) ?>">
  <meta property="og:site_name" content="عالم واحد للإعلام والبرمجيات">

  <!-- Twitter Cards -->
  <meta name="twitter:card" content="player">
  <meta name="twitter:title" content="<?= htmlspecialchars($broadcast['title']) ?>">
  <meta name="twitter:description" content="<?= htmlspecialchars($broadcast['description']) ?>">
  <meta name="twitter:player" content="<?= htmlspecialchars($broadcast['video_url']) ?>">
  <meta name="twitter:player:width" content="1280">
  <meta name="twitter:player:height" content="720">

  <!-- JSON-LD -->
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "BroadcastEvent",
    "name": "<?= htmlspecialchars($broadcast['title']) ?>",
    "description": "<?= htmlspecialchars($broadcast['description']) ?>",
    "startDate": "<?= $start ?>",
    "endDate": "<?= $end ?>",
    "isLiveBroadcast": <?= $broadcast['is_live'] ? 'true' : 'false' ?>,
    "url": "<?= $liveUrl ?>",
    "publication": {
      "@type": "BroadcastService",
      "name": "عالم واحد للإعلام والبرمجيات Live",
      "broadcaster": {
        "@type": "Organization",
        "name": "عالم واحد للإعلام والبرمجيات"
      }
    }
  }
  </script>

  <style>
    body { font-family: Arial, sans-serif; direction: rtl; text-align: right; background:#fff; color:#222; margin:0; padding:0; }
    header { background:#f4f4f4; padding:15px; text-align:center; font-size:24px; font-weight:bold; }
    main { max-width:1200px; margin:20px auto; padding:0 15px; }
    .video-container { position:relative; width:100%; padding-bottom:56.25%; margin-bottom:20px; }
    .video-container iframe, .video-container video { position:absolute; top:0; left:0; width:100%; height:100%; border:0; }
    h1 { font-size:28px; margin-bottom:10px; }
    p { font-size:18px; line-height:1.5; }
    footer { text-align:center; padding:15px; font-size:14px; color:#555; }
    a { color:#0077cc; text-decoration:none; }
  </style>
</head>
<body>

<header>🎥 <?= htmlspecialchars($broadcast['title']) ?></header>

<main>
  <div class="video-container">
    <?= renderVideo($broadcast['video_url']) ?>
  </div>

  <p><?= nl2br(htmlspecialchars($broadcast['description'])) ?></p>
  <p><a href="/live/">← العودة لكل البثوث</a></p>
</main>

<footer>© <?= date('Y') ?> عالم واحد للإعلام والبرمجيات</footer>

</body>
</html>


محمد الضبعان

موضوعات ذات صلة