FROM CACHE - de_header
Gelöst

Customization Box in Productview mit Metafields ?

MosDev__
Shopify Partner
48 10 12

Hallo Forum, 

 

ich möchte auf der Productview eine Customization Box (z. B. Gravierungen) hinzufügen. Erster Gedanke war mit Metafields zu arbeiten, jedoch erschließt sich mir nicht, wie ich aus der Productview/Storefront aus Metafields aktualisieren kann. Wenn ich das nun richtig verstanden habe, wird das nur mittels Storefront API/ GraphQL mutations möglich sein, korrekt ? Wobei der Storefront Approach für das Vorhaben eher Overkill ist und wohl auch mit AJAX zu lösen ist, oder ?

 

Ich stehe gerade auf der Leitung, wäre um jeden "Schubser" dankbar 😛 

1 AKZEPTIERTE LÖSUNG
MosDev__
Shopify Partner
48 10 12

Erfolg.

Hey @Gabe 

 

Die App nimmt immer mehr Form an. Aktuell im Codereview. Ich teile gerne meinen Liquid Code mit euch, schaut mal hier:

 

3 Inputs (Image Upload, Heading, Description)

Image restrictions: max. 800x800, .jpeg-only, max. 2MB

Heading max. 50 digits

Description max. 5 Lines

{% comment %}
  @feature     Customization Section/Block for PDP
  @theme       Dawn 10.0
{% endcomment %}

<div>
  <div class="product-form__input">
    <label class="form__label">Image Upload</label>
    <input
      id="image"
      type="file"
      form="{{ 'product-form-' | append: section.id }}"
      name="properties[Image Upload]"
      accept=".jpg"
      max-width="800"
      max-height="800"
      max-size="2"
      required>
    <script>
      document.addEventListener("DOMContentLoaded", ()=>{document.querySelector("form[novalidate]").removeAttribute("novalidate")})
    </script>
  </div>

  <style>.custom.form__label{margin-bottom: 0.6rem}.field.custom{margin-top:0}.custom .field__input{padding-top:0.8rem}</style>
  <label class="form__label custom" for="heading">Heading</label>
  <div class="field custom">
    <input
      class="field__input"
      form="{{ 'product-form-' | append: section.id }}"
      type="text"
      id="heading"
      name="properties[Heading]"
      maxlength="50"
      required
    >
    <script>
      document.addEventListener("DOMContentLoaded", ()=>{document.querySelector("form[novalidate]").removeAttribute("novalidate")})
      document.querySelector('#heading').addEventListener('input',(e)=>{
        if(!document.querySelector('label[for="heading"] span')){
          const span = document.createElement("span");
          span.style.marginLeft = '10px'
          document.querySelector('label[for="heading"]').appendChild(span)
        }
        document.querySelector('label[for="heading"] span').style.display  = 'inline'
        document.querySelector('label[for="heading"] span').textContent = e.target.value.length + ' | ' + 50
        if(e.target.value.length==0){
          document.querySelector('label[for="heading"] span').style.display  = 'none'
        }})
    </script>
  </div>

  <style>.custom.form__label{margin-bottom: 0.6rem}.field.custom{margin-top:0}.custom .field__input{padding-top:0.8rem}</style>
  <label class="form__label custom" for="description">Description</label>
  <div class="field custom">
        <textarea
          class="text-area field__input"
          id="description"
          form="{{ 'product-form-' | append: section.id }}"
          name="properties[Description]">
        </textarea>
        <script>
          document.getElementById('description').addEventListener('input', function() {
            var lines = this.value.split('\n');
            if (lines.length > 5) {
            alert('Maximum 5 lines allowed.');
            this.value = lines.slice(0, 5).join('\n');
            }
          });
        </script>
  </div>
</div>

<script>
  {% comment %} Logic for Image Requirements {% endcomment %}
  document.getElementById('image').addEventListener('change', function() {
    var fileInput = this;
    var maxWidth = fileInput.getAttribute('max-width');
    var maxHeight = fileInput.getAttribute('max-height');
    var maxSize = fileInput.getAttribute('max-size');

    var file = fileInput.files[0];

    if (file.type !== 'image/jpeg') {
      alert('Please select a valid JPG image.');
      fileInput.value = ''; // clear Input
      return;
    }

    var img = new Image();
    img.onload = function() {
      if (img.width > maxWidth || img.height > maxHeight) {
        alert('Image dimensions must be at most 800x800 pixels.');
        fileInput.value = ''; // clear Input
      }
    };
    img.src=URL.createObjectURL(file);

    if (file.size > maxSize * 1024 * 1024) {
      alert('File size must be at most 2MB.');
      fileInput.value = ''; // clear Input
    }
  });
