تضمين قائمة مواضيع Discourse في موقع آخر

إذا قمت بتحميل أحدث إصدارات من Discourse، فستحصل على إمكانية تضمين قوائم المواضيع في مواقع أخرى عبر بعض أكواد JavaScript و HTML البسيطة.

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

كيفية تضمين قائمة بالمواضيع

أولاً، يجب تمكين إعداد الموقع embed topics list.

ثم، في ملف HTML الخاص بك، أضف وسم <script> يتضمن كود JavaScript اللازم لتضمين مواضيع Discourse. يمكنك إضافة هذا في أي مكان تضيف فيه الأكواد البرمجية عادةً. على سبيل المثال:

<script src="http://URL/javascripts/embed-topics.js"></script>

استبدل URL بعنوان المنتدى، بما في ذلك المجلد الفرعي إذا كان موجودًا.

بعد ذلك، في وسم <body> في مستند HTML الخاص بك، أضف وسم d-topics-list للإشارة إلى قائمة المواضيع التي ترغب في تضمينها. ستحتاج أيضًا إلى استبدال URL بعنوان URL الأساسي الخاص بك هنا:

<d-topics-list discourse-url="URL" category="1234" per-page="5"></d-topics-list>

أي سمات تقدمها (باستثناء discourse-url الذي هو إلزامي) سيتم تحويلها إلى معلمات الاستعلام لبحث المواضيع. لذا، إذا كنت ترغب في البحث عن مواضيع حسب الوسم، يمكنك فعل ذلك كالتالي:

<d-topics-list discourse-url="URL" tags="cool"></d-topics-list>

إذا كان لمعلمة الاستعلام خط سفلي، فحوّله إلى شرطة. في المثال أعلاه، لاحظت على الأرجح أن per_page أصبحت per-page.

في سياقات نفس الموقع (SameSite) (أي أن الموقع المضمن ومنتدىك يشتركان في نطاق رئيسي)، سيعرف Discourse ما إذا كنت مسجلًا في المنتدى، وسيعرض النتائج وفقًا لذلك. لا تتفاجأ إذا رأيت فئات آمنة وما شابه عند تسجيل الدخول - فالمستخدمون المجهولون لن يتمكنوا من ذلك!

قائمة المعلمات

template: إما complete أو basic (الافتراضي). بينما تكون القائمة الأساسية مجرد قائمة بعناوين المواضيع، فإن النسخة الكاملة تجلب العنوان، واسم المستخدم، ورمز المستخدم، وتاريخ الإنشاء، وصورة مصغرة للموضوع.

per-page: رقم. يتحكم في عدد المواضيع التي سيتم إرجاعها.

category: رقم. يقيّد المواضيع بفئة واحدة. مرّر id الفئة المستهدفة.

allow-create: قيمة منطقية (Boolean). إذا تم تمكينها، ستحتوي الأداة المضمنة على زر “موضوع جديد”.

tags: نص. يقيّد المواضيع بتلك المرتبطة بهذا الوسم.

top_period: أحد القيم التالية: all, yearly, quarterly, monthly, weekly, daily. إذا تم تمكينه، سيعيد “أفضل” مواضيع الفترة المحددة.

أمثلة

لقد أنشأت موقعًا تجريبيًا هنا:

https://embed.eviltrout.com

يجب أن تتمكن من عرض مصدر الصفحة في متصفحك لرؤية الكود، ولكن يمكنك أيضًا العثور على المصدر الكامل على GitHub:

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

تنسيق القائمة

يمكنك استخدام ميزة السمة الحالية لدينا لإضافة أنماط مخصصة لقائمة التضمين.

على سبيل المثال، بشكل افتراضي، تبدو قائمة التضمين التي تستخدم قالب complete كالتالي:

إذا كنت تريد أن تبدو مثل شبكة، على سبيل المثال، يمكنك إضافة SCSS مخصص إلى Theme > Common > Embedded CSS:

.topics-list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  
  .topic-list-item { 
    .main-link {
      border: 1px dotted gray;
      padding: 0;
    }
  
    .topic-column-wrapper {
      flex-direction: column-reverse;
      
      .topic-column.details-column {
        width: 100%;
      }
        
      .topic-column.featured-image-column .topic-featured-image img {
        max-width: initial;
        max-height: initial;
        width: 100%;
      }
    }
  }
}

مما سيجعلها تبدو كالتالي:

95 إعجابًا

مرحبًا يا أصدقاء! نود أن تفتح الروابط في تبويب جديد (أي استخدام target=“_blank” بدلاً من target=“_parent”). هل توجد طريقة سهلة للقيام بذلك مع وجود إطار مضمن (iframe)؟

إعجابَين (2)

لا أعرف ما إذا كان هذا ما تبحث عنه، لكن شيء مثل هذا يجب أن يعمل لفتح الروابط في علامات تبويب جديدة. يجب تمكين CORS للنطاق الخارجي. جربتها بهذه الطريقة لأنني أردت تصفية الموضوع المثبت.

