How to add a custom attribute?
Asked Answered
S

6

15

How to add a custom attribute in the field Contact Form 7 without javascript ?

For example, there is such a field on the page:

<input type="text" name="name" class="form-control" id="name-1" data-attr="custom" data-msg="Текст 1"> 

Question: is it possible to set these custom attributes (data-attr, data-msg) of fields in the admin panel?

Shackleford answered 18/9, 2017 at 7:59 Comment(1)
There are not any option for add custom attribute in admin. you need to done with js or any custom code. contactform7.com/text-fieldsJanetjaneta
M
27

Find the name of your field.

[text* text-21]

If the name of your field name="text-21", like in my example, add this code to functions.php file.

add_filter( 'wpcf7_form_elements', 'imp_wpcf7_form_elements' );
function imp_wpcf7_form_elements( $content ) {
    $str_pos = strpos( $content, 'name="text-21"' );
    if ( $str_pos !== false ) {
        $content = substr_replace( $content, ' data-attr="custom" data-msg="Foo Bar 1" ', $str_pos, 0 );
    }
    return $content;
}

Note, it will add those attributes to all forms elements where the name is text-21, if you want prevent it then give your form element some unique name [text* unique-name]

And change the code to

add_filter( 'wpcf7_form_elements', 'imp_wpcf7_form_elements' );
function imp_wpcf7_form_elements( $content ) {
    $str_pos = strpos( $content, 'name="unique-name"' );
    if ( $str_pos !== false ) {
        $content = substr_replace( $content, ' data-attr="custom" data-msg="Foo Bar 1" ', $str_pos, 0 );
    }
    return $content;
}
Memorabilia answered 20/9, 2017 at 8:13 Comment(4)
That filter add data-attr to everything, if field doesn't exists it prints "data-attr" ecc everywhere. How to fix?Renascence
It seems that you have forms with the same element names. Change field name to something unique. Please pay attention I edit my answer.Memorabilia
This one helped great, to add autocomplete="both" autocomplete="off" to disable Chrome autofill dropdown for DATE selector field. Thanks! add_filter( 'wpcf7_form_elements', 'imp_wpcf7_form_elements' ); function imp_wpcf7_form_elements( $content ) { $str_pos = strpos( $content, 'name="date-from"' ); $content = substr_replace( $content, ' autocomplete="both" autocomplete="off" ', $str_pos, 0 ); $str_pos = strpos( $content, 'name="date-to"' ); $content = substr_replace( $content, ' autocomplete="both" autocomplete="off" ', $str_pos, 0 ); return $content; }Est
Thanks Tofandel your remarks have sense I approved your answer editing, and it became better.Memorabilia
S
5

Here is a generic solution that doesn't involve hardcoding the field name and the attributes

add_filter( 'wpcf7_form_tag', function ( $tag ) {
    $datas = [];
    foreach ( (array)$tag['options'] as $option ) {
        if ( strpos( $option, 'data-' ) === 0 ) {
            $option = explode( ':', $option, 2 );
            $datas[$option[0]] = apply_filters('wpcf7_option_value', $option[1], $option[0]);
        }
    }
    if ( ! empty( $datas ) ) {
        $id = uniqid('tmp-wpcf');
        $tag['options'][] = "class:$id";
        add_filter( 'wpcf7_form_elements', function ($content) use ($id, $datas) {
            return str_replace($id, $name, str_replace($id.'"', '"'. wpcf7_format_atts($datas), $content));
        });
    }
    return $tag;
} );

It works on all data attributes so you can use it like this

[text* my-name data-foo:bar data-biz:baz placeholder "Blabla"]
Output: <input type="text" name="my-name" data-foo="bar" data-biz="baz" placeholder="Blabla">

Since wpcf7 doesn't provide a way to hook into options directly the solutions uses a trick and temporary adds a uniquely generated class to the field that is then replaced in a later filter with the added attributes

If you need it to work with more than just data attributes you can whitelist some more attributes by replacing this line