</script>


{% schema %}
{
  "name": "PDP Customization",
  "target": "section"
}
{% endschema %}

 Bei Fragen, gerne melden !

 

cheers,

sam 

Lösung in ursprünglichem Beitrag anzeigen

13 ANTWORTEN 13

Gabe
Shopify Staff
15955 2531 3775

Hey @MosDev__ 

 

Ich werde mal hier reinspringen denn es nicht ganz klar was du mit "Productview" genau meinst - ein "Quickview" auf der Collection Page, oder die PDP? 

 

Metafields sind zwar flexibel und ermöglichen es, zusätzliche Informationen zu Produkten zu speichern, wie z.B. Gravierungstexte. Aber da machst du dir 'ne Heidenarbeit denn das ganze gibt's ja meistens im Theme oder mit einer Product Options/Metafields App meistens out-of-the-box.

 

Das Aktualisieren von Metafields aus der Storefront heraus ist auch nicht direkt möglich so wie ich das verstehe, da normalerweise werden Metafields im Shopify Admin/Admin API aktualisiert. Es gibt auch Apps wie Metafields Manager oder Metafields Guru, die es ermöglichen, Metafields zu verwalten, ohne direkt Code schreiben zu müssen.

 

Die Verwendung der Storefront API mit GraphQL-Mutationen könnte gehen, aber wie du schon sagst, wäre etwas Overkill. Somit könnte man Metafields über die Storefront API abrufen, was aber erfordert, dass die Metafields zuerst der API zugänglich gemacht werden. Dann kannst du über GraphQL Abfragen diese Informationen abrufen.

 

AJAX in Kombination mit den Shopify Ajax APIs oder mit einem Shopify App Proxy zu verwenden könnte auch gehen da mit AJAX kann man asynchron Daten an den Server senden, ohne die Seite refreshen zu müssen. Eben eine serverseitige Logik verwenden, um die Metafields zu aktualisieren.

 

Um Metafields direkt von der Produktseite aus zu aktualisieren, um asynchron Anfragen an deinen Server zu senden - es ist zu lesen, dass das Anhängen von 'json' oder 'js' an eine Produkt-URL Daten zurückgeben kann, ohne dass eine Authentifizierung erforderlich ist. Damit kann man ggf. Informationen abrufen, die dann zur Aktualisierung von Metafields genutzt werden könnten.

 

Ein einfacher Ablauf könnte wie folgt aussehen:

  1. Der Kunde gibt seine Gravierungsdaten in deine Customization Box auf der Produktseite ein.
  2. Wenn der Kunde seine Auswahl bestätigt, sendest du eine AJAX-Anfrage an deinen Server oder an einen Shopify App Proxy.
  3. Dein Server oder der App Proxy empfängt die Daten und führt eine Aktion aus, z.B. das Aktualisieren der Metafields für das betreffende Produkt über die Shopify Admin API.
  4. Der Kunde erhält eine Bestätigung, dass seine Eingabe gespeichert wurde, ohne dass die Seite neu geladen werden muss.

Hoffe das bringt dich in die richtige Richtung. Gerne kann ich bei weiteren Fragen Experten empfehlen! 😉

 

Gabe | Social Care @ Shopify
 - War meine Antwort hilfreich? Klicke Like um es mich wissen zu lassen! 
 - Wurde deine Frage beantwortet? Markiere es als Akzeptierte Lösung 
 - Um mehr zu erfahren, besuche das Shopify Help Center oder den Shopify Blog

MosDev__
Shopify Partner
48 10 12

Hey @Gabe 

 

danke für deine ausführliche Antwort, ja ich meinte die PDP. Ich arbeite mal deine Vorschlaege heute durch und wuerde mich bei Rueckfragen melden. Es wird vermutlich auf die Overill Variante rauslaufen, da ich die Values der Metafields mit in den Cart / Checkout uebernehmen soll. On the long run sollte auch ein Shopify Admin Panel dafuer gebaut werden, um die Bestellungen mit customizations anzuzeigen. Aber bis dahin reicht erst einmal der Part auf der PDP

 

