| |
| <?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| defined( 'ABSPATH' ) || exit;
|
|
|
|
|
|
|
|
|
| add_action( 'rest_api_init', function() {
|
|
|
|
|
|
|
|
|
| $gv_fields = array(
|
|
|
|
|
|
|
| 'view_id' => 'integer',
|
| 'view_slug' => 'string',
|
| 'view_status' => 'string',
|
| 'view_type' => 'string',
|
| 'entry_count' => 'integer',
|
| 'date_created' => 'string',
|
| 'date_modified' => 'string',
|
|
|
|
|
| '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',
|
|
|
|
|
|
|
|
|
| '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',
|
|
|
|
|
|
|
|
|
| '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',
|
|
|
|
|
|
|
|
|
| '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',
|
|
|
|
|
|
|
|
|
| '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',
|
|
|
|
|
|
|
|
|
| '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',
|
|
|
|
|
|
|
|
|
| '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',
|
|
|
|
|
|
|
|
|
| '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',
|
|
|
|
|
|
|
|
|
| 'custom_css' => 'string',
|
| 'custom_javascript' => 'string',
|
| 'custom_php_hooks' => 'string',
|
| 'css_classes' => 'string',
|
|
|
|
|
|
|
|
|
| 'rest_api_enabled' => 'boolean',
|
| 'api_endpoints_list' => 'string',
|
| 'whalesync_status' => 'string',
|
| 'last_sync' => 'string',
|
| 'airtable_record_id' => 'string',
|
| 'sync_errors' => 'string',
|
|
|
|
|
|
|
|
|
| 'embedded_pages_list' => 'string',
|
| 'view_notes' => 'string',
|
| 'cache_enabled' => 'boolean',
|
| 'cache_duration' => 'integer',
|
| 'view_template' => 'string',
|
|
|
|
|
|
|
|
|
| 'field_details_comprehensive' => 'string',
|
| 'field_details_sync_timestamp' => 'string',
|
| 'gv_layout_builder_link' => 'string',
|
| 'gv_settings_link' => 'string',
|
| 'view_statistics' => 'string',
|
| );
|
|
|
|
|
| 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 );
|
|
|
|
|
| if ( $value === '' || $value === false ) {
|
| return null;
|
| }
|
|
|
|
|
| switch ( $field_type ) {
|
| case 'integer':
|
| return intval( $value );
|
| case 'boolean':
|
|
|
| if ( is_string( $value ) ) {
|
| return ( $value === '1' || $value === 'true' || $value === 'yes' );
|
| }
|
| return (bool) $value;
|
| case 'array':
|
|
|
| if ( is_string( $value ) ) {
|
|
|
| $decoded = json_decode( $value, true );
|
| if ( json_last_error() === JSON_ERROR_NONE ) {
|
| return $decoded;
|
| }
|
| }
|
| return is_array( $value ) ? $value : array();
|
| case 'object':
|
|
|
| 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 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' ),
|
| ),
|
| ) );
|
| }
|
|
|
| } );
|
|
|
|
|
|
|
|
|
| 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';
|
|
|
|
|
| if ( ! in_array( 'custom-fields', $args['supports'] ) ) {
|
| $args['supports'][] = 'custom-fields';
|
| }
|
| }
|
|
|
| return $args;
|
| }, 10, 2 );
|
|
|
|
|
|
|
|
|
| add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) {
|
|
|
|
|
| $route = $request->get_route();
|
| if ( strpos( $route, '/wp/v2/gv-views-sync' ) === false &&
|
| strpos( $route, '/gv-views-sync/v1' ) === false ) {
|
| return $result;
|
| }
|
|
|
|
|
| $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 )
|
| );
|
| }
|
|
|
|
|
| $auth_header = $request->get_header( 'authorization' );
|
|
|
|
|
| if ( empty( $auth_header ) ) {
|
| return new WP_Error(
|
| 'rest_forbidden',
|
| __( 'Application Password authentication required. Browser login not allowed.' ),
|
| array( 'status' => 403 )
|
| );
|
| }
|
|
|
|
|
| return $result;
|
|
|
| }, 10, 3 );
|
|
|
|
|
|
|
|
|
| add_action( 'rest_api_init', function() {
|
|
|
|
|
| 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];
|
|
|
|
|
| $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',
|
| ) );
|
|
|
|
|
| register_rest_route( 'gv-views-sync/v1', '/status', array(
|
| 'methods' => 'GET',
|
| 'callback' => function() {
|
|
|
|
|
| $user = wp_get_current_user();
|
| if ( ! $user || ! $user->exists() ) {
|
| return new WP_REST_Response( array(
|
| 'status' => 'error',
|
| 'message' => 'Authentication required.',
|
| ), 401 );
|
| }
|
|
|
|
|
| $total_views = wp_count_posts( 'gravityview' )->publish;
|
| $total_synced = wp_count_posts( 'gv_views_sync' )->publish;
|
|
|
|
|
| $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_filter( 'rest_gv_views_sync_query', function( $args, $request ) {
|
|
|
|
|
| if ( isset( $request['view_id'] ) ) {
|
| $args['meta_key'] = 'view_id';
|
| $args['meta_value'] = intval( $request['view_id'] );
|
| }
|
|
|
|
|
| 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' => '=',
|
| );
|
| }
|
|
|
|
|
| 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' => '=',
|
| );
|
| }
|
|
|
|
|
| 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_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;
|
|
|
| } );
|
|
|
|
|
|
|
|
|
| add_action( 'rest_api_init', function() {
|
|
|
| register_rest_route( 'gv-views-sync/v1', '/sync', array(
|
| 'methods' => 'POST',
|
| 'callback' => function( $request ) {
|
|
|
|
|
| $view_id = $request->get_param( 'view_id' );
|
|
|
| if ( $view_id ) {
|
|
|
| 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 {
|
|
|
| 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_action( 'admin_notices', function() {
|
|
|
|
|
| $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();
|
|
|
|
|
| if ( strpos( $route, 'gv-views-sync' ) !== false || strpos( $route, 'gv_views_sync' ) !== false ) {
|
|
|
|
|
| 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