Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

jsarnowski / jsarnowski/jet-engine   php

Repository URL to install this package:

Version: 2.7.7 

/ modules / rest-api-listings / inc / settings.php

<?php
namespace Jet_Engine\Modules\Rest_API_Listings;

class Settings {

	public $items = false;
	public $nonce_key = 'jet-engine-rest-api-listings';

	/**
	 * Constructor for the class
	 */
	public function __construct() {

		add_action( 'jet-engine/dashboard/tabs', array( $this, 'register_settings_tab' ), 99 );
		add_action( 'jet-engine/dashboard/assets', array( $this, 'register_settings_js' ) );
		add_action( 'jet-engine/dashboard/assets-after', array( $this, 'register_settings_css' ) );
		add_action( 'wp_ajax_jet_engine_api_endpoint_save', array( $this, 'save_endpoint' ) );
		add_action( 'wp_ajax_jet_engine_api_endpoint_delete', array( $this, 'delete_endpoint' ) );

	}

	public function delete_endpoint() {

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Access denied', 'jet-engine' ) ) );
		}

		$nonce = ! empty( $_REQUEST['nonce'] ) ? $_REQUEST['nonce'] : false;

		if ( ! $nonce || ! wp_verify_nonce( $nonce, $this->nonce_key ) ) {
			wp_send_json_error( array( 'message' => __( 'Nonce validation failed', 'jet-engine' ) ) );
		}

		$item_id = ! empty( $_REQUEST['item_id'] ) ? absint( $_REQUEST['item_id'] ) : false;

		if ( ! $item_id ) {
			wp_send_json_error( array( 'message' => __( 'Item ID not found in the request', 'jet-engine' ) ) );
		}

		Module::instance()->data->set_request( array( 'id' => $item_id ) );