Cheers,

sam 

Gabe
Shopify Staff
15955 2531 3775

Ok, hört sich gut an Sam! @MosDev__ 

 

Einen habe ich noch haha...das habe ich etwas weiter recherchiert und vielleicht hilft das auch:

 

Um Metafields in Shopify für die Storefront API zugänglich zu machen und dann über GraphQL abfragen zu können, hier ein paar weitere Schritte die ich aus unserer Developer Doku entnommen habe (vielleicht kannst du gebrauchen 😉 ) :

  1. Metafield-Definition erstellen:

    • Gehe in deinem Shopify-Adminbereich zu Einstellungen > Benutzerdefinierte Daten.
    • Wähle unter Metafields die Kategorie aus, für die du ein Metafield erstellen möchtest (z.B. Produkte, Bestellungen).
    • Klicke auf Definition hinzufügen.
    • Gib deinem Metafield eine Bezeichnung und wähle den Typ aus (z.B. Text, Zahl, Datum).
    • Unter Zugriffsoptionen aktiviere die Option Storefront. Dies ermöglicht es, dass der Inhalt von deinem Online-Shop abgerufen werden kann.
    • Speichere die Metafield-Definition.
  2. Werte zu Metafields hinzufügen:

    • Gehe zu dem Bereich in Shopify (z.B. Produkte), für den du das Metafield erstellt hast.
    • Wähle ein spezifisches Element aus (z.B. ein bestimmtes Produkt) und füge die gewünschten Werte in das entsprechende Metafield ein.
    • Speichere die Änderungen.
  3. Metafields über die Storefront API abrufen:

    • Verwende GraphQL, um eine Anfrage an die Storefront API zu stellen.
    • In deiner GraphQL-Abfrage musst du das Metafield spezifizieren, das du abrufen möchtest. Dies geschieht durch Angabe des Pfades des Metafields in der Abfrage.

Hier ist ein einfaches Beispiel für eine GraphQL-Abfrage, die ein Metafield eines Produkts abruft:

 

{
  productByHandle(handle: "my-product-handle") {
    id
    title
    metafield(namespace: "mein_namespace", key: "mein_schluessel") {
      value
    }
  }
}

 

Da ersetzt du "my-product-handle" mit dem Handle deines Produkts und "mein_namespace" sowie "mein_schluessel" mit dem entsprechenden Namespace und Schlüssel deines Metafields.

 

Alles weitere dazu hier. Und halte mich auf dem Laufenden wie das geht! 😉

Gabe | Social Care @ Shopify
 - War meine Antwort hilfreich? Klicke Like um es mich wissen zu lassen! 
 - Wurde deine Frage beantwortet? Markiere es als Akzeptierte Lösung 
 - Um mehr zu erfahren, besuche das Shopify Help Center oder den Shopify Blog

MosDev__
Shopify Partner
48 10 12

Hey @Gabe 

 

nochmal vielen Dank fuer dein Kommentar, das hat mich in die richtige Richtung gebracht. 

 

Aktueller Stand ist folgender:

  • konnte die Metafields von einem Produkt per GraphQL abfragen (Admin API)
  • Mutations haben nach etwas troubleshooting auch funktioniert. (Admin API)
  • Konnte per Postman ebenfalls die Metafields abfragen (Admin API)

Jetzt bin ich gerade dran, zu schauen wie weit ich hier mit der Storefront API komme, es scheint aber so, als kann die Storefront API nur lesen und nicht schreiben, also mutations werden damit nicht gehen. 

Wie geht man da generell mit sensiblen Daten wie z. B. Admin API Access Token um ? Ich koennte sie in eine .env ablegen, bin allerdings unsicher ob das best practice ist ? 

nächste frage ist wie ich die mutation in den quellcode bekomme und ausfuehren lasse. Ich denke die Antwort werde ich im Laufe des Tages finden und mich erneut melden.

 

Greets,

sam 

Gabe
Shopify Staff
15955 2531 3775

Hey Sam! @MosDev__ 

 

Das Arbeiten mit sensiblen Daten wie Admin API Access Tokens in Shopify und das Durchführen von Mutationen erfordert einige Überlegungen bzgl. der Sicherheit und der Implementierung. Hier sind allgemeine Best Practices und Schritte, die ich dazu gefunden habe:

 

