PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
11.9 11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 All 205 releases
booking / includes / publish / class-wpbc-booking-form-publish-ajax.php

class-wpbc-booking-form-publish-ajax.php in Booking Calendar 11.9, at includes/publish/class-wpbc-booking-form-publish-ajax.php

203 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * AJAX controller for neutral Booking Form publishing.
4 *
5 * @package Booking Calendar
6 * @since 11.6.0
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Authorize and dispatch asynchronous Booking Form publishing requests.
15 */
16 final class WPBC_Booking_Form_Publish_Ajax {
17
18 const ACTION = 'WPBC_AJX_PUBLISH_BOOKING_FORM';
19 const LIST_PAGES_ACTION = 'WPBC_AJX_GET_PUBLISHABLE_PAGES';
20 const NONCE_ACTION = 'wpbc_publish_booking_form';
21
22 /**
23 * Register the authenticated AJAX action.
24 *
25 * @return void
26 */
27 public static function init() {
28 add_action( 'wp_ajax_' . self::ACTION, array( __CLASS__, 'publish' ) );
29 add_action( 'wp_ajax_' . self::LIST_PAGES_ACTION, array( __CLASS__, 'list_pages' ) );
30 }
31
32 /**
33 * Return only WordPress pages the current user is authorized to edit.
34 *
35 * Page titles are discovered lazily after the user chooses the existing-page
36 * workflow. They are never printed into the catalog shell, and live demos are
37 * rejected before any page query is executed.
38 *
39 * @return void Sends JSON and terminates the AJAX request.
40 */
41 public static function list_pages() {
42 check_ajax_referer( self::NONCE_ACTION, 'nonce' );
43
44 $manage_capability = function_exists( 'wpbc_catalog_booking_resources_get_manage_capability' )
45 ? wpbc_catalog_booking_resources_get_manage_capability()
46 : 'manage_options';
47
48 if ( ! current_user_can( $manage_capability ) || ! current_user_can( 'edit_pages' ) ) {
49 self::send_error( __( 'You do not have permission to view publishable pages.', 'booking' ), 'wpbc_publish_pages_forbidden' );
50 }
51
52 if ( WPBC_Booking_Form_Publisher::is_demo_restricted() ) {
53 self::send_error( __( 'In the demo versions this operation is not allowed.', 'booking' ), 'wpbc_publish_demo_restricted' );
54 }
55
56 $page_ids = get_posts(
57 array(
58 'post_type' => 'page',
59 'post_status' => array( 'draft', 'publish', 'private' ),
60 'posts_per_page' => -1,
61 'orderby' => 'title',
62 'order' => 'ASC',
63 'fields' => 'ids',
64 'no_found_rows' => true,
65 'suppress_filters' => false,
66 )
67 );
68 $publishable_pages = array();
69
70 foreach ( $page_ids as $page_id ) {
71 $page_id = absint( $page_id );
72 if ( ! $page_id || ! current_user_can( 'edit_post', $page_id ) ) {
73 continue;
74 }
75
76 $page_title = wp_strip_all_tags( get_the_title( $page_id ) );
77 $publishable_pages[] = array(
78 'id' => $page_id,
79 'title' => '' !== $page_title ? $page_title : __( '(no title)', 'booking' ),
80 );
81 }
82
83 wp_send_json_success(
84 array(
85 'pages' => $publishable_pages,
86 )
87 );
88 }
89
90 /**
91 * Publish one authorized Resource shortcode into a WordPress page.
92 *
93 * @return void Sends JSON and terminates the AJAX request.
94 */
95 public static function publish() {
96 check_ajax_referer( self::NONCE_ACTION, 'nonce' );
97
98 $manage_capability = function_exists( 'wpbc_catalog_booking_resources_get_manage_capability' )
99 ? wpbc_catalog_booking_resources_get_manage_capability()
100 : 'manage_options';
101
102 if ( ! current_user_can( $manage_capability ) ) {
103 self::send_error( __( 'You do not have permission to publish this Booking Resource.', 'booking' ) );
104 }
105
106 $resource_id = self::get_request_integer( 'resource_id' );
107 if ( ! self::is_authorized_resource( $resource_id ) ) {
108 self::send_error( __( 'The selected Booking Resource does not exist or is not available to this user.', 'booking' ) );
109 }
110
111 $publisher = new WPBC_Booking_Form_Publisher();
112 $result = $publisher->publish(
113 array(
114 'publish_mode' => self::get_request_text( 'publish_mode' ),
115 'resource_id' => $resource_id,
116 'form_name' => self::get_request_text( 'form_name' ),
117 'shortcode_raw' => self::get_request_raw( 'shortcode_raw' ),
118 'page_id' => self::get_request_integer( 'page_id' ),
119 'page_title' => self::get_request_text( 'page_title' ),
120 )
121 );
122
123 if ( is_wp_error( $result ) ) {
124 self::send_error( $result->get_error_message(), $result->get_error_code() );
125 }
126
127 wp_send_json_success( $result );
128 }
129
130 /**
131 * Determine whether the current user can see the exact Resource.
132 *
133 * @param int $resource_id Booking Resource ID.
134 *
135 * @return bool True when the independent repository authorizes the Resource.
136 */
137 private static function is_authorized_resource( $resource_id ) {
138 if ( ! $resource_id || ! class_exists( 'WPBC_Catalog_Booking_Resources_Repository' ) ) {
139 return false;
140 }
141
142 $repository = new WPBC_Catalog_Booking_Resources_Repository();
143 $resource = $repository->get_resource( $resource_id );
144
145 return is_array( $resource ) && ! empty( $resource['id'] );
146 }
147
148 /**
149 * Read and sanitize a text request field.
150 *
151 * @param string $request_key Request key.
152 *
153 * @return string Sanitized value.
154 */
155 private static function get_request_text( $request_key ) {
156 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified before this helper is called.
157 return isset( $_POST[ $request_key ] ) ? sanitize_text_field( wp_unslash( $_POST[ $request_key ] ) ) : '';
158 }
159
160 /**
161 * Read a raw shortcode request field for service-level normalization.
162 *
163 * @param string $request_key Request key.
164 *
165 * @return string Unslashed request value.
166 */
167 private static function get_request_raw( $request_key ) {
168 // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce is verified and the publisher normalizes the shortcode.
169 return isset( $_POST[ $request_key ] ) ? trim( wp_unslash( $_POST[ $request_key ] ) ) : '';
170 }
171
172 /**
173 * Read a positive integer request field.
174 *
175 * @param string $request_key Request key.
176 *
177 * @return int Normalized integer.
178 */
179 private static function get_request_integer( $request_key ) {
180 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified before this helper is called.
181 return isset( $_POST[ $request_key ] ) ? absint( $_POST[ $request_key ] ) : 0;
182 }
183
184 /**
185 * Send a consistent JSON publishing error.
186 *
187 * @param string $message Safe user-facing error message.
188 * @param string $error_code Optional stable error code.
189 *
190 * @return void Sends JSON and terminates the AJAX request.
191 */
192 private static function send_error( $message, $error_code = 'wpbc_publish_error' ) {
193 wp_send_json_error(
194 array(
195 'code' => sanitize_key( $error_code ),
196 'message' => wp_kses_post( $message ),
197 )
198 );
199 }
200 }
201
202 WPBC_Booking_Form_Publish_Ajax::init();
203