Home / Admin / Gravity Flow Sync
Duplicate Snippet

Embed Snippet on Your Site

Gravity Flow Sync

Sync Code to Run Gravity Flow Reports

ismail daugherty PRO
<10
Code Preview
php
<?php
/**
 * Gravity Flow Steps to CPT Mirror
 * Creates/updates a gf_workflow_step post for each Gravity Flow step
 * Handles form updates, deletions, and manual sync
 */
defined( 'ABSPATH' ) || exit;
// Add manual sync button in admin bar
add_action( 'admin_bar_menu', function( $wp_admin_bar ) {
    if ( ! current_user_can( 'manage_options' ) ) return;
    
    $wp_admin_bar->add_node( [
        'id'    => 'gf-flow-sync-test',
        'title' => '🔄 Sync GF Workflow Steps',
        'href'  => admin_url( 'admin.php?gf_flow_sync_test=1' ),
    ] );
}, 999 );
// Handle manual sync trigger
add_action( 'admin_init', function() {
    if ( ! isset( $_GET['gf_flow_sync_test'] ) || ! current_user_can( 'manage_options' ) ) return;
    
    if ( ! class_exists( 'GFAPI' ) || ! class_exists( 'Gravity_Flow_API' ) ) {
        wp_die( 'Gravity Forms and/or Gravity Flow not active!' );
    }
    
    // Clean up orphaned workflow steps first
    gf_flow_cleanup_orphaned_steps();
    
    // Sync all forms with workflows
    $forms = GFAPI::get_forms();
    $count = 0;
    
    foreach ( $forms as $form ) {
        if ( gf_flow_mirror_steps_to_cpt( $form ) ) {
            $count++;
        }
    }
    
    wp_redirect( admin_url( 'edit.php?post_type=gf_workflow_step&synced=' . $count ) );
    exit;
} );
// Show success message
add_action( 'admin_notices', function() {
    if ( isset( $_GET['synced'] ) && $_GET['post_type'] === 'gf_workflow_step' ) {
        $count = intval( $_GET['synced'] );
        echo '<div class="notice notice-success"><p>✅ Synced workflows from ' . $count . ' forms to CPT!</p></div>';
    }
} );
/**
 * Clean up steps from deleted forms
 */
function gf_flow_cleanup_orphaned_steps() {
    if ( ! class_exists( 'GFAPI' ) ) {
        return;
    }
    
    // Get all active form IDs
    $forms = GFAPI::get_forms();
    $active_form_ids = array_map( function( $form ) {
        return absint( $form['id'] );
    }, $forms );
    
    error_log( 'GF_FLOW_SYNC: Active form IDs: ' . implode( ', ', $active_form_ids ) );
    
    // Query all workflow step posts
    $all_step_posts = new WP_Query( [
        'post_type'      => 'gf_workflow_step',
        'posts_per_page' => -1,
        'fields'         => 'ids',
    ] );
    
    $deleted_count = 0;
    
    foreach ( $all_step_posts->posts as $post_id ) {
        $form_id = intval( get_post_meta( $post_id, 'form_id', true ) );
        
        // If this step belongs to a form that no longer exists, delete it
        if ( $form_id && ! in_array( $form_id, $active_form_ids, true ) ) {
            wp_delete_post( $post_id, true );
            $deleted_count++;
            error_log( "GF_FLOW_SYNC: Deleted orphaned step from non-existent form {$form_id} (post {$post_id})" );
        }
    }
    
    if ( $deleted_count > 0 ) {
        error_log( "GF_FLOW_SYNC: Cleaned up {$deleted_count} orphaned workflow steps" );
    }
}
/**
 * Main sync function for Gravity Flow steps
 */
