Home / Admin / RESTAPI_DIR – Gravity View
Duplicate Snippet

Embed Snippet on Your Site

RESTAPI_DIR – Gravity View

ismail daugherty PRO
<10
Code Preview
php
<?php
/**
 * WPCode Snippet: Expose GravityView ACF Fields to REST API (Application Password Auth Required)
 * Description: Makes ALL GravityView data accessible ONLY via Application Password authentication
 * Location: Run Everywhere
 * Priority: 15
 */
defined( 'ABSPATH' ) || exit;
/**
 * Register ALL GravityView meta fields in REST API
 */
add_action( 'rest_api_init', function() {
    
    // ========================================
    // GRAVITYVIEW VIEWS SYNC CPT FIELDS
    // ========================================
    $gv_fields = array(
        // ==========================================
        // TAB 1: VIEW OVERVIEW & LINKS
        // ==========================================
        'view_id'                       => 'integer',
        'view_slug'                     => 'string',
        'view_status'                   => 'string',
        'view_type'                     => 'string',
        'entry_count'                   => 'integer',
        'date_created'                  => 'string',
        'date_modified'                 => 'string',
        
        // Edit Links
        'gv_view_edit_link'             => 'string',
        'gv_multiple_entries_edit_link' => 'string',
        'gv_single_entry_edit_link'     => 'string',
        'gv_edit_entry_edit_link'       => 'string',
        'gv_view_preview_link'          => 'string',
        'view_shortcode'                => 'string',
        
        // ==========================================
        // TAB 2: FORM CONNECTIONS
        // ==========================================
        'primary_form_id'               => 'integer',
        'primary_form_title'            => 'string',
        'primary_form_edit_link'        => 'string',
        'multiple_forms_enabled'        => 'boolean',
        'strict_entry_match'            => 'boolean',
        'connected_forms_list'          => 'string',
        'join_conditions_list'          => 'string',
        
        // ==========================================
        // TAB 3: LAYOUT & FIELDS CONFIGURATION
        // ==========================================
        'multiple_entries_fields_list'  => 'string',
        'single_entry_fields_list'      => 'string',
        'edit_entry_fields_list'        => 'string',
        'field_mappings_details'        => 'string',
        'custom_content_fields'         => 'string',
        'total_fields_count'            => 'integer',
        'widgets_top_list'              => 'string',
        'widgets_bottom_list'           => 'string',
        
        // ==========================================
        // TAB 4: FILTER & SORT SETTINGS
        // ==========================================
        'filter_enabled'                => 'boolean',
        'advanced_filter_enabled'       => 'boolean',
        'advanced_filter_rules_list'    => 'string',
        'filter_by_user'                => 'boolean',
        'filter_approval_status'        => 'string',
        'default_sort_field'            => 'string',
        'default_sort_direction'        => 'string',
        'search_enabled'                => 'boolean',
        'search_fields_list'            => 'string',
        'pagination_enabled'            => 'boolean',
        'entries_per_page'              => 'integer',
        
        // ==========================================
        // TAB 5: DISPLAY SETTINGS
        // ==========================================
        'show_only_approved'            => 'boolean',
        'hide_empty_fields'             => 'boolean',
        'hide_until_searched'           => 'boolean',
        'lightbox_enabled'              => 'boolean',
        'featured_entries_enabled'      => 'boolean',
        'ratings_enabled'               => 'boolean',
        'entry_link_type'               => 'string',
        'no_entries_message'            => 'string',
        'table_columns_config'          => 'string',
        'map_settings_details'          => 'string',
        'calendar_settings_details'     => 'string',
        
        // ==========================================
        // TAB 6: PERMISSIONS & CAPABILITIES
        // ==========================================
        'view_permissions'              => 'string',
        'edit_entry_permission'         => 'string',
        'delete_entry_permission'       => 'string',
        'user_edit_enabled'             => 'boolean',
        'user_delete_enabled'           => 'boolean',
        'moderate_entries'              => 'boolean',
        'magic_links_enabled'           => 'boolean',
        'magic_links_config'            => 'string',
        'allowed_user_roles_list'       => 'string',
        
        // ==========================================
        // TAB 7: EXPORT & OUTPUT SETTINGS
        // ==========================================
        'csv_export_enabled'            => 'boolean',
        'csv_export_fields_list'        => 'string',
        'print_enabled'                 => 'boolean',
        'print_layout_config'           => 'string',
        'pdf_export_enabled'            => 'boolean',
        'excel_export_enabled'          => 'boolean',
        'export_permissions'            => 'string',
        
        // ==========================================
        // TAB 8: INTEGRATIONS & EXTENSIONS
        // ==========================================
        'gravity_flow_enabled'          => 'boolean',
        'gravity_flow_settings'         => 'string',
        'gravity_pdf_enabled'           => 'boolean',
        'gravity_pdf_templates'         => 'string',
        'gravity_calendar_enabled'      => 'boolean',
        'gravity_calendar_settings'     => 'string',
        'gravity_charts_enabled'        => 'boolean',
        'gravity_charts_config'         => 'string',
        'gravity_boards_enabled'        => 'boolean',
        'gravity_boards_settings'       => 'string',
        'gravity_math_calculations'     => 'string',
        'connected_feeds_list'          => 'string',
        
        // ==========================================
        // TAB 9: CUSTOM CODE
        // ==========================================
        'custom_css'                    => 'string',
        'custom_javascript'             => 'string',
        'custom_php_hooks'              => 'string',
        'css_classes'                   => 'string',
        
        // ==========================================
        // TAB 10: REST API & SYNC
        // ==========================================
        'rest_api_enabled'              => 'boolean',
        'api_endpoints_list'            => 'string',
        'whalesync_status'              => 'string',
        'last_sync'                     => 'string',
        'airtable_record_id'            => 'string',
        'sync_errors'                   => 'string',
        
        // ==========================================
        // UTILITY FIELDS
        // ==========================================
        'embedded_pages_list'           => 'string',
        'view_notes'                    => 'string',
        'cache_enabled'                 => 'boolean',
        'cache_duration'                => 'integer',
        'view_template'                 => 'string',
        
        // ==========================================
        // ADDITIONAL FIELD DETAILS (from auto-populate)
        // ==========================================
        'field_details_comprehensive'   => 'string',
        'field_details_sync_timestamp'  => 'string',
        'gv_layout_builder_link'        => 'string',
        'gv_settings_link'              => 'string',
        'view_statistics'               => 'string',
    );
    
    // Register GravityView fields
    foreach ( $gv_fields as $field_name => $field_type ) {
        register_rest_field( 'gv_views_sync', $field_name, array(
            'get_callback' => function( $object ) use ( $field_name, $field_type ) {
                $value = get_post_meta( $object['id'], $field_name, true );
                
                // Handle empty values
                if ( $value === '' || $value === false ) {
                    return null;
                }
                
                // ✅ TYPE CONVERSION - Force correct types for Airtable/WhaleSync
                switch ( $field_type ) {
                    case 'integer':
                        return intval( $value );
                    case 'boolean':
                        // Handle various boolean representations
                        if ( is_string( $value ) ) {
                            return ( $value === '1' || $value === 'true' || $value === 'yes' );
                        }
                        return (bool) $value;
                    case 'array':
                        // Ensure arrays are properly formatted
                        if ( is_string( $value ) ) {
                            // Try to decode if it's JSON
                            $decoded = json_decode( $value, true );
                            if ( json_last_error() === JSON_ERROR_NONE ) {
                                return $decoded;
                            }
                        }
                        return is_array( $value ) ? $value : array();
                    case 'object':
                        // Ensure objects are properly formatted
                        if ( is_string( $value ) ) {
                            $decoded = json_decode( $value );
                            if ( json_last_error() === JSON_ERROR_NONE ) {
                                return $decoded;
                            }
                        }
                        return is_array( $value ) || is_object( $value ) ? $value : new stdClass();
                    default:
                        // Return string values as-is
                        return strval( $value );
                }
            },
            'update_callback' => function( $value, $object ) use ( $field_name ) {
                return update_post_meta( $object->ID, $field_name, $value );
            },
            'schema' => array(
                'description' => ucwords( str_replace( '_', ' ', $field_name ) ),
                'type'        => $field_type,
                'context'     => array( 'view', 'edit' ),
            ),
        ) );
    }
    
} );
/**
 * Ensure REST API is enabled for GravityView CPT
 */
