| |
| <?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| defined( 'ABSPATH' ) || exit;
|
|
|
|
|
| add_action( 'admin_bar_menu', function( $wp_admin_bar ) {
|
| if ( ! current_user_can( 'manage_options' ) ) return;
|
|
|
| $wp_admin_bar->add_node( [
|
| 'id' => 'gf-forms-sync-test',
|
| 'title' => '🔄 Sync GF Forms & Feeds',
|
| 'href' => admin_url( 'admin.php?gf_forms_sync_test=1' ),
|
| ] );
|
| }, 999 );
|
|
|
|
|
| add_action( 'admin_init', function() {
|
| if ( ! isset( $_GET['gf_forms_sync_test'] ) || ! current_user_can( 'manage_options' ) ) return;
|
|
|
| if ( ! class_exists( 'GFAPI' ) ) {
|
| wp_die( 'Gravity Forms not active!' );
|
| }
|
|
|
|
|
| gf_cleanup_orphaned_form_posts();
|
|
|
|
|
| $forms = GFAPI::get_forms();
|
| $count = 0;
|
|
|
| foreach ( $forms as $form ) {
|
| gf_mirror_form_to_cpt( $form );
|
| $count++;
|
| }
|
|
|
| wp_redirect( admin_url( 'edit.php?post_type=gf_form_feeds&synced=' . $count ) );
|
| exit;
|
| } );
|
|
|
|
|
| add_action( 'admin_notices', function() {
|
| if ( isset( $_GET['synced'] ) && $_GET['post_type'] === 'gf_form_feeds' ) {
|
| $count = intval( $_GET['synced'] );
|
| echo '<div class="notice notice-success"><p>✅ Synced ' . $count . ' forms to CPT!</p></div>';
|
| }
|
| } );
|
|
|
|
|
|
|
|
|
| function gf_cleanup_orphaned_form_posts() {
|
| if ( ! class_exists( 'GFAPI' ) ) {
|
| return;
|
| }
|
|
|
|
|
| $forms = GFAPI::get_forms();
|
| $active_form_ids = array_map( function( $form ) {
|
| return absint( $form['id'] );
|
| }, $forms );
|
|
|
| error_log( 'GF_FORMS_SYNC: Active form IDs: ' . implode( ', ', $active_form_ids ) );
|
|
|
|
|
| $all_form_posts = new WP_Query( [
|
| 'post_type' => 'gf_form_feeds',
|
| 'posts_per_page' => -1,
|
| 'fields' => 'ids',
|
| ] );
|
|
|
| $deleted_count = 0;
|
|
|
| foreach ( $all_form_posts->posts as $post_id ) {
|
| $form_id = intval( get_post_meta( $post_id, 'form_id', true ) );
|
|
|
|
|
| if ( $form_id && ! in_array( $form_id, $active_form_ids, true ) ) {
|
| wp_delete_post( $post_id, true );
|
| $deleted_count++;
|
| error_log( "GF_FORMS_SYNC: Deleted orphaned form post for non-existent form {$form_id} (post {$post_id})" );
|
| }
|
| }
|
|
|
| if ( $deleted_count > 0 ) {
|
| error_log( "GF_FORMS_SYNC: Cleaned up {$deleted_count} orphaned form posts" );
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| function gf_mirror_form_to_cpt( $form ) {
|
|
|
| if ( ! post_type_exists( 'gf_form_feeds' ) ) {
|
| error_log( 'GF_FORMS_SYNC: CPT gf_form_feeds does not exist!' );
|
| return;
|
| }
|
|
|
|
|
| if ( empty( $form ) || ! is_array( $form ) || empty( $form['id'] ) ) {
|
| error_log( 'GF_FORMS_SYNC: Invalid form data' );
|
| return;
|
| }
|
|
|
| $form_id = absint( $form['id'] );
|
| $form_title = isset( $form['title'] ) ? sanitize_text_field( $form['title'] ) : 'Form ' . $form_id;
|
|
|
| error_log( "GF_FORMS_SYNC: Processing form {$form_id} - {$form_title}" );
|
|
|
|
|
| $existing_query = new WP_Query( [
|
| 'post_type' => 'gf_form_feeds',
|
| 'posts_per_page' => 1,
|
| 'fields' => 'ids',
|
| 'meta_query' => [
|
| [
|
| 'key' => 'form_id',
|
| 'value' => $form_id,
|
| ]
|
| ]
|
| ] );
|
|
|
| $existing_post_id = ! empty( $existing_query->posts ) ? $existing_query->posts[0] : false;
|
|
|
|
|
| $feed_data = gf_get_form_feed_data( $form_id );
|
| $entry_count = gf_get_form_entry_count( $form_id );
|
|
|
| $slug = sanitize_title( "gf-form-{$form_id}" );
|
|
|
| $post_data = [
|
| 'post_type' => 'gf_form_feeds',
|
| 'post_status' => 'publish',
|
| 'post_title' => $form_title,
|
| 'post_name' => $slug,
|
| ];
|
|
|
| $meta_data = [
|
| 'form_id' => $form_id,
|
| 'form_status' => ! empty( $form['is_active'] ) ? 'active' : 'inactive',
|
| 'entry_count' => $entry_count,
|
| 'field_count' => ! empty( $form['fields'] ) ? count( $form['fields'] ) : 0,
|
| 'feed_count_total' => $feed_data['total'],
|
| 'feed_count_active' => $feed_data['active'],
|
| 'feed_count_inactive' => $feed_data['inactive'],
|
| 'feeds_list' => $feed_data['feeds'],
|
| 'form_settings' => [
|
| 'ajax_enabled' => ! empty( $form['enableAjax'] ) ? 1 : 0,
|
| 'honeypot_enabled' => ! empty( $form['enableHoneypot'] ) ? 1 : 0,
|
| 'save_continue' => ! empty( $form['save'] ) && ! empty( $form['save']['enabled'] ) ? 1 : 0,
|
| 'limit_entries' => ! empty( $form['limitEntries'] ) ? 1 : 0,
|
| ],
|
| 'notification_count' => ! empty( $form['notifications'] ) ? count( $form['notifications'] ) : 0,
|
| 'confirmation_count' => ! empty( $form['confirmations'] ) ? count( $form['confirmations'] ) : 0,
|
| 'last_sync' => current_time( 'mysql' ),
|
| 'gf_form_edit_link' => admin_url( 'admin.php?page=gf_edit_forms&id=' . $form_id ),
|
| 'gf_form_entries_link' => admin_url( 'admin.php?page=gf_entries&id=' . $form_id ),
|
| 'notifications_content' => gf_format_notifications_content( $form ),
|
| 'confirmations_content' => gf_format_confirmations_content( $form ),
|
| ];
|
|
|
| if ( $existing_post_id ) {
|
|
|
| $post_data['ID'] = $existing_post_id;
|
| $post_id = wp_update_post( $post_data );
|
| error_log( "GF_FORMS_SYNC: Updated form {$form_id} (post {$post_id})" );
|
| } else {
|
|
|
| $post_id = wp_insert_post( $post_data );
|
| error_log( "GF_FORMS_SYNC: Created form {$form_id} (post {$post_id})" );
|
| }
|
|
|
|
|
| if ( $post_id && ! is_wp_error( $post_id ) ) {
|
| foreach ( $meta_data as $key => $value ) {
|
| update_post_meta( $post_id, $key, $value );
|
| }
|
|
|
|
|
| update_post_meta( $post_id, '_gf_form_edit_link', 'field_gf_form_edit_link' );
|
| update_post_meta( $post_id, '_gf_form_entries_link', 'field_gf_form_entries_link' );
|
|
|
| gf_populate_field_details( $post_id, $form_id, $form );
|
|
|
|
|
| do_action( 'gf_form_feeds_sync_complete', $post_id, $form_id );
|
| error_log( "GF_FORMS_SYNC: Triggered field details sync for form {$form_id}" );
|
| }
|
|
|
| error_log( "GF_FORMS_SYNC: Completed form {$form_id}" );
|
| }
|
|
|
| function gf_format_notifications_content( $form ) {
|
| if ( empty( $form['notifications'] ) || ! is_array( $form['notifications'] ) ) {
|
| return "No notifications configured for this form.";
|
| }
|
|
|
| $output = [];
|
| $count = 1;
|
|
|
| foreach ( $form['notifications'] as $notification_id => $notification ) {
|
| $output[] = "═══════════════════════════════════════════════";
|
| $output[] = "NOTIFICATION #{$count}";
|
| $output[] = "═══════════════════════════════════════════════";
|
| $output[] = "";
|
| $output[] = "Name: " . ( ! empty( $notification['name'] ) ? $notification['name'] : 'Unnamed' );
|
| $output[] = "ID: {$notification_id}";
|
| $output[] = "Status: " . ( ! empty( $notification['isActive'] ) ? 'Active' : 'Inactive' );
|
| $output[] = "";
|
| $output[] = "TO: " . ( ! empty( $notification['to'] ) ? $notification['to'] : 'Not set' );
|
| if ( ! empty( $notification['cc'] ) ) {
|
| $output[] = "CC: " . $notification['cc'];
|
| }
|
| if ( ! empty( $notification['bcc'] ) ) {
|
| $output[] = "BCC: " . $notification['bcc'];
|
| }
|
| $output[] = "FROM: " . ( ! empty( $notification['from'] ) ? $notification['from'] : 'Not set' );
|
| $output[] = "FROM NAME: " . ( ! empty( $notification['fromName'] ) ? $notification['fromName'] : 'Not set' );
|
| $output[] = "";
|
| $output[] = "SUBJECT: " . ( ! empty( $notification['subject'] ) ? $notification['subject'] : 'No subject' );
|
| $output[] = "";
|
| if ( ! empty( $notification['message'] ) ) {
|
| $output[] = "MESSAGE:";
|
| $output[] = "---";
|
| $output[] = strip_tags( $notification['message'] );
|
| $output[] = "---";
|
| }
|
| $output[] = "";
|
| if ( ! empty( $notification['conditionalLogic'] ) ) {
|
| $output[] = "⚠️ Has Conditional Logic";
|
| }
|
| if ( ! empty( $notification['event'] ) ) {
|
| $output[] = "Trigger Event: " . $notification['event'];
|
| }
|
| $output[] = "";
|
| $count++;
|
| }
|
|
|
| return implode( "\n", $output );
|
| }
|
|
|
| function gf_format_confirmations_content( $form ) {
|
| if ( empty( $form['confirmations'] ) || ! is_array( $form['confirmations'] ) ) {
|
| return "No confirmations configured for this form.";
|
| }
|
|
|
| $output = [];
|
| $count = 1;
|
|
|
| foreach ( $form['confirmations'] as $confirmation_id => $confirmation ) {
|
| $output[] = "═══════════════════════════════════════════════";
|
| $output[] = "CONFIRMATION #{$count}";
|
| $output[] = "═══════════════════════════════════════════════";
|
| $output[] = "";
|
| $output[] = "Name: " . ( ! empty( $confirmation['name'] ) ? $confirmation['name'] : 'Unnamed' );
|
| $output[] = "ID: {$confirmation_id}";
|
| $output[] = "Status: " . ( ! empty( $confirmation['isActive'] ) ? 'Active' : 'Inactive' );
|
| $output[] = "Default: " . ( ! empty( $confirmation['isDefault'] ) ? 'Yes' : 'No' );
|
| $output[] = "";
|
| $type = ! empty( $confirmation['type'] ) ? $confirmation['type'] : 'message';
|
| $output[] = "TYPE: " . strtoupper( $type );
|
| $output[] = "";
|
| switch ( $type ) {
|
| case 'message':
|
| if ( ! empty( $confirmation['message'] ) ) {
|
| $output[] = "MESSAGE:";
|
| $output[] = "---";
|
| $output[] = strip_tags( $confirmation['message'] );
|
| $output[] = "---";
|
| }
|
| break;
|
| case 'redirect':
|
| $output[] = "REDIRECT URL: " . ( ! empty( $confirmation['url'] ) ? $confirmation['url'] : 'Not set' );
|
| if ( ! empty( $confirmation['queryString'] ) ) {
|
| $output[] = "Query String: " . $confirmation['queryString'];
|
| }
|
| break;
|
| case 'page':
|
| $output[] = "PAGE ID: " . ( ! empty( $confirmation['pageId'] ) ? $confirmation['pageId'] : 'Not set' );
|
| if ( ! empty( $confirmation['queryString'] ) ) {
|
| $output[] = "Query String: " . $confirmation['queryString'];
|
| }
|
| break;
|
| }
|
| $output[] = "";
|
| if ( ! empty( $confirmation['conditionalLogic'] ) ) {
|
| $output[] = "⚠️ Has Conditional Logic";
|
| $output[] = "";
|
| }
|
| $count++;
|
| }
|
|
|
| return implode( "\n", $output );
|
| }
|
|
|
| function gf_populate_field_details( $post_id, $form_id, $form ) {
|
| if ( empty( $form['fields'] ) || ! is_array( $form['fields'] ) ) {
|
| update_post_meta( $post_id, 'field_details_list', 'No fields in this form.' );
|
| update_post_meta( $post_id, 'field_details_last_sync', current_time( 'mysql' ) );
|
| return;
|
| }
|
|
|
| $output = [];
|
| $output[] = "═══════════════════════════════════════════════════════════════════";
|
| $output[] = "FORM: {$form['title']} (ID: {$form_id})";
|
| $output[] = "TOTAL FIELDS: " . count( $form['fields'] );
|
| $output[] = "SYNCED: " . current_time( 'F j, Y g:i a' );
|
| $output[] = "═══════════════════════════════════════════════════════════════════";
|
| $output[] = "";
|
|
|
| foreach ( $form['fields'] as $field ) {
|
| $output[] = "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━";
|
| $output[] = "FIELD #{$field->id}";
|
| $output[] = "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━";
|
| $output[] = "";
|
| $output[] = "Label: " . ( ! empty( $field->label ) ? $field->label : '[No Label]' );
|
| $output[] = "Type: " . $field->type;
|
| if ( ! empty( $field->adminLabel ) ) {
|
| $output[] = "Admin Label: " . $field->adminLabel;
|
| }
|
| if ( ! empty( $field->description ) ) {
|
| $output[] = "Description: " . $field->description;
|
| }
|
| $output[] = "Required: " . ( ! empty( $field->isRequired ) ? 'Yes' : 'No' );
|
| if ( isset( $field->visibility ) ) {
|
| $output[] = "Visibility: " . $field->visibility;
|
| }
|
| if ( ! empty( $field->cssClass ) ) {
|
| $output[] = "CSS Class: " . $field->cssClass;
|
| }
|
| if ( ! empty( $field->conditionalLogic ) ) {
|
| $output[] = "⚠️ Has Conditional Logic";
|
| }
|
| if ( ! empty( $field->allowsPrepopulate ) ) {
|
| $output[] = "✓ Allows Prepopulation";
|
| if ( ! empty( $field->inputName ) ) {
|
| $output[] = " Parameter Name: " . $field->inputName;
|
| }
|
| }
|
| if ( ! empty( $field->gppa ) || ! empty( $field->gppaDynamicPopulation ) ) {
|
| $output[] = "✓ GPPA ENABLED";
|
| if ( ! empty( $field->choices ) && is_array( $field->choices ) ) {
|
| $output[] = " GPPA Choices: " . count( $field->choices ) . " dynamically populated";
|
| }
|
| }
|
| if ( ! empty( $field->choices ) && is_array( $field->choices ) ) {
|
| $output[] = "";
|
| $output[] = "Choices:";
|
| foreach ( $field->choices as $choice ) {
|
| $choice_text = is_array( $choice ) ? $choice['text'] : $choice;
|
| $choice_value = is_array( $choice ) && isset( $choice['value'] ) ? $choice['value'] : $choice_text;
|
| $output[] = " • {$choice_text}" . ( $choice_text !== $choice_value ? " (value: {$choice_value})" : '' );
|
| }
|
| }
|
| if ( ! empty( $field->inputs ) && is_array( $field->inputs ) ) {
|
| $output[] = "";
|
| $output[] = "Sub-fields:";
|
| foreach ( $field->inputs as $input ) {
|
| if ( is_array( $input ) && ! empty( $input['label'] ) ) {
|
| $output[] = " • {$input['id']}: {$input['label']}";
|
| }
|
| }
|
| }
|
| if ( $field->type === 'fileupload' ) {
|
| if ( ! empty( $field->maxFiles ) ) {
|
| $output[] = "Max Files: " . $field->maxFiles;
|
| }
|
| if ( ! empty( $field->allowedExtensions ) ) {
|
| $output[] = "Allowed Extensions: " . $field->allowedExtensions;
|
| }
|
| }
|
| if ( ! empty( $field->defaultValue ) ) {
|
| $output[] = "Default Value: " . $field->defaultValue;
|
| }
|
| if ( ! empty( $field->placeholder ) ) {
|
| $output[] = "Placeholder: " . $field->placeholder;
|
| }
|
| $output[] = "";
|
| }
|
|
|
| update_post_meta( $post_id, 'field_details_list', implode( "\n", $output ) );
|
| update_post_meta( $post_id, 'field_details_last_sync', current_time( 'mysql' ) );
|
| }
|
|
|
|
|
|
|
|
|
| function gf_get_form_feed_data( $form_id ) {
|
| $feed_data = [
|
| 'total' => 0,
|
| 'active' => 0,
|
| 'inactive' => 0,
|
| 'feeds' => []
|
| ];
|
|
|
|
|
| if ( ! class_exists( 'GFAddOn' ) ) {
|
| return $feed_data;
|
| }
|
|
|
|
|
| $addons = GFAddOn::get_registered_addons();
|
|
|
| foreach ( $addons as $addon_class ) {
|
| if ( ! class_exists( $addon_class ) ) {
|
| continue;
|
| }
|
|
|
| try {
|
| $addon = call_user_func( [ $addon_class, 'get_instance' ] );
|
| if ( ! $addon || ! method_exists( $addon, 'get_feeds' ) ) {
|
| continue;
|
| }
|
|
|
| $feeds = $addon->get_feeds( $form_id );
|
|
|
| if ( ! empty( $feeds ) && is_array( $feeds ) ) {
|
| foreach ( $feeds as $feed ) {
|
| $is_active = ! isset( $feed['is_active'] ) || $feed['is_active'] ? 1 : 0;
|
|
|
| $addon_name = 'Unknown';
|
| if ( method_exists( $addon, 'get_short_title' ) ) {
|
| $addon_name = $addon->get_short_title();
|
| }
|
|
|
| $feed_name = 'Unnamed Feed';
|
| if ( isset( $feed['meta']['feed_name'] ) ) {
|
| $feed_name = $feed['meta']['feed_name'];
|
| } elseif ( isset( $feed['meta']['feedName'] ) ) {
|
| $feed_name = $feed['meta']['feedName'];
|
| }
|
|
|
| $feed_type = '';
|
| if ( isset( $feed['addon_slug'] ) ) {
|
| $feed_type = $feed['addon_slug'];
|
| } elseif ( method_exists( $addon, 'get_slug' ) ) {
|
| $feed_type = $addon->get_slug();
|
| }
|
|
|
| $feed_data['feeds'][] = [
|
| 'addon' => sanitize_text_field( $addon_name ),
|
| 'name' => sanitize_text_field( $feed_name ),
|
| 'type' => sanitize_text_field( $feed_type ),
|
| 'is_active' => $is_active,
|
| ];
|
|
|
| $feed_data['total']++;
|
| if ( $is_active ) {
|
| $feed_data['active']++;
|
| } else {
|
| $feed_data['inactive']++;
|
| }
|
| }
|
| }
|
| } catch ( Exception $e ) {
|
| error_log( 'GF_FORMS_SYNC: Error getting feeds for addon ' . $addon_class . ': ' . $e->getMessage() );
|
| }
|
| }
|
|
|
| return $feed_data;
|
| }
|
|
|
|
|
|
|
|
|
| function gf_get_form_entry_count( $form_id ) {
|
|
|
| if ( class_exists( 'GFAPI' ) ) {
|
| $search_criteria = [
|
| 'status' => 'active',
|
| 'form_id' => $form_id
|
| ];
|
|
|
| try {
|
| $count = GFAPI::count_entries( $form_id, $search_criteria );
|
| return intval( $count );
|
| } catch ( Exception $e ) {
|
| error_log( 'GF_FORMS_SYNC: Error counting entries: ' . $e->getMessage() );
|
| return 0;
|
| }
|
| }
|
|
|
| return 0;
|
| }
|
|
|
|
|
| add_action( 'gform_after_save_form', function( $form, $is_new ) {
|
| error_log( 'GF_FORMS_SYNC: gform_after_save_form fired' );
|
| gf_mirror_form_to_cpt( $form );
|
| }, 20, 2 );
|
|
|
|
|
| add_action( 'gform_forms_post_import', function( $forms ) {
|
| error_log( 'GF_FORMS_SYNC: gform_forms_post_import fired with ' . count( $forms ) . ' forms' );
|
| if ( is_array( $forms ) ) {
|
| foreach ( $forms as $form ) {
|
| gf_mirror_form_to_cpt( $form );
|
| }
|
| }
|
| }, 20, 1 );
|
|
|
|
|
| add_action( 'gform_before_delete_form', function( $form_id ) {
|
| error_log( "GF_FORMS_SYNC: Form {$form_id} is being deleted - removing associated post" );
|
|
|
|
|
| $query = new WP_Query( [
|
| 'post_type' => 'gf_form_feeds',
|
| 'posts_per_page' => 1,
|
| 'fields' => 'ids',
|
| 'meta_query' => [
|
| [
|
| 'key' => 'form_id',
|
| 'value' => absint( $form_id ),
|
| ]
|
| ]
|
| ] );
|
|
|
| if ( ! empty( $query->posts ) ) {
|
| wp_delete_post( $query->posts[0], true );
|
| error_log( "GF_FORMS_SYNC: Deleted post for form {$form_id}" );
|
| }
|
| }, 10, 1 );
|
|
|
|
|
| add_action( 'load-edit.php', function() {
|
| if ( ! isset( $_GET['post_type'] ) || $_GET['post_type'] !== 'gf_form_feeds' ) {
|
| return;
|
| }
|
|
|
|
|
| if ( get_transient( 'gf_forms_sync_cleanup_done' ) ) {
|
| return;
|
| }
|
|
|
| gf_cleanup_orphaned_form_posts();
|
|
|
|
|
| set_transient( 'gf_forms_sync_cleanup_done', true, HOUR_IN_SECONDS );
|
| } );
|
|
|
|
|
| add_action( 'init', function() {
|
| if ( ! class_exists( 'GFCommon' ) ) {
|
| error_log( 'GF_FORMS_SYNC: Gravity Forms not detected!' );
|
| } else {
|
| error_log( 'GF_FORMS_SYNC: Gravity Forms detected, version: ' . GFCommon::$version );
|
| }
|
| }, 999 );
|
| |
| |
Comments