// قد يتطلب `fetch` إضافة مكتبة polyfill
const targetEl = document.getElementById("forumTopics");

function renderTemplate(topicsArr) {
    const items = topicsArr.map(
        (topic) => `<li><a href="${topic[1]}" target="_blank">${topic[0]}</a></li>`
    );

    targetEl.innerHTML = `<ul>${items.join("\n")}</ul>`;
}

// أضف `.json` إلى أي قائمة مواضيع
fetch("https://forum.example.com/latest.json")
    .then((res) => res.json())
    .then((json) => {
        const topics = json.topic_list.topics
            .slice(1, 6)
            .map((t) => [
                t.title,
                `https://forum.example.com/t/${t.slug}/${t.id}`,
            ]);

        renderTemplate(topics);
    });
3 إعجابات

شكرًا لك! أعجبني هذا الفكرة، لكن بناءً على هذا المنشور https://meta.discourse.org/t/what-are-the-risks-of-enabling-cross-origin-resource-sharing-discourse-enable-cors/41248، أعتقد أن تمكين CORS ليس أفضل فكرة.

إعجابَين (2)

يجب عليك تمكين CORS فقط للمواقع التي تثق بها. تمكين CORS لكل مصدر يُفقد الغرض منه.

6 إعجابات

لقد قمت بتمكين CORS فقط للمواقع الأخرى التي أتحكم بها. كان الهدف هو تحميل قائمة بمواضيع المنتدى في مواقعنا الأخرى باستخدام كود الواجهة الأمامية. من المحتمل أن هذه الطريقة لن تعمل للسماح لمواقع عشوائية بتضمين المنشورات.

تعديل: إذا قمت بنسخ/لصق ذلك الكود، فانتبه إلى .slice(1, 6) لأنه يزيل أحد المواضيع. (أعتقد أن هذا كان الموضوع المثبت الذي أردت إزالته.)

3 إعجابات

رائع، هذا شيء يمكننا تجربته إذن - ليس لدي موقع آخر غير localhost في الوقت الحالي (أثناء الاختبار)، وهو ما جعلني مترددًا في إضافته. لكن إذا تمكنت من العثور على شخص لديه مكان، يمكننا تجربة ذلك. شكرًا لمساعدتك!

4 إعجابات

مرحبًا @j127

نواجه حاليًا نفس المشكلة ونرغب في فتح الروابط في علامة تبويب جديدة.
فقط سؤال سريع.

أين بالضبط تضع الكود الذي قدمته؟

@eviltrout هل لديك أي فكرة عن سبب عدم ظهور أنماط CSS في حالتي؟

إعجابَين (2)

هذا الكود مجرد مثال سريع للفكرة العامة. لا أعتقد أن fetch يعمل في جميع المتصفحات. يمكنني إعادة كتابته باستخدام ES5 إذا أردت.

هل موقعك مبني على ووردبريس أم نوع ما من ووردبريس بدون واجهة أمامية؟

4 إعجابات

يبدو أن الأمر يعمل في جميع المتصفحات الحديثة، ولم يعد Discourse يدعم IE11.

4 إعجابات

موقعي هو ووردبريس عادي، وليس بدون رأس (headless).

إعجاب واحد (1)

هل يمكنني استخدام هذا لتضمين قائمة بمواضيع Discourse في مثيل Discourse آخر؟ أم أن هناك طريقة أذكى للقيام بذلك؟

حالة الاستخدام الخاصة بي هي إنشاء “جسر” بين مثيلين كإجراء مؤقت حتى يتم دمجهما في المستقبل. سيكون من الرائع أتمتة هذه العملية وجعلها ديناميكية.

إعجابَين (2)

إذا لم تكن تهتم بـ Internet Explorer، فيجب أن يعمل هذا المقطع. (يجب تمكين CORS للنطاق الخارجي في إعدادات Discourse.)

للتجربة، افتح أي صفحة في هذا المنتدى والصق المقطع أدناه في وحدة تحكم المتصفح. قمت بتغيير العنصر المستهدف إلى document.body، لذا سيستبدل الصفحة بأكملها بقائمة مواضيع المنتدى. لموقع حقيقي، غيّر العنصر المستهدف إلى document.getElementById("#someId") ثم أضف عنصر div يحمل هذا المعرف في أي مكان بالصفحة. سيقوم السكربت بتعبئته بقائمة المواضيع.

// قد يتطلب `fetch` مكتبة بديلة (polyfill) إلا إذا لم تكن تهتم بـ Internet Explorer
// const targetEl = document.getElementById("forumTopics");

// هذا يستبدل جسم الصفحة، كمثال فقط
const targetEl = document.body;

// ضع رابط المنتدى الخاص بك هنا لتجربته على منتدى خاص بك
const baseForumURL = `https://meta.discourse.org`;

// عدد المواضيع التي تريد عرضها
const numTopics = 6;

function renderTemplate(topicsArr) {
    const items = topicsArr.map(
        (topic) => `<li><a href="${topic[1]}" target="_blank">${topic[0]}</li>`
    );

    targetEl.innerHTML = `<ul>${items.join("\n")}</ul>`;
}