add_filter( 'register_post_type_args', function( $args, $post_type ) {
    
    if ( $post_type === 'gv_views_sync' ) {
        $args['show_in_rest'] = true;
        $args['rest_base'] = 'gv-views-sync';
        $args['rest_controller_class'] = 'WP_REST_Posts_Controller';
        
        // Ensure custom fields support
        if ( ! in_array( 'custom-fields', $args['supports'] ) ) {
            $args['supports'][] = 'custom-fields';
        }
    }
    
    return $args;
}, 10, 2 );
/**
 * ✅ SECURITY: Block access unless using Application Password
 */
add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) {
    
    // Only protect GravityView CPT endpoints
    $route = $request->get_route();
    if ( strpos( $route, '/wp/v2/gv-views-sync' ) === false && 
         strpos( $route, '/gv-views-sync/v1' ) === false ) {
        return $result;
    }
    
    // Check if user is authenticated
    $user = wp_get_current_user();
    
    if ( ! $user || ! $user->exists() ) {
        return new WP_Error(
            'rest_forbidden',
            __( 'Authentication required. Please use Application Password credentials.' ),
            array( 'status' => 401 )
        );
    }
    
    // ✅ CRITICAL: Check if authenticated via Application Password
    $auth_header = $request->get_header( 'authorization' );
    
    // If no auth header, they're just logged in via browser - BLOCK IT
    if ( empty( $auth_header ) ) {
        return new WP_Error(
            'rest_forbidden',
            __( 'Application Password authentication required. Browser login not allowed.' ),
            array( 'status' => 403 )
        );
    }
    
    // If they have auth header, they're using Application Password - ALLOW IT
    return $result;
    
}, 10, 3 );
/**
 * GravityView test endpoint to verify REST API functionality
 */