Umgang mit Sensiblen Daten (z.B. Admin API Access Tokens)

  • Verwendung von Umgebungsvariablen (.env-Datei)Es ist eine gängige und empfohlene Praxis, sensible Daten wie API-Tokens in Umgebungsvariablen zu speichern. Eine .env-Datei wird nicht in deinem Quellcode-Repository gespeichert und hilft dabei, sensible Informationen sicher zu halten. Stelle sicher, dass die .env-Datei in deiner .gitignore-Datei aufgelistet ist, um ein versehentliches Hochladen auf öffentliche Repositories zu vermeiden.
  • Serverseitige Speicherung: Bewahre sensible Schlüssel serverseitig auf und nicht im Frontend oder Client-Side-Code, da dieser für Nutzer und Dritte zugänglich ist.
  • Sicherheitspraktiken: Implementiere zusätzliche Sicherheitsmaßnahmen wie HTTPS, um die Datenübertragung zu verschlüsseln, und beschränke den Zugriff auf die API-Tokens nur auf autorisierte Benutzer und Prozesse.

Mutationen in den Quellcode Integrieren und Ausführen

  • Backend-Logik Erstellen: Um Mutationen auszuführen, ist es empfehlenswert, eine serverseitige Logik zu implementieren. Dies könnte ein Backend-Service sein, der mit Shopify über die Admin API kommuniziert.
  • Mutationen über GraphQL: Erstelle eine GraphQL-Mutation, die spezifisch für die Aktion ist, die du ausführen möchtest. Beispielsweise das Aktualisieren eines Metafields eines Produkts.
  • Frontend-Anbindung: Im Frontend (z.B. auf deiner Produktseite) kannst du AJAX oder Fetch verwenden, um Anfragen an deinen Backend-Service zu senden. Dieser Service nimmt die Anfrage entgegen und führt die entsprechende Mutation über die Admin API aus.

Hoffe das hilft dir weiter, Sam! 😉

Gabe | Social Care @ Shopify
 - War meine Antwort hilfreich? Klicke Like um es mich wissen zu lassen! 
 - Wurde deine Frage beantwortet? Markiere es als Akzeptierte Lösung 
 - Um mehr zu erfahren, besuche das Shopify Help Center oder den Shopify Blog

MosDev__
Shopify Partner
48 10 12

Hi @Gabe,

 

Frohes Neues Jahr erst einmal ! 

ich bin weiter dran an der App und wollte an dieser Stelle kurzes Brainstorming/Rubberducking betreiben.

 

Die App soll ja Kunden die Möglichkeit bieten, eine Customization über Inputs auf der ProductDetailPage einzugeben und am Ende sollen diese Daten mit in den Cart/Checkout in die Order wandern. 

 

Die aktuelle Idee wäre folgende:

  • Auf der PDP werden die 3 Inputs (Bild Upload, Text & Bemerkung + Submit) als Section eingebunden
  • Inputs per AJAX an den Node Server zu schicken
  • Node Server schickt mittels GraphQL eine Mutation an die Shopify Admin API und aktualisiert die Metafields basierend auf die Inputs aus dem Frontend

Wichtig an der Stelle ist es zu erwähnen, dass ich mit der Mutation das Metafield eines Produkt aktualisiere. Man könnte die Mutation so schreiben, dass jedes mal ein neues Metafield erzeugt wird - bin mir aber unsicher ob das Best Practice ist.

 

Meine weitere Überlegung ist folgende:

  • Remix bietet mit Prisma eine Möglichkeit Daten in eine SQLite DB zu schreiben
  • Die Customizations eines Users wird mit seiner Cart-Session ID in die DB abgelegt
  • Metafields müssen mit in den Cart übernommen werden (ab hier wird es schwammig für mich)

Das Problem ist ja, wenn ich 2 User gleichzeitig an dem selben Produkt eine Customization machen, gewinnt ja nur die Mutation welche zuletzt gemacht wurde, deswegen muss die Customization für jeden User separat abgelegt werden und wieder mit in den Cart genommen werden soll.

 

Macht das Sinn oder siehst du eine andere Möglichkeit ?

 

Greets,

sam 

Gabe
Shopify Staff
15955 2531 3775

Hey SaM! @MosDev__ 

 

Da bin ich wieder! Wie war dein New Year? Hoffe gut... 😉 

 