// أضف `.json` إلى أي قائمة مواضيع
fetch(`${baseForumURL}/latest.json`)
    .then((res) => res.json())
    .then((json) => {
        const topics = json.topic_list.topics
            .slice(0, numTopics)
            .map((t) => [
                t.title,
                `${baseForumURL}/t/${t.slug}/${t.id}`,
            ]);

        renderTemplate(topics);
    });

مثال: إذا كان عنصر div المستهدف في موقع WordPress الخاص بك يبدو هكذا

<div id="forumTopics">
    <!-- ستظهر منشورات المنتدى هنا -->
</div>

فيمكن للسكربت JavaScript استهداف هذا المعرف كالتالي:

// ابحث عن هذا السطر في المثال الأصلي الذي نشرته
const targetEl = document.getElementById("forumTopics");
4 إعجابات

هل تقصد بذلك الكود في المنشور الأول أم المقطع في المنشور 50؟ ولا، لا أهتم بـ IE. لا حاجة للتكيف مع هذا الديناصور :).
في حالتي، لا يتم تحميل CSS لمقطعي في أي متصفح.

إذن هذا JavaScript وعلي وضع وسم <script> حوله عند تنفيذه على ووردبريس، صحيح؟

إعجابَين (2)

لقد مرّ وقت طويل منذ أن استخدمت WordPress. هل تضيفه إلى HTML القالب؟ إذا كان الأمر كذلك، فقم بتغليف الكود الخاص بي بوسم script وضع العنصر <div> في المكان الذي تريد أن تظهر فيه المنشورات.

أعتقد أنه يمكنك إدراج الكود أدناه مباشرة في HTML لقالب WordPress في أي مكان تريد أن تظهر فيه المنشورات. تأكد من تحديث السطر الذي يحتوي على عنوان URL للمنتدى. إذا لم يعمل، فأخبرني. (لم يتم اختباره بعد.)

انقر هنا للحصول على الكود
<div id="forumTopics"></div>
<script>
// ضع عنوان URL الخاص بمنتداك هنا لتجربته على منتداك الخاص
const baseForumURL = `https://forum.example.com`;

// عدد المواضيع التي تريد عرضها
const numTopics = 6;

const targetEl = document.getElementById("forumTopics");
// إذا لم يتم تحميل المنشورات لسبب ما، يمكنك عرض رابط إلى المنتدى
targetEl.innerHTML = `<a class="link-to-discourse" href="${baseForumURL}/">عرض أحدث منشورات المنتدى</a>`;

function renderTemplate(topicsArr) {
    const items = topicsArr.map(
        (topic) => `<li><a href="${topic[1]}" target="_blank">${topic[0]}</li>`
    );

    targetEl.innerHTML = `<ul>${items.join("\n")}</ul>`;
}

// أضف `.json` إلى أي قائمة مواضيع
fetch(`${baseForumURL}/latest.json`)
    .then((res) => res.json())
    .then((json) => {
        const topics = json.topic_list.topics
            .slice(0, numTopics)
            .map((t) => [
                t.title,
                `${baseForumURL}/t/${t.slug}/${t.id}`,
            ]);

        renderTemplate(topics);
    });
</script>
3 إعجابات

شكرًا لك، نقدر النص الكامل

بعد الاختبار الأولي، يتم عرض رابط فقط. لكنني أعتقد أن CORS معطل، لذا سأطلب من المضيف تمكينه.
في غضون ذلك، كيف يمكنني جعل السكربت يعرض المنشورات التي تحتوي على وسم معين ومن فئة معينة فقط؟

إعجابَين (2)

لست متأكدًا، لكن أعتقد أن الصيغة هي
https://forum.example.com/tags/c/<اسم_الفئة>/<اسم_الوسم>

مثال: إذا كانت الفئة هي “الدعم” والوسم هو “css”:
https://meta.discourse.org/tags/c/support/css

لتحويلها إلى JSON، أضف .json في النهاية:
https://meta.discourse.org/tags/c/support/css.json

لذلك، في دالة fetch، بدلاً من /latest.json، استخدم شيئًا مثل /tags/c/support/css.json.

(لم يُختبر بعد.)

3 إعجابات

وإذا أردت تضمين 5 مواضيع داخل مثيل Discourse نفسه؟

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

شكرًا لك.

إعجاب واحد (1)

ما هو معامل الاستعلام للمواضيع الأبرز؟ جربت order="top" لكنه لا يعيد المواضيع الأبرز بنفس الطريقة التي يفعلها المنتدى بناءً على فترة معينة. كيف يمكنني تكرار نتيجة تصفية المنتدى؟ وأين يمكنني البحث عن قيم السمة التي تأخذها خيارات التصفية في Discourse؟ شكرًا لك!

إعجابَين (2)

هل من الممكن تغيير نمط خط المحتوى المدمج؟ جربت محددات CSS مثل d-topics-list iframe html .topics-list .topic-list-item دون نجاح. مقدّمًا شكرًا على التوجيه!

إعجابَين (2)