oont-contents/plugins/webappick-product-feed-for-woocommerce/V5/API/RestController.php
2025-03-31 21:42:48 +02:00

422 lines
11 KiB
PHP

<?php
namespace CTXFeed\V5\API;
use CTXFeed\V5\API\V1\AttributesMapping;
use CTXFeed\V5\API\V1\CategoryMapping;
use CTXFeed\V5\API\V1\DropDown;
use CTXFeed\V5\API\V1\DynamicAttributes;
use CTXFeed\V5\API\V1\MakeFeed;
use CTXFeed\V5\API\V1\ManageFeeds;
use CTXFeed\V5\API\V1\MerchantInfo;
use CTXFeed\V5\API\V1\ProductCategories;
use CTXFeed\V5\API\V1\Products;
use CTXFeed\V5\API\V1\ProductTaxonomy;
use CTXFeed\V5\API\V1\Settings;
use CTXFeed\V5\API\V1\WooFeedDocs;
use CTXFeed\V5\API\V1\WPStatus;
use CTXFeed\V5\API\V1\WPOptions;
use \WP_REST_Controller;
use \WP_Error;
use CTXFeed\V5\Helper\CommonHelper;
/**
* Class RestController
*
* @package CTXFeed
* @subpackage CTXFeed\V5\API
* @author Azizul Hasan <azizulhasan.cr@gmail.com>
* @link https://azizulhasan.com
* @license https://opensource.org/licenses/gpl-license.php GNU Public License
*/
class RestController extends WP_REST_Controller {
/**
* @var array $response ;
*/
public $response = [
'status' => 200,
'data' => [],
'extra' => null
];
/**
* The single instance of the class
*
* @var RestController
*
*/
protected static $_instance = null;
/**
* @var $version ;
*/
private $version = WOO_FEED_API_VERSION;
protected function __construct() {
$this->namespace = WOO_FEED_API_NAMESPACE . '/' . $this->version;
add_action( 'rest_api_init', [ $this, 'register_api' ] );
add_action( 'rest_api_init', function ( $var ) {
remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
}, 15, 1 );
}
/**
* Main RestController Instance.
*
* Ensures only one instance of RestController is loaded or can be loaded.
*
* @return RestController Main instance
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Return true only user is logged in as $mange_ctx_feed roles.
* Using postman or other API client Basic-Auth plugin must be installed ( URL is below )
* authorization system should be Basic Auth.
*
* @@ -86,7 +86,16 @@ public static function instance() {
* @see https://github.com/WP-API/Basic-Auth
*/
public function get_item_permissions_check( $request ) {
$user = wp_get_current_user();
$mange_ctx_feed = apply_filters( 'ctx_feed_api_accessed_users', [
'manage_options',
'manage_woocommerce'
] );
$current_user_roles = $user->get_role_caps();
$current_user_roles = array_keys( $current_user_roles );
$current_user_can_manage_ctx_feed = false;
foreach ( $mange_ctx_feed as $role ) {
if ( in_array( $role, $current_user_roles ) ) {
$current_user_can_manage_ctx_feed = true;
}
}
return apply_filters( 'ctx_feed_current_user_can_manage_api', $current_user_can_manage_ctx_feed, $user, $current_user_roles, $mange_ctx_feed, $request );
}
/**
* Register routes according to $_SERVER['REQUEST_URI'].
* After 'wp-json' value will be considered as namespace.
* After that v1/v2 will be as api version number.
* Then next value will be considered as route name.
*
* Example : wp-json/ctxfeed/v1/drop_down/?type=feed_country
*
* @description
* ctxfeed: is namespace
* v1: is version number and will indicate version folder number
* drop_down: route. It will look into 'DropDown' class in V1 folder.
* @return void
*/
public function register_api() {
// $uri = trim( $_SERVER['REQUEST_URI'], '/' );
// $uri_arr = explode( '/', $uri );
// $namespace = explode( '/', $this->namespace );
// $uri_namespace = '';
// $class_name = '';
// $version = $this->version;
// Get rest base like : 'wp-json' or 'index.php?rest_route='
// $rest_base = str_replace( home_url(), '', get_rest_url() );
// $rest_base = trim( $rest_base, '/' );
//
// foreach ( $uri_arr as $i => $value ) {
// // Get namespace name;
// if ( $value === $rest_base ) {
// $i ++;
// if ( ! isset( $uri_arr[ $i ] ) ) {
// break;
// }
// $uri_namespace = $uri_arr[ $i ];
// $i += 2;
// // Get current classname from url after version number.
// if ( isset( $uri_arr[ $i ] ) ) {
// $class_name = $uri_arr[ $i ];
// $version = $uri_arr[ -- $i ];
// }
// break;
// }
// }
// If current namespace and url namespace are equal
// load class name from version folder.
// if ( $class_name && count( $namespace ) && $namespace[0] == $uri_namespace ) {
// if ( class_exists( $class_name ) ) {
// self::load_class( $class_name, $version )->register_routes();
// }else{
$classes = [
AttributesMapping::instance(),
CategoryMapping::instance(),
DropDown::instance(),
DynamicAttributes::instance(),
ManageFeeds::instance(),
MerchantInfo::instance(),
ProductCategories::instance(),
Products::instance(),
ProductTaxonomy::instance(),
Settings::instance(),
WPOptions::instance(),
MakeFeed::instance(),
WPStatus::instance(),
WooFeedDocs::instance(),
];
foreach ( $classes as $class ) {
$class->register_routes();
}
// }
// }
}
/**
* Cloning is forbidden.
*/
final public function __clone() {
_doing_it_wrong( __FUNCTION__, esc_attr_e( 'Cloning is forbidden.', 'woo-feed' ), esc_attr(WOO_FEED_FREE_VERSION) );
}
/**
* Unserializing instances of this class is forbidden.
*/
final public function __wakeup() {
_doing_it_wrong( __FUNCTION__, esc_attr_e( 'Unserializing instances of this class is forbidden.', 'woo-feed' ), esc_attr(WOO_FEED_FREE_VERSION) );
}
/**
* @param $data
*
* @return void|\WP_REST_Response
*/
public function success( $data, $status = 200 ) {
$this->response['status'] = $status;
$this->response['data'] = $data;
$response = rest_ensure_response( $this->response );
$response = $this->add_additional_headers( $response );
return $response;
}
/**
* @param $data
*
* @return void|\WP_Error
*/
public function error( $data = '', $code = 'rest_no_data_found', $status = 404 ) {
$this->response['status'] = $status;
$this->response['data'] = $data;
$this->response['code'] = $code;
$this->response['status'] = $status;
$this->response['data'] = $data;
$response = rest_ensure_response( $this->response );
$response = $this->add_additional_headers( $response );
return $response;
}
/**
* @param $response
*
* @return \WP_REST_Response
*/
protected function add_additional_headers( $response ) {
$admin_origin = parse_url( admin_url() );
$response->header( 'Access-Control-Allow-Origin', $admin_origin['host'] );
return $response;
}
/**
* @param $args
* @param $data
* @param $response
*
* @return mixed
*/
protected function maybe_add_pagination( $args, $data, $response ) {
// Get data according to pagination. If $page and $per_page params are passed in the url.
$total = count( $data );
if ( isset( $args['per_page'], $args['page'] ) ) {
$total_pages = ceil( $total / (int) $args['per_page'] );
// Set current page data.
$offset = $args['per_page'] * ( $args['page'] - 1 );
$this->response['data'] = array_slice( $data, $offset, $args['per_page'] );
$response = $this->add_pagination_links( $response, $args, $total_pages, $total );
} else {
$this->response['data'] = $data;
}
$response->data = $this->response;
return $response;
}
/**
* @param $response
* @param $args
* @param $total_pages
* @param $total
*
* @return mixed
*/
protected function add_pagination_links( $response, $args, $total_pages, $total ) {
$url = get_site_url() . '/wp-json/' . $this->namespace . '/' . $this->rest_base . '/?';
$page = (int) $args['page'];
unset( $args['page'] );
$total_args = count( $args );
$count = 0;
foreach ( $args as $arg => $value ) {
$count ++;
if ( $count === $total_args ) {
$url .= $arg . '=' . $value;
} else {
$url .= $arg . '=' . $value . '&';
}
}
// Next page link add.
if ( $total_pages == $page ) {
$next_url = $url . '&page=' . $page;
} else {
$next_page = $page + 1;
$next_url = $url . '&page=' . $next_page;
}
$response->add_link( 'next_page', $next_url );
// Previous page link add.
if ( $page == 1 ) {
$prev_url = $url . '&page=' . $page;
} else {
$prev_page = $page - 1;
$prev_url = $url . '&page=' . $prev_page;
}
$response->add_link( 'prev_page', $prev_url );
// add headers.
$response->header( 'X-WP-TotalPages', (int) $total_pages );
$response->header( 'X-WP-Total', (int) $total );
return $response;
}
/**
* @param $array
*
* @return bool
*/
protected function is_assoc( $array ) {
if ( array() === $array ) {
return false;
}
return ( $array !== array_values( $array ) );
}
public function is_prefix_matched( $string, $prefix ) {
return str_starts_with( $string, $prefix );
}
private static function load_class( $class = null, $version = 'v1' ) {
$class_name = self::get_class_name( $class );
return RestFactory::load( $class_name, $version ) ?? null;
}
/**
* @param $class
*
* @return string
*/
private static function get_class_name( $class ) {
$api_class = array_map( function ( $part ) {
if ( 'wp' === $part ) {
return strtoupper( $part );
}
return ucfirst( $part );
}, explode( '_', $class ) );
return implode( '', $api_class );
}
/**
* @param $request
*
* @return array
*/
protected function get_lists( $request, $arr ) {
$lists = [];
if ( ! empty( $arr ) ) {
foreach ( $arr as $option_name => $attr_list ) {
$item = $this->prepare_item_for_response( $attr_list, $request );
$lists[ $option_name ] = $item;
}
}
return $lists;
}
/**
* @param $item
* @param $request
*
* @return void|\WP_Error|\WP_REST_Response
*/
public function prepare_item_for_response( $item, $request ) {
return maybe_unserialize( $item );
}
public function unique_option_name( $option_name, $prefix, $add_prefix = false ) {
$option_name = preg_replace( "/[^A-Za-z0-9_]/", '', $option_name );
if ( false !== get_option( sanitize_text_field($prefix) . sanitize_text_field($option_name), false ) ) {
$option = CommonHelper::unique_option_name( $option_name, $prefix );
} else {
$option = $add_prefix ? $prefix . $option_name : $option_name;
}
$response = [ 'option_name' => $option ];
return $response;
}
/**
* @param $request
*
* @return string
* If Dynamic Attribute, Category mapping and Attribute mapping option name with special char like '&' by default php split the link when
* get &, to make unique option name with & we use this function.
*/
public function get_feed_option_name( $request ) {
$args = $request->get_params();
$feed_name = $args['name'];
$feed_name = str_replace( "plus", "+", $feed_name );
array_shift( $args );
$temp_arr = [ $feed_name ];
if ( count( array_keys( $args ) ) > 1 ) {
$temp_arr2 = implode( '&', array_keys( $args ) );
array_push( $temp_arr, $temp_arr2 );
$feed_name = implode( '&', $temp_arr );
}
return $feed_name;
}
}