Los campos de pago, dirección e inicio de sesión necesitan etiquetas, autocompletado y errores vinculados
Es en el proceso de pago donde la tienda gana su dinero. Sin etiquetas, quienes usan un lector de pantalla no saben qué escribir; sin autocompletado, las personas con discapacidad motriz o con problemas de memoria tienen que escribir su dirección a mano; y cuando los errores no están vinculados a sus campos, los clientes no encuentran qué ha fallado y abandonan el pedido.
- ID de la regla
- vs-forms-ecommerce
- Origen
- Comprobación de Validiscan
- Impacto
- Crítico
- Nivel de corrección
- AUTO
- en Shopify, Shopware, WooCommerce y Magento
- Estado
- se ejecuta
Qué hace la comprobación
Revisa los campos del proceso de pago, de dirección, de cuenta y de inicio de sesión en busca de tokens de autocomplete que faltan (1.3.5), etiquetas o instrucciones que faltan y campos obligatorios que no se indican como tales (3.3.2), y mensajes de error que no están asociados a sus campos (3.3.1). Sustituye a las reglas de axe label y autocomplete-valid.
En todas las páginas, la comprobación examina cada input, select y textarea que los productos de apoyo pueden percibir, salvo los campos ocultos y los de tipo botón. Una etiqueta cuenta si procede de <label>, aria-label, aria-labelledby o title, no de un placeholder. No se prueba si el texto de la etiqueta describe el campo.
La finalidad de un campo se deduce de su type, su name, su id, el texto de su etiqueta y su placeholder. Una finalidad reconocida sin token de autocomplete, o con on, off o un token no válido, es un hallazgo, salvo off en un campo de contraseña; un token válido pero distinto no lo es.
Un mensaje de error (role="alert" o una clase de error, junto a un único campo) se notifica cuando no está dentro de un label y ningún aria-describedby ni aria-errormessage lo referencia; lo mismo ocurre con un campo con aria-invalid="true" sin mensaje vinculado. Se notifica un campo obligatorio (required o aria-required="true", salvo las casillas de verificación y los botones de opción) cuya etiqueta no muestra ni un asterisco ni un texto que lo indique como obligatorio, a menos que el formulario marque los campos opcionales, indique que todos son obligatorios o exija todos los campos. Un campo marcado como obligatorio solo visualmente también se notifica.
Cómo corregirlo
Dé a cada campo un <label> visible vinculado mediante for e id, añada el token de autocomplete correspondiente (given-name, family-name, street-address, postal-code, email, tel, current-password, etc.), marque los campos obligatorios en la etiqueta y con el atributo required, y vincule los mensajes de error a sus campos con aria-describedby y aria-invalid="true".
Criterios de conformidad de las WCAG
- 1.3.5 Identify Input Purpose, nivel AA
- 3.3.1 Error Identification, nivel A
- 3.3.2 Labels or Instructions, nivel A
Apartados de la norma EN 301 549
| Criterio de las WCAG | Versión 3.2.1 | Versión 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 |
Dónde lo corrige una receta
Shopify: receta autocomplete-tokens
Mostrar el antes y el después (1)
sections/contact-form.liquid Cambios en sections/contact-form.liquid (líneas añadidas: 1; eliminadas: 1)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 14 | 14 | {%- form 'contact', id: 'ContactForm', class: 'contact__form' %} | |
| 15 | 15 | <div class="contact__fields"> | |
| 16 | 16 | <div class="field"> | |
| 17 | Eliminada | <input class="field__input" type="text" name="contact[name]" placeholder="{{ 'templates.contact.form.name' | t }}"> | |
| 17 | Añadida | <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 Cambios en sections/footer.liquid (líneas añadidas: 1; eliminadas: 1)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 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 | Eliminada | <input type="email" name="contact[email]" class="field__input" placeholder="{{ 'newsletter.label' | t }}" autocorrect="off" autocapitalize="off"> | |
| 14 | Añadida | <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 Cambios en sections/main-login.liquid (líneas añadidas: 1; eliminadas: 1)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 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 | Eliminada | <input class="field__input" type="email" name="customer[email]" id="CustomerEmail" autocorrect="off" autocapitalize="off"> | |
| 13 | Añadida | <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 Cambios en snippets/checkout-field.liquid (líneas añadidas: 4; eliminadas: 4)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 15 | 15 | <div class="field"> | |
| 16 | 16 | {%- case legacy %} | |
| 17 | 17 | {%- when 'placeholder' %} | |
| 18 | Eliminada | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}" placeholder="{{ label }}"{% if required %} required{% endif %}> | |
| 18 | Añadida | <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 | Eliminada | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}"> | |
| 21 | Añadida | <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 | Eliminada | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}" autocomplete="off"{% if required %} required{% endif %}> | |
| 24 | Añadida | <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 | Eliminada | <input class="field__input" type="{{ field_type }}" id="{{ field_id }}" name="{{ field_name }}"{% if required %} required{% endif %}> | |
| 27 | Añadida | <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: receta label-association
Mostrar el antes y el después (1)
sections/main-collection.liquid Cambios en sections/main-collection.liquid (líneas añadidas: 2; eliminadas: 2)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 64 | 64 | <div class="collection__products"> | |
| 65 | 65 | <div class="collection__toolbar"> | |
| 66 | 66 | <div class="collection__sort"> | |
| 67 | Eliminada | <label class="collection__sort-label">Sort by</label> | |
| 68 | Eliminada | <select name="sort_by" class="select__select" form="FacetFiltersForm"> | |
| 67 | Añadida | <label class="collection__sort-label" for="SortBy-{{ section.id }}">Sort by</label> | |
| 68 | Añadida | <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 Cambios en sections/main-product.liquid (líneas añadidas: 2; eliminadas: 2)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 94 | 94 | </div> | |
| 95 | 95 | {%- else %} | |
| 96 | 96 | <div class="product-form__input product-form__input--dropdown"> | |
| 97 | Eliminada | <p class="form__label">{{ option.name | escape }}</p> | |
| 97 | Añadida | <p class="form__label" id="Options-{{ section.id }}-{{ forloop.index0 }}-label">{{ option.name | escape }}</p> | |
| 98 | 98 | <div class="select"> | |
| 99 | Eliminada | <select class="select__select" name="options[{{ option.name | escape }}]" data-option-index="{{ option_index }}"> | |
| 99 | Añadida | <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: receta autocomplete-tokens
Mostrar el antes y el después (1)
Resources/views/storefront/component/account/login.html.twig Cambios en Resources/views/storefront/component/account/login.html.twig (líneas añadidas: 1; eliminadas: 1)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 19 | 19 | name="username" | |
| 20 | 20 | placeholder="{{ 'account.loginMailPlaceholder'|trans }}" | |
| 21 | 21 | required | |
| 22 | Eliminada | autocomplete="off"> | |
| 22 | Añadida | autocomplete="email"> | |
| 23 | 23 | </div> | |
| 24 | 24 | ||
| 25 | 25 | <div class="form-group"> |
Resources/views/storefront/component/account/register.html.twig Cambios en Resources/views/storefront/component/account/register.html.twig (líneas añadidas: 8; eliminadas: 4)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 33 | 33 | id="{{ formId }}FirstName" | |
| 34 | 34 | name="firstName" | |
| 35 | 35 | placeholder="{{ 'account.firstNamePlaceholder'|trans }}" | |
| 36 | Eliminada | required> | |
| 36 | Añadida | required | |
| 37 | Añadida | 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 | Eliminada | required> | |
| 45 | Añadida | required | |
| 46 | Añadida | 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 | Eliminada | required> | |
| 57 | Añadida | required | |
| 58 | Añadida | 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 | Eliminada | required> | |
| 68 | Añadida | required | |
| 69 | Añadida | 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 Cambios en Resources/views/storefront/component/address/address-form.html.twig (líneas añadidas: 8; eliminadas: 4)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 14 | 14 | id="{{ prefix }}AddressStreet" | |
| 15 | 15 | name="{{ prefix }}[street]" | |
| 16 | 16 | placeholder="{{ 'address.streetPlaceholder'|trans }}" | |
| 17 | Eliminada | required> | |
| 17 | Añadida | required | |
| 18 | Añadida | 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 | Eliminada | required> | |
| 30 | Añadida | required | |
| 31 | Añadida | 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 | Eliminada | required> | |
| 42 | Añadida | required | |
| 43 | Añadida | 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 | Eliminada | required> | |
| 53 | Añadida | required | |
| 54 | Añadida | 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 Cambios en Resources/views/storefront/element/cms-element-form.html.twig (líneas añadidas: 4; eliminadas: 4)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 18 | 18 | </select> | |
| 19 | 19 | </div> | |
| 20 | 20 | <div class="form-group col-md-4"> | |
| 21 | Eliminada | <input type="text" class="form-control" id="contactFormFirstName" name="firstName" placeholder="{{ 'account.firstNamePlaceholder'|trans }}" required> | |
| 21 | Añadida | <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 | Eliminada | <input type="text" class="form-control" id="contactFormLastName" name="lastName" placeholder="{{ 'account.lastNamePlaceholder'|trans }}" required> | |
| 24 | Añadida | <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 | Eliminada | <input type="email" class="form-control" id="contactFormMail" name="email" placeholder="{{ 'account.emailPlaceholder'|trans }}" required> | |
| 31 | Añadida | <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 | Eliminada | <input type="tel" class="form-control" id="contactFormPhone" name="phone"> | |
| 35 | Añadida | <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 Cambios en Resources/views/storefront/layout/footer/footer.html.twig (líneas añadidas: 2; eliminadas: 1)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 62 | 62 | id="footerNewsletterMail" | |
| 63 | 63 | class="form-control" | |
| 64 | 64 | placeholder="{{ 'footer.newsletterPlaceholder'|trans }}" | |
| 65 | Eliminada | required> | |
| 65 | Añadida | required | |
| 66 | Añadida | 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: receta label-association
Mostrar el antes y el después (1)
Resources/views/storefront/page/product-detail/configurator.html.twig Cambios en Resources/views/storefront/page/product-detail/configurator.html.twig (líneas añadidas: 1; eliminadas: 1)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 13 | 13 | {% for group in product.configurator %} | |
| 14 | 14 | {% if group.display == 'select' %} | |
| 15 | 15 | <div class="product-detail-configurator-group"> | |
| 16 | Eliminada | <div class="product-detail-configurator-group-title">{{ group.name }}</div> | |
| 16 | Añadida | <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: receta autocomplete-tokens
Mostrar el antes y el después (1)
functions.php Cambios en functions.php (líneas añadidas: 44; eliminadas: 0)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 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 | Añadida | ||
| 312 | Añadida | /* validiscan:autocomplete-tokens */ | |
| 313 | Añadida | /** | |
| 314 | Añadida | * Autocomplete tokens for the WooCommerce address fields, so browsers and assistive | |
| 315 | Añadida | * technology know what each field asks for (WCAG 1.3.5). Runs after the theme's own | |
| 316 | Añadida | * field filters. | |
| 317 | Añadida | * | |
| 318 | Añadida | * @param array $fields Checkout fields (grouped by section) or one address section. | |
| 319 | Añadida | * @return array | |
| 320 | Añadida | */ | |
| 321 | Añadida | function kb_address_autocomplete( $fields ) { | |
| 322 | Añadida | $tokens = array( | |
| 323 | Añadida | 'first_name' => 'given-name', | |
| 324 | Añadida | 'last_name' => 'family-name', | |
| 325 | Añadida | 'company' => 'organization', | |
| 326 | Añadida | 'country' => 'country', | |
| 327 | Añadida | 'address_1' => 'address-line1', | |
| 328 | Añadida | 'address_2' => 'address-line2', | |
| 329 | Añadida | 'city' => 'address-level2', | |
| 330 | Añadida | 'state' => 'address-level1', | |
| 331 | Añadida | 'postcode' => 'postal-code', | |
| 332 | Añadida | 'phone' => 'tel', | |
| 333 | Añadida | 'email' => 'email', | |
| 334 | Añadida | ); | |
| 335 | Añadida | foreach ( $fields as $key => $field ) { | |
| 336 | Añadida | if ( ! is_array( $field ) ) { | |
| 337 | Añadida | continue; | |
| 338 | Añadida | } | |
| 339 | Añadida | if ( 'billing' === $key || 'shipping' === $key ) { | |
| 340 | Añadida | $fields[ $key ] = kb_address_autocomplete( $field ); | |
| 341 | Añadida | continue; | |
| 342 | Añadida | } | |
| 343 | Añadida | if ( ! preg_match( '/^(billing|shipping)_(.+)$/', (string) $key, $match ) || ! isset( $tokens[ $match[2] ] ) ) { | |
| 344 | Añadida | continue; | |
| 345 | Añadida | } | |
| 346 | Añadida | $fields[ $key ]['autocomplete'] = ( 'shipping' === $match[1] ? 'shipping ' : '' ) . $tokens[ $match[2] ]; | |
| 347 | Añadida | unset( $fields[ $key ]['custom_attributes']['autocomplete'] ); | |
| 348 | Añadida | } | |
| 349 | Añadida | return $fields; | |
| 350 | Añadida | } | |
| 351 | Añadida | add_filter( 'woocommerce_checkout_fields', 'kb_address_autocomplete', 99 ); | |
| 352 | Añadida | add_filter( 'woocommerce_billing_fields', 'kb_address_autocomplete', 99 ); | |
| 353 | Añadida | add_filter( 'woocommerce_shipping_fields', 'kb_address_autocomplete', 99 ); | |
| 354 | Añadida | /* /validiscan:autocomplete-tokens */ |
woocommerce/myaccount/form-login.php Cambios en woocommerce/myaccount/form-login.php (líneas añadidas: 3; eliminadas: 3)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 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 | Eliminada | <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 | Añadida | <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 | Eliminada | <input class="woocommerce-Input woocommerce-Input--text input-text" type="password" name="password" id="password" autocomplete="off" onpaste="return false;"> | |
| 37 | Añadida | <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 | Eliminada | <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 | Añadida | <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: receta label-association
Mostrar el antes y el después (1)
woocommerce/cart/cart.php Cambios en woocommerce/cart/cart.php (líneas añadidas: 1; eliminadas: 1)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 62 | 62 | <tr> | |
| 63 | 63 | <td colspan="6" class="actions"> | |
| 64 | 64 | <div class="coupon"> | |
| 65 | Eliminada | <label class="screen-reader-text"><?php esc_html_e( 'Coupon:', 'woocommerce' ); ?></label> | |
| 65 | Añadida | <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: receta autocomplete-tokens
Mostrar el antes y el después (1)
app/design/frontend/Validiscan/fixture/Magento_Contact/templates/form.phtml Cambios en app/design/frontend/Validiscan/fixture/Magento_Contact/templates/form.phtml (líneas añadidas: 3; eliminadas: 3)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 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 | Eliminada | <div class="control"><input name="name" id="name" title="<?= $escaper->escapeHtmlAttr(__('Name')) ?>" value="<?= $escaper->escapeHtmlAttr($viewModel->getUserName()) ?>" class="input-text" type="text"></div> | |
| 24 | Añadida | <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 | Eliminada | <div class="control"><input name="email" id="email" title="<?= $escaper->escapeHtmlAttr(__('Email')) ?>" value="<?= $escaper->escapeHtmlAttr($viewModel->getUserEmail()) ?>" class="input-text" type="email"></div> | |
| 28 | Añadida | <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 | Eliminada | <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 | Añadida | <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 Cambios en app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/login.phtml (líneas añadidas: 2; eliminadas: 2)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 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 | Eliminada | <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 | Añadida | <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 | Eliminada | <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 | Añadida | <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 Cambios en app/design/frontend/Validiscan/fixture/Magento_Newsletter/templates/subscribe.phtml (líneas añadidas: 1; eliminadas: 1)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 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 | Eliminada | <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 | Añadida | <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: receta label-association
Mostrar el antes y el después (1)
app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/list/toolbar.phtml Cambios en app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/list/toolbar.phtml (líneas añadidas: 1; eliminadas: 1)
| Línea anterior | Línea nueva | Cambio | Código |
|---|---|---|---|
| 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 | Eliminada | <span class="sorter-label"><?= $escaper->escapeHtml(__('Sort By')) ?></span> | |
| 15 | Añadida | <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> |
Empiece con una revisión gratuita de su tienda.
Envíe la dirección de su tienda. Validiscan la escanea y le responde con cada fallo que el escaneo pueda demostrar, con la página y el código.
Solicitar revisión gratuitaO escriba a info@validiscan.com.
Qué cubre la revisión gratuita y qué deja fuera- Usted envía
- la dirección de su tienda
- Páginas escaneadas
- hasta 15
- Usted recibe
- todos los fallos que el escaneo puede demostrar, con la página y el código
- En su tienda
- solo páginas públicas; sin inicio de sesión, nada comprado, ningún formulario enviado
- Lo que no es
- una auditoría completa