FROM CACHE - fr_header
Cette communauté a fait place à une assistance de pair-à-pair. L’assistance Shopify ne sera plus proposée pour cette communauté. Nous vous encourageons à entrer en contact avec d’autres marchands et partenaires pour obtenir de l’aide et partager vos expériences ! Veuillez continuer à signaler tout ce qui va à l'encontre de notre Code de conduite ou tout contenu que vous souhaitez faire supprimer.

FAQ personnalisée (Metafields) bloquée par 'jQuery is not defined' sur jquery-ui.js

FAQ personnalisée (Metafields) bloquée par 'jQuery is not defined' sur jquery-ui.js

Astellow
Touriste
5 1 0

Bonjour à toutes et à tous,

Je fais face à un problème JavaScript persistant sur mon thème Shopify et j'ai besoin de votre expertise. Mon objectif est d'implémenter une section FAQ interactive et cliquable sur mes articles de blog. Cette FAQ est personnalisable grâce à l'utilisation de champs méta (metafields) Shopify pour chaque question/réponse. Elle doit permettre aux questions de s'ouvrir et de se fermer (effet accordéon) pour révéler des réponses formatées avec du texte riche. J'ai développé le HTML, le CSS et le JavaScript nécessaire pour cette fonctionnalité.

Le problème principal : Malgré l'intégration de mon code dans le fichier theme.liquid, la fonctionnalité ne s'active pas et je vois des erreurs JavaScript bloquantes dans la console de mon navigateur.

Voici les erreurs récurrentes que je rencontre :

  • jquery-ui.js:14 Uncaught ReferenceError: jQuery is not defined
  • vendor.js:142 Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
     

Ma configuration actuelle et les tests effectués :

  1. Objectif du code FAQ : J'utilise du JavaScript pur (sans jQuery) pour gérer l'ouverture/fermeture des réponses FAQ et le rendu du contenu riche des champs méta. Ce script est actuellement encapsulé dans un setTimeout de 100ms pour s'assurer qu'il s'exécute après le chargement du DOM. Voici un extrait de mon code FAQ dans theme.liquid:

<script>
  setTimeout(function() {
    (function() {
      const faqQuestions = document.querySelectorAll('.faq-question');
      const richTextContents = document.querySelectorAll('.faq-answer-richtext-content');

      const faqSectionExists = document.querySelector('.faq-astellow-section');
      if (!faqSectionExists) {
        return;
      }

      // ... (code de rendu du texte riche et gestion des clics) ...

    })();
  }, 100);
</script>

 

  1. Inclusion de jQuery : Pour tenter de résoudre l'erreur jQuery is not defined provenant de jquery-ui.js, j'ai inclus la bibliothèque jQuery via la balise script recommandée par Shopify:

{{ '//ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js' | script_tag }}


Cette ligne est placée juste avant la balise de fermeture </body> dans mon fichier theme.liquid.

 
  • Test de la communauté (suggéré par le support Shopify) : Sur les conseils du support Shopify, j'ai ajouté un script de test tiré d'un fil de discussion de la communauté ([lien vers l'article du forum que le support t'a donné, tu peux le remettre ici si tu veux]). Ce script est censé attendre que jQuery soit chargé et afficher un message en console. Le code ajouté, placé juste après l'inclusion de jQuery et avant </body>, était le suivant:

<script>
  setTimeout(() => {
    while (!window.jQuery) {
      console.log('Waiting for jQuery...');
    }
    window.jQuery( document ).ready(function() {
      console.log('Astellow - jQuery est bien chargé !');
    });
  }, 100);
</script>

 

Résultat du test : Après avoir rechargé la page, le message "Astellow - jQuery est bien chargé !" n'apparaît pas dans la console. Les erreurs jquery-ui.js:14 Uncaught ReferenceError: jQuery is not defined et vendor.js:142 Uncaught (in promise) Error... persistent. Cela suggère que l'erreur jQuery is not defined est si bloquante qu'elle empêche même l'exécution du code de test, et donc de tout autre script JavaScript qui suit.

Hypothèses et pistes explorées / observées dans le forum :

  • Problème d'ordre de chargement : Il semble que jquery-ui.js soit exécuté par le thème avant que jQuery ne soit disponible, même si j'inclus jQuery en bas du <body>.
  • Placement de jQuery dans <head> : Dans le fil de discussion que le support m'a partagé, une solution suggérée pour cette erreur est de placer jQuery directement dans la balise <head>. J'ai tenté cette approche par le passé, mais cela a provoqué des dysfonctionnements sur l'ensemble de mon site.
  • Attribut defer sur jQuery : Un autre intervenant dans le même forum a mentionné une piste pertinente : "This is possible because your jQuery is declared defer, so it won't work when you call at the bottom of body." Cela suggère que le problème pourrait venir du fait que jQuery est chargé avec un attribut 'defer', ce qui ferait qu'il ne s'exécute qu'après le chargement complet du HTML, et donc trop tard pour jquery-ui.js qui en a besoin plus tôt.
  • Conflit avec une application (potentiel) : Toujours dans le fil de discussion, une application ("Smart Tabs") est citée comme pouvant charger jQuery et potentiellement créer des conflits. Bien que je n'utilise pas d'application spécifique pour ma FAQ, pourriez-vous vérifier si une autre application installée sur mon thème (passée ou présente) pourrait être à l'origine de cette interférence avec jQuery ou jquery-ui.js ?