function gf_flow_mirror_steps_to_cpt( $form ) {
    // Verify CPT exists
    if ( ! post_type_exists( 'gf_workflow_step' ) ) {
        error_log( 'GF_FLOW_SYNC: CPT gf_workflow_step does not exist!' );
        return false;
    }
    
    // Validate form data
    if ( empty( $form ) || ! is_array( $form ) || empty( $form['id'] ) ) {
        error_log( 'GF_FLOW_SYNC: Invalid form data' );
        return false;
    }
    
    // Check if Gravity Flow API is available
    if ( ! class_exists( 'Gravity_Flow_API' ) ) {
        error_log( 'GF_FLOW_SYNC: Gravity Flow API not available' );
        return false;
    }
    
    $form_id = absint( $form['id'] );
    $form_title = isset( $form['title'] ) ? sanitize_text_field( $form['title'] ) : 'Form ' . $form_id;
    
    // Get workflow steps for this form
    $gravity_flow_api = new Gravity_Flow_API( $form_id );
    $steps = $gravity_flow_api->get_steps();
    
    if ( empty( $steps ) ) {
        error_log( "GF_FLOW_SYNC: No workflow steps found for form {$form_id}" );
        
        // Delete any existing posts for this form since it has no steps
        $existing_query = new WP_Query( [
            'post_type'      => 'gf_workflow_step',
            'posts_per_page' => -1,
            'fields'         => 'ids',
            'meta_query'     => [
                [
                    'key'   => 'form_id',
                    'value' => $form_id,
                ]
            ]
        ] );
        
        foreach ( $existing_query->posts as $post_id ) {
            wp_delete_post( $post_id, true );
        }
        
        return false;
    }
    
    error_log( "GF_FLOW_SYNC: Processing " . count( $steps ) . " steps for form {$form_id} - {$form_title}" );
    
    // Get existing posts for this form
    $existing_query = new WP_Query( [
        'post_type'      => 'gf_workflow_step',
        'posts_per_page' => -1,
        'fields'         => 'ids',
        'meta_query'     => [
            [
                'key'   => 'form_id',
                'value' => $form_id,
            ]
        ]
    ] );
    
    $post_map = [];
    foreach ( $existing_query->posts as $post_id ) {
        $step_id = get_post_meta( $post_id, 'step_id', true );
        if ( $step_id ) {
            $post_map[ $step_id ] = $post_id;
        }
    }
    
    $processed_steps = [];
    
    // Process each workflow step
    $order = 0;
    foreach ( $steps as $step ) {
        $order++;
        
        if ( ! is_object( $step ) ) {
            continue;
        }
        
        $step_id = $step->get_id();
        $processed_steps[] = $step_id;
        
        $step_name = $step->get_name();
        $step_type = $step->get_type();
        $slug = sanitize_title( "gf-flow-{$form_id}-{$step_id}" );
        
        // Build assignees list
        $assignees = [];
        if ( method_exists( $step, 'get_assignees' ) ) {
            $assignees = $step->get_assignees();
        }
        $assignees_text = gf_flow_format_assignees( $assignees );
        
        // Get routing info if available
        $routing_text = '';
        if ( method_exists( $step, 'get_routing' ) ) {
            $routing = $step->get_routing();
            if ( ! empty( $routing ) ) {
                $routing_text = wp_json_encode( $routing );
            }
        }
        
        // Check for scheduling
        $is_scheduled = false;
        $schedule_type = '';
        $schedule_value = '';
        
        if ( method_exists( $step, 'scheduled' ) && $step->scheduled ) {
            $is_scheduled = true;
            $schedule_type = isset( $step->schedule_type ) ? $step->schedule_type : 'delay';
            
            if ( $schedule_type === 'delay' ) {
                $delay_value = isset( $step->delay_value ) ? $step->delay_value : '';
                $delay_unit = isset( $step->delay_unit ) ? $step->delay_unit : 'hours';
                $schedule_value = $delay_value . ' ' . $delay_unit;
            } else {
                $schedule_value = isset( $step->schedule_date ) ? $step->schedule_date : '';
            }
        }
        
        // Check for expiration
        $has_expiration = false;
        $expiration_value = 0;
        
        if ( method_exists( $step, 'expiration_enabled' ) && $step->expiration_enabled ) {
            $has_expiration = true;
            $expiration_value = isset( $step->expiration ) ? intval( $step->expiration ) : 0;
        }
        
        // Get step settings as JSON
        $settings = $step->get_settings();
        $settings_json = wp_json_encode( $settings );
        
        // Check for conditional logic
        $has_conditional = false;
        $conditional_json = '';
        
        if ( isset( $settings['conditional_logic_enabled'] ) && $settings['conditional_logic_enabled'] ) {
            $has_conditional = true;
            if ( isset( $settings['conditional_logic'] ) ) {
                $conditional_json = wp_json_encode( $settings['conditional_logic'] );
            }
        }
        
        // Get outcomes
        $outcomes = [];
        if ( method_exists( $step, 'get_outcomes' ) ) {
            $outcomes = $step->get_outcomes();
        }
        $outcomes_text = implode( ', ', array_keys( $outcomes ) );
        
        // Get next step info
        $next_steps = [];
        if ( method_exists( $step, 'get_next_step_id' ) ) {
            foreach ( $outcomes as $outcome_key => $outcome_label ) {
                $next_id = $step->get_next_step_id( $outcome_key );
                if ( $next_id ) {
                    $next_steps[] = "{$outcome_key} → Step {$next_id}";
                }
            }
        }
        $next_steps_text = implode( "\n", $next_steps );
        
        $post_data = [
            'post_type'   => 'gf_workflow_step',
            'post_status' => 'publish',
            'post_title'  => $step_name . ' (Form ' . $form_id . ')',
            'post_name'   => $slug,
        ];
        
        $meta_data = [
            'form_id'                => $form_id,
            'form_title'             => $form_title,
            'step_id'                => $step_id,
            'step_name'              => $step_name,
            'step_order'             => $order,
            'step_type'              => $step_type,
            'is_active'              => $step->is_active() ? 1 : 0,
            'assignees'              => $assignees_text,
            'routing_logic'          => $routing_text,
            'is_scheduled'           => $is_scheduled ? 1 : 0,
            'schedule_type'          => $schedule_type,
            'schedule_value'         => $schedule_value,
            'has_expiration'         => $has_expiration ? 1 : 0,
            'expiration_value'       => $expiration_value,
            'settings_json'          => $settings_json,
            'has_conditional_logic'  => $has_conditional ? 1 : 0,
            'conditional_logic_json' => $conditional_json,
            'step_outcomes'          => $outcomes_text,
            'next_steps'             => $next_steps_text,
        ];
        
        if ( isset( $post_map[ $step_id ] ) ) {
            // Update existing
            $post_data['ID'] = $post_map[ $step_id ];
            $post_id = wp_update_post( $post_data );
            error_log( "GF_FLOW_SYNC: Updated step {$step_id} (post {$post_id})" );
        } else {
            // Create new
            $post_id = wp_insert_post( $post_data );
            error_log( "GF_FLOW_SYNC: Created step {$step_id} (post {$post_id})" );
        }
        
        // Update all meta
        if ( $post_id && ! is_wp_error( $post_id ) ) {
            foreach ( $meta_data as $key => $value ) {
                update_post_meta( $post_id, $key, $value );
            }
        }
    }
    
    // Delete orphaned posts (steps removed from this form)
    foreach ( $post_map as $step_id => $post_id ) {
        if ( ! in_array( $step_id, $processed_steps, true ) ) {
            wp_delete_post( $post_id, true );
            error_log( "GF_FLOW_SYNC: Deleted orphaned step {$step_id}" );
        }
    }
    
    error_log( "GF_FLOW_SYNC: Completed form {$form_id}" );
    return true;
}
/**
 * Format assignees array into readable text
 */
