PluginProbe
WPCasa – Real Estate for WordPress / trunk
WPCasa – Real Estate for WordPress vtrunk
1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.1.1 trunk 1.2.0 1.2.1 1.2.10 1.2.10.1 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.2.9.1 1.2.9.2 1.3.0 All 31 releases
wpcasa / includes / class-wpsight-api.php

class-wpsight-api.php in WPCasa – Real Estate for WordPress trunk, at includes/class-wpsight-api.php

135 lines 2.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Secure WPSight API Handler.
4 *
5 * Hardened version of the original WPSight_API class.
6 *
7 * @package WPCasa
8 * @since 1.0.0
9 * @updated 1.4.2
10 */
11
12 // Exit if accessed directly
13 if ( ! defined( 'ABSPATH' ) ) exit;
14
15 class WPSight_API {
16
17 /**
18 * Constructor.
19 */
20 public function __construct() {
21 // Ensure query var is registered early.
22 add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
23
24 // Register API request handler.
25 add_action( 'parse_request', array( $this, 'api_requests' ), 0 );
26 }
27
28 /**
29 * Register custom query vars.
30 *
31 * @param array $vars List of public query vars.
32 * @return array
33 */
34 public function add_query_vars( $vars ) {
35 $vars[] = 'wpsight-api';
36 return $vars;
37 }
38
39 /**
40 * Securely handle API requests.
41 *
42 * @return void
43 */
44 public function api_requests() {
45 global $wp;
46
47 // 1) Preferred getter.
48 $raw = get_query_var( 'wpsight-api' );
49
50 // 2) Fallback: directly from $wp->query_vars.
51 if ( empty( $raw ) && isset( $wp->query_vars['wpsight-api'] ) ) {
52 $raw = $wp->query_vars['wpsight-api'];
53 }
54
55 // 3) Last resort: direct $_GET.
56 if ( empty( $raw ) && ! empty( $_GET['wpsight-api'] ) ) {
57 $raw = sanitize_text_field( wp_unslash( $_GET['wpsight-api'] ) );
58 }
59
60 // No request found → exit early.
61 if ( empty( $raw ) ) {
62 return;
63 }
64
65 // Sanitize to a valid key.
66 $api = sanitize_key( $raw );
67
68 if ( empty( $api ) ) {
69 return;
70 }
71
72 /**
73 * Build allow-list of allowed API endpoints.
74 *
75 * IMPORTANT: Replace or extend this list in your theme or plugin
76 * using the 'wpsight_api_allowed_endpoints' filter.
77 *
78 * Example:
79 *
80 * add_filter( 'wpsight_api_allowed_endpoints', function( $allowed ) {
81 * $allowed['ping'] = array( 'class' => null );
82 * return $allowed;
83 * } );
84 */
85 $allowed = apply_filters(
86 'wpsight_api_allowed_endpoints',
87 array()
88 );
89
90 // If API is not allowed, block access.
91 if ( ! isset( $allowed[ $api ] ) ) {
92 wp_die(
93 sprintf(
94 /* translators: %s: API endpoint slug */
95 esc_html__( 'Endpoint "%s" not allowed.', 'wpcasa' ),
96 esc_html( $api )
97 ),
98 esc_html__( 'Forbidden', 'wpcasa' ),
99 array( 'response' => 403 )
100 );
101 }
102
103 // Start output buffering.
104 ob_start();
105
106 // Optional: safe class instantiation if explicitly allowed.
107 if ( ! empty( $allowed[ $api ]['class'] ) && class_exists( $allowed[ $api ]['class'] ) ) {
108 new $allowed[ $api ]['class']();
109 }
110
111 /**
112 * Trigger API action hook.
113 *
114 * Example usage:
115 * add_action( 'wpsight_api_ping', function() {
116 * echo 'pong';
117 * } );
118 */
119 do_action( 'wpsight_api_' . $api );
120
121 // In development mode, allow buffer output for easier testing.
122 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
123 ob_end_flush();
124 } else {
125 ob_end_clean();
126 }
127
128 // Maintain old behaviour for backward compatibility.
129 die( '1' );
130 }
131 }
132
133 // Instantiate the class.
134 new WPSight_API();
135