function fetch_nepse_data() { // Try transient first $cached = get_transient( 'nepse_market_summary_cache' ); if ( false !== $cached ) { return $cached; } $api_url = 'https://nepseapi.surajrimal.dev'; $args = array( 'timeout' => 20, 'sslverify' => true, 'headers' => array( 'Accept' => 'application/json, text/json, application/*+json, */*' ), ); $response = wp_remote_get( $api_url, $args ); // WP error if ( is_wp_error( $response ) ) { $err_msg = 'Error fetching NEPSE data: ' . $response->get_error_message(); // cache short to avoid hammering endpoint set_transient( 'nepse_market_summary_cache', '
' . esc_html( $err_msg ) . '
', 5 * MINUTE_IN_SECONDS ); if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) error_log( $err_msg ); return '' . esc_html( $err_msg ) . '
'; } $code = wp_remote_retrieve_response_code( $response ); $body = wp_remote_retrieve_body( $response ); $headers = wp_remote_retrieve_headers( $response ); $content_type = isset( $headers['content-type'] ) ? $headers['content-type'] : ( isset( $headers['Content-Type'] ) ? $headers['Content-Type'] : '' ); // non-200 if ( $code < 200 || $code >= 300 ) { $msg = sprintf( 'NEPSE API returned HTTP %d.', intval( $code ) ); // Save raw body for debugging (short-lived) set_transient( 'nepse_market_summary_raw', $body, 5 * MINUTE_IN_SECONDS ); set_transient( 'nepse_market_summary_cache', '' . esc_html( $msg ) . ' Please try again shortly.
', 5 * MINUTE_IN_SECONDS ); if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( $msg . ' Content-Type: ' . $content_type . ' Body (first 500 chars): ' . substr( $body, 0, 500 ) ); } return '' . esc_html( $msg ) . ' Please try again shortly.
'; } // Attempt to decode JSON directly $data = json_decode( $body, true ); if ( json_last_error() !== JSON_ERROR_NONE ) { // Try to extract the first JSON object or array inside the body (handles HTML-wrapped JSON) $json_found = null; // A recursive pattern to capture the first {...} or [...] block (PCRE recursion) if ( preg_match('/(\{(?:[^{}]|(?R))*\}|\[(?:[^\[\]]|(?R))*\])/', $body, $m) ) { $candidate = $m[0]; $tmp = json_decode( $candidate, true ); if ( json_last_error() === JSON_ERROR_NONE ) { $json_found = $tmp; } } if ( $json_found === null ) { // final fallback: strip html tags and try decode $stripped = html_entity_decode( strip_tags( $body ), ENT_QUOTES | ENT_HTML5 ); $tmp2 = json_decode( $stripped, true ); if ( json_last_error() === JSON_ERROR_NONE ) { $json_found = $tmp2; } } if ( $json_found === null ) { // Save raw body for debugging (short-lived) set_transient( 'nepse_market_summary_raw', $body, 10 * MINUTE_IN_SECONDS ); $err = 'Error decoding NEPSE data. Invalid format.'; if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( $err . ' JSON error: ' . json_last_error_msg() . ' Response code: ' . $code . ' Content-Type: ' . $content_type ); error_log( 'Response body (first 1000 chars): ' . substr( $body, 0, 1000 ) ); } $display = '' . esc_html( $err ) . '
'; $display .= 'Raw response saved to transient "nepse_market_summary_raw" for debugging (short-lived).
'; set_transient( 'nepse_market_summary_cache', $display, 5 * MINUTE_IN_SECONDS ); return $display; } else { $data = $json_found; } } // Flexible parsing for many possible shapes $index = $data['index'] ?? $data['nepse']['index'] ?? $data['market']['index'] ?? null; $current = $data['currentValue'] ?? $data['nepse']['currentValue'] ?? $data['market']['currentValue'] ?? $data['value'] ?? null; $point = $data['pointChange'] ?? $data['nepse']['pointChange'] ?? $data['market']['pointChange'] ?? $data['change'] ?? null; $perc = $data['percChange'] ?? $data['nepse']['percChange'] ?? $data['market']['percChange'] ?? $data['percent'] ?? null; if ( $index === null || $current === null ) { // Save raw body for later inspection set_transient( 'nepse_market_summary_raw', $body, 10 * MINUTE_IN_SECONDS ); $output = 'Missing expected NEPSE fields in API response.
'; if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { $output .= '' . esc_html( print_r( array(
'http_code' => $code,
'content_type' => $content_type,
'parsed_json_keys' => is_array( $data ) ? array_keys( $data ) : 'not array',
), true ) ) . '';
error_log( 'NEPSE missing fields. Response keys: ' . ( is_array( $data ) ? implode( ',', array_keys( $data ) ) : 'not array' ) );
}
set_transient( 'nepse_market_summary_cache', $output, 5 * MINUTE_IN_SECONDS );
return $output;
}
// Build output
$output = '| Index | Value | Change | Percentage |
|---|---|---|---|
| ' . esc_html( $index ) . ' | '; $output .= '' . esc_html( number_format( (float) $current, 2 ) ) . ' | '; $output .= '' . esc_html( is_null( $point ) ? '-' : number_format( (float) $point, 2 ) ) . ' | '; $output .= '' . esc_html( is_null( $perc ) ? '-' : number_format( (float) $perc, 2 ) . '%' ) . ' | '; $output .= '
Data is typically delayed and for informational purposes only.
'; // Cache for 10 minutes set_transient( 'nepse_market_summary_cache', $output, 10 * MINUTE_IN_SECONDS ); return $output; }