Plugin Directory

Changeset 3484575


Ignore:
Timestamp:
03/17/2026 08:54:28 AM (11 days ago)
Author:
zeicaro
Message:

v2.0.1 — Bug fixes: rate limit race condition, KSES filter try/finally, JWT propagation in MCP proxy, WP_Error returns in AI providers, WP_Filesystem null check

Location:
wpraiz-content-api-tool
Files:
2 added
14 edited
1 copied

Legend:

Unmodified
Added
Removed
  • wpraiz-content-api-tool/tags/2.0.1/includes/ai/class-deepseek-provider.php

    r3482403 r3484575  
    3030    }
    3131
    32     public function generate( string $prompt, array $params = [] ): string {
     32    public function generate( string $prompt, array $params = [] ) {
    3333        if ( ! $this->is_configured() ) {
    34             return '';
     34            return new \WP_Error( 'deepseek_not_configured', 'DeepSeek API key is not configured.' );
    3535        }
    3636
     
    5353
    5454        if ( is_wp_error( $response ) ) {
    55             return '';
     55            return new \WP_Error( 'deepseek_request_failed', $response->get_error_message() );
    5656        }
    5757
    5858        $body = json_decode( wp_remote_retrieve_body( $response ), true );
    5959
    60         return $body['choices'][0]['message']['content'] ?? '';
     60        if ( empty( $body['choices'][0]['message']['content'] ) ) {
     61            $err = $body['error']['message'] ?? wp_remote_retrieve_response_message( $response );
     62            return new \WP_Error( 'deepseek_empty_response', $err ?: 'DeepSeek returned an empty response.' );
     63        }
     64
     65        return $body['choices'][0]['message']['content'];
    6166    }
    6267}
  • wpraiz-content-api-tool/tags/2.0.1/includes/ai/class-openrouter-provider.php

    r3482403 r3484575  
    3434    }
    3535
    36     public function generate( string $prompt, array $params = [] ): string {
     36    public function generate( string $prompt, array $params = [] ) {
    3737        $headers = [
    3838            'Content-Type'    => 'application/json',
     
    6060
    6161        if ( is_wp_error( $response ) ) {
    62             return '';
     62            return new \WP_Error( 'openrouter_request_failed', $response->get_error_message() );
    6363        }
    6464
    6565        $body = json_decode( wp_remote_retrieve_body( $response ), true );
    6666
    67         return $body['choices'][0]['message']['content'] ?? '';
     67        if ( empty( $body['choices'][0]['message']['content'] ) ) {
     68            $err = $body['error']['message'] ?? wp_remote_retrieve_response_message( $response );
     69            return new \WP_Error( 'openrouter_empty_response', $err ?: 'OpenRouter returned an empty response.' );
     70        }
     71
     72        return $body['choices'][0]['message']['content'];
    6873    }
    6974}
  • wpraiz-content-api-tool/tags/2.0.1/includes/class-auth.php

    r3482396 r3484575  
    126126
    127127        $data['count']++;
    128         set_transient( $key, $data, 60 - ( time() - $data['start'] ) );
     128        set_transient( $key, $data, max( 1, 60 - ( time() - $data['start'] ) ) );
    129129        return true;
    130130    }
  • wpraiz-content-api-tool/tags/2.0.1/includes/class-content-manager.php

    r3482396 r3484575  
    297297        }
    298298        if ( ! empty( $params['content'] ) ) {
    299             remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
    300299            $update_data['post_content'] = $params['content'];
    301300        }
     
    307306        }
    308307
    309         $result = wp_update_post( $update_data, true );
    310         add_filter( 'content_save_pre', 'wp_filter_post_kses' );
     308        $had_kses = has_filter( 'content_save_pre', 'wp_filter_post_kses' );
     309        if ( $had_kses ) {
     310            remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
     311        }
     312        try {
     313            $result = wp_update_post( $update_data, true );
     314        } finally {
     315            if ( $had_kses ) {
     316                add_filter( 'content_save_pre', 'wp_filter_post_kses' );
     317            }
     318        }
    311319
    312320        if ( is_wp_error( $result ) ) {
  • wpraiz-content-api-tool/tags/2.0.1/includes/class-media-handler.php

    r3482396 r3484575  
    6868        }
    6969        WP_Filesystem();
     70
     71        if ( empty( $wp_filesystem ) ) {
     72            return new \WP_Error( 'filesystem_unavailable', __( 'WordPress Filesystem API could not be initialized.', 'wpraiz-content-api' ) );
     73        }
     74
    7075        $wp_filesystem->put_contents( $tmp_file, $image_data );
    7176
  • wpraiz-content-api-tool/tags/2.0.1/includes/mcp/class-mcp-server.php

    r3482396 r3484575  
    4545        $params  = $body['params'] ?? [];
    4646        $id      = $body['id'] ?? null;
     47
     48        // Forward auth header so proxy_rest can re-authenticate internal calls.
     49        MCP_Tools::set_auth_context( $request->get_header( 'Authorization' ) );
    4750
    4851        if ( $jsonrpc !== '2.0' || empty( $method ) ) {
  • wpraiz-content-api-tool/tags/2.0.1/includes/mcp/class-mcp-tools.php

    r3482396 r3484575  
    137137    }
    138138
     139    /** Authorization header forwarded from the incoming MCP request. */
     140    private static ?string $current_auth_header = null;
     141
     142    /**
     143     * Store the Authorization header for use in internal REST proxying.
     144     * Call this once from MCP_Server before dispatching tool calls.
     145     */
     146    public static function set_auth_context( ?string $auth_header ): void {
     147        self::$current_auth_header = $auth_header;
     148    }
     149
    139150    /**
    140151     * Execute a tool by name.
     
    189200        $request->set_header( 'Content-Type', 'application/json' );
    190201
     202        // Propagate the caller's Authorization so permission callbacks pass.
     203        if ( self::$current_auth_header ) {
     204            $request->set_header( 'Authorization', self::$current_auth_header );
     205        }
     206
    191207        $response = rest_do_request( $request->set_route( '/' . $route ) );
    192208
  • wpraiz-content-api-tool/trunk/includes/ai/class-deepseek-provider.php

    r3482403 r3484575  
    3030    }
    3131
    32     public function generate( string $prompt, array $params = [] ): string {
     32    public function generate( string $prompt, array $params = [] ) {
    3333        if ( ! $this->is_configured() ) {
    34             return '';
     34            return new \WP_Error( 'deepseek_not_configured', 'DeepSeek API key is not configured.' );
    3535        }
    3636
     
    5353
    5454        if ( is_wp_error( $response ) ) {
    55             return '';
     55            return new \WP_Error( 'deepseek_request_failed', $response->get_error_message() );
    5656        }
    5757
    5858        $body = json_decode( wp_remote_retrieve_body( $response ), true );
    5959
    60         return $body['choices'][0]['message']['content'] ?? '';
     60        if ( empty( $body['choices'][0]['message']['content'] ) ) {
     61            $err = $body['error']['message'] ?? wp_remote_retrieve_response_message( $response );
     62            return new \WP_Error( 'deepseek_empty_response', $err ?: 'DeepSeek returned an empty response.' );
     63        }
     64
     65        return $body['choices'][0]['message']['content'];
    6166    }
    6267}
  • wpraiz-content-api-tool/trunk/includes/ai/class-openrouter-provider.php

    r3482403 r3484575  
    3434    }
    3535
    36     public function generate( string $prompt, array $params = [] ): string {
     36    public function generate( string $prompt, array $params = [] ) {
    3737        $headers = [
    3838            'Content-Type'    => 'application/json',
     
    6060
    6161        if ( is_wp_error( $response ) ) {
    62             return '';
     62            return new \WP_Error( 'openrouter_request_failed', $response->get_error_message() );
    6363        }
    6464
    6565        $body = json_decode( wp_remote_retrieve_body( $response ), true );
    6666
    67         return $body['choices'][0]['message']['content'] ?? '';
     67        if ( empty( $body['choices'][0]['message']['content'] ) ) {
     68            $err = $body['error']['message'] ?? wp_remote_retrieve_response_message( $response );
     69            return new \WP_Error( 'openrouter_empty_response', $err ?: 'OpenRouter returned an empty response.' );
     70        }
     71
     72        return $body['choices'][0]['message']['content'];
    6873    }
    6974}
  • wpraiz-content-api-tool/trunk/includes/class-auth.php

    r3482396 r3484575  
    126126
    127127        $data['count']++;
    128         set_transient( $key, $data, 60 - ( time() - $data['start'] ) );
     128        set_transient( $key, $data, max( 1, 60 - ( time() - $data['start'] ) ) );
    129129        return true;
    130130    }
  • wpraiz-content-api-tool/trunk/includes/class-content-manager.php

    r3482396 r3484575  
    297297        }
    298298        if ( ! empty( $params['content'] ) ) {
    299             remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
    300299            $update_data['post_content'] = $params['content'];
    301300        }
     
    307306        }
    308307
    309         $result = wp_update_post( $update_data, true );
    310         add_filter( 'content_save_pre', 'wp_filter_post_kses' );
     308        $had_kses = has_filter( 'content_save_pre', 'wp_filter_post_kses' );
     309        if ( $had_kses ) {
     310            remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
     311        }
     312        try {
     313            $result = wp_update_post( $update_data, true );
     314        } finally {
     315            if ( $had_kses ) {
     316                add_filter( 'content_save_pre', 'wp_filter_post_kses' );
     317            }
     318        }
    311319
    312320        if ( is_wp_error( $result ) ) {
  • wpraiz-content-api-tool/trunk/includes/class-media-handler.php

    r3482396 r3484575  
    6868        }
    6969        WP_Filesystem();
     70
     71        if ( empty( $wp_filesystem ) ) {
     72            return new \WP_Error( 'filesystem_unavailable', __( 'WordPress Filesystem API could not be initialized.', 'wpraiz-content-api' ) );
     73        }
     74
    7075        $wp_filesystem->put_contents( $tmp_file, $image_data );
    7176
  • wpraiz-content-api-tool/trunk/includes/mcp/class-mcp-server.php

    r3482396 r3484575  
    4545        $params  = $body['params'] ?? [];
    4646        $id      = $body['id'] ?? null;
     47
     48        // Forward auth header so proxy_rest can re-authenticate internal calls.
     49        MCP_Tools::set_auth_context( $request->get_header( 'Authorization' ) );
    4750
    4851        if ( $jsonrpc !== '2.0' || empty( $method ) ) {
  • wpraiz-content-api-tool/trunk/includes/mcp/class-mcp-tools.php

    r3482396 r3484575  
    137137    }
    138138
     139    /** Authorization header forwarded from the incoming MCP request. */
     140    private static ?string $current_auth_header = null;
     141
     142    /**
     143     * Store the Authorization header for use in internal REST proxying.
     144     * Call this once from MCP_Server before dispatching tool calls.
     145     */
     146    public static function set_auth_context( ?string $auth_header ): void {
     147        self::$current_auth_header = $auth_header;
     148    }
     149
    139150    /**
    140151     * Execute a tool by name.
     
    189200        $request->set_header( 'Content-Type', 'application/json' );
    190201
     202        // Propagate the caller's Authorization so permission callbacks pass.
     203        if ( self::$current_auth_header ) {
     204            $request->set_header( 'Authorization', self::$current_auth_header );
     205        }
     206
    191207        $response = rest_do_request( $request->set_route( '/' . $route ) );
    192208
Note: See TracChangeset for help on using the changeset viewer.