get_bundled_templates(); $cloud = $this->get_cloud_templates(); // Merge lists (cloud templates overwrite bundled templates of the same ID) $merged = []; foreach ( $bundled as $b_item ) { $merged[ $b_item['id'] ] = $b_item; } foreach ( $cloud as $c_item ) { $merged[ $c_item['id'] ] = $c_item; } return array_values( $merged ); } /** * Get a specific template by ID. * * @param string $id Template ID. * @return array|false Template details or false on failure. */ public function get_template( $id ) { $id = preg_replace( '/[^a-zA-Z0-9_-]/', '', $id ); // 1. Check if it is a bundled template $bundled_data = hundred_prints_get_bundled_template_data( $id ); if ( $bundled_data ) { $bundled_data['source'] = 'bundled'; return $bundled_data; } // 2. Check if API Key exists before trying cloud fetching $conn_service = new Hundred_Prints_Connection_Service(); $api_key = $conn_service->get_key(); if ( empty( $api_key ) ) { return new WP_Error( '100prints_no_api_key', 'API Secret Key not connected.', [ 'status' => 401 ] ); } // 3. Check fresh transient cache $transient_key = "100p_template_{$id}"; $cached = get_transient( $transient_key ); if ( $cached !== false ) { $cached['source'] = 'cloud'; return $cached; } // 3. Check persistent option cache (stale fallback) $option_key = "100p_template_cache_{$id}"; $stale = get_option( $option_key, false ); if ( $stale ) { // Trigger background refresh in single cron event wp_schedule_single_event( time(), 'hundred_prints_refresh_template', [ $id ] ); $stale['source'] = 'cloud'; return $stale; } // 4. Fallback to immediate live API fetch $live_data = $this->fetch_template_from_api( $id ); if ( $live_data ) { $live_data['source'] = 'cloud'; return $live_data; } return false; } /** * Sync cloud templates index and options cache. * * @return array Synchronized template count or error string. */ public function sync_cloud_templates() { $conn_service = new Hundred_Prints_Connection_Service(); $api_key = $conn_service->get_key(); if ( empty( $api_key ) ) { return [ 'error' => 'API Secret Key not connected.' ]; } $api_url = $conn_service->get_api_base_url() . '/templates'; $response = wp_remote_get( $api_url, [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ], 'timeout' => 20, ] ); if ( is_wp_error( $response ) ) { update_option( '100p_last_sync_error', $response->get_error_message() ); return [ 'error' => 'Sync failed: ' . $response->get_error_message() ]; } $status = wp_remote_retrieve_response_code( $response ); if ( $status !== 200 ) { $msg = 'Sync failed with API status ' . $status; update_option( '100p_last_sync_error', $msg ); return [ 'error' => $msg ]; } $body = wp_remote_retrieve_body( $response ); $templates = json_decode( $body, true ); if ( ! is_array( $templates ) ) { update_option( '100p_last_sync_error', 'Invalid API response format' ); return [ 'error' => 'Invalid templates manifest format.' ]; } // Build templates index $index = []; foreach ( $templates as $t ) { $index[] = [ 'id' => sanitize_key( $t['id'] ), 'name' => sanitize_text_field( $t['name'] ), 'category' => sanitize_key( $t['category'] ), 'variables' => is_array( $t['variables'] ) ? array_map( 'sanitize_text_field', $t['variables'] ) : [], 'source' => 'cloud', ]; } // Update option index update_option( '100p_template_index', $index ); update_option( '100p_last_sync_time', current_time( 'timestamp' ) ); delete_option( '100p_last_sync_error' ); // Clear stale/corrupted template detail cache during sync foreach ( $templates as $t ) { $t_id = isset( $t['id'] ) ? sanitize_key( $t['id'] ) : ''; if ( '' === $t_id ) { continue; } delete_option( '100p_template_cache_' . $t_id ); delete_transient( '100p_template_' . $t_id ); } return [ 'count' => count( $index ) ]; } /** * Fetch template JSON from the API. * * @param string $id Template ID. * @return array|false The template details, or false. */ public function fetch_template_from_api( $id ) { $conn_service = new Hundred_Prints_Connection_Service(); $api_key = $conn_service->get_key(); if ( empty( $api_key ) ) { return false; } $api_url = $conn_service->get_api_base_url() . "/template/{$id}"; $response = wp_remote_get( $api_url, [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ], 'timeout' => 15, ] ); if ( is_wp_error( $response ) ) { return false; } $status = wp_remote_retrieve_response_code( $response ); if ( $status !== 200 ) { return false; } $body = wp_remote_retrieve_body( $response ); $template = json_decode( $body, true ); if ( ! is_array( $template ) ) { return false; } // Cache template data update_option( "100p_template_cache_{$id}", $template ); $settings = hundred_prints_get_settings(); $ttl = min( 168, max( 1, absint( $settings['cache_ttl_hours'] ) ) ) * HOUR_IN_SECONDS; set_transient( "100p_template_{$id}", $template, $ttl ); return $template; } }