Deine App, die es Kunden ermöglicht, Produkte auf der Produkt-Detailseite (PDP) zu individualisieren, wird eine tolle Sache! Hast du schon ein Name oder Branding für die App? 2024 wird ein spannendes Jahr!

 

Die Sorge hinsichtlich der Handhabung gleichzeitiger Anpassungen durch verschiedene Nutzer ist auch berechtigt. Deine Idee, einen Bild-Upload, Text und Bemerkungen als Inputs auf der PDP zu integrieren und dann per AJAX an den Node-Server zu senden, könnte gehen und es deinen User ermöglichen eine seamless UX zu geniessen ohne die Notwendigkeit, die Seite neu laden zu müssen, was ja keine gute UX ist, aus versch. Gründen.

 

Das Aktualisieren der Metafields eines Produkts erlaubt das Speichern zusätzlicher Informationen. Ob du für jede Customization ein neues Metafield erstellen solltest oder nicht, hängt aber von deinem genauen Use-Case ab. Wenn beispielsweise die Customizations nur temporär sind und für den aktuellen Einkauf relevant, könnte es besser sein, sie separat und nicht direkt als Metafield des Produkts zu speichern.

 

Dann die Customization-Daten in einer SQLite-Datenbank mit der Cart-Session-ID zu verknüpfen, scheint ein guter Weg zu sein, um die Daten für jeden Benutzer individuell zu halten. So vermeidest du beispielsweise das Problem, dass die letzte Mutation die vorherigen überschreibt.

 

Der schwierigste Teil scheint die Übernahme der Metafields in den Warenkorb und Checkout zu sein. Eine Möglichkeit könnte sein, die Customization-Daten in der Datenbank zu speichern und dann beim Checkout eine Verbindung zwischen diesen Daten und der jeweiligen Bestellung herzustellen. Du könntest auch überlegen, ob es sinnvoller ist, die Customization-Informationen als Teil des Line-Item-Objekts im Warenkorb zu speichern, anstatt sie als Metafields an Produkten anzuhängen. Dies könnte es einfacher machen, die Individualisierungen mit den Bestellungen zu verknüpfen.

 

Ab der API-Version 2023-04 wurden Metafelder für die Warenkorbrssource eingeführt. Diese Erweiterung bietet neue Möglichkeiten für die Speicherung von benutzerdefinierten Daten auf Warenkorbebene (siehe in der Dev Doku die neue CartTransform Funktion). Allerdings gibt es noch Unsicherheiten darüber, wie diese Metafelder in Shopify-Funktionsinputs integriert werden können. 

 

​Es gibt auch eine Diskussionen über die Möglichkeit, Metafelder, die im Warenkorb gesetzt wurden, automatisch in Bestellungen zu übernehmen, wenn diese aufgegeben werden. Dies könnte angeblich durch die Verwendung von Webhooks oder durch direktes Speichern der Metafeldwerte in der Bestellung selbst erreicht werden​​.

 

Es könnte also sinnvoll sein, die Metafelder auf Warenkorbebene zu nutzen, um die Anpassungen zu speichern und sicherzustellen, dass sie mit der Bestellung verknüpft werden. 

Gabe | Social Care @ Shopify
 - War meine Antwort hilfreich? Klicke Like um es mich wissen zu lassen! 
 - Wurde deine Frage beantwortet? Markiere es als Akzeptierte Lösung 
 - Um mehr zu erfahren, besuche das Shopify Help Center oder den Shopify Blog

MosDev__
Shopify Partner
48 10 12

Hey @Gabe,

 

Danke für deine ausführliche Antwort 😛 - ich komme dem Ziel mit der App immer näher. Ich komme auf deine Vorschläge aus deiner letzten Antwort im Laufe des nachmittags noch zurück, einige gute Ansätze die ich mitnehmen kann. 

 

Gehen wir einen Schritt zurück, denn es hakt an einem wichtigen Punkt auf meiner Seite - ich bin mir nicht ganz klar darüber, wie ich die Daten aus den Inputs von der Storefront an meine Remix App im Backend schicken kann. Wir hatten weiter oben über AJAX gesprochen, habe mir dazu einiges an Content durchgelesen und angeschaut, habe jedoch Probleme beim Umsetzen. Hast du vielleicht ein einfaches Beispiel für mich im Sinn ? Ich habe mein Formular (extensions/customization/form.liquid) und mein remix backend (app/server.jsx).

 

