SVE
SVE

Reputation: 1655

How to add a custom attribute?

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?

Upvotes: 15

Views: 25571

Answers (6)

Oleg Apanovich
Oleg Apanovich

Reputation: 710

Find the name of your field.

[text* text-21]

If the name of your field is name="text-21", like in my example, add this code to your 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 to prevent this, then give your form elements unique names [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;
}

Upvotes: 27

Tofandel
Tofandel

Reputation: 3585

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

Upvotes: 6

ahmed khan
ahmed khan

Reputation: 35

I use this simple method for setting attribute

[checkbox optName use_label_element "optName"]
<script>
document.querySelector(".optName").setAttribute("onchange","myscript");
</script>

Upvotes: 0

Killian Leroux
Killian Leroux

Reputation: 11

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');

Upvotes: 1

Drif.io
Drif.io

Reputation: 36

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).

Upvotes: 1

Victor Drover
Victor Drover

Reputation: 31

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;        
}

Upvotes: 3

Related Questions