Checkout-, Adress- und Anmeldefelder brauchen Beschriftungen, automatisches Ausfüllen und verknüpfte Fehlermeldungen
Im Checkout verdient der Shop sein Geld. Ohne Beschriftungen wissen Menschen, die einen Screenreader nutzen, nicht, was sie eingeben sollen; ohne automatisches Ausfüllen müssen Menschen mit motorischen oder Gedächtniseinschränkungen ihre Adresse von Hand eintippen; und wenn Fehlermeldungen nicht mit ihren Feldern verknüpft sind, finden Kundinnen und Kunden nicht heraus, was schiefgelaufen ist, und brechen die Bestellung ab.
- Regel-ID
- vs-forms-ecommerce
- Quelle
- Validiscan-Prüfung
- Auswirkung
- Kritisch
- Korrekturstufe
- AUTO
- auf Shopify, Shopware, WooCommerce und Magento
- Status
- wird ausgeführt
Was geprüft wird
Prüft Felder in Checkout, Adresse, Kundenkonto und Anmeldung auf fehlende autocomplete-Tokens (1.3.5), fehlende Beschriftungen oder Anleitungen und nicht gekennzeichnete Pflichtfelder (3.3.2) sowie Fehlermeldungen, die nicht mit ihren Feldern verknüpft sind (3.3.1). Ersetzt die axe-Regeln label und autocomplete-valid.
Auf jeder Seite betrachtet die Prüfung jedes input, select und textarea, das assistive Technologien wahrnehmen können, außer versteckten Feldern und Eingaben vom Typ Schaltfläche. Als Beschriftung zählt ein <label>, aria-label, aria-labelledby oder title, ein Platzhalter dagegen nicht. Ob der Text der Beschriftung das Feld zutreffend beschreibt, wird nicht getestet.
Den Zweck eines Feldes vermutet die Prüfung anhand von type, name, id, dem Text der Beschriftung und placeholder. Ist ein Zweck erkannt und hat das Feld kein autocomplete-Token oder steht dort on, off oder ein ungültiges Token, ist das ein Befund. Ausgenommen ist off an einem Passwortfeld. Ein gültiges Token, das vom erwarteten abweicht, ergibt keinen Befund.
Eine Fehlermeldung (role="alert" oder eine Fehlerklasse, neben einem einzelnen Feld) wird gemeldet, wenn sie nicht in einem label steht und weder aria-describedby noch aria-errormessage auf sie verweist. Dasselbe gilt für ein Feld mit aria-invalid="true" ohne verknüpfte Meldung. Ein Pflichtfeld (required oder aria-required="true", Kontrollkästchen und Radiobuttons ausgenommen), dessen Beschriftung weder ein Sternchen noch einen Hinweis auf die Pflichtangabe zeigt, wird gemeldet. Das gilt nicht, wenn das Formular die optionalen Felder kennzeichnet, angibt, dass alle Felder Pflicht sind, oder tatsächlich jedes Feld verlangt. Ein Feld, das nur optisch als Pflichtfeld markiert ist, wird ebenfalls gemeldet.
So wird es behoben
Geben Sie jedem Feld ein sichtbares <label>, das über for und id verknüpft ist, ergänzen Sie das passende autocomplete-Token (given-name, family-name, street-address, postal-code, email, tel, current-password und so weiter), kennzeichnen Sie Pflichtfelder in der Beschriftung und mit dem required-Attribut, und verbinden Sie Fehlermeldungen über aria-describedby und aria-invalid="true" mit ihren Feldern.
WCAG-Erfolgskriterien
- 1.3.5 Identify Input Purpose, Stufe AA
- 3.3.1 Error Identification, Stufe A
- 3.3.2 Labels or Instructions, Stufe A
Abschnitte der EN 301 549
| WCAG-Kriterium | Version 3.2.1 | Version 4.1.1 |
|---|---|---|
| 1.3.5 | 9.1.3.5 | 9.1.3.5 |
| 3.3.1 | 9.3.3.1 | 9.3.3.1 |
| 3.3.2 | 9.3.3.2 | 9.3.3.2 |
Wo ein Rezept es behebt
Shopify: Rezept autocomplete-tokens
Vorher und nachher anzeigen (1)
sections/contact-form.liquid Änderungen an sections/contact-form.liquid: 1 hinzugefügt, 1 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 14 | 14 | {%- form 'contact', id: 'ContactForm', class: 'contact__form' %} | |
| 15 | 15 | <div class="contact__fields"> | |
| 16 | 16 | <div class="field"> | |
| 17 | Entfernt | <input class="field__input" type="text" name="contact[name]" placeholder="{{ 'templates.contact.form.name' | t }}"> | |
| 17 | Hinzugefügt | <input class="field__input" type="text" name="contact[name]" placeholder="{{ 'templates.contact.form.name' | t }}" autocomplete="name"> | |
| 18 | 18 | </div> | |
| 19 | 19 | <div class="field"> | |
| 20 | 20 | <input class="field__input" type="email" name="contact[email]" placeholder="{{ 'templates.contact.form.email' | t }} *" required> |
sections/footer.liquid Änderungen an sections/footer.liquid: 1 hinzugefügt, 1 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 11 | 11 | {%- form 'customer', id: 'ContactFooter', class: 'footer__newsletter newsletter-form' -%} | |
| 12 | 12 | <input type="hidden" name="contact[tags]" value="newsletter"> | |
| 13 | 13 | <div class="newsletter-form__field-wrapper"> | |
| 14 | Entfernt | <input type="email" name="contact[email]" class="field__input" placeholder="{{ 'newsletter.label' | t }}" autocorrect="off" autocapitalize="off"> | |
| 14 | Hinzugefügt | <input type="email" name="contact[email]" class="field__input" placeholder="{{ 'newsletter.label' | t }}" autocorrect="off" autocapitalize="off" autocomplete="email"> | |
| 15 | 15 | <button type="submit" class="button newsletter-form__button" name="commit">{{ 'newsletter.button' | t }}</button> | |
| 16 | 16 | </div> | |
| 17 | 17 | {%- endform -%} |
sections/main-login.liquid Änderungen an sections/main-login.liquid: 1 hinzugefügt, 1 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 10 | 10 | {%- form 'customer_login', novalidate: 'novalidate' %} | |
| 11 | 11 | <div class="field"> | |
| 12 | 12 | <label class="field__label" for="CustomerEmail">{{ 'customer.login_page.email' | t }}</label> | |
| 13 | Entfernt | <input class="field__input" type="email" name="customer[email]" id="CustomerEmail" autocorrect="off" autocapitalize="off"> | |
| 13 | Hinzugefügt | <input class="field__input" type="email" name="customer[email]" id="CustomerEmail" autocorrect="off" autocapitalize="off" autocomplete="email"> | |
| 14 | 14 | </div> | |
| 15 | 15 | <div class="field"> | |
| 16 | 16 | <label class="field__label" for="CustomerPassword">{{ 'customer.login_page.password' | t }}</label> |
snippets/checkout-field.liquid Änderungen an snippets/checkout-field.liquid: 4 hinzugefügt, 4 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 15 | 15 | <div class="field"> | |
| 16 | 16 | {%- case legacy %} | |
| 17 | 17 | {%- when 'placeholder' %} | |
| 18 | Entfernt | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}" placeholder="{{ label }}"{% if required %} required{% endif %}> | |
| 18 | Hinzugefügt | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}" placeholder="{{ label }}"{% if required %} required{% endif %} autocomplete="{{ autocomplete }}"> | |
| 19 | 19 | {%- when 'starred' %} | |
| 20 | 20 | <label class="field__label" for="{{ field_id }}">{{ label }} *</label> | |
| 21 | Entfernt | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}"> | |
| 21 | Hinzugefügt | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}" autocomplete="{{ autocomplete }}"> | |
| 22 | 22 | {%- when 'off' %} | |
| 23 | 23 | <label class="field__label" for="{{ field_id }}">{{ label }}</label> | |
| 24 | Entfernt | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}" autocomplete="off"{% if required %} required{% endif %}> | |
| 24 | Hinzugefügt | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}" autocomplete="{{ autocomplete }}"{% if required %} required{% endif %}> | |
| 25 | 25 | {%- else %} | |
| 26 | 26 | <label class="field__label" for="{{ field_id }}">{{ label }}</label> | |
| 27 | Entfernt | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}"{% if required %} required{% endif %}> | |
| 27 | Hinzugefügt | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}"{% if required %} required{% endif %} autocomplete="{{ autocomplete }}"> | |
| 28 | 28 | {%- endcase %} | |
| 29 | 29 | </div> |
Shopify: Rezept label-association
Vorher und nachher anzeigen (1)
sections/main-collection.liquid Änderungen an sections/main-collection.liquid: 2 hinzugefügt, 2 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 64 | 64 | <div class="collection__products"> | |
| 65 | 65 | <div class="collection__toolbar"> | |
| 66 | 66 | <div class="collection__sort"> | |
| 67 | Entfernt | <label class="collection__sort-label">Sort by</label> | |
| 68 | Entfernt | <select name="sort_by" class="select__select" form="FacetFiltersForm"> | |
| 67 | Hinzugefügt | <label class="collection__sort-label" for="SortBy-{{ section.id }}">Sort by</label> | |
| 68 | Hinzugefügt | <select name="sort_by" class="select__select" form="FacetFiltersForm" id="SortBy-{{ section.id }}"> | |
| 69 | 69 | <option value="manual" selected>Featured</option> | |
| 70 | 70 | <option value="best-selling">Best selling</option> | |
| 71 | 71 | <option value="price-ascending">Price, low to high</option> |
sections/main-product.liquid Änderungen an sections/main-product.liquid: 2 hinzugefügt, 2 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 94 | 94 | </div> | |
| 95 | 95 | {%- else %} | |
| 96 | 96 | <div class="product-form__input product-form__input--dropdown"> | |
| 97 | Entfernt | <p class="form__label">{{ option.name | escape }}</p> | |
| 97 | Hinzugefügt | <p class="form__label" id="Options-{{ section.id }}-{{ forloop.index0 }}-label">{{ option.name | escape }}</p> | |
| 98 | 98 | <div class="select"> | |
| 99 | Entfernt | <select class="select__select" name="options[{{ option.name | escape }}]" data-option-index="{{ option_index }}"> | |
| 99 | Hinzugefügt | <select class="select__select" name="options[{{ option.name | escape }}]" data-option-index="{{ option_index }}" aria-labelledby="Options-{{ section.id }}-{{ forloop.index0 }}-label"> | |
| 100 | 100 | {%- for value in option.values %} | |
| 101 | 101 | <option value="{{ value | escape }}"{% if value == option.selected_value %} selected{% endif %}>{{ value | escape }}</option> | |
| 102 | 102 | {%- endfor %} |
Shopware: Rezept autocomplete-tokens
Vorher und nachher anzeigen (1)
Resources/views/storefront/component/account/login.html.twig Änderungen an Resources/views/storefront/component/account/login.html.twig: 1 hinzugefügt, 1 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 19 | 19 | name="username" | |
| 20 | 20 | placeholder="{{ 'account.loginMailPlaceholder'|trans }}" | |
| 21 | 21 | required | |
| 22 | Entfernt | autocomplete="off"> | |
| 22 | Hinzugefügt | autocomplete="email"> | |
| 23 | 23 | </div> | |
| 24 | 24 | ||
| 25 | 25 | <div class="form-group"> |
Resources/views/storefront/component/account/register.html.twig Änderungen an Resources/views/storefront/component/account/register.html.twig: 8 hinzugefügt, 4 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 33 | 33 | id="{{ formId }}FirstName" | |
| 34 | 34 | name="firstName" | |
| 35 | 35 | placeholder="{{ 'account.firstNamePlaceholder'|trans }}" | |
| 36 | Entfernt | required> | |
| 36 | Hinzugefügt | required | |
| 37 | Hinzugefügt | autocomplete="given-name"> | |
| 37 | 38 | </div> | |
| 38 | 39 | <div class="form-group col-sm-6"> | |
| 39 | 40 | <input type="text" | |
| 41 | 42 | id="{{ formId }}LastName" | |
| 42 | 43 | name="lastName" | |
| 43 | 44 | placeholder="{{ 'account.lastNamePlaceholder'|trans }}" | |
| 44 | Entfernt | required> | |
| 45 | Hinzugefügt | required | |
| 46 | Hinzugefügt | autocomplete="family-name"> | |
| 45 | 47 | </div> | |
| 46 | 48 | </div> | |
| 47 | 49 | <div class="row g-2"> | |
| 52 | 54 | id="{{ formId }}Mail" | |
| 53 | 55 | name="email" | |
| 54 | 56 | placeholder="{{ 'account.emailPlaceholder'|trans }}" | |
| 55 | Entfernt | required> | |
| 57 | Hinzugefügt | required | |
| 58 | Hinzugefügt | autocomplete="email"> | |
| 56 | 59 | </div> | |
| 57 | 60 | <div class="form-group col-sm-6"> | |
| 58 | 61 | <label class="form-label" for="{{ formId }}Password">{{ 'account.passwordLabel'|trans }}</label> | |
| 62 | 65 | name="password" | |
| 63 | 66 | minlength="8" | |
| 64 | 67 | aria-describedby="{{ formId }}PasswordHint" | |
| 65 | Entfernt | required> | |
| 68 | Hinzugefügt | required | |
| 69 | Hinzugefügt | autocomplete="new-password"> | |
| 66 | 70 | <small class="form-text" id="{{ formId }}PasswordHint">{{ 'account.passwordHint'|trans }}</small> | |
| 67 | 71 | </div> | |
| 68 | 72 | </div> |
Resources/views/storefront/component/address/address-form.html.twig Änderungen an Resources/views/storefront/component/address/address-form.html.twig: 8 hinzugefügt, 4 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 14 | 14 | id="{{ prefix }}AddressStreet" | |
| 15 | 15 | name="{{ prefix }}[street]" | |
| 16 | 16 | placeholder="{{ 'address.streetPlaceholder'|trans }}" | |
| 17 | Entfernt | required> | |
| 17 | Hinzugefügt | required | |
| 18 | Hinzugefügt | autocomplete="address-line1"> | |
| 18 | 19 | </div> | |
| 19 | 20 | {% endblock %} | |
| 20 | 21 | ||
| 26 | 27 | name="{{ prefix }}[zipcode]" | |
| 27 | 28 | placeholder="{{ 'address.zipcodePlaceholder'|trans }}" | |
| 28 | 29 | inputmode="numeric" | |
| 29 | Entfernt | required> | |
| 30 | Hinzugefügt | required | |
| 31 | Hinzugefügt | autocomplete="postal-code"> | |
| 30 | 32 | </div> | |
| 31 | 33 | {% endblock %} | |
| 32 | 34 | ||
| 37 | 39 | class="form-control" | |
| 38 | 40 | id="{{ prefix }}AddressCity" | |
| 39 | 41 | name="{{ prefix }}[city]" | |
| 40 | Entfernt | required> | |
| 42 | Hinzugefügt | required | |
| 43 | Hinzugefügt | autocomplete="address-level2"> | |
| 41 | 44 | </div> | |
| 42 | 45 | {% endblock %} | |
| 43 | 46 | ||
| 47 | 50 | <select class="form-select" | |
| 48 | 51 | id="{{ prefix }}AddressCountry" | |
| 49 | 52 | name="{{ prefix }}[countryId]" | |
| 50 | Entfernt | required> | |
| 53 | Hinzugefügt | required | |
| 54 | Hinzugefügt | autocomplete="country"> | |
| 51 | 55 | {% for country in countries %} | |
| 52 | 56 | <option value="{{ country.id }}"{% if loop.first %} selected{% endif %}>{{ country.name }}</option> | |
| 53 | 57 | {% endfor %} |
Resources/views/storefront/element/cms-element-form.html.twig Änderungen an Resources/views/storefront/element/cms-element-form.html.twig: 4 hinzugefügt, 4 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 18 | 18 | </select> | |
| 19 | 19 | </div> | |
| 20 | 20 | <div class="form-group col-md-4"> | |
| 21 | Entfernt | <input type="text" class="form-control" id="contactFormFirstName" name="firstName" placeholder="{{ 'account.firstNamePlaceholder'|trans }}" required> | |
| 21 | Hinzugefügt | <input type="text" class="form-control" id="contactFormFirstName" name="firstName" placeholder="{{ 'account.firstNamePlaceholder'|trans }}" required autocomplete="given-name"> | |
| 22 | 22 | </div> | |
| 23 | 23 | <div class="form-group col-md-4"> | |
| 24 | Entfernt | <input type="text" class="form-control" id="contactFormLastName" name="lastName" placeholder="{{ 'account.lastNamePlaceholder'|trans }}" required> | |
| 24 | Hinzugefügt | <input type="text" class="form-control" id="contactFormLastName" name="lastName" placeholder="{{ 'account.lastNamePlaceholder'|trans }}" required autocomplete="family-name"> | |
| 25 | 25 | </div> | |
| 26 | 26 | </div> | |
| 27 | 27 | ||
| 28 | 28 | <div class="row g-2"> | |
| 29 | 29 | <div class="form-group col-md-6"> | |
| 30 | 30 | <label class="form-label" for="contactFormMail">{{ 'account.emailLabel'|trans }}</label> | |
| 31 | Entfernt | <input type="email" class="form-control" id="contactFormMail" name="email" placeholder="{{ 'account.emailPlaceholder'|trans }}" required> | |
| 31 | Hinzugefügt | <input type="email" class="form-control" id="contactFormMail" name="email" placeholder="{{ 'account.emailPlaceholder'|trans }}" required autocomplete="email"> | |
| 32 | 32 | </div> | |
| 33 | 33 | <div class="form-group col-md-6"> | |
| 34 | 34 | <label class="form-label" for="contactFormPhone">{{ 'contact.phoneLabel'|trans }}</label> | |
| 35 | Entfernt | <input type="tel" class="form-control" id="contactFormPhone" name="phone"> | |
| 35 | Hinzugefügt | <input type="tel" class="form-control" id="contactFormPhone" name="phone" autocomplete="tel"> | |
| 36 | 36 | </div> | |
| 37 | 37 | </div> | |
| 38 | 38 |
Resources/views/storefront/layout/footer/footer.html.twig Änderungen an Resources/views/storefront/layout/footer/footer.html.twig: 2 hinzugefügt, 1 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 62 | 62 | id="footerNewsletterMail" | |
| 63 | 63 | class="form-control" | |
| 64 | 64 | placeholder="{{ 'footer.newsletterPlaceholder'|trans }}" | |
| 65 | Entfernt | required> | |
| 65 | Hinzugefügt | required | |
| 66 | Hinzugefügt | autocomplete="email"> | |
| 66 | 67 | <button type="submit" class="btn btn-primary newsletter-submit">{{ 'footer.newsletterSubmit'|trans }}</button> | |
| 67 | 68 | </div> | |
| 68 | 69 | <div class="form-check newsletter-privacy"> |
Shopware: Rezept label-association
Vorher und nachher anzeigen (1)
Resources/views/storefront/page/product-detail/configurator.html.twig Änderungen an Resources/views/storefront/page/product-detail/configurator.html.twig: 1 hinzugefügt, 1 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 13 | 13 | {% for group in product.configurator %} | |
| 14 | 14 | {% if group.display == 'select' %} | |
| 15 | 15 | <div class="product-detail-configurator-group"> | |
| 16 | Entfernt | <div class="product-detail-configurator-group-title">{{ group.name }}</div> | |
| 16 | Hinzugefügt | <label class="product-detail-configurator-group-title" for="configurator-{{ group.id }}">{{ group.name }}</label> | |
| 17 | 17 | <select class="form-select product-detail-configurator-select-input" | |
| 18 | 18 | id="configurator-{{ group.id }}" | |
| 19 | 19 | name="{{ group.id }}"{% if group.price|default(false) %} |
WooCommerce: Rezept autocomplete-tokens
Vorher und nachher anzeigen (1)
functions.php Änderungen an functions.php: 44 hinzugefügt, 0 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 308 | 308 | * here; the remediation adds one for pages with the _kb_content_language meta and marks the | |
| 309 | 309 | * English header and footer with lang="en-GB". | |
| 310 | 310 | */ | |
| 311 | Hinzugefügt | ||
| 312 | Hinzugefügt | /* validiscan:autocomplete-tokens */ | |
| 313 | Hinzugefügt | /** | |
| 314 | Hinzugefügt | * Autocomplete tokens for the WooCommerce address fields, so browsers and assistive | |
| 315 | Hinzugefügt | * technology know what each field asks for (WCAG 1.3.5). Runs after the theme's own | |
| 316 | Hinzugefügt | * field filters. | |
| 317 | Hinzugefügt | * | |
| 318 | Hinzugefügt | * @param array $fields Checkout fields (grouped by section) or one address section. | |
| 319 | Hinzugefügt | * @return array | |
| 320 | Hinzugefügt | */ | |
| 321 | Hinzugefügt | function kb_address_autocomplete( $fields ) { | |
| 322 | Hinzugefügt | $tokens = array( | |
| 323 | Hinzugefügt | 'first_name' => 'given-name', | |
| 324 | Hinzugefügt | 'last_name' => 'family-name', | |
| 325 | Hinzugefügt | 'company' => 'organization', | |
| 326 | Hinzugefügt | 'country' => 'country', | |
| 327 | Hinzugefügt | 'address_1' => 'address-line1', | |
| 328 | Hinzugefügt | 'address_2' => 'address-line2', | |
| 329 | Hinzugefügt | 'city' => 'address-level2', | |
| 330 | Hinzugefügt | 'state' => 'address-level1', | |
| 331 | Hinzugefügt | 'postcode' => 'postal-code', | |
| 332 | Hinzugefügt | 'phone' => 'tel', | |
| 333 | Hinzugefügt | 'email' => 'email', | |
| 334 | Hinzugefügt | ); | |
| 335 | Hinzugefügt | foreach ( $fields as $key => $field ) { | |
| 336 | Hinzugefügt | if ( ! is_array( $field ) ) { | |
| 337 | Hinzugefügt | continue; | |
| 338 | Hinzugefügt | } | |
| 339 | Hinzugefügt | if ( 'billing' === $key || 'shipping' === $key ) { | |
| 340 | Hinzugefügt | $fields[ $key ] = kb_address_autocomplete( $field ); | |
| 341 | Hinzugefügt | continue; | |
| 342 | Hinzugefügt | } | |
| 343 | Hinzugefügt | if ( ! preg_match( '/^(billing|shipping)_(.+)$/', (string) $key, $match ) || ! isset( $tokens[ $match[2] ] ) ) { | |
| 344 | Hinzugefügt | continue; | |
| 345 | Hinzugefügt | } | |
| 346 | Hinzugefügt | $fields[ $key ]['autocomplete'] = ( 'shipping' === $match[1] ? 'shipping ' : '' ) . $tokens[ $match[2] ]; | |
| 347 | Hinzugefügt | unset( $fields[ $key ]['custom_attributes']['autocomplete'] ); | |
| 348 | Hinzugefügt | } | |
| 349 | Hinzugefügt | return $fields; | |
| 350 | Hinzugefügt | } | |
| 351 | Hinzugefügt | add_filter( 'woocommerce_checkout_fields', 'kb_address_autocomplete', 99 ); | |
| 352 | Hinzugefügt | add_filter( 'woocommerce_billing_fields', 'kb_address_autocomplete', 99 ); | |
| 353 | Hinzugefügt | add_filter( 'woocommerce_shipping_fields', 'kb_address_autocomplete', 99 ); | |
| 354 | Hinzugefügt | /* /validiscan:autocomplete-tokens */ |
woocommerce/myaccount/form-login.php Änderungen an woocommerce/myaccount/form-login.php: 3 hinzugefügt, 3 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 29 | 29 | ||
| 30 | 30 | <p class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide"> | |
| 31 | 31 | <label for="username"><?php esc_html_e( 'Username or email address', 'woocommerce' ); ?> <span class="required">*</span></label> | |
| 32 | Entfernt | <input type="text" class="woocommerce-Input woocommerce-Input--text input-text" name="username" id="username" autocomplete="off" value="<?php echo ( ! empty( $_POST['username'] ) ) ? esc_attr( wp_unslash( $_POST['username'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized ?>"> | |
| 32 | Hinzugefügt | <input type="text" class="woocommerce-Input woocommerce-Input--text input-text" name="username" id="username" autocomplete="username" value="<?php echo ( ! empty( $_POST['username'] ) ) ? esc_attr( wp_unslash( $_POST['username'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized ?>"> | |
| 33 | 33 | </p> | |
| 34 | 34 | <p class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide"> | |
| 35 | 35 | <label for="password"><?php esc_html_e( 'Password', 'woocommerce' ); ?> <span class="required">*</span></label> | |
| 36 | 36 | <span class="password-input"> | |
| 37 | Entfernt | <input class="woocommerce-Input woocommerce-Input--text input-text" type="password" name="password" id="password" autocomplete="off" onpaste="return false;"> | |
| 37 | Hinzugefügt | <input class="woocommerce-Input woocommerce-Input--text input-text" type="password" name="password" id="password" autocomplete="current-password" onpaste="return false;"> | |
| 38 | 38 | <button type="button" class="show-password-input"><?php kb_icon( 'eye' ); ?></button> | |
| 39 | 39 | </span> | |
| 40 | 40 | </p> | |
| 63 | 63 | <?php do_action( 'woocommerce_register_form_start' ); ?> | |
| 64 | 64 | ||
| 65 | 65 | <p class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide"> | |
| 66 | Entfernt | <input type="email" class="woocommerce-Input woocommerce-Input--text input-text" name="email" id="reg_email" autocomplete="off" value="" placeholder="<?php esc_attr_e( 'Email address *', 'kestrel-birch' ); ?>"> | |
| 66 | Hinzugefügt | <input type="email" class="woocommerce-Input woocommerce-Input--text input-text" name="email" id="reg_email" autocomplete="email" value="" placeholder="<?php esc_attr_e( 'Email address *', 'kestrel-birch' ); ?>"> | |
| 67 | 67 | </p> | |
| 68 | 68 | <p><?php esc_html_e( 'A link to set a new password will be sent to your email address.', 'woocommerce' ); ?></p> | |
| 69 | 69 |
WooCommerce: Rezept label-association
Vorher und nachher anzeigen (1)
woocommerce/cart/cart.php Änderungen an woocommerce/cart/cart.php: 1 hinzugefügt, 1 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 62 | 62 | <tr> | |
| 63 | 63 | <td colspan="6" class="actions"> | |
| 64 | 64 | <div class="coupon"> | |
| 65 | Entfernt | <label class="screen-reader-text"><?php esc_html_e( 'Coupon:', 'woocommerce' ); ?></label> | |
| 65 | Hinzugefügt | <label class="screen-reader-text" for="coupon_code"><?php esc_html_e( 'Coupon:', 'woocommerce' ); ?></label> | |
| 66 | 66 | <input type="text" name="coupon_code" class="input-text" id="coupon_code" value="" placeholder="<?php esc_attr_e( 'Coupon code', 'woocommerce' ); ?>"> | |
| 67 | 67 | <button type="submit" class="button" name="apply_coupon" value="<?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?>"><?php esc_html_e( 'Apply coupon', 'woocommerce' ); ?></button> | |
| 68 | 68 | </div> |
Magento: Rezept autocomplete-tokens
Vorher und nachher anzeigen (1)
app/design/frontend/Validiscan/fixture/Magento_Contact/templates/form.phtml Änderungen an app/design/frontend/Validiscan/fixture/Magento_Contact/templates/form.phtml: 3 hinzugefügt, 3 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 21 | 21 | <!-- VALIDISCAN-SEEDED vs-forms-ecommerce: name, email and phone lack autocomplete; required only via the CSS asterisk --> | |
| 22 | 22 | <div class="field name required"> | |
| 23 | 23 | <label class="label" for="name"><span><?= $escaper->escapeHtml(__('Name')) ?></span></label> | |
| 24 | Entfernt | <div class="control"><input name="name" id="name" title="<?= $escaper->escapeHtmlAttr(__('Name')) ?>" value="<?= $escaper->escapeHtmlAttr($viewModel->getUserName()) ?>" class="input-text" type="text"></div> | |
| 24 | Hinzugefügt | <div class="control"><input name="name" id="name" title="<?= $escaper->escapeHtmlAttr(__('Name')) ?>" value="<?= $escaper->escapeHtmlAttr($viewModel->getUserName()) ?>" class="input-text" type="text" autocomplete="name"></div> | |
| 25 | 25 | </div> | |
| 26 | 26 | <div class="field email required"> | |
| 27 | 27 | <label class="label" for="email"><span><?= $escaper->escapeHtml(__('Email')) ?></span></label> | |
| 28 | Entfernt | <div class="control"><input name="email" id="email" title="<?= $escaper->escapeHtmlAttr(__('Email')) ?>" value="<?= $escaper->escapeHtmlAttr($viewModel->getUserEmail()) ?>" class="input-text" type="email"></div> | |
| 28 | Hinzugefügt | <div class="control"><input name="email" id="email" title="<?= $escaper->escapeHtmlAttr(__('Email')) ?>" value="<?= $escaper->escapeHtmlAttr($viewModel->getUserEmail()) ?>" class="input-text" type="email" autocomplete="email"></div> | |
| 29 | 29 | </div> | |
| 30 | 30 | <div class="field telephone"> | |
| 31 | 31 | <label class="label" for="telephone"><span><?= $escaper->escapeHtml(__('Phone Number')) ?></span></label> | |
| 32 | Entfernt | <div class="control"><input name="telephone" id="telephone" title="<?= $escaper->escapeHtmlAttr(__('Phone Number')) ?>" value="<?= $escaper->escapeHtmlAttr($viewModel->getUserTelephone()) ?>" class="input-text" type="tel"></div> | |
| 32 | Hinzugefügt | <div class="control"><input name="telephone" id="telephone" title="<?= $escaper->escapeHtmlAttr(__('Phone Number')) ?>" value="<?= $escaper->escapeHtmlAttr($viewModel->getUserTelephone()) ?>" class="input-text" type="tel" autocomplete="tel"></div> | |
| 33 | 33 | </div> | |
| 34 | 34 | <div class="field comment required"> | |
| 35 | 35 | <label class="label" for="comment"><span><?= $escaper->escapeHtml(__('What’s on your mind?')) ?></span></label> |
app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/login.phtml Änderungen an app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/login.phtml: 2 hinzugefügt, 2 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 27 | 27 | <div class="field email required"> | |
| 28 | 28 | <label class="label" for="email"><span><?= $escaper->escapeHtml(__('Email')) ?></span></label> | |
| 29 | 29 | <div class="control"> | |
| 30 | Entfernt | <input name="login[username]" value="<?= $escaper->escapeHtmlAttr($username) ?>" autocomplete="off" id="email" type="email" class="input-text mage-error" title="<?= $escaper->escapeHtmlAttr(__('Email')) ?>" aria-invalid="true" tabindex="1" onpaste="return false;" data-mage-init='{"mage/trim-input":{}}'> | |
| 30 | Hinzugefügt | <input name="login[username]" value="<?= $escaper->escapeHtmlAttr($username) ?>" autocomplete="email" id="email" type="email" class="input-text mage-error" title="<?= $escaper->escapeHtmlAttr(__('Email')) ?>" aria-invalid="true" tabindex="1" onpaste="return false;" data-mage-init='{"mage/trim-input":{}}'> | |
| 31 | 31 | <div for="email" generated="true" class="mage-error" id="email-error"><?= $escaper->escapeHtml(__('Please enter a valid email address (Ex: johndoe@domain.com).')) ?></div> | |
| 32 | 32 | </div> | |
| 33 | 33 | </div> | |
| 35 | 35 | <div class="field password required"> | |
| 36 | 36 | <label for="pass" class="label"><span><?= $escaper->escapeHtml(__('Password')) ?></span></label> | |
| 37 | 37 | <div class="control"> | |
| 38 | Entfernt | <input name="login[password]" type="password" autocomplete="off" class="input-text" id="pass" title="<?= $escaper->escapeHtmlAttr(__('Password')) ?>" tabindex="2" onpaste="return false;" oncopy="return false;"> | |
| 38 | Hinzugefügt | <input name="login[password]" type="password" autocomplete="current-password" class="input-text" id="pass" title="<?= $escaper->escapeHtmlAttr(__('Password')) ?>" tabindex="2" onpaste="return false;" oncopy="return false;"> | |
| 39 | 39 | </div> | |
| 40 | 40 | </div> | |
| 41 | 41 | <!-- VALIDISCAN-SEEDED vs-accessible-auth: arithmetic CAPTCHA with no alternative --> |
app/design/frontend/Validiscan/fixture/Magento_Newsletter/templates/subscribe.phtml Änderungen an app/design/frontend/Validiscan/fixture/Magento_Newsletter/templates/subscribe.phtml: 1 hinzugefügt, 1 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 18 | 18 | <!-- VALIDISCAN-SEEDED vs-forms-ecommerce (label): newsletter email only has a placeholder, no label and no autocomplete --> | |
| 19 | 19 | <div class="field newsletter"> | |
| 20 | 20 | <div class="control"> | |
| 21 | Entfernt | <input name="email" type="email" id="newsletter" placeholder="<?= $escaper->escapeHtmlAttr(__('Enter your email address')) ?>" data-mage-init='{"mage/trim-input":{}}' data-validate="{required:true, 'validate-email':true}"> | |
| 21 | Hinzugefügt | <input name="email" type="email" id="newsletter" placeholder="<?= $escaper->escapeHtmlAttr(__('Enter your email address')) ?>" data-mage-init='{"mage/trim-input":{}}' data-validate="{required:true, 'validate-email':true}" autocomplete="email"> | |
| 22 | 22 | </div> | |
| 23 | 23 | </div> | |
| 24 | 24 | <div class="actions"> |
Magento: Rezept label-association
Vorher und nachher anzeigen (1)
app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/list/toolbar.phtml Änderungen an app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/list/toolbar.phtml: 1 hinzugefügt, 1 entfernt
| Zeile vorher | Zeile nachher | Änderung | Code |
|---|---|---|---|
| 12 | 12 | <div class="toolbar-sorter sorter"> | |
| 13 | 13 | <!-- VALIDISCAN-SEEDED select-name + vs-forms-ecommerce: the "Sort By" text is a span, not a label for the select --> | |
| 14 | 14 | <?php /* Fixed variant: <label class="sorter-label" for="sorter">Sort By</label>. */ ?> | |
| 15 | Entfernt | <span class="sorter-label"><?= $escaper->escapeHtml(__('Sort By')) ?></span> | |
| 15 | Hinzugefügt | <label class="sorter-label" for="sorter"><?= $escaper->escapeHtml(__('Sort By')) ?></label> | |
| 16 | 16 | <select id="sorter" data-role="sorter" class="sorter-options"> | |
| 17 | 17 | <?php foreach ($block->getAvailableOrders() as $key => $order): ?> | |
| 18 | 18 | <option value="<?= $escaper->escapeHtmlAttr($key) ?>"<?= $block->isOrderCurrent($key) ? ' selected' : '' ?>><?= $escaper->escapeHtml(__($order)) ?></option> |
Beginnen Sie mit einem kostenlosen Check Ihres Shops.
Senden Sie die Adresse Ihres Shops. Validiscan scannt ihn und antwortet mit jedem Fehler, den der Scan nachweisen kann, jeweils mit der Seite und dem Code.
Kostenlosen Check anfordernOder schreiben Sie an info@validiscan.com.
Was der kostenlose Check umfasst und was nicht- Sie senden
- die Adresse Ihres Shops
- Gescannte Seiten
- bis zu 15
- Sie erhalten
- jeden Fehler, den der Scan nachweisen kann, mit Seite und Code
- In Ihrem Shop
- nur öffentliche Seiten; keine Anmeldung, nichts gekauft, kein Formular abgeschickt
- Was er nicht ist
- ein vollständiges Audit