add_action( 'rest_api_init', function() {
    
    // GravityView test endpoint
    register_rest_route( 'gv-views-sync/v1', '/test', array(
        'methods'  => 'GET',
        'callback' => function() {
            
            $posts = get_posts( array(
                'post_type' => 'gv_views_sync',
                'numberposts' => 1,
            ) );
            
            if ( empty( $posts ) ) {
                return new WP_REST_Response( array(
                    'status' => 'error',
                    'message' => 'No GravityView sync posts found. Run sync first.',
                    'sync_url' => add_query_arg( 'sync_gravityview', '1', admin_url() ),
                ), 404 );
            }
            
            $post = $posts[0];
            
            // Get some sample meta fields
            $view_id = get_post_meta( $post->ID, 'view_id', true );
            $view_type = get_post_meta( $post->ID, 'view_type', true );
            $primary_form_id = get_post_meta( $post->ID, 'primary_form_id', true );
            $field_details = get_post_meta( $post->ID, 'field_details_comprehensive', true );
            
            return new WP_REST_Response( array(
                'status' => 'success',
                'message' => 'GravityView REST API is working!',
                'post_info' => array(
                    'id' => $post->ID,
                    'title' => $post->post_title,
                    'view_id' => $view_id,
                    'view_type' => $view_type,
                    'primary_form_id' => $primary_form_id,
                    'has_field_details' => ! empty( $field_details ),
                ),
                'total_fields_available' => count( $GLOBALS['gv_fields'] ?? [] ) ?: 105,
                'endpoints' => array(
                    'collection' => rest_url( 'wp/v2/gv-views-sync' ),
                    'single' => rest_url( 'wp/v2/gv-views-sync/' . $post->ID ),
                    'test' => rest_url( 'gv-views-sync/v1/test' ),
                ),
            ), 200 );
        },
        'permission_callback' => '__return_true', // Test endpoint is public
    ) );
    
    // GravityView sync status endpoint
    register_rest_route( 'gv-views-sync/v1', '/status', array(
        'methods'  => 'GET',
        'callback' => function() {
            
            // Check if user is authenticated with Application Password
            $user = wp_get_current_user();
            if ( ! $user || ! $user->exists() ) {
                return new WP_REST_Response( array(
                    'status' => 'error',
                    'message' => 'Authentication required.',
                ), 401 );
            }
            
            // Get sync statistics
            $total_views = wp_count_posts( 'gravityview' )->publish;
            $total_synced = wp_count_posts( 'gv_views_sync' )->publish;
            
            // Get last sync time
            $latest_sync = get_posts( array(
                'post_type' => 'gv_views_sync',
                'numberposts' => 1,
                'orderby' => 'modified',
                'order' => 'DESC',
            ) );
            
            $last_sync_time = ! empty( $latest_sync ) ? $latest_sync[0]->post_modified : 'Never';
            
            return new WP_REST_Response( array(
                'status' => 'success',
                'sync_info' => array(
                    'total_gravityviews' => $total_views,
                    'total_synced' => $total_synced,
                    'last_sync' => $last_sync_time,
                    'sync_percentage' => $total_views > 0 ? round( ( $total_synced / $total_views ) * 100, 2 ) : 0,
                ),
                'available_fields' => count( $GLOBALS['gv_fields'] ?? [] ) ?: 105,
            ), 200 );
        },
        'permission_callback' => function() {
            return current_user_can( 'edit_posts' );
        },
    ) );
    
} );
/**
 * Add custom REST API query parameters for GravityView
 */