Mon site est accessible ici : https://astellow.com/blogs/blogstellow-spiritualite-esoterisme-bien-etre/20h20-signification-heure-m.... Vous pouvez y observer les erreurs en console.

Je joins également une capture d'écran de ma console et le contenu de mon fichier theme.liquid actuel pour une analyse complète.

-----------------------------------

Mon fichier theme.liquid : 

<!doctype html>
<html class="no-js" lang="{{ request.locale.iso_code }}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="theme-color" content="">
    <link rel="canonical" href="{{ canonical_url }}">
    {%- if settings.favicon != blank -%}
      <link rel="icon" href="{{ settings.favicon | image_url: width: 32, height: 32 }}" type="image/png">
      <link rel="apple-touch-icon-precomposed" href="{{ settings.favicon | image_url: width: 48, height: 48 }}" type="image/png">
      <link rel="nokia-touch-icon" href="{{ settings.favicon | image_url: width: 48, height: 48 }}" type="image/png">
    {%- endif -%}

    <title>{{- shop.name -}}</title>

    {%- if page_description -%}
      <meta name="description" content="{{ page_description | escape }}">
    {%- endif -%}

    {%- render 'meta-tags' -%}

    {%- render 'header-fonts' -%}
    {%- render 'header-styles' -%}
    {%- render 'header-javascript' -%}
    {{ content_for_header }}
    {%- render 'css-variables' -%}

    <script>document.documentElement.className = document.documentElement.className.replace('no-js', 'js');</script>
  {% include 'pagefly-app-header' %}</head>
  <body id="{{ page_title | handle }}" class="{% if customer %}customer-logged-in {% endif %}template-{{ request.page_type | handle }} {{ template.suffix }} gx-3 gx-md-4">
    {%- if settings.preloading -%}
      {% render 'preloading' %}
    {%- endif -%}
    {%- if settings.header_layout == "header2" -%}
      {% sections 'header-group2' %}
    {%- elsif settings.header_layout == "header3"-%}
      {% sections 'header-group3' %}
    {%- elsif settings.header_layout == "header4"-%}
      {% sections 'header-group4' %}
      {%- elsif settings.header_layout == "header5"-%}
        {% sections 'header-group5' %}
    {%- else -%}
      {% sections 'header-group1' %}
    {% endif %}
    <main id="MainContent" class="main-content content-for-layout" tabindex="-1">
      <div class="main-content__inner">
        {{ content_for_layout }}
      </div>
    </main>
    {%- if settings.footer_layout == "footer2" -%}
      {% sections 'footer-group2' %}
    {%- elsif settings.footer_layout == "footer3"-%}
      {% sections 'footer-group3' %}
    {%- else -%}
      {% sections 'footer-group1' %}
    {% endif %}
    {% include 'footer-javascript' %}
    {% include 'site-template' %}
    {%- if settings.saleNotifi_enable and settings.collection_notification -%}
      {% render 'sale-notification' %}
    {%- endif -%}
    {% render 'svg' %}
    {%- if settings.header_bottom_mobile -%}
      {%- render 'menu-fixed-mobile' -%}
    {%- endif -%}
    <script>
      window.shopUrl = '{{ shop.url }}';
      window.routes = {
        origin: '{{ request.origin }}',
        cart_url: '{{ routes.cart_url }}',
        cart_add_url: '{{ routes.cart_add_url }}',
        cart_clear_url: '{{ routes.cart_clear_url }}',
        cart_change_url: '{{ routes.cart_change_url }}',
        cart_update_url: '{{ routes.cart_update_url }}',
        predictive_search_url: '{{ routes.predictive_search_url }}',
        user_purchased: '{{ settings.user_purchased }}',
        list_time: '{{ settings.time_suggest }}'
      };
    </script>