if ( strpos( $option, 'data-' ) === 0 ) {

to something like the following

if ( preg_match( '/^(data-|pattern|my-custom-attribute)/', $option ) ) {

Note: wpcf7_format_atts will not output empty attributes, so make sure you give a value to your attributes

Shyster answered 20/12, 2019 at 18:8 Comment(10)
Cannot get it to work with CF7 v5.1.8. data-* stuff is simply ignored. Did you test your solution with CF7 v5.1.8?Xanthus
Yes, it still works, just make sure the attribute is right after the name and not after an attribute like placeholder "Blabla" or contact form will not parse the field at all (regex issue, not related to my code). I see no reason the backward compatibility for this filter will ever be broken as it's pretty low levelShyster
thanks! How would you provide a pattern like [0-9()#&+*-=.]+? I tried it with your solution and the output could not be created.Xanthus
$tag['name'] = $id = uniqid(); this part is wrong as it make the field id for the email part change to uniq id of the form isntade. So it should be - $tag['name'] = $id = $name;Lockhart
@Lockhart No it's not... That's the whole point of this function. We need a unique id in the name of the field that is latter being replaced correctly in the output html to avoid conflicts with other contact forms that may use the same field nameShyster
@Upvote I don't think special characters are well handled by cf's regex, you could maybe use an identifier and add a filter on the option value in my code and add your filter checking for option name and identifier to replace to the correct value, I'll add the filter in the snippetShyster
Note that this solution breaks CF7's validation: invalid required input fields using custom data-* attributes won't be given the wpcf7-not-valid CSS class on submission.Unknow
That is because the unique id generated starts with a number, which is not a valid name for wpfc7 (see function wpcf7_is_name), I added a prefix to the unique id, let me know if it fixes the issueShyster
No, unfortunately it doesn't @Tofandel. Thanks for trying though.Unknow
I updated my answer to add a unique class and use that instead of changing the tag name, which should take care of the validation problemShyster
H
3

Multiple attributes can be added also. eg

add_filter( 'wpcf7_form_elements', 'imp_wpcf7_form_elements' );

function imp_wpcf7_form_elements( $content ) {
    $str_pos = strpos( $content, 'name="your-email-homepage"' );
    $content = substr_replace( $content, ' aria-describedby="emailHelp" ', $str_pos, 0 );

    $str_pos2 = strpos( $content, 'name="your-fname-homepage"' );
    $content = substr_replace( $content, ' aria-describedby="fnameHelp" ', $str_pos2, 0 );

    $str_pos3 = strpos( $content, 'name="your-lname-homepage"' );
    $content = substr_replace( $content, ' aria-describedby="lnameHelp" ', $str_pos3, 0 );
    return $content;        
}
Hiding answered 16/4, 2018 at 20:30 Comment(0)
S
1

Extending on from Tofandel's solution, for the benefit of those who got 99% of the way there, but suffered validation issues - I've resolved that in my case and would like to offer an extended solution that gets as far as Tofandel's (putting the attribute into the form proper) but also successfully validates on submission.

    add_filter('wpcf7_form_tag', function($tag) {
      $data = [];
      foreach ((array)$tag['options'] as $option) {
        if (strpos( $option, 'autocomplete') === 0) {
          $option = explode(':', $option, 2);
          $data[$option[0]] = apply_filters('wpcf7_option_value', $option[1], $option[0]);
        }
      }
      if(!empty($data)) {
        add_filter('wpcf7_form_elements', function ($content) use ($tag, $data) {
          $data_attrs = wpcf7_format_atts($data);
          $name = $tag['name'];
          $content_plus_data_attrs = str_replace("name=\"$name\"", "name=\"$name\" " . $data_attrs, $content);

          return $content_plus_data_attrs;
        });
      }
      return $tag;
    } );

Rather than changing the tag ID to a random value only to replace it with the "real" value later, we just reference the real value in the first place, replacing the relevant part of the content in the wpcf7_form_elements filter (in my case, autocomplete, but as Tofandel's example shows, this can be extended to any data attribute you'd like).

Sultana answered 8/10, 2020 at 14:42 Comment(2)
Just FYI, I didn't do it like this because I needed to support multiple contact forms on a same page, and this will mix up the attributes between themShyster
I updated my answer to add a unique class and use that instead of changing the tag name, which should take care of both problemsShyster
F
1

I propose a solution from the one given by Tofandel without JS (CF7) error and to authorize the use of an attribute without value:

/**
 * Add custom attributes on inputs
 * Put "data-my-attribute" to use it, with or without value
 *
 * @param array $tag
 *
 * @return array
 */
function cf7AddCustomAttributes($tag) {
    $datas = [];

    foreach ((array) $tag['options'] as $option) {
        if (strpos($option, 'data-') === 0 || strpos($option, 'id:') === 0) {
            $option = explode(':', $option, 2);
            $datas[$option[0]] = apply_filters('wpcf7_option_value', $option[1], $option[0]);
        }
    }

    if (!empty($datas)) {
        $id = $tag['name'];

        if (array_key_exists('id', $datas)) {
            $id = $datas['id'];
        } else {
            $tag['options'][] = "id:$id";
        }

        add_filter('wpcf7_form_elements', function ($content) use ($id, $datas) {
            $attributesHtml = '';
            $idHtml = "id=\"$id\"";

            foreach ($datas as $key => $value) {
                $attributesHtml .= " $key";

                if (is_string($value) && strlen($value) > 0) {
                    $attributesHtml .= "=\"$value\"";
                }
            }

            return str_replace($idHtml, "$idHtml $attributesHtml ", $content);
        });
    }

    return $tag;
}
add_filter('wpcf7_form_tag', 'cf7AddCustomAttributes');
Fifty answered 18/8, 2021 at 6:30 Comment(0)
H
0

I use this simple method for setting attribute

[checkbox optName use_label_element "optName"]
<script>
document.querySelector(".optName").setAttribute("onchange","myscript");
</script>
Hadria answered 21/12, 2021 at 10:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.