add_filter( 'rest_gv_views_sync_query', function( $args, $request ) {
    
    // Allow filtering by view_id
    if ( isset( $request['view_id'] ) ) {
        $args['meta_key'] = 'view_id';
        $args['meta_value'] = intval( $request['view_id'] );
    }
    
    // Allow filtering by view_type
    if ( isset( $request['view_type'] ) ) {
        if ( ! isset( $args['meta_query'] ) ) {
            $args['meta_query'] = array();
        }
        $args['meta_query'][] = array(
            'key' => 'view_type',
            'value' => sanitize_text_field( $request['view_type'] ),
            'compare' => '=',
        );
    }
    
    // Allow filtering by primary_form_id
    if ( isset( $request['form_id'] ) ) {
        if ( ! isset( $args['meta_query'] ) ) {
            $args['meta_query'] = array();
        }
        $args['meta_query'][] = array(
            'key' => 'primary_form_id',
            'value' => intval( $request['form_id'] ),
            'compare' => '=',
        );
    }
    
    // Allow filtering by sync status
    if ( isset( $request['sync_status'] ) ) {
        if ( ! isset( $args['meta_query'] ) ) {
            $args['meta_query'] = array();
        }
        $args['meta_query'][] = array(
            'key' => 'whalesync_status',
            'value' => sanitize_text_field( $request['sync_status'] ),
            'compare' => '=',
        );
    }
    
    return $args;
    
}, 10, 2 );
/**
 * Add collection parameters for REST API
 */
add_filter( 'rest_gv_views_sync_collection_params', function( $params ) {
    
    $params['view_id'] = array(
        'description' => 'Filter by GravityView ID',
        'type' => 'integer',
        'sanitize_callback' => 'absint',
    );
    
    $params['view_type'] = array(
        'description' => 'Filter by view type (table, list, map, calendar, datatables, diy)',
        'type' => 'string',
        'enum' => array( 'table', 'list', 'map', 'calendar', 'datatables', 'diy' ),
        'sanitize_callback' => 'sanitize_text_field',
    );
    
    $params['form_id'] = array(
        'description' => 'Filter by connected Gravity Form ID',
        'type' => 'integer',
        'sanitize_callback' => 'absint',
    );
    
    $params['sync_status'] = array(
        'description' => 'Filter by sync status',
        'type' => 'string',
        'enum' => array( 'active', 'paused', 'error' ),
        'sanitize_callback' => 'sanitize_text_field',
    );
    
    return $params;
    
} );
/**
 * Helper function to trigger sync via REST API (requires authentication)
 */
add_action( 'rest_api_init', function() {
    
    register_rest_route( 'gv-views-sync/v1', '/sync', array(
        'methods'  => 'POST',
        'callback' => function( $request ) {
            
            // Get specific view ID if provided
            $view_id = $request->get_param( 'view_id' );
            
            if ( $view_id ) {
                // Sync single view
                gv_sync_single_view_by_post_id( intval( $view_id ) );
                
                return new WP_REST_Response( array(
                    'status' => 'success',
                    'message' => 'View ' . $view_id . ' synced successfully.',
                ), 200 );
            } else {
                // Sync all views
                gv_sync_all_views();
                
                $total_synced = wp_count_posts( 'gv_views_sync' )->publish;
                
                return new WP_REST_Response( array(
                    'status' => 'success',
                    'message' => 'All views synced successfully.',
                    'total_synced' => $total_synced,
                ), 200 );
            }
        },
        'permission_callback' => function() {
            return current_user_can( 'manage_options' );
        },
        'args' => array(
            'view_id' => array(
                'description' => 'Optional: Specific GravityView ID to sync',
                'type' => 'integer',
                'required' => false,
                'sanitize_callback' => 'absint',
            ),
        ),
    ) );
    
} );
/**
 * Add REST API info to admin notices
 */
add_action( 'admin_notices', function() {
    
    // Only show on GravityView pages
    $screen = get_current_screen();
    if ( ! $screen || strpos( $screen->id, 'gv_views_sync' ) === false ) {
        return;
    }
    
    ?>
    <div class="notice notice-info">
        <p><strong>GravityView REST API Endpoints:</strong></p>
        <ul style="list-style: disc; margin-left: 20px;">
            <li>Collection: <code><?php echo rest_url( 'wp/v2/gv-views-sync' ); ?></code></li>
            <li>Test: <code><?php echo rest_url( 'gv-views-sync/v1/test' ); ?></code></li>
            <li>Status: <code><?php echo rest_url( 'gv-views-sync/v1/status' ); ?></code></li>
            <li>Sync: <code><?php echo rest_url( 'gv-views-sync/v1/sync' ); ?></code> (POST)</li>
        </ul>
        <p><em>Authentication: Application Password required for all data endpoints.</em></p>
    </div>
    <?php
} );
/**
 * Log REST API access for debugging
 */
add_filter( 'rest_request_after_callbacks', function( $response, $handler, $request ) {
    
    $route = $request->get_route();
    
    // Only log GravityView endpoints
    if ( strpos( $route, 'gv-views-sync' ) !== false || strpos( $route, 'gv_views_sync' ) !== false ) {
        
        // Log the access
        error_log( sprintf(
            'GV_REST_API: %s request to %s from user %s',
            $request->get_method(),
            $route,
            wp_get_current_user()->user_login ?: 'anonymous'
        ) );
    }
    
    return $response;
    
}, 10, 3 );

Comments

Add a Comment