Für meine form.liquid hatte ich an so etwas gedacht:

<form method="post" action="/cart/update" id="dataForm" enctype="multipart/form-data">
  <!-- Texteingabe -->
  <label for="customer-input">Kundeninput:</label>
  <input type="text" id="customer-input" name="properties[customText]" required>

  <!-- Bildupload -->
  <label for="customer-image">Bild hochladen:</label>
  <input type="file" id="customer-image" name="properties[customImg]" accept="image/*" required>

  <!-- Multi-Line Texteingabe -->
  <label for="customer-comments">Bemerkung:</label>
  <input type="text" id="customer-comments" name="properties[customComments]" required>

  <!-- Button zum Hinzufügen -->
  <button type="button" onclick="dataCollect()">Send</button>
</form>

<script>
  function dataCollect() {
    // Informationen aus den Input-Feldern sammeln
    var customerInput = document.getElementById('customer-input').value;
    var customerImage = document.getElementById('customer-image').value;
    var customerComments = document.getElementById('customer-comments').value;

    // Daten in einem JSON-Objekt zusammenfassen
    var daten = {
      textInput: customerInput,
      imageInput: customerImage,
      commentInput: customerComments
    };

    // Daten an den Server senden (hier wird die Funktion zum Senden angenommen)
    sendDataToBackend(daten);
  }

  function sendDataToBackend(daten) {

    fetch('/dein-endpunkt', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(daten)
    })
      .then(response => response.json())
      .then(data => {
        console.log('Antwort vom Server:', data);
      })
      .catch(error => {
        console.error('Fehler beim Senden der Daten:', error);
      });
  }
</script>

 

Bin mir nicht ganz sicher, wie mein fetch Endpoint in der setDataToBackend() ausschauen muss. Hast du eine Idee ? 

cheers, 

sam 

Gabe
Shopify Staff
15955 2531 3775

Hey Sam! @MosDev__ 

 

Deine Idee, AJAX für das Sammeln und Senden von Benutzer-Inputs von der Product Detail Page (PDP) zum Server zu nutzen, ist definitiv ein guter Ansatz und könnte eine reibungslose UX ermöglichen, da die Seite dann nicht neu geladen werden muss. Hier ein paar weitere Punkte die meine Recherche unserer Entwickler Doku und der verschiedenen API Forums wie MDN Web Docs und W3Schools ergeben hat (alles aber ohne gewähr und musst du selber testen) :

AJAX-Anfrage mit fetch()

  • Der fetch()-Aufruf in deiner sendDataToBackend-Funktion scheint korrekt zu sein. Du sendest die Daten als JSON an deinen Server.
  • Der Endpunkt, an den du die Daten sendest ('/dein-endpunkt'), sollte die URL sein, die von deinem Node-Server oder deinem Remix Backend verarbeitet wird. Diese URL ist der API-Endpunkt, den du auf deinem Server definieren musst, um die eingehenden Daten zu empfangen und zu verarbeiten.

Backend-Einrichtung

  • In deinem Node-Server oder Remix-Backend musst du einen Endpunkt einrichten, der POST-Anfragen akzeptiert und die JSON-Daten verarbeitet, die von deiner PDP gesendet werden.
  • Du musst sicherstellen, dass dieser Endpunkt korrekt in deiner Serverkonfiguration eingerichtet ist und dass die entsprechenden Routen und Controller zum Empfangen und Verarbeiten der Daten vorhanden sind.

Sicherheits- und Fehlerbehandlung

  • Denke an die Sicherheit: Stelle sicher, dass dein Backend validiert und die eingehenden Daten bereinigt, um Sicherheitsprobleme wie SQL-Injection oder Cross-Site Scripting (XSS) zu vermeiden.
  • Implementiere eine robuste Fehlerbehandlung sowohl auf der Client- als auch auf der Serverseite. Auf der Clientseite solltest du Feedback an den Benutzer geben, falls etwas schiefgeht (z.B. Anzeige einer Fehlermeldung).

Verbindung zum Warenkorb und Checkout

  • Die größte Herausforderung, wie du bereits erwähnt hast, ist die Verbindung der individuellen Benutzeranpassungen mit dem Warenkorb und dem Checkout-Prozess. Dies erfordert eine sorgfältige Planung, wie diese Daten in deiner Datenbank gespeichert und mit den entsprechenden Benutzer- und Bestelldaten verknüpft werden.