<script>
document.addEventListener("DOMContentLoaded", function() {
    setTimeout(function() {
        // Désactive l'élément "terms_conditions"
        const termsCheckbox = document.querySelector("#terms_conditions");
        const quickviewTermsCheckbox = document.querySelector("#quickview-terms-condition");

        // Si la case existe, coche-la automatiquement et enlève "required"
        if (termsCheckbox) {
            termsCheckbox.checked = true;
            termsCheckbox.removeAttribute("required");
            termsCheckbox.style.display = "none"; // Cache la case, si nécessaire
        }
        
        if (quickviewTermsCheckbox) {
            quickviewTermsCheckbox.checked = true;
            quickviewTermsCheckbox.removeAttribute("required");
            quickviewTermsCheckbox.style.display = "none"; // Cache la case, si nécessaire
        }

        // Forcer l'activation du bouton "continuer vers le paiement"
        const checkoutButton = document.querySelector('button[name="checkout"]');
        if (checkoutButton) {
            checkoutButton.disabled = false;
            checkoutButton.classList.remove("disabled");
            checkoutButton.removeAttribute("disabled");
            checkoutButton.style.pointerEvents = 'auto'; // Force l'activation
            checkoutButton.style.opacity = 1; // S'assure que l'élément n'est pas "transparent"
        }

        // Forcer l'activation du bouton "justify-content-between"
        const quickviewButton = document.querySelector("button.justify-content-between");
        if (quickviewButton) {
            quickviewButton.disabled = false;
            quickviewButton.classList.remove("disabled");
            quickviewButton.removeAttribute("disabled");
            quickviewButton.style.pointerEvents = 'auto'; // Force l'activation
            quickviewButton.style.opacity = 1; // Assure qu'il n'est pas transparent
        }
    }, 500); // Laisser le temps aux éléments de se charger
});
</script>

<script>
  // Utilisation d'un setTimeout pour s'assurer que notre script s'exécute un peu après
  // que le navigateur ait traité le reste du DOM et des scripts critiques du thème.
  // Un délai de 100ms est souvent suffisant pour laisser le temps aux choses de se stabiliser.
  setTimeout(function() {
    // Encapsulation dans une IIFE pour isoler la portée des variables.
    (function() {
      const faqQuestions = document.querySelectorAll('.faq-question');
      const richTextContents = document.querySelectorAll('.faq-answer-richtext-content');

      // Important: Vérifier si le conteneur de la FAQ existe sur la page actuelle.
      // Si cette balise est présente uniquement sur les articles de blog, cela évitera d'exécuter le script
      // inutilement sur d'autres pages.
      const faqSectionExists = document.querySelector('.faq-astellow-section');
      if (!faqSectionExists) {
        return; // Sortir si la section FAQ n'est pas présente sur cette page.
      }

      // Fonction pour rendre le contenu de l'éditeur de texte riche de Shopify (Lexical JSON)
      function renderShopifyRichText(jsonContent) {
        let html = '';
        if (!jsonContent || jsonContent === 'null') {
          return '';
        }
        try {
          const data = JSON.parse(jsonContent);

          if (data && Array.isArray(data.children)) {
            data.children.forEach(node => {
              if (node.type === 'paragraph' && Array.isArray(node.children)) {
                let paragraphHtml = '';
                node.children.forEach(textNode => {
                  if (textNode.type === 'text') {
                    let text = textNode.value || '';
                    if (textNode.bold) {
                      text = '<strong>' + text + '</strong>';
                    }
                    if (textNode.italic) {
                      text = '<em>' + text + '</em>';
                    }
                    paragraphHtml += text;
                  }
                });
                html += '<p>' + paragraphHtml + '</p>';
              } else if (node.type === 'list' && Array.isArray(node.children)) {
                  let listHtml = '<ul>';
                  if (node.format === 'ordered') {
                      listHtml = '<ol>';
                  }
                  node.children.forEach(listItem => {
                      if (listItem.type === 'listitem' && Array.isArray(listItem.children)) {
                          let listItemContent = '';
                          listItem.children.forEach(liTextNode => {
                              if (liTextNode.type === 'text') {
                                  let text = liTextNode.value || '';
                                  if (liTextNode.bold) { text = '<strong>' + text + '</strong>'; }
                                  if (liTextNode.italic) { text = '<em>' + text + '</em>'; }
                                  listItemContent += text;
                              }
                          });
                          listHtml += '<li>' + listItemContent + '</li>';
                      }
                  });
                  html += listHtml + (node.format === 'ordered' ? '</ol>' : '</ul>');
              }
            });
          }
        } catch (e) {
          console.error("Erreur de parsing JSON ou de rendu Rich Text:", e, jsonContent);
          html = '<p>Erreur d\'affichage de la réponse.</p>';
        }
        return html;
      }

      // Rendre le contenu riche en texte pour chaque réponse
      richTextContents.forEach(container => {
        const jsonContent = container.dataset.richtextJson;
        if (jsonContent) {
          container.innerHTML = renderShopifyRichText(jsonContent);
        }
      });

      // Gestion des collapsibles
      faqQuestions.forEach(button => {
        button.addEventListener('click', () => {
          const answer = button.nextElementSibling;
          button.classList.toggle('active');

          if (button.classList.contains('active')) {
            answer.style.maxHeight = answer.scrollHeight + "px";
          } else {
            answer.style.maxHeight = null;
          }
        });
      });
    })(); // Fin de l'IIFE
  }, 100); // Délai de 100 millisecondes avant l'exécution du script.
</script>
    {{ '//ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js' | script_tag }}
  </body>
</html>

 

screen console.png

0 RÉPONSES 0