		if ( Module::instance()->data->delete_item( false ) ) {
			return wp_send_json_success( array( 'message' => __( 'Endpoint settings updated', 'jet-engine' ) ) );
		} else {
			return wp_send_json_error( Module::instance()->get_notices() );
		}

	}

	/**
	 * Ajax callback to save settings
	 *
	 * @return [type] [description]
	 */
	public function save_endpoint() {

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Access denied', 'jet-engine' ) ) );
		}

		$nonce = ! empty( $_REQUEST['nonce'] ) ? $_REQUEST['nonce'] : false;

		if ( ! $nonce || ! wp_verify_nonce( $nonce, $this->nonce_key ) ) {
			wp_send_json_error( array( 'message' => __( 'Nonce validation failed', 'jet-engine' ) ) );
		}

		$item    = ! empty( $_REQUEST['item'] ) ? $_REQUEST['item'] : array();
		$item_id = ! empty( $_REQUEST['item_id'] ) ? absint( $_REQUEST['item_id'] ) : false;
		$with_sample_request = isset( $_REQUEST['with_sample_request'] ) ? $_REQUEST['with_sample_request'] : false;
		$with_sample_request = filter_var( $with_sample_request, FILTER_VALIDATE_BOOLEAN );

		if ( $item_id ) {
			$item['id'] = $item_id;
		}

		if ( $with_sample_request ) {

			$items = Module::instance()->request->set_endpoint( $item )->get_items( array(), true );

			if ( false === $items ) {
				wp_send_json_error( array( 'message' => Module::instance()->request->get_error() ) );
			}

			if ( ! is_array( $items ) ) {
				wp_send_json_error( array( 'message' => __( 'API endpoint, connected but items list has incorrect format. Please check Path option to make sure you set correct path to the items list in the response', 'jet-engine' ) ) );
			}

			$sample_item = $items[0];

			$item['connected'] = true;
			$item['sample_item'] = $sample_item;
			$item['fetched_fields'] = array_keys( get_object_vars( $sample_item ) );

		} elseif ( $item_id ) {

			$prev_item = Module::instance()->data->get_item_for_edit( $item_id );
			$args      = isset( $prev_item['args'] ) ? maybe_unserialize( $prev_item['args'] ) : false;

			$item['connected']      = isset( $args['connected'] ) ? $args['connected'] : false;
			$item['sample_item']    = isset( $args['sample_item'] ) ? $args['sample_item'] : false;
			$item['fetched_fields'] = isset( $args['fetched_fields'] ) ? $args['fetched_fields'] : array();

		}

		Module::instance()->data->set_request( $item );

		if ( ! $item_id ) {
			$done = Module::instance()->data->create_item( false );
		} else {
			$done = Module::instance()->data->edit_item( false );
		}

		if ( ! empty( $done ) ) {

			$message = __( 'Endpoint settings updated', 'jet-engine' );

			if ( $with_sample_request ) {
				$message = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><rect x="0" fill="none" width="20" height="20"></rect><g><path d="M10 2c-4.42 0-8 3.58-8 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm-.615 12.66h-1.34l-3.24-4.54 1.34-1.25 2.57 2.4 5.14-5.93 1.34.94-5.81 8.38z"></path></g></svg>' . __( 'Request succesfully sent. Sample item is fetched. Endpoint settings updated', 'jet-engine' );
			}

			wp_send_json_success( array(
				'item_id' => $done,
				'message' => $message,
			) );
		} else {

			$raw_notices = array();
			$notices     = Module::instance()->get_notices();

			if ( ! empty( $notices ) ) {
				foreach ( $notices as $notice ) {
					$raw_notices[] = $notice['message'];
				}
			}

			wp_send_json_error( array(
				'message' => implode( ', ', $raw_notices ),
			) );
		}

	}

	public function register_settings_css() {

		wp_add_inline_style( 'jet-engine-dashboard', '
			.jet-rest-api-connected,
			.jet-rest-api-not-connected {
				display: flex;
				align-items: center;
				align-content: center;
			}
			.jet-rest-api-connected {
				color: #46B450;
				font-weight: bold;
			}
			.jet-rest-api-connected svg,
			.jet-rest-api-not-connected svg {
				width: 20px;
				height: 20px;
				margin: 0 4px 0 0;
			}
			.rtl .jet-rest-api-connected svg,
			.rtl .jet-rest-api-not-connected svg {
				margin: 0 0 0 4px;
			}
			.jet-rest-api-connected svg path {
				fill: #46B450;
			}
			.jet-rest-api-not-connected svg path {
				fill: #DCDCDD;
			}
			.cx-vui-button + .jet-rest-api-connected {
				padding: 10px 0 0 0;
				font-weight: normal;
			}
			.jet-rest-api-error {
				color: #C92C2C;
				padding: 10px 0 0 0;
				display: flex;
				align-items: center;
				align-content: center;
			}
			.jet-rest-api-error:before {
				content: "\f534";
				margin: 0 5px 0 0;
				font-family: dashicons;
				font-size: 20px;
			}
			.rtl .jet-rest-api-error:before {
				margin: 0 0 0 5px;
			}
		' );

	}

	/**
	 * Register settings JS file
	 *
	 * @return [type] [description]
	 */
	public function register_settings_js() {

		wp_enqueue_script(
			'jet-engine-rest-listings',
			Module::instance()->module_url( 'assets/js/admin/settings.js' ),
			array( 'cx-vue-ui' ),
			jet_engine()->get_version(),
			true
		);

		$items = $this->get();

		wp_localize_script(
			'jet-engine-rest-listings',
			'JetEngineRestListingsConfig',
			array(
				'items'       => $items,
				'_nonce'      => wp_create_nonce( $this->nonce_key ),
				'auth_types'  => array_merge(
					array(
						array(
							'value' => '',
							'label' => __( 'Select type...', 'jet-engine' ),
						),
					),
					Module::instance()->auth_types->get_types_for_js()
				),
				'sample_item' => array(
					'name'          => 'Crocoblock Widgets',
					'url'           => 'https://crocoblock.com/wp-json/croco-site-api/v1/get-widgets',
					'items_path'    => '/items',
					'authorization' => false,
				),
				'save_label' => __( 'Save', 'jet-engine' ),
				'saving_label' => __( 'Saving...', 'jet-engine' ),
			)
		);

		add_action( 'admin_footer', array( $this, 'print_templates' ) );

	}

	/**
	 * Print VU template for maps settings
	 *
	 * @return [type] [description]
	 */
	public function print_templates() {
		?>
		<script type="text/x-template" id="jet_engine_rest_api_listings">
			<div class="cx-vui-inner-panel">
				<div tabindex="0" class="cx-vui-repeater">
					<div class="cx-vui-repeater__items">
						<div :class="{ 'cx-vui-repeater-item': true, 'cx-vui-panel': true, 'cx-vui-repeater-item--is-collpased': editID !== item.id }" v-for="( item, index ) in items">
							<div :class="{ 'cx-vui-repeater-item__heading': true, 'cx-vui-repeater-item__heading--is-collpased': editID !== item.id }">
								<div class="cx-vui-repeater-item__heading-start" @click="setEdit( item.id )">
									<svg v-if="editID !== item.id" width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" class="cx-vui-repeater-item__collapse cx-vui-repeater-item__collapse--is-collpased"><rect width="14" height="14" transform="matrix(1 0 0 -1 0 14)" fill="white"></rect><path d="M13 5.32911L7 11L1 5.32911L2.40625 4L7 8.34177L11.5938 4L13 5.32911Z"></path></svg>
									<svg v-else width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" class="cx-vui-repeater-item__collapse"><rect width="14" height="14" transform="matrix(1 0 0 -1 0 14)" fill="white"></rect><path d="M13 5.32911L7 11L1 5.32911L2.40625 4L7 8.34177L11.5938 4L13 5.32911Z"></path></svg>
									<div class="cx-vui-repeater-item__title">{{ item.name }}</div>
									<div class="cx-vui-repeater-item__subtitle">{{ item.url }}</div>
								</div>
								<div class="cx-vui-repeater-item__heading-end">
									<div class="cx-vui-repeater-item__clean" @click="deleteID = item.id">
										<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="16" height="16" transform="matrix(1 0 0 -1 0 16)" fill="white"></rect><path d="M2.28564 14.192V3.42847H13.7142V14.192C13.7142 14.6685 13.5208 15.0889 13.1339 15.4533C12.747 15.8177 12.3005 15.9999 11.7946 15.9999H4.20529C3.69934 15.9999 3.25291 15.8177 2.866 15.4533C2.4791 15.0889 2.28564 14.6685 2.28564 14.192Z"></path><path d="M14.8571 1.14286V2.28571H1.14282V1.14286H4.57139L5.56085 0H10.4391L11.4285 1.14286H14.8571Z"></path></svg>
										<div class="cx-vui-tooltip" v-if="deleteID === item.id">
											<?php _e( 'Are you sure?', 'jet-engine' ); ?>
											<br><span class="cx-vui-repeater-item__confrim-del" @click.stop="deleteEndpoint( item.id, index )"><?php _e( 'Yes', 'jet-engine' ); ?></span>&nbsp;/&nbsp;<span class="cx-vui-repeater-item__cancel-del" @click.stop="deleteID = false"><?php _e( 'No', 'jet-engine' ); ?></span>
										</div>
									</div>
								</div>
							</div>
							<div :class="{ 'cx-vui-repeater-item__content': true, 'cx-vui-repeater-item__content--is-collpased': editID !== item.id }">
								<jet-engine-rest-api-listing-item :value="item"/>
							</div>
						</div>
					</div>
					<div class="cx-vui-repeater__actions">
						<cx-vui-button
							button-style="accent-border"
							size="mini"
							:disabled="isBusy"
							@click="newEndpoint"
						>
							<span
								slot="label"
								v-html="'<?php _e( '+ New Endpoint', 'jet-engine' ); ?>'"
							></span>
						</cx-vui-button>
						<cx-vui-button
							button-style="link-accent"
							size="mini"
							:disabled="isBusy"
							@click="newEndpoint( $event, true )"
						>
							<span
								slot="label"
								v-html="'<?php _e( 'Add Sample Endpoint', 'jet-engine' ); ?>'"
							></span>
						</cx-vui-button>
					</div>
				</div>
			</div>
		</script>
		<script type="text/x-template" id="jet_engine_rest_api_listing_item">
			<div>
				<cx-vui-input
					label="<?php _e( 'Name', 'jet-engine' ); ?>"
					description="<?php _e( 'Endpoint name', 'jet-engine' ); ?>"
					:wrapper-css="[ 'equalwidth' ]"
					size="fullwidth"
					v-model="settings.name"
				></cx-vui-input>
				<cx-vui-input
					label="<?php _e( 'API Endpoint URL', 'jet-engine' ); ?>"
					description="<?php _e( 'URL for the API endpoints to get items from', 'jet-engine' ); ?>"
					:wrapper-css="[ 'equalwidth' ]"
					size="fullwidth"
					v-model="settings.url"
				></cx-vui-input>
				<cx-vui-input
					label="<?php _e( 'Items path', 'jet-engine' ); ?>"
					description="<?php _e( 'Path to the items inside APIs response. If reponse contain only items leave `/`, if items are nested please set path to the items separated with `/` for example `/data/items`', 'jet-engine' ); ?>"
					:wrapper-css="[ 'equalwidth' ]"
					size="fullwidth"
					v-model="settings.items_path"
				></cx-vui-input>
				<cx-vui-switcher
					label="<?php _e( 'Authorization', 'jet-engine' ); ?>"
					description="<?php _e( 'API endpoints requires authorization', 'jet-engine' ); ?>"
					:wrapper-css="[ 'equalwidth' ]"
					v-model="settings.authorization"
				></cx-vui-switcher>
				<cx-vui-select
					label="<?php _e( 'Authorization type', 'jet-engine' ); ?>"
					description="<?php _e( 'Select authorization type', 'jet-engine' ); ?>"
					:wrapper-css="[ 'equalwidth' ]"
					:size="'fullwidth'"
					:options-list="authTypes"
					v-model="settings.auth_type"
					:conditions="[
						{
							input: settings.authorization,
							compare: 'equal',
							value: true,
						}
					]"
				></cx-vui-select>
				<?php do_action( 'jet-engine/rest-api-listings/settings/auth-controls' ); ?>
				<cx-vui-component-wrapper
					label="<?php _e( 'Status', 'jet-engine' ); ?>"
					description="<?php _e( 'Is endpoint connected or not. To make endpoint connected you need to send a sample request to test authorization and fetch sample data. Without this it may not work properly in the listing grid.', 'jet-engine' ); ?>"
					:wrapper-css="[ 'equalwidth' ]"
				>
					<div v-if="settings.connected" class="jet-rest-api-connected">
						<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><rect x="0" fill="none" width="20" height="20"/><g><path d="M10 2c-4.42 0-8 3.58-8 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm-.615 12.66h-1.34l-3.24-4.54 1.34-1.25 2.57 2.4 5.14-5.93 1.34.94-5.81 8.38z"/></g></svg>
						<?php _e( 'Connected', 'jet-engine' ); ?>
					</div>
					<div v-else class="jet-rest-api-not-connected">
						<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><rect x="0" fill="none" width="20" height="20"/><g><path d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm1 4c0-.55-.45-1-1-1s-1 .45-1 1 .45 1 1 1 1-.45 1-1zm0 9V9H9v6h2z"/></g></svg>
						<?php _e( 'Not connected. Set up authorization settings if required and press&nbsp;&nbsp;<b>Send Request</b>', 'jet-engine' ); ?>
					</div>
				</cx-vui-component-wrapper>
				<cx-vui-component-wrapper
					label="<?php _e( 'Sample request', 'jet-engine' ); ?>"
					description="<?php _e( 'Send a sample request to check API endpoint connection and fetch available fields', 'jet-engine' ); ?>"
					:wrapper-css="[ 'equalwidth' ]"
				>
					<cx-vui-button
						button-style="accent-border"
						size="mini"
						:loading="makingSampleRequest"
						@click="makeSampleRequest"
					>
						<span
							slot="label"
						><?php _e( 'Send Request', 'jet-engine' ); ?></span>
					</cx-vui-button>
					<div v-if="sampleRequestError" v-html="sampleRequestError" class="jet-rest-api-error"></div>
					<div v-if="sampleRequestSuccess" v-html="sampleRequestSuccess" class="jet-rest-api-connected"></div>
				</cx-vui-component-wrapper>
				<cx-vui-switcher
					label="<?php _e( 'Cache', 'jet-engine' ); ?>"
					description="<?php _e( 'Cache API responses. Responses will be cached by used request arguments. So if 2 widgets use the same query arguments, the data will be returned from the same cached storage.', 'jet-engine' ); ?>"
					:wrapper-css="[ 'equalwidth' ]"
					v-model="settings.cache"
				></cx-vui-switcher>
				<cx-vui-select
					label="<?php _e( 'Cache duration period', 'jet-engine' ); ?>"
					description="<?php _e( 'Select duration period - minutes, hours or days', 'jet-engine' ); ?>"
					:wrapper-css="[ 'equalwidth' ]"
					:size="'fullwidth'"
					:options-list="[
						{
							value: 'minutes',
							label: '<?php _e( 'Minutes', 'jet-engine' ) ?>',
						},
						{
							value: 'hours',
							label: '<?php _e( 'Hours', 'jet-engine' ) ?>',
						},
						{
							value: 'days',
							label: '<?php _e( 'Days', 'jet-engine' ) ?>',
						},
					]"
					v-model="settings.cache_period"
					:conditions="[
						{
							input: settings.cache,
							compare: 'equal',
							value: true,
						}
					]"
				></cx-vui-select>
				<cx-vui-input
					label="<?php _e( 'Cache duration value', 'jet-engine' ); ?>"
					description="<?php _e( 'Set numerice value, eg. 5, 10, 15, 30', 'jet-engine' ); ?>"
					:wrapper-css="[ 'equalwidth' ]"
					size="fullwidth"
					v-model="settings.cache_value"
					:conditions="[
						{
							input: settings.cache,
							compare: 'equal',
							value: true,
						}
					]"
				></cx-vui-input>
				<cx-vui-component-wrapper
					:wrapper-css="[ 'equalwidth' ]"
				>
					<cx-vui-button
						button-style="accent"
						:loading="saving"
						:disabled="isDisabled()"
						@click="saveEndpoint"
					>
						<span
							slot="label"
						>{{ buttonLabel() }}</span>
					</cx-vui-button>
				</cx-vui-component-wrapper>
			</div>
		</script>
		<?php
	}

	/**
	 * Returns all settings
	 *
	 * @return [type] [description]
	 */
	public function get( $endpoint_id = false ) {

		if ( false === $this->items ) {
			$this->items = Module::instance()->data->get_item_for_register();

			if ( empty( $this->items ) ) {
				$this->items = array();
			}

			usort( $this->items, function( $a, $b ) {

				if ( $a['id'] === $b['id'] ) {
					return 0;
				}

				return ( $a['id'] < $b['id'] ) ? -1 : 1;
			} );

		}

		if ( false === $endpoint_id ) {
			return $this->items;
		} else {

			foreach ( $this->items as $item ) {
				if ( $item['id'] === $endpoint_id ) {
					return $item;
				}
			}

			return false;
		}


	}

	/**
	 * Register settings tab
	 *
	 * @return [type] [description]
	 */
	public function register_settings_tab() {
		?>
		<cx-vui-tabs-panel
			name="rest_api_endpoints"
			label="<?php _e( 'REST API Endpoints', 'jet-engine' ); ?>"
			key="rest_api_endpoints"
		>
			<keep-alive>
				<jet-engine-rest-api-listings></jet-engine-rest-api-listings>
			</keep-alive>
		</cx-vui-tabs-panel>
		<?php
	}

}