Metafelder und Shopify API

  • Bezüglich der Metafelder und der Shopify API: Es ist wichtig, die neuesten Best Practices und Dokumentationen zu berücksichtigen, insbesondere wenn es um die Integration mit dem Warenkorb und dem Checkout-Prozess geht. Du könntest in Shopify-Foren oder in der Entwickler-Community nachfragen, um aktuelle Empfehlungen zu erhalten.

Um Daten von einer HTML-Form an einen Node.js-Server zu senden, gibt es verschiedene Ansätze. Die allgemeine Methode besteht darin, die Daten mit AJAX zu erfassen und sie an einen Server-Endpunkt zu senden, der für ihre Verarbeitung zuständig ist.

Schritte zum Senden von Formulardaten mit AJAX:

  • Erstellen einer HTML-Form: Deine HTML-Form kann verschiedene Eingabefelder enthalten. Ein Beispiel für eine einfache Form mit einem Textfeld könnte so aussehen:

 

<form action="/team_name_url/" method="post">
  <label for="team_name">Enter name: </label>
  <input id="team_name" type="text" name="name_field" value="Default name for team." />
  <input type="submit" value="OK" />
</form>

 

  • Verwenden von AJAX zum Senden der Daten: Anstatt die Daten direkt beim Formular-Submit zu senden, kannst du JavaScript und AJAX verwenden, um die Daten asynchron zu erfassen und zu senden. Zum Beispiel:

 

$('#formId').on('submit', function(e) {
  e.preventDefault();
  var data = $(this).serialize();
  $.ajax({
    type: 'POST',
    url: '/dein-endpunkt',
    data: data,
    success: function(response) {
      // Handle success
    },
    error: function(error) {
      // Handle error
    }
  });
});

 

  • Einrichten des Node.js-Servers: Auf der Serverseite musst du einen Express-Server einrichten, der in der Lage ist, POST-Anfragen zu verarbeiten:

 

const express = require('express');
const app = express();

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.post('/dein-endpunkt', (req, res) => {
  // Verarbeite die Daten
});

app.listen(3000, () => {
  console.log('Server läuft auf Port 3000');
});

 

Stelle sicher, dass die Daten auf dem Server validiert und bereinigt werden, um Sicherheitsrisiken wie SQL-Injection oder Cross-Site Scripting zu vermeiden.

 

Gabe | Social Care @ Shopify
 - War meine Antwort hilfreich? Klicke Like um es mich wissen zu lassen! 
 - Wurde deine Frage beantwortet? Markiere es als Akzeptierte Lösung 
 - Um mehr zu erfahren, besuche das Shopify Help Center oder den Shopify Blog

MosDev__
Shopify Partner
48 10 12

Hey @Gabe,

 

Danke für deine Antwort - der Input war sehr hilfreich !

Es gibt gute Neuigkeiten, ich hab das Feature zu Ende entwickelt bekommen - allerdings mit einem völlig anderen Ansatz als den, welchen wir die letzten 2 Wochen besprochen hatten. Mit GraphQL/mutations etc. wäre das ebenfalls alles möglich gewesen, jedoch nach langem Chat mit meinem Kollegen ein absoluter Overkill bzw. way-to-complicated. 

Die Antwort sind simple Custom Field Input, welche an die Product Form angehängt werden und vom Cart über den Checkout bis in die Order Details mitgegeben werden. Die notwendigen Input Felder konnte ich mir hier generieren lassen -> https://amineammari.com/field-generator-for-shopify-product-pages/ 

 

Vielen Dank für deine Unterstützung mit dieser Frage ! Hier wird einem geholfen 😛

 

cheers,

sam 

Gabe
Shopify Staff
15955 2531 3775

Wow, das hört sich viel besser an! Poste hier einen Link zu deiner App sobald sie proof-of-concept ist und wir können auch etwas User-Testing durchführen!! 😉

Gabe | Social Care @ Shopify
 - War meine Antwort hilfreich? Klicke Like um es mich wissen zu lassen! 
 - Wurde deine Frage beantwortet? Markiere es als Akzeptierte Lösung 
 - Um mehr zu erfahren, besuche das Shopify Help Center oder den Shopify Blog

MosDev__
Shopify Partner
48 10 12

Erfolg.

Hey @Gabe 

 

