commit
4a583a03be
@ -1,110 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Define
|
||||
* Note: only use for internal purpose.
|
||||
*
|
||||
* @package OpalJob
|
||||
* @copyright Copyright (c) 2019, WpOpal <https://www.wpopal.com>
|
||||
* @license https://opensource.org/licenses/gpl-license GNU Public License
|
||||
* @since 1.0
|
||||
*/
|
||||
/**
|
||||
* Api_Auth class for authorizing to access api resources
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package Opal_Job
|
||||
* @subpackage Opal_Job/API
|
||||
*/
|
||||
class Opalestate_Api_Auth extends Opalestate_Base_API {
|
||||
|
||||
/**
|
||||
* Register user endpoints.
|
||||
*
|
||||
* to check post method need authorization to continue completing action
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return avoid
|
||||
*/
|
||||
public function register_routes() {
|
||||
// check all request must to have public key and token
|
||||
register_rest_route( $this->namespace, '/job/list', array(
|
||||
'methods' => 'GET',
|
||||
'permission_callback' => array( $this, 'validate_request' ),
|
||||
), 9 );
|
||||
|
||||
////////////////// Check User Authorizcation must to have account logined
|
||||
// check authorcation for all delete in route
|
||||
register_rest_route($this->namespace, '/(?P<path>[\S]+)/delete', array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( $this, 'check' ),
|
||||
));
|
||||
// check authorcation for all delete in route
|
||||
register_rest_route($this->namespace, '/(?P<path>[\S]+)/edit', array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( $this, 'check' ),
|
||||
));
|
||||
// check authorcation for all delete in route
|
||||
register_rest_route($this->namespace, '/(?P<path>[\S]+)/create', array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( $this, 'check' ),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check authorization
|
||||
*
|
||||
* check user request having passing username and password, then check them be valid or not.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @since 1.0
|
||||
*
|
||||
* @return WP_REST_Response is json data
|
||||
*/
|
||||
public function check( WP_REST_Request $request ) {
|
||||
$response = array();
|
||||
|
||||
$default = array(
|
||||
'username' => '',
|
||||
'password' => ''
|
||||
);
|
||||
|
||||
$parameters = $request->get_params();
|
||||
$parameters = array_merge( $default, $parameters );
|
||||
|
||||
$username = sanitize_text_field( $parameters['username'] );
|
||||
$password = sanitize_text_field( $parameters['password'] );
|
||||
|
||||
// Error Handling.
|
||||
$error = new WP_Error();
|
||||
if ( empty( $username ) ) {
|
||||
$error->add(
|
||||
400,
|
||||
__( "Username field is required", 'rest-api-endpoints' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
return $error;
|
||||
}
|
||||
if ( empty( $password ) ) {
|
||||
$error->add(
|
||||
400,
|
||||
__( "Password field is required", 'rest-api-endpoints' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
return $error;
|
||||
}
|
||||
$user = wp_authenticate( $username, $password );
|
||||
|
||||
// If user found
|
||||
if ( ! is_wp_error( $user ) ) {
|
||||
$response['status'] = 200;
|
||||
$response['user'] = $user;
|
||||
} else {
|
||||
// If user not found
|
||||
$error->add( 406, esc_html_e( 'User not found. Check credentials', 'rest-api-endpoints' ) );
|
||||
return $error;
|
||||
}
|
||||
return new WP_REST_Response( $response );
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -38,12 +38,12 @@ class Opalestate_API {
|
||||
$this->includes( [
|
||||
'class-opalestate-admin-api-keys.php',
|
||||
'class-opalestate-admin-api-keys-table-list.php',
|
||||
'class-opalestate-rest-authentication.php',
|
||||
'class-opalestate-base-api.php',
|
||||
'v1/property.php',
|
||||
'v1/agent.php',
|
||||
'v1/agency.php',
|
||||
'v1/search-form.php',
|
||||
'class-opalestate-api-auth.php',
|
||||
'functions.php',
|
||||
] );
|
||||
|
||||
|
@ -144,6 +144,17 @@ abstract class Opalestate_Base_API {
|
||||
return apply_filters( 'opalestate_api_results_per_page', $per_page );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object.
|
||||
*
|
||||
* @param int $id Object ID.
|
||||
* @return object WC_Data object or WP_Error object.
|
||||
*/
|
||||
protected function get_object( $id ) {
|
||||
// translators: %s: Class method name.
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass.", 'opalestate-pro' ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a missing authentication error if all the parameters aren't
|
||||
* provided
|
||||
@ -161,8 +172,6 @@ abstract class Opalestate_Base_API {
|
||||
* credentials
|
||||
*
|
||||
* @access private
|
||||
* @since 1.1
|
||||
* @uses Opaljob_API::output()
|
||||
* @return WP_Error with message key rest_forbidden
|
||||
*/
|
||||
private function invalid_auth() {
|
||||
@ -195,6 +204,22 @@ abstract class Opalestate_Base_API {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to read an item.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|boolean
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
$object = $this->get_object( (int) $request['id'] );
|
||||
|
||||
if ( $object && 0 !== $object->get_id() && ! opalestate_rest_check_post_permissions( $this->post_type, 'read', $object->get_id() ) ) {
|
||||
return new WP_Error( 'opalestate_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'opalestate-pro' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to create an item.
|
||||
*
|
||||
@ -209,6 +234,22 @@ abstract class Opalestate_Base_API {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to update an item.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|boolean
|
||||
*/
|
||||
public function update_item_permissions_check( $request ) {
|
||||
$object = $this->get_object( (int) $request['id'] );
|
||||
|
||||
if ( $object && 0 !== $object->get_id() && ! opalestate_rest_check_post_permissions( $this->post_type, 'edit', $object->get_id() ) ) {
|
||||
return new WP_Error( 'opalestate_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'opalestate-pro' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query params for collections of attachments.
|
||||
*
|
||||
|
608
inc/api/class-opalestate-rest-authentication.php
Normal file
608
inc/api/class-opalestate-rest-authentication.php
Normal file
@ -0,0 +1,608 @@
|
||||
<?php
|
||||
/**
|
||||
* REST API Authentication
|
||||
*
|
||||
* @package Opalestate/API
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* REST API authentication class.
|
||||
*/
|
||||
class Opalestate_REST_Authentication {
|
||||
|
||||
/**
|
||||
* Authentication error.
|
||||
*
|
||||
* @var WP_Error
|
||||
*/
|
||||
protected $error = null;
|
||||
|
||||
/**
|
||||
* Logged in user data.
|
||||
*
|
||||
* @var stdClass
|
||||
*/
|
||||
protected $user = null;
|
||||
|
||||
/**
|
||||
* Current auth method.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $auth_method = '';
|
||||
|
||||
/**
|
||||
* Initialize authentication actions.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_filter( 'determine_current_user', [ $this, 'authenticate' ], 15 );
|
||||
add_filter( 'rest_authentication_errors', [ $this, 'check_authentication_error' ], 15 );
|
||||
add_filter( 'rest_post_dispatch', [ $this, 'send_unauthorized_headers' ], 50 );
|
||||
add_filter( 'rest_pre_dispatch', [ $this, 'check_user_permissions' ], 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if is request to our REST API.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_request_to_rest_api() {
|
||||
if ( empty( $_SERVER['REQUEST_URI'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rest_prefix = trailingslashit( rest_get_url_prefix() );
|
||||
$request_uri = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) );
|
||||
|
||||
// Check if the request is to the Opalestate API endpoints.
|
||||
$opalestate = ( false !== strpos( $request_uri, $rest_prefix . 'estate-api/' ) );
|
||||
|
||||
// Allow third party plugins use our authentication methods.
|
||||
$third_party = ( false !== strpos( $request_uri, $rest_prefix . 'estate-api-' ) );
|
||||
|
||||
return apply_filters( 'opalestate_rest_is_request_to_rest_api', $opalestate || $third_party );
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate user.
|
||||
*
|
||||
* @param int|false $user_id User ID if one has been determined, false otherwise.
|
||||
* @return int|false
|
||||
*/
|
||||
public function authenticate( $user_id ) {
|
||||
// Do not authenticate twice and check if is a request to our endpoint in the WP REST API.
|
||||
if ( ! empty( $user_id ) || ! $this->is_request_to_rest_api() ) {
|
||||
return $user_id;
|
||||
}
|
||||
|
||||
if ( is_ssl() ) {
|
||||
$user_id = $this->perform_basic_authentication();
|
||||
}
|
||||
|
||||
if ( $user_id ) {
|
||||
return $user_id;
|
||||
}
|
||||
|
||||
return $this->perform_oauth_authentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for authentication error.
|
||||
*
|
||||
* @param WP_Error|null|bool $error Error data.
|
||||
* @return WP_Error|null|bool
|
||||
*/
|
||||
public function check_authentication_error( $error ) {
|
||||
// Pass through other errors.
|
||||
if ( ! empty( $error ) ) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
return $this->get_error();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set authentication error.
|
||||
*
|
||||
* @param WP_Error $error Authentication error data.
|
||||
*/
|
||||
protected function set_error( $error ) {
|
||||
// Reset user.
|
||||
$this->user = null;
|
||||
|
||||
$this->error = $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication error.
|
||||
*
|
||||
* @return WP_Error|null.
|
||||
*/
|
||||
protected function get_error() {
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Authentication.
|
||||
*
|
||||
* SSL-encrypted requests are not subject to sniffing or man-in-the-middle
|
||||
* attacks, so the request can be authenticated by simply looking up the user
|
||||
* associated with the given consumer key and confirming the consumer secret
|
||||
* provided is valid.
|
||||
*
|
||||
* @return int|bool
|
||||
*/
|
||||
private function perform_basic_authentication() {
|
||||
$this->auth_method = 'basic_auth';
|
||||
$consumer_key = '';
|
||||
$consumer_secret = '';
|
||||
|
||||
// If the $_GET parameters are present, use those first.
|
||||
if ( ! empty( $_GET['consumer_key'] ) && ! empty( $_GET['consumer_secret'] ) ) { // WPCS: CSRF ok.
|
||||
$consumer_key = $_GET['consumer_key']; // WPCS: CSRF ok, sanitization ok.
|
||||
$consumer_secret = $_GET['consumer_secret']; // WPCS: CSRF ok, sanitization ok.
|
||||
}
|
||||
|
||||
// If the above is not present, we will do full basic auth.
|
||||
if ( ! $consumer_key && ! empty( $_SERVER['PHP_AUTH_USER'] ) && ! empty( $_SERVER['PHP_AUTH_PW'] ) ) {
|
||||
$consumer_key = $_SERVER['PHP_AUTH_USER']; // WPCS: CSRF ok, sanitization ok.
|
||||
$consumer_secret = $_SERVER['PHP_AUTH_PW']; // WPCS: CSRF ok, sanitization ok.
|
||||
}
|
||||
|
||||
// Stop if don't have any key.
|
||||
if ( ! $consumer_key || ! $consumer_secret ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get user data.
|
||||
$this->user = $this->get_user_data_by_consumer_key( $consumer_key );
|
||||
if ( empty( $this->user ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate user secret.
|
||||
if ( ! hash_equals( $this->user->consumer_secret, $consumer_secret ) ) { // @codingStandardsIgnoreLine
|
||||
$this->set_error( new WP_Error( 'opalestate_rest_authentication_error', __( 'Consumer secret is invalid.', 'opalestate-pro' ), [ 'status' => 401 ] ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->user->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the Authorization header into parameters.
|
||||
*
|
||||
* @param string $header Authorization header value (not including "Authorization: " prefix).
|
||||
*
|
||||
* @return array Map of parameter values.
|
||||
*/
|
||||
public function parse_header( $header ) {
|
||||
if ( 'OAuth ' !== substr( $header, 0, 6 ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// From OAuth PHP library, used under MIT license.
|
||||
$params = [];
|
||||
if ( preg_match_all( '/(oauth_[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $header, $matches ) ) {
|
||||
foreach ( $matches[1] as $i => $h ) {
|
||||
$params[ $h ] = urldecode( empty( $matches[3][ $i ] ) ? $matches[4][ $i ] : $matches[3][ $i ] );
|
||||
}
|
||||
if ( isset( $params['realm'] ) ) {
|
||||
unset( $params['realm'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authorization header.
|
||||
*
|
||||
* On certain systems and configurations, the Authorization header will be
|
||||
* stripped out by the server or PHP. Typically this is then used to
|
||||
* generate `PHP_AUTH_USER`/`PHP_AUTH_PASS` but not passed on. We use
|
||||
* `getallheaders` here to try and grab it out instead.
|
||||
*
|
||||
* @return string Authorization header if set.
|
||||
*
|
||||
*/
|
||||
public function get_authorization_header() {
|
||||
if ( ! empty( $_SERVER['HTTP_AUTHORIZATION'] ) ) {
|
||||
return wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] ); // WPCS: sanitization ok.
|
||||
}
|
||||
|
||||
if ( function_exists( 'getallheaders' ) ) {
|
||||
$headers = getallheaders();
|
||||
// Check for the authoization header case-insensitively.
|
||||
foreach ( $headers as $key => $value ) {
|
||||
if ( 'authorization' === strtolower( $key ) ) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get oAuth parameters from $_GET, $_POST or request header.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function get_oauth_parameters() {
|
||||
$params = array_merge( $_GET, $_POST ); // WPCS: CSRF ok.
|
||||
$params = wp_unslash( $params );
|
||||
$header = $this->get_authorization_header();
|
||||
|
||||
if ( ! empty( $header ) ) {
|
||||
// Trim leading spaces.
|
||||
$header = trim( $header );
|
||||
$header_params = $this->parse_header( $header );
|
||||
|
||||
if ( ! empty( $header_params ) ) {
|
||||
$params = array_merge( $params, $header_params );
|
||||
}
|
||||
}
|
||||
|
||||
$param_names = [
|
||||
'oauth_consumer_key',
|
||||
'oauth_timestamp',
|
||||
'oauth_nonce',
|
||||
'oauth_signature',
|
||||
'oauth_signature_method',
|
||||
];
|
||||
|
||||
$errors = [];
|
||||
$have_one = false;
|
||||
|
||||
// Check for required OAuth parameters.
|
||||
foreach ( $param_names as $param_name ) {
|
||||
if ( empty( $params[ $param_name ] ) ) {
|
||||
$errors[] = $param_name;
|
||||
} else {
|
||||
$have_one = true;
|
||||
}
|
||||
}
|
||||
|
||||
// All keys are missing, so we're probably not even trying to use OAuth.
|
||||
if ( ! $have_one ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// If we have at least one supplied piece of data, and we have an error,
|
||||
// then it's a failed authentication.
|
||||
if ( ! empty( $errors ) ) {
|
||||
$message = sprintf(
|
||||
/* translators: %s: amount of errors */
|
||||
_n( 'Missing OAuth parameter %s', 'Missing OAuth parameters %s', count( $errors ), 'opalestate-pro' ),
|
||||
implode( ', ', $errors )
|
||||
);
|
||||
|
||||
$this->set_error( new WP_Error( 'opalestate_rest_authentication_missing_parameter', $message, [ 'status' => 401 ] ) );
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform OAuth 1.0a "one-legged" (http://oauthbible.com/#oauth-10a-one-legged) authentication for non-SSL requests.
|
||||
*
|
||||
* This is required so API credentials cannot be sniffed or intercepted when making API requests over plain HTTP.
|
||||
*
|
||||
* This follows the spec for simple OAuth 1.0a authentication (RFC 5849) as closely as possible, with two exceptions:
|
||||
*
|
||||
* 1) There is no token associated with request/responses, only consumer keys/secrets are used.
|
||||
*
|
||||
* 2) The OAuth parameters are included as part of the request query string instead of part of the Authorization header,
|
||||
* This is because there is no cross-OS function within PHP to get the raw Authorization header.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc5849 for the full spec.
|
||||
*
|
||||
* @return int|bool
|
||||
*/
|
||||
private function perform_oauth_authentication() {
|
||||
$this->auth_method = 'oauth1';
|
||||
|
||||
$params = $this->get_oauth_parameters();
|
||||
if ( empty( $params ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fetch WP user by consumer key.
|
||||
$this->user = $this->get_user_data_by_consumer_key( $params['oauth_consumer_key'] );
|
||||
|
||||
if ( empty( $this->user ) ) {
|
||||
$this->set_error( new WP_Error( 'opalestate_rest_authentication_error', __( 'Consumer key is invalid.', 'opalestate-pro' ), [ 'status' => 401 ] ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Perform OAuth validation.
|
||||
$signature = $this->check_oauth_signature( $this->user, $params );
|
||||
if ( is_wp_error( $signature ) ) {
|
||||
$this->set_error( $signature );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$timestamp_and_nonce = $this->check_oauth_timestamp_and_nonce( $this->user, $params['oauth_timestamp'], $params['oauth_nonce'] );
|
||||
if ( is_wp_error( $timestamp_and_nonce ) ) {
|
||||
$this->set_error( $timestamp_and_nonce );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->user->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the consumer-provided request signature matches our generated signature,
|
||||
* this ensures the consumer has a valid key/secret.
|
||||
*
|
||||
* @param stdClass $user User data.
|
||||
* @param array $params The request parameters.
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
private function check_oauth_signature( $user, $params ) {
|
||||
$http_method = isset( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( $_SERVER['REQUEST_METHOD'] ) : ''; // WPCS: sanitization ok.
|
||||
$request_path = isset( $_SERVER['REQUEST_URI'] ) ? wp_parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ) : ''; // WPCS: sanitization ok.
|
||||
$wp_base = get_home_url( null, '/', 'relative' );
|
||||
if ( substr( $request_path, 0, strlen( $wp_base ) ) === $wp_base ) {
|
||||
$request_path = substr( $request_path, strlen( $wp_base ) );
|
||||
}
|
||||
$base_request_uri = rawurlencode( get_home_url( null, $request_path, is_ssl() ? 'https' : 'http' ) );
|
||||
|
||||
// Get the signature provided by the consumer and remove it from the parameters prior to checking the signature.
|
||||
$consumer_signature = rawurldecode( str_replace( ' ', '+', $params['oauth_signature'] ) );
|
||||
unset( $params['oauth_signature'] );
|
||||
|
||||
// Sort parameters.
|
||||
if ( ! uksort( $params, 'strcmp' ) ) {
|
||||
return new WP_Error( 'opalestate_rest_authentication_error', __( 'Invalid signature - failed to sort parameters.', 'opalestate-pro' ), [ 'status' => 401 ] );
|
||||
}
|
||||
|
||||
// Normalize parameter key/values.
|
||||
$params = $this->normalize_parameters( $params );
|
||||
$query_string = implode( '%26', $this->join_with_equals_sign( $params ) ); // Join with ampersand.
|
||||
$string_to_sign = $http_method . '&' . $base_request_uri . '&' . $query_string;
|
||||
|
||||
if ( 'HMAC-SHA1' !== $params['oauth_signature_method'] && 'HMAC-SHA256' !== $params['oauth_signature_method'] ) {
|
||||
return new WP_Error( 'opalestate_rest_authentication_error', __( 'Invalid signature - signature method is invalid.', 'opalestate-pro' ), [ 'status' => 401 ] );
|
||||
}
|
||||
|
||||
$hash_algorithm = strtolower( str_replace( 'HMAC-', '', $params['oauth_signature_method'] ) );
|
||||
$secret = $user->consumer_secret . '&';
|
||||
$signature = base64_encode( hash_hmac( $hash_algorithm, $string_to_sign, $secret, true ) );
|
||||
|
||||
if ( ! hash_equals( $signature, $consumer_signature ) ) { // @codingStandardsIgnoreLine
|
||||
return new WP_Error( 'opalestate_rest_authentication_error', __( 'Invalid signature - provided signature does not match.', 'opalestate-pro' ), [ 'status' => 401 ] );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of urlencoded strings out of each array key/value pairs.
|
||||
*
|
||||
* @param array $params Array of parameters to convert.
|
||||
* @param array $query_params Array to extend.
|
||||
* @param string $key Optional Array key to append.
|
||||
* @return string Array of urlencoded strings.
|
||||
*/
|
||||
private function join_with_equals_sign( $params, $query_params = [], $key = '' ) {
|
||||
foreach ( $params as $param_key => $param_value ) {
|
||||
if ( $key ) {
|
||||
$param_key = $key . '%5B' . $param_key . '%5D'; // Handle multi-dimensional array.
|
||||
}
|
||||
|
||||
if ( is_array( $param_value ) ) {
|
||||
$query_params = $this->join_with_equals_sign( $param_value, $query_params, $param_key );
|
||||
} else {
|
||||
$string = $param_key . '=' . $param_value; // Join with equals sign.
|
||||
$query_params[] = opalestate_rest_urlencode_rfc3986( $string );
|
||||
}
|
||||
}
|
||||
|
||||
return $query_params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize each parameter by assuming each parameter may have already been
|
||||
* encoded, so attempt to decode, and then re-encode according to RFC 3986.
|
||||
*
|
||||
* Note both the key and value is normalized so a filter param like:
|
||||
*
|
||||
* 'filter[period]' => 'week'
|
||||
*
|
||||
* is encoded to:
|
||||
*
|
||||
* 'filter%255Bperiod%255D' => 'week'
|
||||
*
|
||||
* This conforms to the OAuth 1.0a spec which indicates the entire query string
|
||||
* should be URL encoded.
|
||||
*
|
||||
* @param array $parameters Un-normalized parameters.
|
||||
* @return array Normalized parameters.
|
||||
* @see rawurlencode()
|
||||
*/
|
||||
private function normalize_parameters( $parameters ) {
|
||||
$keys = opalestate_rest_urlencode_rfc3986( array_keys( $parameters ) );
|
||||
$values = opalestate_rest_urlencode_rfc3986( array_values( $parameters ) );
|
||||
$parameters = array_combine( $keys, $values );
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the timestamp and nonce provided with the request are valid. This prevents replay attacks where
|
||||
* an attacker could attempt to re-send an intercepted request at a later time.
|
||||
*
|
||||
* - A timestamp is valid if it is within 15 minutes of now.
|
||||
* - A nonce is valid if it has not been used within the last 15 minutes.
|
||||
*
|
||||
* @param stdClass $user User data.
|
||||
* @param int $timestamp The unix timestamp for when the request was made.
|
||||
* @param string $nonce A unique (for the given user) 32 alphanumeric string, consumer-generated.
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
private function check_oauth_timestamp_and_nonce( $user, $timestamp, $nonce ) {
|
||||
global $wpdb;
|
||||
|
||||
$valid_window = 15 * 60; // 15 minute window.
|
||||
|
||||
if ( ( $timestamp < time() - $valid_window ) || ( $timestamp > time() + $valid_window ) ) {
|
||||
return new WP_Error( 'opalestate_rest_authentication_error', __( 'Invalid timestamp.', 'opalestate-pro' ), [ 'status' => 401 ] );
|
||||
}
|
||||
|
||||
$used_nonces = maybe_unserialize( $user->nonces );
|
||||
|
||||
if ( empty( $used_nonces ) ) {
|
||||
$used_nonces = [];
|
||||
}
|
||||
|
||||
if ( in_array( $nonce, $used_nonces, true ) ) {
|
||||
return new WP_Error( 'opalestate_rest_authentication_error', __( 'Invalid nonce - nonce has already been used.', 'opalestate-pro' ), [ 'status' => 401 ] );
|
||||
}
|
||||
|
||||
$used_nonces[ $timestamp ] = $nonce;
|
||||
|
||||
// Remove expired nonces.
|
||||
foreach ( $used_nonces as $nonce_timestamp => $nonce ) {
|
||||
if ( $nonce_timestamp < ( time() - $valid_window ) ) {
|
||||
unset( $used_nonces[ $nonce_timestamp ] );
|
||||
}
|
||||
}
|
||||
|
||||
$used_nonces = maybe_serialize( $used_nonces );
|
||||
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'opalestate_api_keys',
|
||||
[ 'nonces' => $used_nonces ],
|
||||
[ 'key_id' => $user->key_id ],
|
||||
[ '%s' ],
|
||||
[ '%d' ]
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user data for the given consumer_key.
|
||||
*
|
||||
* @param string $consumer_key Consumer key.
|
||||
* @return array
|
||||
*/
|
||||
private function get_user_data_by_consumer_key( $consumer_key ) {
|
||||
global $wpdb;
|
||||
|
||||
$consumer_key = opalestate_api_hash( sanitize_text_field( $consumer_key ) );
|
||||
$user = $wpdb->get_row(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT key_id, user_id, permissions, consumer_key, consumer_secret, nonces
|
||||
FROM {$wpdb->prefix}opalestate_api_keys
|
||||
WHERE consumer_key = %s
|
||||
",
|
||||
$consumer_key
|
||||
)
|
||||
);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the API keys provided have the proper key-specific permissions to either read or write API resources.
|
||||
*
|
||||
* @param string $method Request method.
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
private function check_permissions( $method ) {
|
||||
$permissions = $this->user->permissions;
|
||||
|
||||
switch ( $method ) {
|
||||
case 'HEAD':
|
||||
case 'GET':
|
||||
if ( 'read' !== $permissions && 'read_write' !== $permissions ) {
|
||||
return new WP_Error( 'opalestate_rest_authentication_error', __( 'The API key provided does not have read permissions.', 'opalestate-pro' ), [ 'status' => 401 ] );
|
||||
}
|
||||
break;
|
||||
case 'POST':
|
||||
case 'PUT':
|
||||
case 'PATCH':
|
||||
case 'DELETE':
|
||||
if ( 'write' !== $permissions && 'read_write' !== $permissions ) {
|
||||
return new WP_Error( 'opalestate_rest_authentication_error', __( 'The API key provided does not have write permissions.', 'opalestate-pro' ), [ 'status' => 401 ] );
|
||||
}
|
||||
break;
|
||||
case 'OPTIONS':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return new WP_Error( 'opalestate_rest_authentication_error', __( 'Unknown request method.', 'opalestate-pro' ), [ 'status' => 401 ] );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updated API Key last access datetime.
|
||||
*/
|
||||
private function update_last_access() {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'opalestate_api_keys',
|
||||
[ 'last_access' => current_time( 'mysql' ) ],
|
||||
[ 'key_id' => $this->user->key_id ],
|
||||
[ '%s' ],
|
||||
[ '%d' ]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the consumer_key and consumer_secret $_GET parameters are NOT provided
|
||||
* and the Basic auth headers are either not present or the consumer secret does not match the consumer
|
||||
* key provided, then return the correct Basic headers and an error message.
|
||||
*
|
||||
* @param WP_REST_Response $response Current response being served.
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function send_unauthorized_headers( $response ) {
|
||||
if ( is_wp_error( $this->get_error() ) && 'basic_auth' === $this->auth_method ) {
|
||||
$auth_message = __( 'Opalestate API. Use a consumer key in the username field and a consumer secret in the password field.', 'opalestate-pro' );
|
||||
$response->header( 'WWW-Authenticate', 'Basic realm="' . $auth_message . '"', true );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for user permissions and register last access.
|
||||
*
|
||||
* @param mixed $result Response to replace the requested version with.
|
||||
* @param WP_REST_Server $server Server instance.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
* @return mixed
|
||||
*/
|
||||
public function check_user_permissions( $result, $server, $request ) {
|
||||
if ( $this->user ) {
|
||||
// Check API Key permissions.
|
||||
$allowed = $this->check_permissions( $request->get_method() );
|
||||
if ( is_wp_error( $allowed ) ) {
|
||||
return $allowed;
|
||||
}
|
||||
|
||||
// Register last access.
|
||||
$this->update_last_access();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
new Opalestate_REST_Authentication();
|
@ -116,5 +116,20 @@ function opalestate_rand_hash() {
|
||||
* @return string
|
||||
*/
|
||||
function opalestate_api_hash( $data ) {
|
||||
return hash_hmac( 'sha256', $data, 'opalestate-api' );
|
||||
return hash_hmac( 'sha256', $data, 'estate-api' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a value according to RFC 3986.
|
||||
* Supports multidimensional arrays.
|
||||
*
|
||||
* @param string|array $value The value to encode.
|
||||
* @return string|array Encoded values.
|
||||
*/
|
||||
function opalestate_rest_urlencode_rfc3986( $value ) {
|
||||
if ( is_array( $value ) ) {
|
||||
return array_map( 'opalestate_rest_urlencode_rfc3986', $value );
|
||||
}
|
||||
|
||||
return str_replace( array( '+', '%7E' ), array( ' ', '~' ), rawurlencode( $value ) );
|
||||
}
|
||||
|
@ -1,13 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Define
|
||||
* Note: only use for internal purpose.
|
||||
*
|
||||
* @package OpalJob
|
||||
* @copyright Copyright (c) 2019, WpOpal <https://www.wpopal.com>
|
||||
* @license https://opensource.org/licenses/gpl-license GNU Public License
|
||||
* @since 1.0
|
||||
*/
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
@ -16,7 +7,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
/**
|
||||
* @class Job_Api
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package Opal_Job
|
||||
* @subpackage Opal_Job/controllers
|
||||
*/
|
||||
@ -25,7 +15,6 @@ class Opalestate_Agency_Api extends Opalestate_Base_API {
|
||||
/**
|
||||
* The unique identifier of the route resource.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @access public
|
||||
* @var string $base .
|
||||
*/
|
||||
@ -42,9 +31,6 @@ class Opalestate_Agency_Api extends Opalestate_Base_API {
|
||||
* Register Routes
|
||||
*
|
||||
* Register all CURD actions with POST/GET/PUT and calling function for each
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
*/
|
||||
public function register_routes() {
|
||||
/**
|
||||
@ -59,7 +45,7 @@ class Opalestate_Agency_Api extends Opalestate_Base_API {
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_items' ],
|
||||
// 'permission_callback' => [ $this, 'get_items_permissions_check' ],
|
||||
'permission_callback' => [ $this, 'get_items_permissions_check' ],
|
||||
'args' => $this->get_collection_params(),
|
||||
],
|
||||
]
|
||||
@ -78,7 +64,7 @@ class Opalestate_Agency_Api extends Opalestate_Base_API {
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_item' ],
|
||||
// 'permission_callback' => [ $this, 'get_item_permissions_check' ],
|
||||
'permission_callback' => [ $this, 'get_item_permissions_check' ],
|
||||
],
|
||||
// [
|
||||
// 'methods' => WP_REST_Server::EDITABLE,
|
||||
@ -101,12 +87,22 @@ class Opalestate_Agency_Api extends Opalestate_Base_API {
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_listings' ],
|
||||
// 'permission_callback' => [ $this, 'get_item_permissions_check' ],
|
||||
'permission_callback' => [ $this, 'get_item_permissions_check' ],
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object.
|
||||
*
|
||||
* @param int $id Object ID.
|
||||
*
|
||||
* @return Opalestate_Agency
|
||||
*/
|
||||
protected function get_object( $id ) {
|
||||
return opalesetate_agency( $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get List Of agencies.
|
||||
@ -114,8 +110,6 @@ class Opalestate_Agency_Api extends Opalestate_Base_API {
|
||||
* Based on request to get collection
|
||||
*
|
||||
* @return WP_REST_Response is json data
|
||||
* @since 1.0
|
||||
*
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
$agencies['agencies'] = [];
|
||||
@ -149,8 +143,6 @@ class Opalestate_Agency_Api extends Opalestate_Base_API {
|
||||
* Based on request to get a agency.
|
||||
*
|
||||
* @return WP_REST_Response is json data
|
||||
* @since 1.0
|
||||
*
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
$response = [];
|
||||
@ -178,8 +170,6 @@ class Opalestate_Agency_Api extends Opalestate_Base_API {
|
||||
* @param object $agency_info The Download Post Object
|
||||
*
|
||||
* @return array Array of post data to return back in the API
|
||||
* @since 1.0
|
||||
*
|
||||
*/
|
||||
public function get_agency_data( $agency_info ) {
|
||||
$agency = new OpalEstate_Agency( $agency_info->ID );
|
||||
|
@ -50,7 +50,7 @@ class Opalestate_Agent_Api extends Opalestate_Base_API {
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_items' ],
|
||||
// 'permission_callback' => [ $this, 'get_items_permissions_check' ],
|
||||
'permission_callback' => [ $this, 'get_items_permissions_check' ],
|
||||
'args' => $this->get_collection_params(),
|
||||
],
|
||||
]
|
||||
@ -69,7 +69,7 @@ class Opalestate_Agent_Api extends Opalestate_Base_API {
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_item' ],
|
||||
// 'permission_callback' => [ $this, 'get_item_permissions_check' ],
|
||||
'permission_callback' => [ $this, 'get_item_permissions_check' ],
|
||||
],
|
||||
// [
|
||||
// 'methods' => WP_REST_Server::EDITABLE,
|
||||
@ -92,7 +92,7 @@ class Opalestate_Agent_Api extends Opalestate_Base_API {
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_listings' ],
|
||||
// 'permission_callback' => [ $this, 'get_item_permissions_check' ],
|
||||
'permission_callback' => [ $this, 'get_item_permissions_check' ],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -7,7 +7,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
/**
|
||||
* Property_Api
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package Property_Api
|
||||
*/
|
||||
class Opalestate_Property_Api extends Opalestate_Base_API {
|
||||
@ -15,7 +14,6 @@ class Opalestate_Property_Api extends Opalestate_Base_API {
|
||||
/**
|
||||
* The unique identifier of the route resource.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @access public
|
||||
* @var string $base .
|
||||
*/
|
||||
@ -32,9 +30,6 @@ class Opalestate_Property_Api extends Opalestate_Base_API {
|
||||
* Register Routes
|
||||
*
|
||||
* Register all CURD actions with POST/GET/PUT and calling function for each
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
*/
|
||||
public function register_routes() {
|
||||
/**
|
||||
@ -49,14 +44,14 @@ class Opalestate_Property_Api extends Opalestate_Base_API {
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_items' ],
|
||||
// 'permission_callback' => [ $this, 'get_items_permissions_check' ],
|
||||
'permission_callback' => [ $this, 'get_items_permissions_check' ],
|
||||
'args' => $this->get_collection_params(),
|
||||
],
|
||||
// [
|
||||
// 'methods' => WP_REST_Server::CREATABLE,
|
||||
// 'callback' => [ $this, 'create_item' ],
|
||||
// // 'permission_callback' => [ $this, 'create_item_permissions_check' ],
|
||||
// ],
|
||||
[
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'create_item' ],
|
||||
'permission_callback' => [ $this, 'create_item_permissions_check' ],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
@ -73,7 +68,7 @@ class Opalestate_Property_Api extends Opalestate_Base_API {
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_item' ],
|
||||
// 'permission_callback' => [ $this, 'get_item_permissions_check' ],
|
||||
'permission_callback' => [ $this, 'get_item_permissions_check' ],
|
||||
],
|
||||
// [
|
||||
// 'methods' => WP_REST_Server::EDITABLE,
|
||||
@ -102,13 +97,24 @@ class Opalestate_Property_Api extends Opalestate_Base_API {
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'get_results' ],
|
||||
// 'permission_callback' => [ $this, 'get_items_permissions_check' ],
|
||||
'permission_callback' => [ $this, 'get_items_permissions_check' ],
|
||||
'args' => $this->get_search_params(),
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object.
|
||||
*
|
||||
* @param int $id Object ID.
|
||||
*
|
||||
* @return Opalestate_Property
|
||||
*/
|
||||
protected function get_object( $id ) {
|
||||
return opalesetate_property( $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get List Of Properties
|
||||
*
|
||||
@ -152,8 +158,6 @@ class Opalestate_Property_Api extends Opalestate_Base_API {
|
||||
* Based on request to get a property.
|
||||
*
|
||||
* @return WP_REST_Response is json data
|
||||
* @since 1.0
|
||||
*
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
$response = [];
|
||||
@ -215,8 +219,6 @@ class Opalestate_Property_Api extends Opalestate_Base_API {
|
||||
* @param object $property_info The Download Post Object
|
||||
*
|
||||
* @return array Array of post data to return back in the API
|
||||
* @since 1.0
|
||||
*
|
||||
*/
|
||||
private function get_property_data( $property_info ) {
|
||||
return opalestate_api_get_property_data( $property_info );
|
||||
|
@ -32,10 +32,10 @@ class Opalestate_Agency_Collection_Elementor_Widget extends Opalestate_Elementor
|
||||
*
|
||||
* Used to set scripts dependencies required to run the widget.
|
||||
*
|
||||
* @return array Widget scripts dependencies.
|
||||
* @since 1.3.0
|
||||
* @access public
|
||||
*
|
||||
* @return array Widget scripts dependencies.
|
||||
*/
|
||||
public function get_script_depends() {
|
||||
return [ 'jquery-slick' ];
|
||||
@ -95,18 +95,18 @@ class Opalestate_Agency_Collection_Elementor_Widget extends Opalestate_Elementor
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'search_form',
|
||||
[
|
||||
'label' => esc_html__('Search Form', 'opalestate-pro'),
|
||||
'type' => \Elementor\Controls_Manager::SELECT,
|
||||
'default' => '',
|
||||
'options' => array(
|
||||
'' => esc_html__( 'Advanded', 'opalestate-pro' ),
|
||||
'address' => esc_html__( 'Search By Address', 'opalestate-pro' ),
|
||||
)
|
||||
]
|
||||
);
|
||||
// $this->add_control(
|
||||
// 'search_form',
|
||||
// [
|
||||
// 'label' => esc_html__('Search Form', 'opalestate-pro'),
|
||||
// 'type' => \Elementor\Controls_Manager::SELECT,
|
||||
// 'default' => '',
|
||||
// 'options' => array(
|
||||
// '' => esc_html__( 'Advanded', 'opalestate-pro' ),
|
||||
// 'address' => esc_html__( 'Search By Address', 'opalestate-pro' ),
|
||||
// )
|
||||
// ]
|
||||
// );
|
||||
|
||||
$this->add_control(
|
||||
'enable_sortable_bar',
|
||||
@ -122,10 +122,10 @@ class Opalestate_Agency_Collection_Elementor_Widget extends Opalestate_Elementor
|
||||
'label' => esc_html__( 'Item Layout', 'opalestate-pro' ),
|
||||
'type' => \Elementor\Controls_Manager::SELECT,
|
||||
'default' => 'grid',
|
||||
'options' => array(
|
||||
'options' => [
|
||||
'grid' => esc_html__( 'Grid', 'opalestate-pro' ),
|
||||
'list' => esc_html__( 'List', 'opalestate-pro' ),
|
||||
)
|
||||
],
|
||||
]
|
||||
);
|
||||
$this->add_responsive_control(
|
||||
@ -137,8 +137,8 @@ class Opalestate_Agency_Collection_Elementor_Widget extends Opalestate_Elementor
|
||||
'options' => [ 1 => 1, 2 => 2, 3 => 3, 4 => 4, 6 => 6 ],
|
||||
'prefix_class' => 'elementor-grid%s-',
|
||||
'condition' => [
|
||||
'item_layout' => 'grid'
|
||||
]
|
||||
'item_layout' => 'grid',
|
||||
],
|
||||
|
||||
]
|
||||
);
|
||||
@ -156,12 +156,12 @@ class Opalestate_Agency_Collection_Elementor_Widget extends Opalestate_Elementor
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-items-container' => 'grid-column-gap: {{SIZE}}{{UNIT}}'
|
||||
'{{WRAPPER}} .elementor-items-container' => 'grid-column-gap: {{SIZE}}{{UNIT}}',
|
||||
|
||||
],
|
||||
'condition' => [
|
||||
'item_layout' => 'grid'
|
||||
]
|
||||
'item_layout' => 'grid',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
@ -174,7 +174,7 @@ class Opalestate_Agency_Collection_Elementor_Widget extends Opalestate_Elementor
|
||||
);
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->add_slick_controls( array('enable_carousel' => 'yes') , ' .agency-slick-carousel ' );
|
||||
$this->add_slick_controls( [ 'enable_carousel' => 'yes' ], ' .agency-slick-carousel ' );
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_query',
|
||||
@ -194,7 +194,6 @@ class Opalestate_Agency_Collection_Elementor_Widget extends Opalestate_Elementor
|
||||
);
|
||||
|
||||
|
||||
|
||||
$this->add_control(
|
||||
'advanced',
|
||||
[
|
||||
@ -253,7 +252,7 @@ class Opalestate_Agency_Collection_Elementor_Widget extends Opalestate_Elementor
|
||||
'NOT IN' => esc_html__( 'NOT IN', 'opalestate-pro' ),
|
||||
],
|
||||
'condition' => [
|
||||
'categories!' => ''
|
||||
'categories!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
@ -264,24 +263,19 @@ class Opalestate_Agency_Collection_Elementor_Widget extends Opalestate_Elementor
|
||||
'section_pagination',
|
||||
[
|
||||
'label' => esc_html__( 'Pagination', 'opalestate-pro' ),
|
||||
'condition' => [
|
||||
'enable_carousel!' => 'yes'
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_type',
|
||||
'pagination',
|
||||
[
|
||||
'label' => esc_html__( 'Pagination', 'opalestate-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => '',
|
||||
'options' => [
|
||||
'' => esc_html__( 'None', 'opalestate-pro' ),
|
||||
'numbers' => esc_html__('Numbers', 'opalestate-pro'),
|
||||
'prev_next' => esc_html__('Previous/Next', 'opalestate-pro'),
|
||||
'numbers_and_prev_next' => esc_html__('Numbers', 'opalestate-pro') . ' + ' . esc_html__('Previous/Next', 'opalestate-pro'),
|
||||
]
|
||||
'show' => esc_html__( 'Show', 'opalestate-pro' ),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
@ -289,92 +283,21 @@ class Opalestate_Agency_Collection_Elementor_Widget extends Opalestate_Elementor
|
||||
'pagination_page_limit',
|
||||
[
|
||||
'label' => esc_html__( 'Page Limit', 'opalestate-pro' ),
|
||||
'default' => '5',
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'default' => '3',
|
||||
'condition' => [
|
||||
'pagination_type!' => ''
|
||||
'pagination' => 'show',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_numbers_shorten',
|
||||
[
|
||||
'label' => esc_html__('Shorten', 'opalestate-pro'),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'default' => '',
|
||||
'condition' => [
|
||||
'pagination_type' => [
|
||||
'numbers',
|
||||
'numbers_and_prev_next',
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_prev_label',
|
||||
[
|
||||
'label' => esc_html__('Previous Label', 'opalestate-pro'),
|
||||
'default' => esc_html__('« Previous', 'opalestate-pro'),
|
||||
'condition' => [
|
||||
'pagination_type' => [
|
||||
'prev_next',
|
||||
'numbers_and_prev_next',
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_next_label',
|
||||
[
|
||||
'label' => esc_html__('Next Label', 'opalestate-pro'),
|
||||
'default' => esc_html__('Next »', 'opalestate-pro'),
|
||||
'condition' => [
|
||||
'pagination_type' => [
|
||||
'prev_next',
|
||||
'numbers_and_prev_next',
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_align',
|
||||
[
|
||||
'label' => esc_html__('Alignment', 'opalestate-pro'),
|
||||
'type' => Controls_Manager::CHOOSE,
|
||||
'options' => [
|
||||
'flex-start' => [
|
||||
'title' => esc_html__('Left', 'opalestate-pro'),
|
||||
'icon' => 'fa fa-align-left',
|
||||
],
|
||||
'center' => [
|
||||
'title' => esc_html__('Center', 'opalestate-pro'),
|
||||
'icon' => 'fa fa-align-center',
|
||||
],
|
||||
'flex-end' => [
|
||||
'title' => esc_html__('Right', 'opalestate-pro'),
|
||||
'icon' => 'fa fa-align-right',
|
||||
],
|
||||
],
|
||||
'default' => 'flex-start',
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .pagination' => 'justify-content: {{VALUE}};',
|
||||
],
|
||||
'condition' => [
|
||||
'pagination_type!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
}
|
||||
|
||||
public function get_post_categories() {
|
||||
$list = array();
|
||||
$list = [];
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
|
@ -32,10 +32,10 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
*
|
||||
* Used to set scripts dependencies required to run the widget.
|
||||
*
|
||||
* @return array Widget scripts dependencies.
|
||||
* @since 1.3.0
|
||||
* @access public
|
||||
*
|
||||
* @return array Widget scripts dependencies.
|
||||
*/
|
||||
public function get_script_depends() {
|
||||
return [ 'jquery-slick' ];
|
||||
@ -51,7 +51,7 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
* @return string Widget title.
|
||||
*/
|
||||
public function get_title() {
|
||||
return esc_html__( 'Block: Agent Collection', 'opalestate-pro' );
|
||||
return esc_html__( 'Block: Agents Collection', 'opalestate-pro' );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,18 +95,18 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'search_form',
|
||||
[
|
||||
'label' => esc_html__('Search Form', 'opalestate-pro'),
|
||||
'type' => \Elementor\Controls_Manager::SELECT,
|
||||
'default' => '',
|
||||
'options' => array(
|
||||
'' => esc_html__( 'Advanded', 'opalestate-pro' ),
|
||||
'address' => esc_html__( 'Search By Address', 'opalestate-pro' ),
|
||||
)
|
||||
]
|
||||
);
|
||||
// $this->add_control(
|
||||
// 'search_form',
|
||||
// [
|
||||
// 'label' => esc_html__('Search Form', 'opalestate-pro'),
|
||||
// 'type' => \Elementor\Controls_Manager::SELECT,
|
||||
// 'default' => '',
|
||||
// 'options' => array(
|
||||
// '' => esc_html__( 'Advanded', 'opalestate-pro' ),
|
||||
// 'address' => esc_html__( 'Search By Address', 'opalestate-pro' ),
|
||||
// )
|
||||
// ]
|
||||
// );
|
||||
|
||||
$this->add_control(
|
||||
'enable_sortable_bar',
|
||||
@ -122,10 +122,10 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
'label' => esc_html__( 'Item Layout', 'opalestate-pro' ),
|
||||
'type' => \Elementor\Controls_Manager::SELECT,
|
||||
'default' => 'grid',
|
||||
'options' => array(
|
||||
'options' => [
|
||||
'grid' => esc_html__( 'Grid', 'opalestate-pro' ),
|
||||
'list' => esc_html__( 'List', 'opalestate-pro' ),
|
||||
)
|
||||
],
|
||||
]
|
||||
);
|
||||
$this->add_responsive_control(
|
||||
@ -137,8 +137,8 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
'options' => [ 1 => 1, 2 => 2, 3 => 3, 4 => 4, 6 => 6 ],
|
||||
'prefix_class' => 'elementor-grid%s-',
|
||||
'condition' => [
|
||||
'item_layout' => 'grid'
|
||||
]
|
||||
'item_layout' => 'grid',
|
||||
],
|
||||
|
||||
]
|
||||
);
|
||||
@ -156,12 +156,12 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
],
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .elementor-items-container' => 'grid-column-gap: {{SIZE}}{{UNIT}}'
|
||||
'{{WRAPPER}} .elementor-items-container' => 'grid-column-gap: {{SIZE}}{{UNIT}}',
|
||||
|
||||
],
|
||||
'condition' => [
|
||||
'item_layout' => 'grid'
|
||||
]
|
||||
'item_layout' => 'grid',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
@ -174,7 +174,7 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
);
|
||||
$this->end_controls_section();
|
||||
|
||||
$this->add_slick_controls( array('enable_carousel' => 'yes') , ' .agent-slick-carousel ' );
|
||||
$this->add_slick_controls( [ 'enable_carousel' => 'yes' ], ' .agent-slick-carousel ' );
|
||||
|
||||
$this->start_controls_section(
|
||||
'section_query',
|
||||
@ -194,7 +194,6 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
);
|
||||
|
||||
|
||||
|
||||
$this->add_control(
|
||||
'advanced',
|
||||
[
|
||||
@ -253,7 +252,7 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
'NOT IN' => esc_html__( 'NOT IN', 'opalestate-pro' ),
|
||||
],
|
||||
'condition' => [
|
||||
'categories!' => ''
|
||||
'categories!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
@ -264,24 +263,19 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
'section_pagination',
|
||||
[
|
||||
'label' => esc_html__( 'Pagination', 'opalestate-pro' ),
|
||||
'condition' => [
|
||||
'enable_carousel!' => 'yes'
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_type',
|
||||
'pagination',
|
||||
[
|
||||
'label' => esc_html__( 'Pagination', 'opalestate-pro' ),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => '',
|
||||
'options' => [
|
||||
'' => esc_html__( 'None', 'opalestate-pro' ),
|
||||
'numbers' => esc_html__('Numbers', 'opalestate-pro'),
|
||||
'prev_next' => esc_html__('Previous/Next', 'opalestate-pro'),
|
||||
'numbers_and_prev_next' => esc_html__('Numbers', 'opalestate-pro') . ' + ' . esc_html__('Previous/Next', 'opalestate-pro'),
|
||||
]
|
||||
'show' => esc_html__( 'Show', 'opalestate-pro' ),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
@ -289,92 +283,21 @@ class Opalestate_Agent_Collection_Elementor_Widget extends Opalestate_Elementor_
|
||||
'pagination_page_limit',
|
||||
[
|
||||
'label' => esc_html__( 'Page Limit', 'opalestate-pro' ),
|
||||
'default' => '5',
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'default' => '3',
|
||||
'condition' => [
|
||||
'pagination_type!' => ''
|
||||
'pagination' => 'show',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_numbers_shorten',
|
||||
[
|
||||
'label' => esc_html__('Shorten', 'opalestate-pro'),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'default' => '',
|
||||
'condition' => [
|
||||
'pagination_type' => [
|
||||
'numbers',
|
||||
'numbers_and_prev_next',
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_prev_label',
|
||||
[
|
||||
'label' => esc_html__('Previous Label', 'opalestate-pro'),
|
||||
'default' => esc_html__('« Previous', 'opalestate-pro'),
|
||||
'condition' => [
|
||||
'pagination_type' => [
|
||||
'prev_next',
|
||||
'numbers_and_prev_next',
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_next_label',
|
||||
[
|
||||
'label' => esc_html__('Next Label', 'opalestate-pro'),
|
||||
'default' => esc_html__('Next »', 'opalestate-pro'),
|
||||
'condition' => [
|
||||
'pagination_type' => [
|
||||
'prev_next',
|
||||
'numbers_and_prev_next',
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'pagination_align',
|
||||
[
|
||||
'label' => esc_html__('Alignment', 'opalestate-pro'),
|
||||
'type' => Controls_Manager::CHOOSE,
|
||||
'options' => [
|
||||
'flex-start' => [
|
||||
'title' => esc_html__('Left', 'opalestate-pro'),
|
||||
'icon' => 'fa fa-align-left',
|
||||
],
|
||||
'center' => [
|
||||
'title' => esc_html__('Center', 'opalestate-pro'),
|
||||
'icon' => 'fa fa-align-center',
|
||||
],
|
||||
'flex-end' => [
|
||||
'title' => esc_html__('Right', 'opalestate-pro'),
|
||||
'icon' => 'fa fa-align-right',
|
||||
],
|
||||
],
|
||||
'default' => 'flex-start',
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .pagination' => 'justify-content: {{VALUE}};',
|
||||
],
|
||||
'condition' => [
|
||||
'pagination_type!' => '',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
$this->end_controls_section();
|
||||
|
||||
}
|
||||
|
||||
public function get_post_categories() {
|
||||
$list = array();
|
||||
$list = [];
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
|
@ -316,9 +316,10 @@ class Opalestate_Property_collection_Elementor_Widget extends Opalestate_Element
|
||||
'pagination_page_limit',
|
||||
[
|
||||
'label' => esc_html__( 'Page Limit', 'opalestate-pro' ),
|
||||
'default' => '5',
|
||||
'type' => Controls_Manager::NUMBER,
|
||||
'default' => '3',
|
||||
'condition' => [
|
||||
'pagination_type!' => '',
|
||||
'pagination' => 'show',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Plugin Name: Opal Estate Pro
|
||||
* Plugin URI: http://www.wpopal.com/product/opal-estate-wordpress-plugin/
|
||||
* Description: Opal Real Estate Plugin is an ideal solution and brilliant choice for you to set up a professional estate website.
|
||||
* Version: 1.1.3
|
||||
* Version: 1.1.4
|
||||
* Author: WPOPAL
|
||||
* Author URI: http://www.wpopal.com
|
||||
* Requires at least: 4.6
|
||||
@ -151,7 +151,7 @@ if ( ! class_exists( 'OpalEstate' ) ) {
|
||||
*/
|
||||
public function __clone() {
|
||||
// Cloning instances of the class is forbidden
|
||||
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'opalestate-pro' ), '1.1.3' );
|
||||
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'opalestate-pro' ), '1.1.4' );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,7 +160,7 @@ if ( ! class_exists( 'OpalEstate' ) ) {
|
||||
public function setup_constants() {
|
||||
// Plugin version
|
||||
if ( ! defined( 'OPALESTATE_VERSION' ) ) {
|
||||
define( 'OPALESTATE_VERSION', '1.1.3' );
|
||||
define( 'OPALESTATE_VERSION', '1.1.4' );
|
||||
}
|
||||
|
||||
// Plugin Folder Path
|
||||
|
@ -4,7 +4,7 @@ Donate link: http://www.wpopal.com/product/opal-estate-wordpress-plugin/
|
||||
Tags: estate, property, opalestate, house for rent, agency for lease, estate submission, agents estate property, property marketplace
|
||||
Requires at least: 4.6
|
||||
Tested up to: 5.2.3
|
||||
Stable tag: 1.1.3
|
||||
Stable tag: 1.1.4
|
||||
License: GPLv3
|
||||
License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
@ -153,6 +153,11 @@ This section describes how to install the plugin and get it working.
|
||||
* System tickets support 24/7 available : [free support](https://wpopal.ticksy.com/ "Visit the Plugin support Page")
|
||||
|
||||
== Changelog ==
|
||||
= 1.1.4 - 2019-10-17 =
|
||||
* Fixes - Properties collection pagination.
|
||||
* Fixes - Agents collection pagination.
|
||||
* Fixes - Agencies collection pagination.
|
||||
|
||||
= 1.1.3 - 2019-10-15 =
|
||||
* Fixes - Submission.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
$settings = $this->get_settings_for_display();
|
||||
extract( $settings );
|
||||
$layout = $settings['item_layout'];
|
||||
$attrs = $this->get_render_attribute_string( 'wrapper-style' );
|
||||
if ( isset( $_GET['display'] ) && $_GET['display'] == 'grid' ) {
|
||||
@ -9,13 +10,20 @@ if ( isset( $_GET['display'] ) && $_GET['display'] == 'grid' ) {
|
||||
$layout = 'list';
|
||||
$attrs = 'class="column-list"';
|
||||
}
|
||||
$onlyfeatured = 0;
|
||||
if ( isset( $_GET['s_agents'] ) ) {
|
||||
$query = Opalestate_Agency_Query::get_agencies( [ "posts_per_page" => $limit, 'paged' => $paged ], $onlyfeatured );
|
||||
|
||||
if ( is_front_page() ) {
|
||||
$paged = ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1;
|
||||
} else {
|
||||
$query = Opalestate_Agency_Query::get_search_agencies_query();
|
||||
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
|
||||
}
|
||||
|
||||
$onlyfeatured = 0;
|
||||
// if ( isset( $_GET['s_agents'] ) ) {
|
||||
$query = Opalestate_Agency_Query::get_agencies( [ 'posts_per_page' => $posts_per_page, 'paged' => $paged ], $onlyfeatured );
|
||||
// } else {
|
||||
// $query = Opalestate_Agency_Query::get_search_agencies_query();
|
||||
// }
|
||||
|
||||
$rowcls = apply_filters( 'opalestate_row_container_class', 'opal-row' );
|
||||
?>
|
||||
|
||||
@ -48,10 +56,8 @@ $rowcls = apply_filters( 'opalestate_row_container_class', 'opal-row' );
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ( $query->max_num_pages ): ?>
|
||||
<div class="w-pagination">
|
||||
<?php opalestate_pagination( $query->max_num_pages ); ?>
|
||||
</div>
|
||||
<?php if ( isset( $pagination ) && $pagination && ( ! isset( $enable_carousel ) || ! $enable_carousel ) ): ?>
|
||||
<div class="w-pagination"><?php opalestate_pagination( $pagination_page_limit ); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<div class="agency-results">
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
$settings = $this->get_settings_for_display();
|
||||
extract( $settings );
|
||||
$layout = $settings['item_layout'];
|
||||
$attrs = $this->get_render_attribute_string( 'wrapper-style' );
|
||||
if ( isset( $_GET['display'] ) && $_GET['display'] == 'grid' ) {
|
||||
@ -10,13 +11,19 @@ if ( isset( $_GET['display'] ) && $_GET['display'] == 'grid' ) {
|
||||
$attrs = 'class="column-list"';
|
||||
}
|
||||
|
||||
if ( is_front_page() ) {
|
||||
$paged = ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1;
|
||||
} else {
|
||||
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
|
||||
}
|
||||
|
||||
$onlyfeatured = 0;
|
||||
|
||||
if ( isset( $_GET['s_agents'] ) ) {
|
||||
$query = Opalestate_Query::get_agents( [ "posts_per_page" => $limit, 'paged' => $paged ], $onlyfeatured );
|
||||
} else {
|
||||
$query = OpalEstate_Search::get_search_agents_query();
|
||||
}
|
||||
// if ( isset( $_GET['s_agents'] ) ) {
|
||||
$query = Opalestate_Query::get_agents( [ "posts_per_page" => $posts_per_page, 'paged' => $paged ], $onlyfeatured );
|
||||
// } else {
|
||||
// $query = OpalEstate_Search::get_search_agents_query();
|
||||
// }
|
||||
|
||||
$form = $settings['search_form'] ? "search-agents-form-" . $settings['search_form'] : "search-agents-form";
|
||||
$rowcls = apply_filters( 'opalestate_row_container_class', 'opal-row' );
|
||||
@ -51,10 +58,8 @@ $rowcls = apply_filters( 'opalestate_row_container_class', 'opal-row' );
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ( $query->max_num_pages ): ?>
|
||||
<div class="w-pagination">
|
||||
<?php opalestate_pagination( $query->max_num_pages ); ?>
|
||||
</div>
|
||||
<?php if ( isset( $pagination ) && $pagination && ( ! isset( $enable_carousel ) || ! $enable_carousel ) ): ?>
|
||||
<div class="w-pagination"><?php opalestate_pagination( $pagination_page_limit ); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<div class="agents-results">
|
||||
|
Loading…
Reference in New Issue
Block a user