Part of it is the limitation that the shortcode executed through a dynamic field can only access data that is global (like current page, user, url parameters, etc.), directly passed to it through attributes (like the key
attribute for CF7_GET
), or set in a custom shortcode itself, like getting an ACF field from a specific post.
This means that at the time of the custom shortcode running, it does not know important information necessary like the form tag’s name attribute, not unless your custom shortcode includes it in the attributes or you’re hardcoding it in your shortcode.
In the demo form where it loops the products, render out input
elements with type="checkbox"
instead of option
elements. So instead of this:
// Add products to the $html string
if (is_array($products) && count($products)) {
foreach ($products as $product_id) {
// Use the product ID as the option's value and the product's title as the label
$html .= sprintf('<option value="%s">%s</option>', esc_attr($product_id), esc_html(get_the_title($product_id)));
}
}
You would change it to this:
// Add products to the $html string
if (is_array($products) && count($products)) {
foreach ($products as $product_id) {
// Use the product ID as the option's value and the product's title as the label
$html .= sprintf(
'<label>
<input type="checkbox" name="product[]" value="%s"> %s
</label>',
esc_attr($product_id),
esc_html(get_the_title($product_id))
);
}
}
The biggest difference here is that the whole HTML element needs to be rendered, including the field name, which we use product
but also with []
at the end to allow for multiple selections to be made. Then in the form template, you’d use it like this:
[dynamic_checkbox product "au_dtx_demo_get_wordpress_plugin_options"]
And in the mail template, display them using the product
name attribute, or render it yourself with the wpcf7_before_send_mail
hook.
As you can see though, this doesn’t show pre-checked options, just dynamic options. If you use the HTML method, you’ll need to perform the logic to get your default values and then compare them in the loop like this:
// If viewing product page, get the current product
$selected_value = get_the_ID();
// Get the 'product_id' ACF from post 123
$selected_value = intval(sanitize_text_field(get_field('product_id', 123')));
// Get the 'product-id' parameter from the URL
$selected_value = intval(sanitize_text_field(array_key_exists('product-id', $_GET) ? $_GET['product-id'] : 0));
// Add products to the $html string
if (is_array($products) && count($products)) {
foreach ($products as $product_id) {
// Use the product ID as the option's value and the product's title as the label
$html .= sprintf(
'<label>
<input type="checkbox" name="product[]" value="%s"%s> %s
</label>',
esc_attr($product_id),
$selected_value == $product_id ? ' checked' : '', // Check me if match!
esc_html(get_the_title($product_id))
);
}
}
And you can also do checks for multiple values if $selected_value
is an array, let’s say a sequential array of post ids like [123, 456, 789]
and then instead of
$selected_value == $product_id ? ' checked' : '', // Check me if match!
You could instead use
in_array($product_id, $selected_value) ? ' checked' : '', // I'm among them!
Two helper functions in the utilities.php
file can help you. They are wpcf7dtx_checkbox_group_html() and wpcf7dtx_checkbox_html(). The first one can render a group of checkboxes or radio buttons while the latter is for a singleton. So in the case of the demo above, instead of writing the HTML yourself, you can replace that bit inside the loop with the helper function like so:
// Before the loop
$selected_value = 123; // Pre-check just this product
$selected_value = 123_456_7890; // Pre-check these 3 products, underscore delimited
// Open checkbox group
$html = '<span id="products" class="wpcf7-form-control-wrap product" data-name="product">';
foreach ($products as $product_id) {
$html .= '<span class="wpcf7-list-item">';
$html .= wpcf7dtx_checkbox_html(
array(
'name' => 'product', // Field name
'id' => 'product-' . $product_id, // Element id
'value' => $product_id, // Checkbox value
'dtx-default' => $selected_value // Value(s) to match
),
get_the_title($product_id) // Checkbox label text
true, // True to wrap it all in a single <label> element
false, // True to put label first then checkbox
);
$html .= '</span>';
}
// Close checkbox group
$html .= '</span>';
Hope that’s enough to help!