PluginProbe
WP VR – 360 Panorama and Virtual Tour Builder / 9.0.3
WP VR – 360 Panorama and Virtual Tour Builder v9.0.3
9.1.1 9.1.0 9.0.3 9.0.2 9.0.1 9.0.0 8.5.79 8.5.78 8.5.77 8.5.76 8.5.75 8.5.74 8.5.73 8.5.72 8.5.71 8.5.70 8.5.69 8.5.68 8.5.35 8.5.36 8.5.37 8.5.38 8.5.39 8.5.4 8.5.40 All 220 releases
wpvr / src / Admin / Admin.php

Admin.php in WP VR – 360 Panorama and Virtual Tour Builder 9.0.3, at src/Admin/Admin.php

599 lines 24.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace RexTheme\WPVR\Admin;
4
5 /**
6 * Manages the custom tour-editor admin page and CPT edit suppression.
7 *
8 * Step 1 — Register hidden admin page (wpvr-tour-editor).
9 * Step 2 — Redirect post.php / post-new.php for wpvr_item to custom page.
10 * Step 3 — Override edit links in WP posts list.
11 * Step 4 — Render page shell (#wpvr-tour-editor-root) + enqueue assets.
12 * Step 5 — New tour: React creates post on mount; history.replaceState URL.
13 */
14 class Admin {
15
16 const POST_TYPE = 'wpvr_item';
17 const PAGE_SLUG = 'wpvr-tour-editor';
18 const HOOK_SUFFIX = 'admin_page_wpvr-tour-editor';
19
20 private $editor_enabled;
21
22 public function __construct( bool $editor_enabled = true ) {
23 $this->editor_enabled = $editor_enabled;
24
25 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_listing_assets' ] );
26
27 if ( $this->editor_enabled ) {
28 add_action( 'admin_footer', [ $this, 'render_listing_modal' ] );
29 }
30
31 if ( ! $this->editor_enabled ) {
32 return;
33 }
34
35 add_action( 'admin_menu', [ $this, 'register_editor_page' ] );
36 add_action( 'load-post.php', [ $this, 'redirect_cpt_edit' ] );
37 add_action( 'load-post-new.php', [ $this, 'redirect_cpt_new' ] );
38 add_filter( 'get_edit_post_link', [ $this, 'filter_edit_link' ], 10, 3 );
39 add_filter( 'post_row_actions', [ $this, 'filter_row_actions' ], 10, 2 );
40 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_tour_editor_assets' ] );
41 add_filter( 'admin_body_class', [ $this, 'add_body_class' ] );
42 add_filter( 'admin_title', [ $this, 'filter_admin_title' ], 10, 2 );
43 add_action( 'current_screen', [ $this, 'set_screen_title' ] );
44 add_filter( 'parent_file', [ $this, 'set_menu_parent' ] );
45 add_filter( 'submenu_file', [ $this, 'set_menu_submenu' ] );
46 add_action( 'admin_head', [ $this, 'editor_head_scripts' ] );
47 add_action( 'admin_footer', [ $this, 'editor_footer_scripts' ] );
48 }
49
50 // -------------------------------------------------------------------------
51 // Step 1 — Register hidden admin page
52 // -------------------------------------------------------------------------
53
54 public function register_editor_page(): void {
55 $tour_id = isset( $_GET['tour_id'] ) ? (int) $_GET['tour_id'] : 0;
56 $page_title = $tour_id
57 ? __( 'Edit Tour', 'wpvr' )
58 : __( 'Add New Tour', 'wpvr' );
59
60 $post_type_obj = get_post_type_object( self::POST_TYPE );
61 $capability = $post_type_obj ? $post_type_obj->cap->edit_posts : 'edit_wpvr_tours';
62
63 add_submenu_page(
64 '',
65 $page_title,
66 $page_title,
67 $capability,
68 self::PAGE_SLUG,
69 [ $this, 'render_editor_page' ]
70 );
71 }
72
73 // -------------------------------------------------------------------------
74 // Step 2 — Redirect post.php / post-new.php
75 // -------------------------------------------------------------------------
76
77 public function redirect_cpt_edit(): void {
78 $action = isset( $_GET['action'] ) ? sanitize_key( $_GET['action'] ) : '';
79 if ( $action && $action !== 'edit' ) {
80 return;
81 }
82 $post_id = isset( $_GET['post'] ) ? (int) $_GET['post'] : 0;
83 if ( ! $post_id ) {
84 return;
85 }
86 $post = get_post( $post_id );
87 if ( ! $post || $post->post_type !== self::POST_TYPE ) {
88 return;
89 }
90 wp_redirect( $this->editor_url( $post_id ) );
91 exit;
92 }
93
94 public function redirect_cpt_new(): void {
95 $post_type = isset( $_GET['post_type'] ) ? sanitize_key( $_GET['post_type'] ) : '';
96 if ( $post_type !== self::POST_TYPE ) {
97 return;
98 }
99 wp_redirect( $this->editor_url() );
100 exit;
101 }
102
103 // -------------------------------------------------------------------------
104 // Step 3 — Override edit links
105 // -------------------------------------------------------------------------
106
107 public function filter_edit_link( string $url, int $post_id, string $context ): string {
108 $post = get_post( $post_id );
109 if ( ! $post || $post->post_type !== self::POST_TYPE ) {
110 return $url;
111 }
112 return $this->editor_url( $post_id );
113 }
114
115 public function filter_row_actions( array $actions, \WP_Post $post ): array {
116 if ( $post->post_type !== self::POST_TYPE ) {
117 return $actions;
118 }
119 if ( isset( $actions['edit'] ) ) {
120 $actions['edit'] = sprintf(
121 '<a href="%s">%s</a>',
122 esc_url( $this->editor_url( $post->ID ) ),
123 __( 'Edit', 'wpvr' )
124 );
125 }
126 return $actions;
127 }
128
129 // -------------------------------------------------------------------------
130 // Step 4 — Render + enqueue
131 // -------------------------------------------------------------------------
132
133 public function render_editor_page(): void {
134 $tour_id = isset( $_GET['tour_id'] ) ? (int) $_GET['tour_id'] : 0;
135 if ( $tour_id ) {
136 $post = get_post( $tour_id );
137 if ( ! $post || $post->post_type !== self::POST_TYPE || ! current_user_can( 'edit_post', $tour_id ) ) {
138 wp_die( esc_html__( 'Sorry, you are not allowed to edit this tour.', 'wpvr' ), 403 );
139 }
140 }
141
142 echo '<div id="wpvr-tour-editor-root"></div>';
143
144 if ( ! wpvr_is_pro_active() ) {
145 require WPVR_PLUGIN_LEGACY_DIR_PATH . 'admin/partials/wpvr-premium-feature-popup.php';
146 }
147
148 // Hidden wp_editor() output forces TinyMCE HTML/scripts to load so
149 // wp.editor.initialize() is available for WYSIWYG fields in React.
150 echo '<div style="display:none">';
151 wp_editor( '', 'wpvr_wysiwyg_seed', [
152 'tinymce' => true,
153 'quicktags' => false,
154 'media_buttons' => false,
155 ] );
156 echo '</div>';
157 }
158
159 public function enqueue_tour_editor_assets( string $hook ): void {
160 if ( ! $this->is_editor_page( $hook ) ) {
161 return;
162 }
163
164 $tour_id_cfg = isset( $_GET['tour_id'] ) ? (int) $_GET['tour_id'] : 0;
165 if ( $tour_id_cfg ) {
166 $post = get_post( $tour_id_cfg );
167 if ( ! $post || $post->post_type !== self::POST_TYPE || ! current_user_can( 'edit_post', $tour_id_cfg ) ) {
168 return;
169 }
170 }
171
172 $plugin_url = plugin_dir_url( WPVR_FILE );
173 $plugin_path = plugin_dir_path( WPVR_FILE );
174 $build_dir = $plugin_path . 'build/tour-editor/';
175
176 // Load Pannellum (from legacy bundle).
177 $pano_base = $plugin_url . 'legacy/admin/lib/pannellum/src/';
178 wp_enqueue_style( 'wpvr-pannellum-css', $pano_base . 'css/pannellum.css', [], WPVR_VERSION );
179 wp_enqueue_script( 'wpvr-libpannellum', $pano_base . 'js/libpannellum.js', [], WPVR_VERSION, true );
180 wp_enqueue_script( 'wpvr-pannellum', $pano_base . 'js/pannellum.js', [ 'wpvr-libpannellum' ], WPVR_VERSION, true );
181
182 wp_enqueue_style( 'wpvr-fontawesome', $plugin_url . 'legacy/admin/lib/fontawesome/css/all.min.css', [], WPVR_VERSION );
183
184 // Tour editor React bundle.
185 $js_file = $build_dir . 'index.js';
186 $css_file = $build_dir . 'style-index.css';
187 $asset_file = $build_dir . 'index.asset.php';
188
189 if ( ! file_exists( $js_file ) ) {
190 return;
191 }
192
193 $asset = file_exists( $asset_file )
194 ? require $asset_file
195 : [ 'dependencies' => [ 'wp-element', 'wp-data', 'wp-api-fetch' ], 'version' => WPVR_VERSION ];
196
197 wp_enqueue_script(
198 'wpvr-tour-editor',
199 $plugin_url . 'build/tour-editor/index.js',
200 array_merge( $asset['dependencies'], [ 'wpvr-pannellum' ] ),
201 $asset['version'],
202 true
203 );
204
205 $tour_id_cfg = isset( $_GET['tour_id'] ) ? (int) $_GET['tour_id'] : 0;
206 $tour_status = $tour_id_cfg ? ( get_post_status( $tour_id_cfg ) ?: 'draft' ) : 'draft';
207
208 $fa_icons = [];
209 if ( class_exists( 'Wpvr_fontawesome_icons' ) ) {
210 $fa_icons = ( new \Wpvr_fontawesome_icons() )->icon;
211 }
212
213 wp_localize_script( 'wpvr-tour-editor', 'wpvrTourEditor', [
214 'tourId' => $tour_id_cfg ?: null,
215 'tourStatus' => $tour_status,
216 'nonce' => wp_create_nonce( 'wp_rest' ),
217 'apiBase' => rest_url( 'wpvr/v1' ),
218 'mediaUrl' => rest_url( 'wp/v2/media' ),
219 'isPro' => wpvr_is_pro_active(),
220 'pluginUrl' => $plugin_url,
221 'listUrl' => admin_url( 'edit.php?post_type=' . self::POST_TYPE ),
222 'postEditUrl' => admin_url( 'post.php' ),
223 'faIcons' => $fa_icons,
224 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
225 'exportNonce' => wp_create_nonce( 'wpvr_export_tour' ),
226 'imageResizeWarning' => [
227 'ajaxNonce' => wp_create_nonce( 'wpvr' ),
228 'canManageSettings' => current_user_can( 'manage_options' ),
229 'settingEnabled' => get_option( 'high_res_image' ) === 'true',
230 'heading' => __( 'Keep this panorama in High Resolution', 'wpvr' ),
231 'scaledMessage' => __( 'By default, a resized version is created while the original image is still available.', 'wpvr' ),
232 'disableHandler' => __( 'Disable WordPress Large Image Handler on WP VR for future uploads', 'wpvr' ),
233 'highResolutionNote'=> __( '*Note: Turn this on to use the high-resolution image.', 'wpvr' ),
234 'close' => __( 'Close', 'wpvr' ),
235 ],
236 ] );
237
238 if ( file_exists( $css_file ) ) {
239 wp_enqueue_style(
240 'wpvr-tour-editor',
241 $plugin_url . 'build/tour-editor/style-index.css',
242 [ 'wpvr-pannellum-css' ],
243 $asset['version']
244 );
245 }
246 }
247
248 public function filter_admin_title( string $admin_title, string $title ): string {
249 if ( ! isset( $_GET['page'] ) || sanitize_key( $_GET['page'] ) !== self::PAGE_SLUG ) {
250 return $admin_title;
251 }
252 $tour_id = isset( $_GET['tour_id'] ) ? (int) $_GET['tour_id'] : 0;
253 $page_title = $tour_id ? __( 'Edit Tour', 'wpvr' ) : __( 'Add New Tour', 'wpvr' );
254 return $page_title . ' &lsaquo; ' . get_bloginfo( 'name' ) . ' &#8212; WordPress';
255 }
256
257 public function add_body_class( string $classes ): string {
258 if ( isset( $_GET['page'] ) && sanitize_key( $_GET['page'] ) === self::PAGE_SLUG ) {
259 $classes .= ' wpvr-tour-editor-page';
260 }
261 return $classes;
262 }
263
264 public function set_menu_parent( string $parent_file ): string {
265 if ( isset( $_GET['page'] ) && sanitize_key( $_GET['page'] ) === self::PAGE_SLUG ) {
266 return 'edit.php?post_type=' . self::POST_TYPE;
267 }
268 return $parent_file;
269 }
270
271 public function set_menu_submenu( ?string $submenu_file ): ?string {
272 if ( isset( $_GET['page'] ) && sanitize_key( $_GET['page'] ) === self::PAGE_SLUG ) {
273 return 'post-new.php?post_type=' . self::POST_TYPE;
274 }
275 return $submenu_file;
276 }
277
278 public function editor_head_scripts(): void {
279 if ( ! isset( $_GET['page'] ) || sanitize_key( $_GET['page'] ) !== self::PAGE_SLUG ) {
280 return;
281 }
282 ?>
283 <script>
284 ( function() {
285 var narrowEditor = window.matchMedia( '(max-width: 1279px)' );
286
287 function applyEditorMenuState() {
288 if ( ! document.body ) {
289 window.requestAnimationFrame( applyEditorMenuState );
290 return;
291 }
292
293 document.body.classList.toggle( 'folded', narrowEditor.matches );
294 }
295
296 applyEditorMenuState();
297
298 if ( narrowEditor.addEventListener ) {
299 narrowEditor.addEventListener( 'change', applyEditorMenuState );
300 } else {
301 narrowEditor.addListener( applyEditorMenuState );
302 }
303 }() );
304 </script>
305 <?php
306 }
307
308 public function editor_footer_scripts(): void {
309 if ( ! isset( $_GET['page'] ) || sanitize_key( $_GET['page'] ) !== self::PAGE_SLUG ) {
310 return;
311 }
312 ?>
313 <script>
314 jQuery( window ).on( 'load', function() {
315 // Intercept WP sidebar toggle so it doesn't persist state to user meta.
316 // The editor's initial state is viewport-dependent; manual toggling should
317 // work visually but must not overwrite the user's real preference.
318 jQuery( '#collapse-button' ).off( 'click' ).on( 'click', function() {
319 jQuery( 'body' ).toggleClass( 'folded' );
320 } );
321 } );
322 </script>
323 <?php
324 }
325
326 public function render_mode_switch_notice(): void {
327 if ( ! current_user_can( 'edit_posts' ) ) {
328 return;
329 }
330
331 if ( ! $this->is_listing_page() && ! $this->is_editor_request() ) {
332 return;
333 }
334
335 $tour_id = isset( $_GET['tour_id'] ) ? absint( $_GET['tour_id'] ) : 0;
336 $switch_url = $this->get_ui_mode_switch_url( 'legacy', $tour_id );
337 $button_label = __( 'Switch to Classic UI', 'wpvr' );
338 ?>
339 <div class="notice notice-info">
340 <p>
341 <?php esc_html_e( 'You are using the latest WP VR editor.', 'wpvr' ); ?>
342 <a class="button button-secondary" href="<?php echo esc_url( $switch_url ); ?>" style="margin-left:8px;">
343 <?php echo esc_html( $button_label ); ?>
344 </a>
345 </p>
346 </div>
347 <?php
348 }
349
350 public function handle_ui_mode_switch(): void {
351 if ( ! current_user_can( 'edit_posts' ) ) {
352 wp_die( esc_html__( 'You are not allowed to switch UI modes.', 'wpvr' ) );
353 }
354
355 check_admin_referer( 'wpvr_switch_ui_mode' );
356
357 $mode = isset( $_GET['mode'] ) && sanitize_key( $_GET['mode'] ) === 'latest' ? 'latest' : 'legacy';
358 $tour_id = isset( $_GET['tour_id'] ) ? absint( $_GET['tour_id'] ) : 0;
359
360 update_option( 'wpvr_ui_mode', $mode );
361
362 wp_safe_redirect( $this->get_ui_mode_redirect_url( $mode, $tour_id ) );
363 exit;
364 }
365
366 // -------------------------------------------------------------------------
367 // Step 5 — Set $title global so admin-header.php doesn't get null
368 // -------------------------------------------------------------------------
369
370 public function set_screen_title( \WP_Screen $screen ): void {
371 if ( $screen->id !== 'admin_page_' . self::PAGE_SLUG ) {
372 return;
373 }
374 global $title;
375 $tour_id = isset( $_GET['tour_id'] ) ? (int) $_GET['tour_id'] : 0;
376 $title = $tour_id ? __( 'Edit Tour', 'wpvr' ) : __( 'Add New Tour', 'wpvr' );
377 }
378
379 // -------------------------------------------------------------------------
380 // Helpers
381 // -------------------------------------------------------------------------
382
383 private function editor_url( int $post_id = 0 ): string {
384 $args = [ 'page' => self::PAGE_SLUG ];
385 if ( $post_id > 0 ) {
386 $args['tour_id'] = $post_id;
387 }
388 return add_query_arg( $args, admin_url( 'admin.php' ) );
389 }
390
391 private function is_editor_page( string $hook ): bool {
392 return $hook === self::HOOK_SUFFIX
393 || ( isset( $_GET['page'] ) && sanitize_key( $_GET['page'] ) === self::PAGE_SLUG );
394 }
395
396 private function is_editor_request(): bool {
397 return isset( $_GET['page'] ) && sanitize_key( $_GET['page'] ) === self::PAGE_SLUG;
398 }
399
400 private function is_listing_page(): bool {
401 $screen = get_current_screen();
402 return $screen && $screen->id === 'edit-' . self::POST_TYPE;
403 }
404
405 private function get_ui_mode_switch_url( string $mode, int $tour_id = 0 ): string {
406 $args = [
407 'action' => 'wpvr_switch_ui_mode',
408 'mode' => $mode,
409 ];
410
411 if ( $tour_id > 0 ) {
412 $args['tour_id'] = $tour_id;
413 }
414
415 return wp_nonce_url( add_query_arg( $args, admin_url( 'admin-post.php' ) ), 'wpvr_switch_ui_mode' );
416 }
417
418 private function get_ui_mode_redirect_url( string $mode, int $tour_id = 0 ): string {
419 if ( $mode === 'latest' ) {
420 return $this->editor_url( $tour_id );
421 }
422
423 if ( $tour_id > 0 ) {
424 return add_query_arg(
425 [
426 'post' => $tour_id,
427 'action' => 'edit',
428 ],
429 admin_url( 'post.php' )
430 );
431 }
432
433 return admin_url( 'edit.php?post_type=' . self::POST_TYPE );
434 }
435
436 // -------------------------------------------------------------------------
437 // Listing page — Create Tour modal
438 // -------------------------------------------------------------------------
439
440 public function enqueue_listing_assets( string $hook ): void {
441 if ( ! $this->is_listing_page() ) {
442 return;
443 }
444
445 $plugin_url = plugin_dir_url( WPVR_FILE );
446 $style_dependencies = [];
447 $script_dependencies = [];
448
449 if ( $this->editor_enabled ) {
450 wp_enqueue_style(
451 'wpvr-create-tour-modal',
452 $plugin_url . 'app/admin/create-tour-modal.css',
453 [],
454 WPVR_VERSION
455 );
456
457 wp_enqueue_script(
458 'wpvr-create-tour-modal',
459 $plugin_url . 'app/admin/create-tour-modal.js',
460 [],
461 WPVR_VERSION,
462 true
463 );
464
465 wp_localize_script( 'wpvr-create-tour-modal', 'wpvrListingModal', [
466 'nonce' => wp_create_nonce( 'wp_rest' ),
467 'apiBase' => rest_url( 'wpvr/v1' ),
468 'editorUrl' => admin_url( 'admin.php?page=' . self::PAGE_SLUG ),
469 'isPro' => wpvr_is_pro_active(),
470 'iconsUrl' => $plugin_url . 'app/assets/icons/tour-types/',
471 ] );
472
473 $style_dependencies[] = 'wpvr-create-tour-modal';
474 $script_dependencies[] = 'wpvr-create-tour-modal';
475 }
476
477 wp_enqueue_style(
478 'wpvr-tour-listing',
479 $plugin_url . 'app/admin/tour-listing.css',
480 $style_dependencies,
481 WPVR_VERSION
482 );
483
484 wp_enqueue_script(
485 'wpvr-tour-listing',
486 $plugin_url . 'app/admin/tour-listing.js',
487 $script_dependencies,
488 WPVR_VERSION,
489 true
490 );
491 }
492
493 public function render_listing_modal(): void {
494 if ( ! $this->editor_enabled || ! $this->is_listing_page() ) {
495 return;
496 }
497
498 $is_pro = apply_filters( 'is_wpvr_pro_active', false ) && get_option( 'wpvr_edd_license_status' ) === 'valid';
499 $icons_url = plugin_dir_url( WPVR_FILE ) . 'app/assets/icons/tour-types/';
500 ?>
501 <div id="wpvr-ctm-overlay" class="wpvr-ctm-overlay" style="display:none;" role="dialog" aria-modal="true" aria-label="Create New Tour">
502 <div class="wpvr-ctm">
503
504 <header class="wpvr-ctm__header">
505 <div>
506 <h2 class="wpvr-ctm__title"><?php esc_html_e( 'Create New Tour', 'wpvr' ); ?></h2>
507 <p class="wpvr-ctm__subtitle"><?php esc_html_e( 'Choose your tour type and get started', 'wpvr' ); ?></p>
508 </div>
509 <button class="wpvr-ctm__close" id="wpvr-ctm-close" type="button" aria-label="<?php esc_attr_e( 'Close', 'wpvr' ); ?>">×</button>
510 </header>
511
512 <div class="wpvr-ctm__body">
513
514 <div class="wpvr-ctm__field">
515 <label for="wpvr-ctm-name" class="wpvr-ctm__label">
516 <?php esc_html_e( 'Tour Name', 'wpvr' ); ?>
517 <span class="wpvr-ctm__required">*</span>
518 </label>
519 <input
520 type="text"
521 id="wpvr-ctm-name"
522 class="wpvr-ctm__input"
523 placeholder="<?php esc_attr_e( 'Enter tour name...', 'wpvr' ); ?>"
524 autocomplete="off"
525 />
526 <span class="wpvr-ctm__error" id="wpvr-ctm-name-error" style="display:none;">
527 <?php esc_html_e( 'Tour name is required.', 'wpvr' ); ?>
528 </span>
529 </div>
530
531 <div class="wpvr-ctm__field">
532 <label class="wpvr-ctm__label">
533 <?php esc_html_e( 'Tour Type', 'wpvr' ); ?>
534 <span class="wpvr-ctm__required">*</span>
535 </label>
536 <div class="wpvr-ctm__cards">
537
538 <?php /* 360° Image — always free, selected by default */ ?>
539 <button type="button" class="wpvr-ctm__card wpvr-ctm__card--selected" data-type="image">
540 <img class="wpvr-ctm__card-icon"
541 src="<?php echo esc_url( $icons_url . 'scene-image-filled.svg' ); ?>"
542 data-active="<?php echo esc_url( $icons_url . 'scene-image-filled.svg' ); ?>"
543 data-inactive="<?php echo esc_url( $icons_url . 'scene-image.svg' ); ?>"
544 alt="" />
545 <span class="wpvr-ctm__card-title"><?php esc_html_e( '360° Image', 'wpvr' ); ?></span>
546 <span class="wpvr-ctm__card-desc"><?php esc_html_e( 'Create immersive panoramic image tours', 'wpvr' ); ?></span>
547 <span class="wpvr-ctm__card-radio wpvr-ctm__card-radio--checked"></span>
548 </button>
549
550 <?php /* 360° Video — free */ ?>
551 <button type="button" class="wpvr-ctm__card" data-type="video">
552 <img class="wpvr-ctm__card-icon"
553 src="<?php echo esc_url( $icons_url . 'scene-video.svg' ); ?>"
554 data-active="<?php echo esc_url( $icons_url . 'scene-video-filled.svg' ); ?>"
555 data-inactive="<?php echo esc_url( $icons_url . 'scene-video.svg' ); ?>"
556 alt="" />
557 <span class="wpvr-ctm__card-title"><?php esc_html_e( '360° Video', 'wpvr' ); ?></span>
558 <span class="wpvr-ctm__card-desc"><?php esc_html_e( 'Build dynamic video-based experiences', 'wpvr' ); ?></span>
559 <span class="wpvr-ctm__card-radio"></span>
560 </button>
561
562 <?php /* Street View — PRO only */ ?>
563 <button type="button" class="wpvr-ctm__card<?php echo $is_pro ? '' : ' wpvr-ctm__card--disabled'; ?>"
564 data-type="street-view"
565 <?php echo $is_pro ? '' : 'disabled'; ?>
566 title="<?php echo $is_pro ? '' : esc_attr__( 'Requires WP VR Pro', 'wpvr' ); ?>">
567 <?php if ( ! $is_pro ) : ?>
568 <span class="is-pro" aria-hidden="true">Pro</span>
569 <?php endif; ?>
570 <img class="wpvr-ctm__card-icon"
571 src="<?php echo esc_url( $icons_url . 'scene-street.svg' ); ?>"
572 data-active="<?php echo esc_url( $icons_url . 'scene-street-filled.svg' ); ?>"
573 data-inactive="<?php echo esc_url( $icons_url . 'scene-street.svg' ); ?>"
574 alt="" />
575 <span class="wpvr-ctm__card-title"><?php esc_html_e( 'Street View', 'wpvr' ); ?></span>
576 <span class="wpvr-ctm__card-desc"><?php esc_html_e( 'Integrate Google Street View locations', 'wpvr' ); ?></span>
577 <span class="wpvr-ctm__card-radio"></span>
578 </button>
579
580 </div>
581 </div>
582
583 </div>
584
585 <div class="wpvr-ctm__footer">
586 <button type="button" class="wpvr-ctm__btn wpvr-ctm__btn--secondary" id="wpvr-ctm-cancel">
587 <?php esc_html_e( 'Cancel', 'wpvr' ); ?>
588 </button>
589 <button type="button" class="wpvr-ctm__btn wpvr-ctm__btn--primary" id="wpvr-ctm-submit">
590 <?php esc_html_e( '+ Create Tour', 'wpvr' ); ?>
591 </button>
592 </div>
593
594 </div>
595 </div>
596 <?php
597 }
598 }
599