Contact Form 7 form data not being copied over

@Ignacio

1. I am looking for an automatic way to create contact forms for new blogs using the popular "contact form 7" plugin.

However, similar to the the google fonts plugin issue we resolved recently ( https://premium.wpmudev.org/forums/topic/easy-google-fonts-plugin-not-copying-over-settings ), the data for this plugin is also being stored in posts. So contact forms will copy over only if I select copy posts in the blog template settings (which i don't want to do)

You mentioned you are going to address this issue in the next release for easy google fonts plugin, will your fix also address all the other plugins that are storing their settings in the post data? Also is there a code snippit i could use to address the contact form 7 issue immediately. After reading through the forums I noticed there are a probably others out there not knowing the solution ( https://premium.wpmudev.org/forums/topic/contact-form-7-form-not-being-created-when-add-new-site ) .

Thanks.

2. Follow up...the blog template plugin is great. However I am having issues with plugins being pre-populated with the admin email of the template originator blog, versus showing the admin email of the newly created blog. The 2 plugins that are giving me issue with this are: wpmudev marketpress store settings, and the contact form 7 plugin (if i enable posts to copy)

Is it possibly to have a setting in blog templates that could be set to replace all emails addresses with the admin email of the new sign up? (perhaps it would run a find and replace for emails in the settings on creation)

Thanks again.

-Ben

  • Vaughan

    Hi @ben,

    Thanks for your feedback.

    It is unlikely that the issue for google fonts will also fix your question regarding contact 7, but I will certainly ask the developer for some feedback on this for you, just in case it actually will.

    #2. I'm not sure if that would be viable thinking about it, as many plugins store their details in various tables, and options, and it might be difficult in some case to just do a search & replace, especially where they are stored in serialized arrays. But I will certainly ask the developer for some feedback for you.

    Hope this helps

  • Ben

    @Vaughan thanks for the quick response

    It is unlikely that the issue for google fonts will also fix your question regarding contact 7,

    The fix he gave for easy google fonts was specific to that plugin, and wont fix contact 7, but hoping for a generalized fix as it is needed for the templates plugin to work as described if other plugins are storing data in that fashion.

    #2. I'm not sure if that would be viable thinking about it, as many plugins store their details in various tables,

    One of the big selling points was the ability to create new blog stores with the blog templates plugin in conjunction with the marketpress plugin...however the email address in the settings of marketpress is showing the old admin email versus the new blogs admin email...am i doing something wrong or is everybody having to go into every new blog in this senario and manually change the email in the store settings?

  • Ignacio

    Ok, I think we are going to take another approach as this could lead to other problems with other users.

    As this is a fix speciffically for you we are going to move the code you need to another plugin. I'll think about another system to copy custom post types by selecting them in the template settings instead of adding more and more code.

    So, here's what you need to do:

    1. Remember the code we added for Easy Google Fonts? Remove it :slight_smile:.
    2. You'll need to create a mu-plugin. MU plugins are always activated (you don't need to activate them from admin panel). They are always located at wp-content/mu-plugins. If you don't see that folder, create it.
    3. Now, inside that folder, uncompress and upload the attached file (nbt-hooks.php.zip).

    So, we have just moved the code in integration.php to a mu-plugin (I also included some improvements).

    Now, for Marketpress. We have to go back to integration.php as we are going to include that code for all users, I think it makes the worth. So the thing is that we are going to try to change the store email for the new admin email in that subsite. As we did with Easy GF we just need to add the following code in integration.php (inside NBT plugin):

    /** MARKETPRESS **/
    add_action( 'blog_templates-copy-after_copying', 'nbt_set_marketpress_email', 10, 2 );
    function nbt_set_marketpress_email( $template, $destination_blog_id ) {
    
    	if ( ! function_exists( 'is_plugin_active' ) )
    		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
    
    	switch_to_blog( $destination_blog_id );
    	if ( ! is_plugin_active( 'marketpress/marketpress.php' ) ) {
    		restore_current_blog();
    		return;
    	}
    	restore_current_blog();
    
    	$source_blog_id = $template['blog_id'];
    
    	if ( in_array( 'settings', $template['to_copy'] ) && get_blog_details( $source_blog_id ) && get_blog_details( $destination_blog_id ) ) {
    		switch_to_blog( $destination_blog_id );
    		$marketpress_options = get_option( 'mp_settings', array() );
    		$marketpress_options['store_email'] = get_option( 'admin_email' );
    		update_option( 'mp_settings', $marketpress_options );
    		restore_current_blog();
    	}
    
    }

    And I think that's all, Every subsite should take the admin email as store email.

    Let me know if you have any other issues.

    Regards.
    Ignacio.

  • Ben

    @Ignacio

    1. that fix works for the market press, well done!
    2. Form was successfully copied over for contact form 7 plugin without having to enable posts in the blog template settings

    Two issues still remaining:
    1. Similar to marketpress, contact form 7 pre-populates the form with the email, and when this is replicated to the new site, the old email address still remains, is there a fix that can be provided similar to what you did for marketpress

    2. I notice in the blog settings, if I uncheck "All categories" withing posts, it doesn't remained un-checked (was trying to have everything unchecked in posts area. Even the the main "checkbox" is unchecked, not sure if that "all categories" remaining checked is having an effect on somthing.

    Thanks,

    -Ben

    • Ignacio

      Hi @Ben

      1. That can be "almost done". You can change the recipient in every form but there may be more emails in the body, subject, from sender that are not so easy to change (maybe with a regular expression patter if you know what I am talking about) but I'll give you the code and you can work from it:

      In the mu-plugin I attached before, you need to add some more code to the nbt_hooks_copy_contact_form_7_formsfunction:

      /** CONTACT FORMS 7 **/
      add_action( 'blog_templates-copy-after_copying', 'nbt_hooks_copy_contact_form_7_forms', 10, 2 );
      function nbt_hooks_copy_contact_form_7_forms( $template, $destination_blog_id ) {
      	global $wpdb;
      
      	if ( ! function_exists( 'is_plugin_active' ) )
      		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
      
      	switch_to_blog( $destination_blog_id );
      	if ( ! is_plugin_active( 'contact-form-7/wp-contact-form-7.php' ) ) {
      		restore_current_blog();
      		return;
      	}
      	restore_current_blog();
      
      	nbt_hooks_copy_extra_post_types( 'wpcf7_contact_form', $template, $destination_blog_id );
      
      	// Now, to change the recipient email
      	switch_to_blog( $destination_blog_id );
      	// We get all the posts IDs that has _mail post meta (that belongs to a Contact Form)
      	$results = $wpdb->get_col( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_mail'" );
      
      	foreach ( $results as $post_id ) {
      		// Here we get the form settings and modify them
      		$contact_form_settings = get_post_meta( $post_id, '_mail', true );
      
      		if ( isset( $contact_form_settings['recipient'] ) )
      			$contact_form_settings['recipient'] = get_option( 'admin_email' );
      
      		update_post_meta( $post_id, '_mail', $contact_form_settings );
      	}
      
      	restore_current_blog();
      
      }

      The _mail postmeta saves the attributes for every form. If you need to change something from a contact from, it will be in that array most probably. So I first get all the post IDs that have that meta and then I get them one by one and change the recipient. You can change more attributes if you need.

      2. Don't worry about that. If you uncheck "Posts", categories checks do not mean anythingg.

      Regards.
      Ignacio.

  • Ben

    @Ignacio

    Thanks for the quick response, I am definitely eager to launch this soon and this might be the final piece of my puzzle...famous last words.

    Tried the code but replacing the necessary mu plugin, the revised code does not have an effect on sending it to the admin email we want for the created default recipient address....doesn't work.

    Trying to debug the issue I noticed the line:

    $results = $wpdb->get_col( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_mail'" );

    Isn't returning any results. Not sure how to completely follow the code for that query, but not seeing a reference to a blog id in that query so wondering if that has anything to do with the problem of it not returning results.

    Let me know what you think or if you might know where this issue is...eagerly awaiting your response if anybody else knows please chime in!

    So close.

    2. Thanks for that info.

    -Ben

  • Ben

    Been stomping around trying to figure things out. As I was digging in the database and I see what you were saying about a need for a regular expression to find the email, however I as I did more digging through the database, I am wondering if a more generalized strategy could be used for the whole plugin...

    Instead of needing a regular expression to find all email address, you could first grab the email as a search term, and then do a search and replace for that originating admin email to the new sign up admin email, in addition this could perhaps should be done for the site title and blog domain.

    As I was digging around and found that in a new site derived from a template, the new site was carrying over some more data than just originating admin email, here is what i found in regards just to contact form 7 data:

    in options:
    ust_signup_data->user_email (NAME@ORIGINATINGTEMPLATESITEEMAIL.COM)
    ust_signup_data->blog_domain (http://localhost/wordpress/TEMPLATESITE)
    ust_signup_data->blog_title (ORIGINATING TEMPLATE SITE DESCRIPTION )

    in postmeta:
    meta_key-> _mail with meta_value
    (i found:
    This e-mail was sent from a contact form on ORIGINATING TEMPLATE SITE DESCRIPTION (http://localhost/wordpress/TEMPLATESITE)";s:9:"recipient";s:17:"ADMIN@ORIGINATINGTEMPLATESITEEMAIL.COM";s:18:"additional_headers";s:0:"";s:11:"attachments";s:0:"";s:8:"use_html";b:0;}

    )

    in posts:
    post_content
    (i found:
    This e-mail was sent from a contact form on ORIGINATING TEMPLATE SITE DESCRIPTION (http://localhost/wordpress/TEMPLATESITE)
    ADMIN@ORIGINATINGTEMPLATESITEEMAIL.COM

    )

    So perhaps you could grab the template admin email, template site title, and template url in the ust_signup_data and do a search and replace for those terms in the new blog.

    Perhaps this would solve the contact form 7 issues, and clean up other areas of the newly created site.

    Another note specific to the plugin, in addition to meta_key '_mail' the info needs to be updated in '_mail_2'

    Addition newly created blog site wide notes: I found in the posts, there are guid fields with the originating template url , in addition the post_author field id seems to be the originating template blog id in some rows.

    does this help...? Thoughts?

    Thanks @Ignacio

    -Ben

  • Ignacio

    Hi @Ben.

    There was a mistake in the function I posted above. It was trying to get the contact form settings from the destination blog (where's there's no data). Here's the good one:

    /** CONTACT FORMS 7 **/
    add_action( 'blog_templates-copy-after_copying', 'nbt_hooks_copy_contact_form_7_forms', 10, 2 );
    function nbt_hooks_copy_contact_form_7_forms( $template, $destination_blog_id ) {
    	global $wpdb;
    
    	if ( ! function_exists( 'is_plugin_active' ) )
    		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
    
    	switch_to_blog( $destination_blog_id );
    	if ( ! is_plugin_active( 'contact-form-7/wp-contact-form-7.php' ) ) {
    		restore_current_blog();
    		return;
    	}
    	restore_current_blog();
    
    	nbt_hooks_copy_extra_post_types( 'wpcf7_contact_form', $template, $destination_blog_id );
    
    	$source_blog_id = absint( $template['blog_id'] );
    
    	switch_to_blog( $source_blog_id );
    	// We get all the posts IDs that has _mail post meta (that belongs to a Contact Form)
    	$results = $wpdb->get_col( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_mail'" );
    	$contact_form_meta = array();
    	foreach ( $results as $post_id ) {
    		$contact_form_meta[] = get_post_meta( $post_id, '_mail', true );
    	}
    	restore_current_blog();
    
    	// Now, to change the recipient email
    	switch_to_blog( $destination_blog_id );
    
    	foreach ( $contact_form_meta as $contact_form_settings ) {
    		if ( isset( $contact_form_settings['recipient'] ) )
    			$contact_form_settings['recipient'] = get_option( 'admin_email' );
    
    		update_post_meta( $post_id, '_mail', $contact_form_settings );
    	}
    
    	restore_current_blog();
    
    }

    I cannot use a regular expression for the site title/site domain except for images or files (and it doesn't work properly in some situations) because everyone has its own needs so I try not to generalize a lot with this plugin. The best I can do is make it the more extensible as possible so everyone can add its own scripts to the plugin.

    If someone else has problems with Contact Form 7, I can add it in the future but for the moment these scripts can make the work for you. If you need to replace more things this line:

    if ( isset( $contact_form_settings['recipient'] ) )
    			$contact_form_settings['recipient'] = get_option( 'admin_email' );

    can be extended so you can replace more values. However, I think that Contact Form has more metadata in wp_postmeta, you can take a look at it using the following query:

    SELECT meta_key,meta_value FROM wp_postmeta LEFT JOIN wp_posts ON wp_posts.ID = wp_postmeta.post_id WHERE wp_posts.post_type = 'wpcf7_contact_form'

    Then you'll have an idea of what values you should copy to the destination blog maybe changing this line in the function:

    $results = $wpdb->get_col( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_mail'" );

    As you can see there are millions of different possibilities so I cannot cover every one of them :slight_smile:.

    Let me know if the function is working now, I haven't tested it a lot so new issues could appear.

    Regards.
    Ignacio.

  • Ben

    @Ignacio

    I did a var dump on the original data, and the data that we are trying to update the field with, and the structure is slightly different:

    Original:

    array(1) { [0]=> array(7) { ["subject"]=> string(14) "[your-subject]" ["sender"]=> string(26) "[your-name] <[your-email]>" ["body"]=> string(189) "From: [your-name] <[your-email]> Subject: [your-subject] Message Body: [your-message] -- This e-mail was sent from a contact form on Blue Store One (http://localhost/wordpress/bluestore1)&quot; ["recipient"]=> string(17) "admin@templateemail.com" ["additional_headers"]=> string(0) "" ["attachments"]=> string(0) "" ["use_html"]=> bool(false) } }

    The modified data we are trying to update with:

    array(7) { ["subject"]=> string(14) "[your-subject]" ["sender"]=> string(26) "[your-name] <[your-email]>" ["body"]=> string(189) "From: [your-name] <[your-email]> Subject: [your-subject] Message Body: [your-message] -- This e-mail was sent from a contact form on Blue Store One (http://localhost/wordpress/bluestore1)&quot; ["recipient"]=> string(16) "ionicm@yahoo.com" ["additional_headers"]=> string(0) "" ["attachments"]=> string(0) "" ["use_html"]=> bool(false) }

    Perhaps this is why the update isn't working?

  • Ben

    @Ignacio

    Disregard my last post regarding the two var dumps, i see what you were doing now.

    Been doing more testing, and for some reason where you are doing:

    update_post_meta( $post_id, '_mail', $contact_form_settings );

    Instead of updating the entry, it is creating a brand new entry so that there are 2 rows in the database with meta key '_mail'

    If try to run before the update_post_meta:

    delete_post_meta( $post_id, '_mail' );

    It doesn't seem to perform a delete.

    If however I delete the undesired row via phpmyadmin, then we get the desired results.

    Any ideas why the update or delete isn't working?

  • Ben

    @Ignacio

    I got it working with a workaround...! Before the update_post_meta I added the following code:

    $delete_query = "DELETE FROM $wpdb->postmeta WHERE meta_key = '_mail' AND post_id = $post_id";
    $delete_results = $wpdb->get_results( $delete_query );

    Any idea why both update_post_meta to update info (this function reverts to add_post_meta if that meta_key and post_id don't exist) and why delete_post_meta functions are not working properly in this instance?

    We are close!

  • Ignacio

    Hi @Ben.

    I think I have it but if you need more customized things I guess you'll need to work from this on your own unless there's a bug or something:

    Is slightly harder to understand, and now there are two functions, one of them replaces a string inside multidimensional array.

    add_action( 'blog_templates-copy-after_copying', 'nbt_hooks_copy_contact_form_7_forms', 10, 2 );
    function nbt_hooks_copy_contact_form_7_forms( $template, $destination_blog_id ) {
    	global $wpdb;
    
    	if ( ! function_exists( 'is_plugin_active' ) )
    		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
    
    	switch_to_blog( $destination_blog_id );
    	if ( ! is_plugin_active( 'contact-form-7/wp-contact-form-7.php' ) ) {
    		restore_current_blog();
    		return;
    	}
    	restore_current_blog();
    
    	nbt_hooks_copy_extra_post_types( 'wpcf7_contact_form', $template, $destination_blog_id );
    
    	$source_blog_id = absint( $template['blog_id'] );
    
    	switch_to_blog( $source_blog_id );
    	// We get all the posts IDs that has _mail post meta (that belongs to a Contact Form)
    	$results = $wpdb->get_results( "SELECT pm.post_id, pm.meta_key FROM $wpdb->postmeta pm LEFT JOIN $wpdb->posts p ON p.ID = pm.post_id WHERE p.post_type='wpcf7_contact_form'" );
    
    	$all_meta = array();
    	foreach ( $results as $row ) {
    		// We get all the meta for every post
    		$all_meta[ $row->post_id ][ $row->meta_key ] = get_post_meta( $row->post_id, $row->meta_key, true );
    	}
    	restore_current_blog();
    
    	// Now, to change the recipient email in every meta value
    	switch_to_blog( $destination_blog_id );
    	$email_to_search = 'emailtoreplace@gmail.com';
    	$replace_email_with = get_option( 'admin_email' );
    
    	// This will replace all ocurrences of the email you're looking for
    	$new_all_meta = nbt_hooks_str_replace_deep( $email_to_search, $replace_email_with, $all_meta );
    
    	foreach ( $new_all_meta as $post_id => $all_post_meta ) {
    		foreach ( $all_post_meta as $meta_key => $meta_value ) {
    			update_post_meta( $post_id, $meta_key, $meta_value );
    		}
    	}
    
    	restore_current_blog();
    
    }
    
    function nbt_hooks_str_replace_deep($search, $replace, $subject) {
        if (is_array($subject)) {
            foreach($subject as &$oneSubject)
                $oneSubject = nbt_hooks_str_replace_deep($search, $replace, $oneSubject);
            unset($oneSubject);
            return $subject;
        } else {
            return str_replace($search, $replace, $subject);
        }
    }

    Watch out, you have to change the value of $email_to_search manually (or get it from the source blog with get_option('admin_email'), it depends on what you have in the forms.

    I've tested it a lot and is working fine.

    Regards.
    Ignacio.

  • Ben

    @Ignacio

    This is beautiful, well done...almost works for me...but once i do the work around it works!

    For the work around, I did the following(similar to the work around i mentioned for the previous version):

    just before your code line:

    update_post_meta( $post_id, $meta_key, $meta_value );

    I inserted the following code:

    $delete_query = "DELETE FROM $wpdb->postmeta WHERE meta_key = '$meta_key' AND post_id = $post_id";
    $delete_results = $wpdb->get_results( $delete_query );

    If I don't do this workaround, it does not work.

    Just curious, are you testing it with the multi-db plugin? If not, I wonder if perhaps we found a bug in the multi-db plugin?

  • Ben

    @Ignacio

    I further modified the code you created to now auto replace the admin email as well as blogname, description, siteurl (as they are referenced in the form)

    It seems to be working well for me! Check it out!

    add_action( 'blog_templates-copy-after_copying', 'nbt_hooks_copy_contact_form_7_forms', 10, 2 );
    function nbt_hooks_copy_contact_form_7_forms( $template, $destination_blog_id ) {
    	global $wpdb;
    
    	if ( ! function_exists( 'is_plugin_active' ) )
    		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
    
    	switch_to_blog( $destination_blog_id );
    	if ( ! is_plugin_active( 'contact-form-7/wp-contact-form-7.php' ) ) {
    		restore_current_blog();
    		return;
    	}
    	restore_current_blog();
    
    	nbt_hooks_copy_extra_post_types( 'wpcf7_contact_form', $template, $destination_blog_id );
    
    	$source_blog_id = absint( $template['blog_id'] );
    
    	switch_to_blog( $source_blog_id );
    	$email_to_search = get_option( 'admin_email' );
    	$blogname_template = get_option( 'blogname' );
    	$blogdescription_template = get_option( 'blogdescription' );
    
    	$siteurl_template = get_option( 'siteurl' );
    	// We get all the posts IDs that has _mail post meta (that belongs to a Contact Form)
    	$results = $wpdb->get_results( "SELECT pm.post_id, pm.meta_key FROM $wpdb->postmeta pm LEFT JOIN $wpdb->posts p ON p.ID = pm.post_id WHERE p.post_type='wpcf7_contact_form'" );
    
    	$all_meta = array();
    	foreach ( $results as $row ) {
    		// We get all the meta for every post
    		$all_meta[ $row->post_id ][ $row->meta_key ] = get_post_meta( $row->post_id, $row->meta_key, true );
    	}
    	restore_current_blog();
    
    	// Now, to change the recipient email in every meta value
    	switch_to_blog( $destination_blog_id );
    	// $email_to_search = 'emailtoreplace@gmail.com';
    	// $replace_email_with = get_option( 'admin_email' );
    
    	// This will replace all ocurrences of the email you're looking for
    	$new_all_meta_admin_email 	  = nbt_hooks_str_replace_deep( $email_to_search,
    		                                                    	get_option( 'admin_email' ),
    		                                                    	$all_meta
    		                                                    	);
    
    	$new_all_meta_blogname 		  = nbt_hooks_str_replace_deep( $blogname_template,
    																get_option( 'blogname' ),
    																$new_all_meta_admin_email
    																);
    	$new_all_meta_blogdescription = nbt_hooks_str_replace_deep( $blogdescription_template,
    																get_option( 'blogdescription' ),
    																$new_all_meta_blogname
    																);
    	$new_all_meta_siteurl 		  = nbt_hooks_str_replace_deep( $siteurl_template,
    																get_option( 'siteurl' ),
    																$new_all_meta_blogdescription );
    
    	$new_all_meta = $new_all_meta_siteurl; 
    
    	foreach ( $new_all_meta as $post_id => $all_post_meta ) {
    		foreach ( $all_post_meta as $meta_key => $meta_value ) {
    			$delete_query = "DELETE FROM $wpdb->postmeta WHERE meta_key = '$meta_key' AND post_id = $post_id";
    			$delete_results = $wpdb->get_results( $delete_query );
    			update_post_meta( $post_id, $meta_key, $meta_value );
    		}
    	}
    
    	restore_current_blog();
    }

    I even though I have a working work-around, if you happen to know why "update_post_meta" wouldn't be working properly for me (perhaps its a multi-db plugin bug or something else), otherwise this seems to be doing the trick. Will test on my live server soon. Great work and tell me what you think!

    -Ben

Thank NAME, for their help.

Let NAME know exactly why they deserved these points.

Gift a custom amount of points.