Here’s a code snippet that duplicates associated views when you duplicate a form in Formidable Forms. This ensures that any views linked to the original form are also duplicated and correctly linked to the new form.
// Hook the function to frm_after_duplicate_form
add_action( 'frm_after_duplicate_form', 'duplicate_views_after_form', 10, 3 );
/**
* Duplicate the views associated with a form when it is duplicated
*
* @param int $new_form_id The ID of the duplicated form
* @param array $new_form The data of the duplicated form
* @param array $args Additional arguments, including the original form ID
*/
function duplicate_views_after_form( $new_form_id, $new_form, $args ) {
$old_form_id = $args['old_id'];
// Check if FrmViewsDisplay class and method exist to verify Pro license for views
if ( ! class_exists( 'FrmViewsDisplay' ) || ! method_exists( 'FrmViewsDisplay', 'get_display_ids_by_form' ) ) {
return; // Exit if views are not supported in this setup
}
// Get the views associated with the original form
$views = FrmViewsDisplay::get_display_ids_by_form( $old_form_id );
// Exit if there are no associated views to duplicate
if ( empty( $views ) ) {
return;
}
// Get the fields of the original and duplicated forms, indexed by 'field_name'
$old_fields_by_name = array_column( FrmField::get_all_for_form( $old_form_id ), null, 'name' );
$new_fields_by_name = array_column( FrmField::get_all_for_form( $new_form_id ), null, 'name' );
foreach ( $views as $view_id ) {
// Duplicate the view
$new_view_id = FrmViewsDisplay::duplicate( $view_id );
// Update the title and slug of the duplicated view
$new_view_slug = get_post( $view_id )->post_name . '-' . $new_form_id;
wp_update_post( array(
'ID' => $new_view_id,
'post_name' => $new_view_slug,
'post_title' => $new_view_slug,
));
// Update the form ID in the duplicated view
update_post_meta( $new_view_id, 'frm_form_id', $new_form_id );
// Update fields in post_content, frm_options, and frm_dyncontent
update_fields_in_post( $new_view_id, 'post_content', $old_fields_by_name, $new_fields_by_name );
update_fields_in_post( $new_view_id, 'frm_options', $old_fields_by_name, $new_fields_by_name, true );
update_fields_in_post( $new_view_id, 'frm_dyncontent', $old_fields_by_name, $new_fields_by_name, true );
}
}
/**
* Update field IDs in post meta or post content
*
* @param int $view_id The ID of the post or view
* @param string $field The field to update (post_content, frm_options, frm_dyncontent)
* @param array $old_fields_by_name The fields of the original form, indexed by name
* @param array $new_fields_by_name The fields of the duplicated form, indexed by name
* @param bool $is_meta True if it's meta data, false if it's post_content
*/
function update_fields_in_post( $view_id, $field, $old_fields_by_name, $new_fields_by_name, $is_meta = false ) {
// Get the current content
$content = $is_meta ? get_post_meta( $view_id, $field, true ) : get_post_field( $field, $view_id );
if ( empty( $content ) ) {
return;
}
// If we're in frm_options, specifically modify 'where' and 'order_by' fields
if ( $field === 'frm_options' && is_array( $content ) ) {
$content = replace_field_ids_in_options( $content, $old_fields_by_name, $new_fields_by_name );
} else {
// For non-serialized content like `post_content` and `frm_dyncontent`
$content = replace_field_ids_in_content( $content, $old_fields_by_name, $new_fields_by_name );
}
// Save the updated content
if ( $is_meta ) {
update_post_meta( $view_id, $field, $content );
} else {
wp_update_post( array( 'ID' => $view_id, $field => $content ) );
}
}
/**
* Replace the IDs in 'where' and 'order_by' within frm_options
*
* @param array $options The options array from frm_options
* @param array $old_fields_by_name The fields of the original form, indexed by name
* @param array $new_fields_by_name The fields of the duplicated form, indexed by name
* @return array The updated options array
*/
function replace_field_ids_in_options( $options, $old_fields_by_name, $new_fields_by_name ) {
// Modify IDs in the 'where' field if it exists
if ( isset( $options['where'] ) && is_array( $options['where'] ) ) {
foreach ( $options['where'] as &$value ) {
foreach ( $old_fields_by_name as $field_name => $old_field ) {
if ( $value === (string) $old_field->id && isset( $new_fields_by_name[ $field_name ] ) ) {
$value = (string) $new_fields_by_name[ $field_name ]->id;
break;
}
}
}
}
// Modify IDs in the 'order_by' field if it exists
if ( isset( $options['order_by'] ) && is_array( $options['order_by'] ) ) {
foreach ( $options['order_by'] as &$value ) {
foreach ( $old_fields_by_name as $field_name => $old_field ) {
if ( $value === (string) $old_field->id && isset( $new_fields_by_name[ $field_name ] ) ) {
$value = (string) $new_fields_by_name[ $field_name ]->id;
break;
}
}
}
}
return $options;
}
/**
* Replace the field IDs in the content
*
* @param string $content The content where IDs will be replaced
* @param array $old_fields_by_name The fields of the original form, indexed by name
* @param array $new_fields_by_name The fields of the duplicated form, indexed by name
* @return string The content with the IDs replaced
*/
function replace_field_ids_in_content( $content, $old_fields_by_name, $new_fields_by_name ) {
$pattern = '/\[(\/?)(if|foreach)?\s*(\d+)([^\]]*)\]/';
return preg_replace_callback( $pattern, function ( $matches ) use ( $old_fields_by_name, $new_fields_by_name ) {
$old_field_id = $matches[3]; // The field ID
$extra_params = $matches[4]; // Additional parameters
// Find the old field by its ID and get the new ID
foreach ( $old_fields_by_name as $field_name => $old_field ) {
if ( $old_field->id == $old_field_id && isset( $new_fields_by_name[ $field_name ] ) ) {
$new_field_id = $new_fields_by_name[ $field_name ]->id;
return '[' . $matches[1] . $matches[2] . ($matches[2] ? ' ' : '') . $new_field_id . $extra_params . ']';
}
}
return $matches[0]; // If the field is not found, return the original match
}, $content );
}
Explanation:
duplicate_views_after_form
function is hooked to the frm_after_duplicate_form
action, which is triggered after a form is duplicated.FrmViewsDisplay::duplicate
.duplicate_views_after_form
: Main function that handles the duplication process.update_fields_in_post
: Updates field IDs in the post content or meta fields.replace_field_ids_in_options
: Specifically updates field IDs in the frm_options
array, handling where
and order_by
clauses.replace_field_ids_in_content
: Uses regex to find and replace field IDs within shortcodes in the content.Usage Instructions:
functions.php
file or in a custom plugin.Notes:
Conclusion: By adding this code to your WordPress site, you streamline the process of duplicating forms and their associated views, saving time and reducing the potential for errors in manually updating IDs and references.
Hello Victor,
Thank you for your feedback and for highlighting the potential issues in the code. I've updated it to check for a Formidable license and ensure views are present before running the duplication process. This should help prevent unnecessary executions and errors when duplicating forms without associated views or lacking the required license.
Your comments were very helpful in improving the code’s reliability—thank you once again!
Best regards,
Ernesto
Please login or Register to submit your answer