Die App nimmt immer mehr Form an. Aktuell im Codereview. Ich teile gerne meinen Liquid Code mit euch, schaut mal hier:

 

3 Inputs (Image Upload, Heading, Description)

Image restrictions: max. 800x800, .jpeg-only, max. 2MB

Heading max. 50 digits

Description max. 5 Lines

{% comment %}
  @feature     Customization Section/Block for PDP
  @theme       Dawn 10.0
{% endcomment %}

<div>
  <div class="product-form__input">
    <label class="form__label">Image Upload</label>
    <input
      id="image"
      type="file"
      form="{{ 'product-form-' | append: section.id }}"
      name="properties[Image Upload]"
      accept=".jpg"
      max-width="800"
      max-height="800"
      max-size="2"
      required>
    <script>
      document.addEventListener("DOMContentLoaded", ()=>{document.querySelector("form[novalidate]").removeAttribute("novalidate")})
    </script>
  </div>

  <style>.custom.form__label{margin-bottom: 0.6rem}.field.custom{margin-top:0}.custom .field__input{padding-top:0.8rem}</style>
  <label class="form__label custom" for="heading">Heading</label>
  <div class="field custom">
    <input
      class="field__input"
      form="{{ 'product-form-' | append: section.id }}"
      type="text"
      id="heading"
      name="properties[Heading]"
      maxlength="50"
      required
    >
    <script>
      document.addEventListener("DOMContentLoaded", ()=>{document.querySelector("form[novalidate]").removeAttribute("novalidate")})
      document.querySelector('#heading').addEventListener('input',(e)=>{
        if(!document.querySelector('label[for="heading"] span')){
          const span = document.createElement("span");
          span.style.marginLeft = '10px'
          document.querySelector('label[for="heading"]').appendChild(span)
        }
        document.querySelector('label[for="heading"] span').style.display  = 'inline'
        document.querySelector('label[for="heading"] span').textContent = e.target.value.length + ' | ' + 50
        if(e.target.value.length==0){
          document.querySelector('label[for="heading"] span').style.display  = 'none'
        }})
    </script>
  </div>

  <style>.custom.form__label{margin-bottom: 0.6rem}.field.custom{margin-top:0}.custom .field__input{padding-top:0.8rem}</style>
  <label class="form__label custom" for="description">Description</label>
  <div class="field custom">
        <textarea
          class="text-area field__input"
          id="description"
          form="{{ 'product-form-' | append: section.id }}"
          name="properties[Description]">
        </textarea>
        <script>
          document.getElementById('description').addEventListener('input', function() {
            var lines = this.value.split('\n');
            if (lines.length > 5) {
            alert('Maximum 5 lines allowed.');
            this.value = lines.slice(0, 5).join('\n');
            }
          });
        </script>
  </div>
</div>

<script>
  {% comment %} Logic for Image Requirements {% endcomment %}
  document.getElementById('image').addEventListener('change', function() {
    var fileInput = this;
    var maxWidth = fileInput.getAttribute('max-width');
    var maxHeight = fileInput.getAttribute('max-height');
    var maxSize = fileInput.getAttribute('max-size');

    var file = fileInput.files[0];

    if (file.type !== 'image/jpeg') {
      alert('Please select a valid JPG image.');
      fileInput.value = ''; // clear Input
      return;
    }

    var img = new Image();
    img.onload = function() {
      if (img.width > maxWidth || img.height > maxHeight) {
        alert('Image dimensions must be at most 800x800 pixels.');
        fileInput.value = ''; // clear Input
      }
    };
    img.src=URL.createObjectURL(file);

    if (file.size > maxSize * 1024 * 1024) {
      alert('File size must be at most 2MB.');
      fileInput.value = ''; // clear Input
    }
  });
</script>


{% schema %}
{
  "name": "PDP Customization",
  "target": "section"
}
{% endschema %}

 Bei Fragen, gerne melden !

 

cheers,

sam 

Gabe
Shopify Staff
15955 2531 3775

Wow sieht super aus! Gute arbeit Sam! 😉

giphy

Gabe | Social Care @ Shopify
 - War meine Antwort hilfreich? Klicke Like um es mich wissen zu lassen! 
 - Wurde deine Frage beantwortet? Markiere es als Akzeptierte Lösung 
 - Um mehr zu erfahren, besuche das Shopify Help Center oder den Shopify Blog