function gf_flow_format_assignees( $assignees ) {
    if ( empty( $assignees ) || ! is_array( $assignees ) ) {
        return '';
    }
    
    $formatted = [];
    
    foreach ( $assignees as $assignee ) {
        if ( is_array( $assignee ) ) {
            $type = isset( $assignee['type'] ) ? $assignee['type'] : '';
            $value = isset( $assignee['value'] ) ? $assignee['value'] : '';
            
            if ( $type && $value ) {
                $formatted[] = "{$type}: {$value}";
            }
        } elseif ( is_string( $assignee ) ) {
            $formatted[] = $assignee;
        }
    }
    
    return implode( "\n", $formatted );
}
// Hook 1: Form save - sync workflow steps
add_action( 'gform_after_save_form', function( $form, $is_new ) {
    error_log( 'GF_FLOW_SYNC: gform_after_save_form fired' );
    
    // Small delay to ensure Gravity Flow has saved its data
    add_action( 'shutdown', function() use ( $form ) {
        gf_flow_mirror_steps_to_cpt( $form );
    } );
}, 30, 2 );  // Higher priority to run after Gravity Flow
// Hook 2: Form deletion - remove all steps
add_action( 'gform_before_delete_form', function( $form_id ) {
    error_log( "GF_FLOW_SYNC: Form {$form_id} is being deleted - removing all workflow steps" );
    
    $query = new WP_Query( [
        'post_type'      => 'gf_workflow_step',
        'posts_per_page' => -1,
        'fields'         => 'ids',
        'meta_query'     => [
            [
                'key'   => 'form_id',
                'value' => absint( $form_id ),
            ]
        ]
    ] );
    
    $deleted_count = 0;
    foreach ( $query->posts as $post_id ) {
        wp_delete_post( $post_id, true );
        $deleted_count++;
    }
    
    error_log( "GF_FLOW_SYNC: Deleted {$deleted_count} workflow steps from form {$form_id}" );
}, 10, 1 );
// Hook 3: Gravity Flow step saved
add_action( 'gravityflow_step_saved', function( $step_id, $form_id, $step_settings ) {
    error_log( "GF_FLOW_SYNC: Step {$step_id} saved in form {$form_id}" );
    
    $form = GFAPI::get_form( $form_id );
    if ( $form ) {
        gf_flow_mirror_steps_to_cpt( $form );
    }
}, 10, 3 );
// Hook 4: Periodic cleanup
add_action( 'load-edit.php', function() {
    if ( ! isset( $_GET['post_type'] ) || $_GET['post_type'] !== 'gf_workflow_step' ) {
        return;
    }
    
    if ( get_transient( 'gf_flow_sync_cleanup_done' ) ) {
        return;
    }
    
    gf_flow_cleanup_orphaned_steps();
    set_transient( 'gf_flow_sync_cleanup_done', true, HOUR_IN_SECONDS );
} );
// Verify requirements
add_action( 'init', function() {
    if ( ! class_exists( 'Gravity_Flow' ) ) {
        error_log( 'GF_FLOW_SYNC: Gravity Flow not detected!' );
    } else {
        error_log( 'GF_FLOW_SYNC: Gravity Flow detected' );
    }
}, 999 );

Comments

Add a Comment