PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 4.6.5
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v4.6.5
4.6.5 4.6.4 4.6.3 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / EmbedPress / Ends / Back / Settings / EmbedpressSettings.php
embedpress / EmbedPress / Ends / Back / Settings Last commit date
templates 1 month ago EmbedpressSettings.php 5 days ago
EmbedpressSettings.php
1037 lines
1 <?php
2 namespace EmbedPress\Ends\Back\Settings;
3
4 use EmbedPress\Includes\Classes\Helper;
5 use EmbedPress\Includes\Classes\EmbedPress_Plugin_Usage_Tracker;
6
7 class EmbedpressSettings {
8 var $page_slug = '';
9 /**
10 * @var int|string
11 */
12 protected $file_version;
13
14 public function __construct($page_slug = 'embedpress') {
15 $this->page_slug = $page_slug;
16 $this->file_version = defined( 'WP_DEBUG') && WP_DEBUG ? time() : EMBEDPRESS_VERSION;
17
18 // One-time install-type detection. Must run before any default settings are
19 // written below, otherwise every site looks "non-empty" by the time the
20 // activation hook fires. Existing users keep the 'existing' marker; only
21 // truly fresh sites get marked 'fresh' and will be eligible for the wizard.
22 if ( ! get_option( 'embedpress_install_type', false ) ) {
23 $had_prior_data = (bool) get_option( 'embedpress_elements_updated', false )
24 || ! empty( get_option( EMBEDPRESS_PLG_NAME, [] ) )
25 || ! empty( get_option( EMBEDPRESS_PLG_NAME . ':elements', [] ) );
26 update_option( 'embedpress_install_type', $had_prior_data ? 'existing' : 'fresh' );
27
28 // Existing users may carry a stuck need_first_time_redirect flag set by
29 // an earlier buggy migration. Clear it so they aren't dropped into the
30 // wizard after updating to this version.
31 if ( $had_prior_data ) {
32 $prior_settings = get_option( EMBEDPRESS_PLG_NAME, [] );
33 if ( isset( $prior_settings['need_first_time_redirect'] ) ) {
34 unset( $prior_settings['need_first_time_redirect'] );
35 update_option( EMBEDPRESS_PLG_NAME, $prior_settings );
36 }
37 }
38 }
39
40 add_action('admin_menu', [$this, 'register_menu']);
41 add_action( 'init', [$this, 'save_settings']);
42
43 // Add activation redirect hook
44 add_action( 'admin_init', [$this, 'embedpress_maybe_redirect_to_settings']);
45
46 // ajax
47 add_action( 'wp_ajax_embedpress_elements_action', [$this, 'update_elements_list']);
48 add_action( 'wp_ajax_embedpress_settings_action', [$this, 'save_settings']);
49 add_action( 'wp_ajax_save_global_brand_image', [$this, 'save_global_brand_image']);
50 add_action( 'wp_ajax_embedpress_dismiss_element', [$this, 'dismiss_element']);
51 add_action( 'wp_ajax_embedpress_dismiss_feature_notice', [$this, 'dismiss_feature_notice']);
52 add_action( 'wp_ajax_embedpress_save_onboarding', [$this, 'save_onboarding_settings']);
53 add_action( 'wp_ajax_embedpress_install_site_performance', [$this, 'install_site_performance']);
54
55 // Hide all admin notices on onboarding page
56 add_action( 'in_admin_header', function() {
57 if ( isset( $_GET['page'] ) && $_GET['page'] === 'embedpress-onboarding' ) {
58 remove_all_actions( 'admin_notices' );
59 remove_all_actions( 'all_admin_notices' );
60 }
61 }, 999 );
62
63 $g_settings = get_option( EMBEDPRESS_PLG_NAME, [] );
64
65 if(!isset($g_settings['turn_off_rating_help'])){
66 $g_settings['turn_off_rating_help'] = true;
67 update_option(EMBEDPRESS_PLG_NAME, $g_settings);
68 }
69 if(!isset($g_settings['turn_off_milestone'])){
70 $g_settings['turn_off_milestone'] = true;
71 update_option(EMBEDPRESS_PLG_NAME, $g_settings);
72 }
73
74 // Set default value for embedpress_document_powered_by to 'yes' on fresh installations
75 if(!isset($g_settings['embedpress_document_powered_by'])){
76 $g_settings['embedpress_document_powered_by'] = 'yes';
77 update_option(EMBEDPRESS_PLG_NAME, $g_settings);
78 }
79
80
81 // Migration
82 $option = 'embedpress_elements_updated'; // to update initially for backward compatibility
83 if ( !get_option( $option, false) ) {
84 $elements_initial_states = [
85 'gutenberg' => [
86 'google-docs-block' => 'google-docs-block',
87 'document' => 'document',
88 'embedpress' => 'embedpress',
89 'embedpress-pdf' => 'embedpress-pdf',
90 'google-sheets-block' => 'google-sheets-block',
91 'google-slides-block' => 'google-slides-block',
92 'youtube-block' => 'youtube-block',
93 'google-forms-block' => 'google-forms-block',
94 'google-drawings-block' => 'google-drawings-block',
95 'google-maps-block' => 'google-maps-block',
96 'twitch-block' => 'twitch-block',
97 'wistia-block' => 'wistia-block',
98 'vimeo-block' => 'vimeo-block',
99 'pdf-gallery' => 'pdf-gallery',
100 'google-reviews' => 'google-reviews',
101 ],
102 'elementor' => [
103 'embedpress-document' => 'embedpress-document',
104 'embedpress' => 'embedpress',
105 'embedpress-pdf' => 'embedpress-pdf',
106 'embedpress-google-reviews' => 'embedpress-google-reviews',
107 ]
108 ];
109
110
111 $settings = get_option( EMBEDPRESS_PLG_NAME, [] );
112 $yt = get_option( EMBEDPRESS_PLG_NAME.':youtube' );
113 if ( empty( $settings) && empty( $yt) ) {
114 $settings['need_first_time_redirect'] = true;
115 }
116 if ( !isset( $settings['enablePluginInAdmin']) ) {
117 $settings['enablePluginInAdmin'] = 1;
118 }
119 if ( !isset( $settings['enablePluginInFront']) ) {
120 $settings['enablePluginInFront'] = 1;
121 }
122
123 update_option( EMBEDPRESS_PLG_NAME.":elements", $elements_initial_states);
124 update_option( EMBEDPRESS_PLG_NAME, $settings);
125 update_option( $option, true);
126 }
127 $migration_v_320 = 'embedpress_v_320_migration';
128 if ( !get_option( $migration_v_320, false) ) {
129 $elements = (array) get_option( EMBEDPRESS_PLG_NAME.":elements", []);
130 $elements['gutenberg']['embedpress-pdf'] = 'embedpress-pdf';
131 $elements['elementor']['embedpress-pdf'] = 'embedpress-pdf';
132 update_option( EMBEDPRESS_PLG_NAME.":elements", $elements);
133 update_option( $migration_v_320, true);
134 }
135
136 $migration_v_330 = 'embedpress_v_330_migration';
137 if ( !get_option( $migration_v_330, false) ) {
138 $elements = (array) get_option( EMBEDPRESS_PLG_NAME.":elements", []);
139 $elements['gutenberg']['embedpress-calendar'] = 'embedpress-calendar';
140 $elements['elementor']['embedpress-calendar'] = 'embedpress-calendar';
141 update_option( EMBEDPRESS_PLG_NAME.":elements", $elements);
142 update_option( $migration_v_330, true);
143 }
144
145 }
146 function embedpress_maybe_redirect_to_settings() {
147 $settings = get_option( EMBEDPRESS_PLG_NAME, [] );
148 if ( isset( $settings['need_first_time_redirect']) && $settings['need_first_time_redirect'] ) {
149 // Skip redirect if already done, doing AJAX, or in certain admin contexts
150 if ( get_option( 'embedpress_activation_redirect_done' ) || wp_doing_ajax() || wp_doing_cron() ) {
151 return;
152 }
153
154 // Skip redirect for bulk activations, network admin, or CLI
155 if ( is_network_admin() || isset( $_GET['activate-multi'] ) || defined( 'WP_CLI' ) ) {
156 return;
157 }
158
159 // Skip redirect if not in admin area or if user doesn't have proper capabilities
160 if ( ! is_admin() || ! current_user_can( 'manage_options' ) ) {
161 return;
162 }
163
164 // Skip redirect if we're already on the EmbedPress settings or onboarding page
165 if ( isset( $_GET['page'] ) && in_array( $_GET['page'], [ $this->page_slug, 'embedpress-onboarding' ], true ) ) {
166 return;
167 }
168
169 // If onboarding is not complete and pro is not active, redirect to onboarding wizard
170 $pro_active = apply_filters( 'embedpress/is_allow_rander', false );
171 if ( ! $pro_active && ! get_option( 'embedpress_onboarding_complete', false ) ) {
172 update_option( 'embedpress_activation_redirect_done', true );
173 $settings['need_first_time_redirect'] = false;
174 update_option( EMBEDPRESS_PLG_NAME, $settings );
175
176 wp_safe_redirect( admin_url( 'admin.php?page=embedpress-onboarding' ) );
177 exit;
178 }
179
180 // Set redirect done flag and clear the redirect trigger
181 update_option( 'embedpress_activation_redirect_done', true );
182 $settings['need_first_time_redirect'] = false;
183 update_option( EMBEDPRESS_PLG_NAME, $settings);
184
185 // Perform the redirect
186 wp_safe_redirect( admin_url('admin.php?page='.$this->page_slug) );
187 exit;
188 }
189 }
190 public function update_elements_list() {
191
192 if (!current_user_can('manage_options')) {
193 wp_send_json_error(array('message' => 'You do not have sufficient permissions to access this functionality.'));
194 return;
195 }
196
197 if ( !empty($_POST['_wpnonce'] && wp_verify_nonce( $_POST['_wpnonce'], 'embedpress_elements_action')) ) {
198 $option = EMBEDPRESS_PLG_NAME.":elements";
199 $elements = (array) get_option( $option, []);
200 $settings = (array) get_option( EMBEDPRESS_PLG_NAME, []);
201
202 $type = !empty( $_POST['element_type']) ? sanitize_text_field( $_POST['element_type']) : '';
203 $name = !empty( $_POST['element_name']) ? sanitize_text_field( $_POST['element_name']) : '';
204 $checked = !empty( $_POST['checked']) ? $_POST['checked'] : false;
205 if ( 'false' != $checked ) {
206 $elements[$type][$name] = $name;
207 if ( $type === 'classic' ) {
208 $settings[$name] = 1;
209 }
210 }else{
211 if( isset( $elements[$type]) && isset( $elements[$type][$name])){
212 unset( $elements[$type][$name]);
213 }
214 if ( $type === 'classic' ) {
215 $settings[$name] = 0;
216 }
217 }
218 update_option( EMBEDPRESS_PLG_NAME, $settings);
219 update_option( $option, $elements);
220 wp_send_json_success();
221 }
222 wp_send_json_error();
223 }
224
225 public function register_menu() {
226 add_menu_page( __('EmbedPress Settings', 'embedpress'), __('EmbedPress', 'embedpress'), 'manage_options', $this->page_slug,
227 [ $this, 'render_settings_page' ], EMBEDPRESS_URL_ASSETS.'images/menu-icon.svg', 64 );
228
229 // Add Dashboard submenu (replaces the default first submenu item)
230 add_submenu_page( $this->page_slug, __('EmbedPress Dashboard', 'embedpress'), __('Dashboard', 'embedpress'), 'manage_options', $this->page_slug,
231 [ $this, 'render_settings_page' ] );
232
233 // Add Branding submenu
234 add_submenu_page( $this->page_slug, __('EmbedPress Branding', 'embedpress'), __('Branding', 'embedpress'), 'manage_options', $this->page_slug . '&page_type=custom-logo',
235 [ $this, 'render_settings_page' ] );
236
237 // Add Custom Ads submenu
238 add_submenu_page( $this->page_slug, __('EmbedPress Custom Ads', 'embedpress'), __('Custom Ads', 'embedpress'), 'manage_options', $this->page_slug . '&page_type=ads',
239 [ $this, 'render_settings_page' ] );
240
241
242 // Add Shortcode submenu
243 add_submenu_page( $this->page_slug, __('EmbedPress Shortcode', 'embedpress'), __('Shortcode', 'embedpress'), 'manage_options', $this->page_slug . '&page_type=shortcode',
244 [ $this, 'render_settings_page' ] );
245
246 // Add Settings submenu
247 add_submenu_page( $this->page_slug, __('EmbedPress Settings', 'embedpress'), __('Settings', 'embedpress'), 'manage_options', $this->page_slug . '&page_type=settings',
248 [ $this, 'render_settings_page' ] );
249
250
251 // Add License submenu (only if pro is active)
252 if ( apply_filters('embedpress/is_allow_rander', false) ) {
253 add_submenu_page( $this->page_slug, __('EmbedPress License', 'embedpress'), __('License', 'embedpress'), 'manage_options', $this->page_slug . '&page_type=license',
254 [ $this, 'render_settings_page' ] );
255 }
256
257 // Player & Engagement submenu — registered only when Pro is NOT active.
258 // When Pro IS active, Pro plugin's Admin_Page registers the real React
259 // page on the SAME slug (embedpress-player-engagement), so saved bookmarks
260 // and links keep working across the freemium boundary.
261 if ( ! apply_filters('embedpress/is_allow_rander', false) ) {
262 add_submenu_page(
263 $this->page_slug,
264 __('EmbedPress Player & Engagement', 'embedpress'),
265 __('Player & Engagement', 'embedpress'),
266 'manage_options',
267 'embedpress-player-engagement',
268 [ $this, 'render_player_engagement_page' ]
269 );
270 }
271
272 // Register Setup Wizard submenu page
273 add_submenu_page( $this->page_slug, __('EmbedPress Setup Wizard', 'embedpress'), __('Setup Wizard', 'embedpress'), 'manage_options', 'embedpress-onboarding',
274 [ $this, 'render_onboarding_page' ] );
275
276 // Add admin footer script to handle menu highlighting
277 add_action('admin_footer', [$this, 'admin_menu_highlight_script']);
278
279 // Pro badge styling for upsell submenu items
280 add_action('admin_head', function () {
281 echo '<style>
282 #adminmenu .ep-menu-pro-badge {
283 display: inline-block;
284 margin-left: 6px;
285 padding: 1px 6px;
286 font-size: 9px;
287 font-weight: 700;
288 line-height: 1.4;
289 letter-spacing: 0.4px;
290 color: #fff;
291 background: linear-gradient(90deg, #5b4e96 0%, #8a72d8 100%);
292 border-radius: 3px;
293 vertical-align: middle;
294 }
295 </style>';
296 });
297
298 // Add filter to reorder menu items - License should be last
299 add_filter('admin_menu', [$this, 'reorder_submenu_items'], 999);
300 }
301
302
303 public function admin_menu_highlight_script() {
304 // Only load on EmbedPress admin pages
305 $current_page = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : '';
306 if ($current_page !== $this->page_slug) {
307 return;
308 }
309
310 $page_type = isset($_GET['page_type']) ? sanitize_text_field($_GET['page_type']) : '';
311 // Fixed: Evaluate PHP filter on server-side before passing to JavaScript
312 $is_pro_active = apply_filters('embedpress/is_allow_rander', false);
313
314 ?>
315 <script type="text/javascript">
316 /* EmbedPress Admin Menu Highlight Script - Fixed apply_filters issue */
317 jQuery(document).ready(function($) {
318 // Remove current highlighting
319 $('#adminmenu .wp-submenu li').removeClass('current');
320 $('#adminmenu .wp-submenu a').removeClass('current');
321
322 var pageType = '<?php echo esc_js($page_type); ?>';
323 var isProActive = <?php echo $is_pro_active ? 'true' : 'false'; ?>;
324 var menuSelector = '';
325
326 // Map page types to menu selectors
327 switch(pageType) {
328 case 'settings':
329 menuSelector = 'a[href*="page_type=settings"]';
330 break;
331 case 'shortcode':
332 menuSelector = 'a[href*="page_type=shortcode"]';
333 break;
334 case 'sources':
335 menuSelector = 'a[href*="page_type=sources"]';
336 break;
337 case 'elements':
338 menuSelector = 'a[href*="page_type=elements"]';
339 break;
340 case 'custom-logo':
341 menuSelector = 'a[href*="page_type=custom-logo"]';
342 break;
343 case 'ads':
344 menuSelector = 'a[href*="page_type=ads"]';
345 break;
346 case 'license':
347 menuSelector = 'a[href*="page_type=license"]';
348 break;
349 default:
350 // Default to Dashboard (no page_type or hub)
351 menuSelector = 'a[href="admin.php?page=<?php echo esc_js($this->page_slug); ?>"]';
352 break;
353 }
354
355 // Highlight the correct menu item
356 if (menuSelector) {
357 var $menuItem = $('#adminmenu .wp-submenu ' + menuSelector);
358 if ($menuItem.length) {
359 $menuItem.addClass('current').parent().addClass('current');
360 }
361 }
362 });
363 </script>
364 <?php
365 }
366
367
368 public function render_settings_page( ) {
369 global $template, $page_slug, $nonce_field, $ep_page, $gen_menu_template_names, $brand_menu_template_names, $pro_active, $coming_soon, $success_message, $error_message, $platform_menu_template_names;
370
371 $page_slug = $this->page_slug; // make this available for included template
372 $template = !empty( $_GET['page_type'] ) ? sanitize_file_name( $_GET['page_type']) : 'hub';
373
374 $nonce_field = wp_nonce_field('ep_settings_nonce', 'ep_settings_nonce', true, false);
375 $ep_page = admin_url('admin.php?page='.$this->page_slug);
376 $gen_menu_template_names = apply_filters('ep_general_menu_tmpl_names', ['settings', 'shortcode',]);
377 $platform_menu_template_names = apply_filters('ep_platform_menu_tmpl_names', [ 'youtube', 'vimeo', 'wistia', 'twitch','dailymotion', 'soundcloud' ,'spotify','google-calendar','opensea']);
378 $brand_menu_template_names = apply_filters('ep_brand_menu_templates', ['custom-logo', 'branding',]);
379 $pro_active = apply_filters('embedpress/is_allow_rander', false);
380 $coming_soon = "<span class='ep-coming-soon'>". esc_html__( '(Coming soon)', 'embedpress'). "</span>";
381 $success_message = esc_html__( "Settings Updated", "embedpress" );
382 $error_message = esc_html__( "Ops! Something went wrong.", "embedpress" );
383 include_once EMBEDPRESS_SETTINGS_PATH . 'templates/main-template.php';
384 }
385
386 /**
387 * Render the free Player & Engagement landing page on the
388 * `embedpress-player-engagement` slug — same slug Pro's Admin_Page uses.
389 *
390 * The same `custom-player.build.js` React app mounts here. We localize
391 * `isProActive: false` so the app renders its UpgradePanel in the body
392 * instead of fetching engagement data from REST endpoints that don't
393 * exist on free.
394 */
395 public function render_player_engagement_page() {
396 if ( ! current_user_can( 'manage_options' ) ) {
397 return;
398 }
399
400 // AssetManager auto-enqueues custom-player.build.js + .css on this
401 // page slug. Just feed the React app its localize blob, matching
402 // the keys Pro's Admin_Page::render_page() uses.
403 wp_localize_script( 'embedpress-custom-player', 'embedpressCustomPlayerData', [
404 'restUrl' => esc_url_raw( rest_url( 'embedpress/v1/' ) ),
405 'nonce' => wp_create_nonce( 'wp_rest' ),
406 'adminUrl' => esc_url_raw( admin_url( 'admin.php' ) ),
407 'assetsUrl' => defined( 'EMBEDPRESS_URL_ASSETS' ) ? EMBEDPRESS_URL_ASSETS : '',
408 'isProActive' => false,
409 ] );
410
411 include_once EMBEDPRESS_SETTINGS_PATH . 'templates/player-engagement.php';
412 }
413
414 public function save_settings() {
415 // needs to check for ajax and return response accordingly.
416 if ( !empty( $_POST['ep_settings_nonce']) && wp_verify_nonce( $_POST['ep_settings_nonce'], 'ep_settings_nonce') ) {
417 $submit_type = !empty( $_POST['submit'] ) ? $_POST['submit'] : '';
418 $save_handler_method = "save_{$submit_type}_settings";
419 do_action( "before_{$save_handler_method}");
420 do_action( "before_embedpress_settings_save");
421 if ( method_exists( $this, $save_handler_method ) ) {
422 $this->$save_handler_method();
423 }
424 do_action( "after_embedpress_settings_save");
425 $return_url = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : admin_url();
426 $return_url = add_query_arg( 'success', 1, $return_url );
427 if ( wp_doing_ajax() ) {
428 wp_send_json_success();
429 }
430 wp_safe_redirect( $return_url);
431 exit();
432 }
433 }
434
435 public function save_settings_settings() {
436 $settings = (array) get_option( EMBEDPRESS_PLG_NAME, []);
437 $settings ['enableEmbedResizeWidth'] = isset( $_POST['enableEmbedResizeWidth']) ? intval( $_POST['enableEmbedResizeWidth']) : 600;
438 $settings ['enableEmbedResizeHeight'] = isset( $_POST['enableEmbedResizeHeight']) ? intval( $_POST['enableEmbedResizeHeight']) : 550;
439 $settings ['pdf_custom_color_settings'] = isset( $_POST['pdf_custom_color_settings']) ? intval( $_POST['pdf_custom_color_settings']) : 0;
440 $settings ['turn_off_rating_help'] = isset( $_POST['turn_off_rating_help']) ? intval( $_POST['turn_off_rating_help']) : 0;
441 $settings ['turn_off_milestone'] = isset( $_POST['turn_off_milestone']) ? intval( $_POST['turn_off_milestone']) : 0;
442
443 $settings ['custom_color'] = isset( $_POST['custom_color']) ? $_POST['custom_color'] : '#333333';
444
445 // Pro will handle g_loading_animation settings and other
446 // Keep backward compatibility with old filter names
447 $settings = apply_filters( 'ep_general_settings_before_save', $settings, $_POST);
448 $settings = apply_filters( 'ep_settings_settings_before_save', $settings, $_POST);
449
450 update_option( EMBEDPRESS_PLG_NAME, $settings);
451
452 // Keep backward compatibility with old action names
453 do_action( 'ep_general_settings_after_save', $settings, $_POST);
454 do_action( 'ep_settings_settings_after_save', $settings, $_POST);
455 }
456
457 // Keep backward compatibility method
458 public function save_general_settings() {
459 return $this->save_settings_settings();
460 }
461
462 public function save_youtube_settings() {
463 $option_name = EMBEDPRESS_PLG_NAME.':youtube';
464 $settings = get_option( $option_name, []);
465 $settings['api_key'] = isset( $_POST['api_key']) ? sanitize_text_field( $_POST['api_key']) : 0;
466 $settings['pagesize'] = isset( $_POST['pagesize']) ? sanitize_text_field( $_POST['pagesize']) : 0;
467 $settings['start_time'] = isset( $_POST['start_time']) ? sanitize_text_field( $_POST['start_time']) : 0;
468 $settings['end_time'] = isset( $_POST['end_time']) ? sanitize_text_field( $_POST['end_time']) : 0;
469 $settings['autoplay'] = isset( $_POST['autoplay']) ? sanitize_text_field( $_POST['autoplay']) : '';
470 $settings['controls'] = isset( $_POST['controls']) ? sanitize_text_field( $_POST['controls']) : '';
471 $settings['fs'] = isset( $_POST['fs']) ? sanitize_text_field( $_POST['fs']) : '';
472 $settings['iv_load_policy'] = isset( $_POST['iv_load_policy']) ? sanitize_text_field( $_POST['iv_load_policy']) : 1;
473 $settings['color'] = isset( $_POST['color']) ? sanitize_text_field( $_POST['color']) : 'red';
474 $settings['rel'] = isset( $_POST['rel']) ? sanitize_text_field( $_POST['rel']) : 1;
475 $settings['license_key'] = 1; // backward compatibility
476
477 // Pro will handle g_loading_animation settings and other
478 $settings = apply_filters( 'ep_youtube_settings_before_save', $settings);
479 update_option( $option_name, $settings);
480 do_action( 'ep_youtube_settings_after_save', $settings);
481
482 }
483
484 public function save_wistia_settings() {
485 $option_name = EMBEDPRESS_PLG_NAME.':wistia';
486 $settings = get_option( $option_name, []);
487 $settings['start_time'] = isset( $_POST['start_time']) ? sanitize_text_field( $_POST['start_time']) : 0;
488 $settings['autoplay'] = isset( $_POST['autoplay']) ? sanitize_text_field( $_POST['autoplay']) : '';
489 $settings['display_fullscreen_button'] = isset( $_POST['display_fullscreen_button']) ? sanitize_text_field( $_POST['display_fullscreen_button']) : '';
490 $settings['small_play_button'] = isset( $_POST['small_play_button']) ? sanitize_text_field( $_POST['small_play_button']) : '';
491 $settings['player_color'] = isset( $_POST['player_color']) ? sanitize_text_field( $_POST['player_color']) : '';
492 $settings['plugin_resumable'] = isset( $_POST['plugin_resumable']) ? sanitize_text_field( $_POST['plugin_resumable']) : '';
493 $settings['plugin_focus'] = isset( $_POST['plugin_focus']) ? sanitize_text_field( $_POST['plugin_focus']) : '';
494 $settings['plugin_rewind'] = isset( $_POST['plugin_rewind']) ? sanitize_text_field( $_POST['plugin_rewind']) : '';
495 $settings['display_playbar'] = isset( $_POST['display_playbar']) ? sanitize_text_field( $_POST['display_playbar']) : 1;
496 $settings['plugin_rewind_time'] = isset( $_POST['plugin_rewind_time']) ? sanitize_text_field( $_POST['plugin_rewind_time']) : 10;
497 $settings['always_show_controls'] = isset( $_POST['always_show_controls']) ? sanitize_text_field( $_POST['always_show_controls']) : '';
498 $settings['license_key'] = 1; // backward compatibility
499 // Pro will handle g_loading_animation settings and other
500 $settings = apply_filters( 'ep_wistia_settings_before_save', $settings);
501 update_option( $option_name, $settings);
502 do_action( 'ep_wistia_settings_after_save', $settings);
503 }
504
505 public function save_vimeo_settings() {
506 $option_name = EMBEDPRESS_PLG_NAME.':vimeo';
507 $settings = get_option( $option_name, []);
508 $settings['start_time'] = isset( $_POST['start_time']) ? sanitize_text_field( $_POST['start_time']) : 0;
509 $settings['autoplay'] = isset( $_POST['autoplay']) ? sanitize_text_field( $_POST['autoplay']) : '';
510 $settings['color'] = isset( $_POST['color']) ? sanitize_text_field( $_POST['color']) : '#00adef';
511 $settings['display_title'] = isset( $_POST['display_title']) ? sanitize_text_field( $_POST['display_title']) : 1;
512 $settings['display_author'] = isset( $_POST['display_author']) ? sanitize_text_field( $_POST['display_author']) : 1;
513 $settings['display_avatar'] = isset( $_POST['display_avatar']) ? sanitize_text_field( $_POST['display_avatar']) : 1;
514 $settings['license_key'] = 1; // backward compatibility
515 // Pro will handle g_loading_animation settings and other
516 $settings = apply_filters( 'ep_vimeo_settings_before_save', $settings);
517 update_option( $option_name, $settings);
518 do_action( 'ep_vimeo_settings_after_save', $settings);
519 }
520
521 public function save_twitch_settings() {
522 $option_name = EMBEDPRESS_PLG_NAME.':twitch';
523 $settings = get_option( $option_name, []);
524 $settings['embedpress_pro_twitch_autoplay'] = isset( $_POST['autoplay']) ? sanitize_text_field( $_POST['autoplay']) : 'no';
525 $settings['embedpress_pro_fs'] = isset( $_POST['fs']) ? sanitize_text_field( $_POST['fs']) : 'yes';
526 $settings['start_time'] = isset( $_POST['start_time']) ? sanitize_text_field( $_POST['start_time']) : 0;
527 $settings['embedpress_pro_twitch_theme'] = isset( $_POST['theme']) ? sanitize_text_field( $_POST['theme']) : 'dark';
528 $settings['embedpress_pro_twitch_mute'] = isset( $_POST['mute']) ? sanitize_text_field( $_POST['mute']) : 'yes';
529 $settings['license_key'] = 1; // backward compatibility
530 // Pro will handle g_loading_animation settings and other
531 $settings = apply_filters( 'ep_twitch_settings_before_save', $settings);
532 update_option( $option_name, $settings);
533 do_action( 'ep_twitch_settings_after_save', $settings);
534 }
535
536 public function save_spotify_settings() {
537 $option_name = EMBEDPRESS_PLG_NAME.':spotify';
538 $settings = get_option( $option_name, []);
539 $settings['theme'] = isset( $_POST['spotify_theme']) ? sanitize_text_field( $_POST['spotify_theme']) : '1';
540 $settings['license_key'] = 1; // backward compatibility
541
542 $settings = apply_filters( 'ep_spotify_settings_before_save', $settings);
543 update_option( $option_name, $settings);
544 do_action( 'ep_spotify_settings_after_save', $settings);
545 return $settings;
546 }
547
548 public function save_custom_logo_settings() {
549 do_action( 'before_embedpress_branding_save');
550 $settings = (array) get_option( EMBEDPRESS_PLG_NAME, []);
551
552 // If checkbox is checked, it will be in POST data with value 'yes'
553 // If unchecked, it won't be in POST data, so we set it to 'no'
554 $settings['embedpress_document_powered_by'] = isset( $_POST['embedpress_document_powered_by'] ) ? sanitize_text_field( $_POST['embedpress_document_powered_by'] ) : 'no';
555
556 update_option( EMBEDPRESS_PLG_NAME, $settings);
557 do_action( 'after_embedpress_branding_save');
558
559 }
560
561 public function save_dailymotion_settings() {
562 $option_name = EMBEDPRESS_PLG_NAME.':dailymotion';
563 $settings = get_option( $option_name, []);
564 $settings['start_time'] = isset( $_POST['start_time']) ? sanitize_text_field( $_POST['start_time']) : 0;
565 $settings['visual'] = isset( $_POST['visual']) ? sanitize_text_field( $_POST['visual']) : '';
566 $settings['autoplay'] = isset( $_POST['autoplay']) ? sanitize_text_field( $_POST['autoplay']) : '';
567 $settings['play_on_mobile'] = isset( $_POST['play_on_mobile']) ? sanitize_text_field( $_POST['play_on_mobile']) : '';
568 $settings['color'] = isset( $_POST['color']) ? sanitize_text_field( $_POST['color']) : '#dd3333';
569 $settings['controls'] = isset( $_POST['controls']) ? sanitize_text_field( $_POST['controls']) : '';
570 $settings['video_info'] = isset( $_POST['video_info']) ? sanitize_text_field( $_POST['video_info']) : '';
571 $settings['mute'] = isset( $_POST['mute']) ? sanitize_text_field( $_POST['mute']) : '';
572 // Pro will handle g_loading_animation settings and other
573 $settings = apply_filters( 'ep_dailymotion_settings_before_save', $settings);
574 update_option( $option_name, $settings);
575 do_action( 'ep_dailymotion_settings_after_save', $settings);
576 }
577
578 public function save_soundcloud_settings() {
579 $option_name = EMBEDPRESS_PLG_NAME.':soundcloud';
580 $settings = get_option( $option_name, []);
581 $settings['visual'] = isset( $_POST['visual']) ? sanitize_text_field( $_POST['visual']) : '';
582 $settings['autoplay'] = isset( $_POST['autoplay']) ? sanitize_text_field( $_POST['autoplay']) : '';
583 $settings['play_on_mobile'] = isset( $_POST['play_on_mobile']) ? sanitize_text_field( $_POST['play_on_mobile']) : '';
584 $settings['share_button'] = isset( $_POST['share_button']) ? sanitize_text_field( $_POST['share_button']) : '';
585 $settings['comments'] = isset( $_POST['comments']) ? sanitize_text_field( $_POST['comments']) : '';
586 $settings['color'] = isset( $_POST['color']) ? sanitize_text_field( $_POST['color']) : '';
587 $settings['artwork'] = isset( $_POST['artwork']) ? sanitize_text_field( $_POST['artwork']) : '';
588 $settings['play_count'] = isset( $_POST['play_count']) ? sanitize_text_field( $_POST['play_count']) : '';
589 $settings['username'] = isset( $_POST['username']) ? sanitize_text_field( $_POST['username']) : '';
590
591 $settings['license_key'] = 1; // backward compatibility
592 // Pro will handle g_loading_animation settings and other
593 $settings = apply_filters( 'ep_soundcloud_settings_before_save', $settings);
594 update_option( $option_name, $settings);
595 do_action( 'ep_soundcloud_settings_after_save', $settings);
596 }
597
598 public function save_gcalendar_settings() {
599 $epgc_cache_time = !empty( $_POST['epgc_cache_time'] ) ? absint( $_POST['epgc_cache_time']) : 0;
600 $epgc_selected_calendar_ids = !empty( $_POST['epgc_selected_calendar_ids'] ) ? array_map( 'sanitize_text_field', $_POST['epgc_selected_calendar_ids']) : [];
601
602 // New two-field form: Client ID + Client Secret. Legacy: full JSON pasted
603 // into epgc_client_secret. Accept both so sites upgrading mid-stream still save.
604 $posted_client_id = isset( $_POST['epgc_client_id'] ) ? sanitize_text_field( wp_unslash( $_POST['epgc_client_id'] ) ) : '';
605 $posted_client_secret = isset( $_POST['epgc_client_secret_value'] ) ? trim( wp_unslash( $_POST['epgc_client_secret_value'] ) ) : '';
606 $posted_legacy_json = isset( $_POST['epgc_client_secret'] ) ? trim( wp_unslash( $_POST['epgc_client_secret'] ) ) : '';
607
608 $pretty_client_secret = '';
609
610 if ( $posted_client_id !== '' || $posted_client_secret !== '' ) {
611 // Two-field form path. Preserve the existing secret if the field was
612 // left blank (the UI surfaces "Stored — leave blank to keep").
613 $existing = json_decode( get_option( 'epgc_client_secret', '' ), true );
614 $effective_secret = $posted_client_secret !== ''
615 ? $posted_client_secret
616 : ( isset( $existing['web']['client_secret'] ) ? $existing['web']['client_secret'] : '' );
617
618 if ( $posted_client_id !== '' && $effective_secret !== '' ) {
619 $pretty_client_secret = $this->get_pretty_json_string( [
620 'web' => [
621 'client_id' => $posted_client_id,
622 'client_secret' => $effective_secret,
623 'redirect_uris' => [ admin_url( 'admin.php?page=embedpress&page_type=google-calendar' ) ],
624 ],
625 ] );
626 }
627 } elseif ( $posted_legacy_json !== '' ) {
628 // Legacy full-JSON path (kept for backward compatibility).
629 $decoded = json_decode( $posted_legacy_json, true );
630 if ( !empty( $decoded ) ) {
631 $pretty_client_secret = $this->get_pretty_json_string( $decoded );
632 }
633 }
634
635 update_option( 'epgc_client_secret', $pretty_client_secret);
636 update_option( 'epgc_cache_time', $epgc_cache_time);
637 update_option( 'epgc_selected_calendar_ids', $epgc_selected_calendar_ids);
638
639 }
640
641 public function save_opensea_settings() {
642 $option_name = EMBEDPRESS_PLG_NAME.':opensea';
643 $settings = get_option( $option_name, []);
644 $settings['api_key'] = isset( $_POST['api_key']) ? sanitize_text_field( $_POST['api_key']) : 0;
645 $settings['limit'] = isset( $_POST['limit']) ? sanitize_text_field( $_POST['limit']) : 0;
646 $settings['orderby'] = isset( $_POST['orderby']) ? sanitize_text_field( $_POST['orderby']) : 0;
647
648 $settings['license_key'] = 1; // backward compatibility
649
650 // Pro will handle g_loading_animation settings and other
651 $settings = apply_filters( 'ep_opensea_settings_before_save', $settings);
652 update_option( $option_name, $settings);
653 do_action( 'ep_opensea_settings_after_save', $settings);
654 }
655
656
657 function get_pretty_json_string($array) {
658 return str_replace(" ", " ", json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
659 }
660
661 /**
662 * AJAX handler for saving global brand image
663 */
664 public function save_global_brand_image() {
665 // Verify nonce for security
666 if (!wp_verify_nonce($_POST['nonce'], 'embedpress_ajax_nonce')) {
667 wp_die('Security check failed');
668 }
669
670 // Check user capabilities
671 if (!current_user_can('manage_options')) {
672 wp_die('Insufficient permissions');
673 }
674
675 $logo_url = isset($_POST['logo_url']) ? esc_url_raw($_POST['logo_url']) : '';
676 $logo_id = isset($_POST['logo_id']) ? intval($_POST['logo_id']) : '';
677
678 // Save global brand settings
679 $global_brand_settings = [
680 'logo_url' => $logo_url,
681 'logo_id' => $logo_id,
682 ];
683
684 $updated = update_option(EMBEDPRESS_PLG_NAME . ':global_brand', $global_brand_settings);
685
686 // If global brand image is being set, auto-enable branding for providers without custom logos
687 if (!empty($logo_url)) {
688 $this->auto_enable_global_branding($logo_url, $logo_id);
689 }
690
691 if ($updated !== false) {
692 wp_send_json_success([
693 'message' => 'Global brand image saved successfully',
694 'logo_url' => $logo_url,
695 'logo_id' => $logo_id
696 ]);
697 } else {
698 wp_send_json_error('Failed to save global brand image');
699 }
700 }
701
702 /**
703 * AJAX handler for dismissing UI elements (banners, popups, etc.)
704 */
705 public function dismiss_element() {
706 // Verify nonce for security
707 if (!wp_verify_nonce($_POST['nonce'], 'embedpress_ajax_nonce')) {
708 wp_die('Security check failed');
709 }
710
711 // Check user capabilities
712 if (!current_user_can('manage_options')) {
713 wp_die('Insufficient permissions');
714 }
715
716 $element_type = isset($_POST['element_type']) ? sanitize_text_field($_POST['element_type']) : '';
717
718 // Define valid dismiss types and their corresponding option names
719 $valid_dismiss_types = [
720 'main_banner' => 'embedpress_main_banner_dismissed',
721 'hub_popup' => 'embedpress_hub_popup_dismissed',
722 'popup_banner' => 'embedpress_popup_dismissed', // Legacy support
723 ];
724
725 if (array_key_exists($element_type, $valid_dismiss_types)) {
726 $option_name = $valid_dismiss_types[$element_type];
727 update_option($option_name, true);
728
729 // Store current plugin version when hub_popup is dismissed
730 // This ensures popup shows again on next version update
731 if ($element_type === 'hub_popup') {
732 update_option('embedpress_last_popup_version', EMBEDPRESS_VERSION);
733 }
734
735 wp_send_json_success([
736 'message' => ucfirst(str_replace('_', ' ', $element_type)) . ' dismissed successfully',
737 'element_type' => $element_type,
738 'option_name' => $option_name
739 ]);
740 }
741
742 wp_send_json_error([
743 'message' => 'Invalid element type: ' . $element_type,
744 'valid_types' => array_keys($valid_dismiss_types)
745 ]);
746 }
747
748 /**
749 * AJAX handler for dismissing feature notices
750 */
751 public function dismiss_feature_notice() {
752 // Verify nonce for security
753 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'embedpress_feature_notice_nonce')) {
754 wp_send_json_error(['message' => 'Security check failed']);
755 }
756
757 // Check user capabilities
758 if (!current_user_can('manage_options')) {
759 wp_send_json_error(['message' => 'Insufficient permissions']);
760 }
761
762 $notice_id = isset($_POST['notice_id']) ? sanitize_text_field($_POST['notice_id']) : '';
763
764 if (empty($notice_id)) {
765 wp_send_json_error(['message' => 'Notice ID is required']);
766 }
767
768 // Define valid notice types and their corresponding option names
769 $valid_notices = [
770 'analytics' => 'embedpress_feature_notice_analytics_dismissed',
771 ];
772
773 if (array_key_exists($notice_id, $valid_notices)) {
774 $option_name = $valid_notices[$notice_id];
775 update_option($option_name, true);
776
777 wp_send_json_success([
778 'message' => 'Feature notice dismissed successfully',
779 'notice_id' => $notice_id,
780 'option_name' => $option_name
781 ]);
782 }
783
784 wp_send_json_error([
785 'message' => 'Invalid notice ID: ' . $notice_id,
786 'valid_notices' => array_keys($valid_notices)
787 ]);
788 }
789
790 /**
791 * Auto-enable branding for all providers that don't have custom logos
792 */
793 private function auto_enable_global_branding($logo_url, $logo_id) {
794 $providers = ['youtube', 'vimeo', 'wistia', 'twitch', 'dailymotion', 'document'];
795
796 foreach ($providers as $provider) {
797 $option_name = EMBEDPRESS_PLG_NAME . ':' . $provider;
798 $settings = get_option($option_name, []);
799
800 // Only auto-enable if provider doesn't have a custom logo set
801 $has_custom_logo = isset($settings['logo_url']) && !empty($settings['logo_url']);
802
803 if (!$has_custom_logo) {
804 // Enable branding but don't set logo_url/logo_id - let the template logic handle global fallback
805 $settings['branding'] = 'yes';
806 update_option($option_name, $settings);
807 }
808 }
809 }
810
811 /**
812 * Render the onboarding wizard page
813 */
814 public function render_onboarding_page() {
815 $settings = (array) get_option( EMBEDPRESS_PLG_NAME, [] );
816 $elements = (array) get_option( EMBEDPRESS_PLG_NAME . ':elements', [] );
817 $pro_active = apply_filters( 'embedpress/is_allow_rander', false );
818
819 $onboarding_data = [
820 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
821 'nonce' => wp_create_nonce( 'embedpress_onboarding_nonce' ),
822 'settingsUrl' => admin_url( 'admin.php?page=' . $this->page_slug . '&page_type=settings' ),
823 'dashboardUrl' => admin_url( 'admin.php?page=' . $this->page_slug ),
824 'proActive' => $pro_active,
825 'upgradeUrl' => 'https://wpdeveloper.com/in/upgrade-embedpress',
826 'settings' => $settings,
827 'elements' => $elements,
828 'assetsUrl' => EMBEDPRESS_URL_ASSETS,
829 'analyticsTracking' => get_option( 'embedpress_analytics_tracking_enabled', true ),
830 'sitePerformance' => \EmbedPress\Includes\Classes\SitePerformance::get_status(),
831 ];
832
833 // Enqueue onboarding assets explicitly
834 wp_enqueue_script( 'embedpress-onboarding' );
835 wp_enqueue_style( 'embedpress-onboarding-css' );
836 wp_localize_script( 'embedpress-onboarding', 'embedpressOnboardingData', $onboarding_data );
837
838 echo '<div class="embedpress-onboarding-wrapper">';
839 echo '<div id="embedpress-onboarding-root"></div>';
840 echo '</div>';
841 }
842
843 /**
844 * AJAX handler: install + activate xSpeed Cache from the onboarding wizard.
845 *
846 * Page caching is enabled only when nothing else already owns it — that
847 * decision lives in SitePerformance, which asks the portable Detector.
848 */
849 public function install_site_performance() {
850 if ( ! current_user_can( 'install_plugins' ) ) {
851 wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'embedpress' ) ] );
852 }
853
854 if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'embedpress_onboarding_nonce' ) ) {
855 wp_send_json_error( [ 'message' => __( 'Security check failed.', 'embedpress' ) ] );
856 }
857
858 $result = \EmbedPress\Includes\Classes\SitePerformance::install();
859
860 if ( empty( $result['success'] ) ) {
861 wp_send_json_error( $result );
862 }
863
864 wp_send_json_success( $result );
865 }
866
867 /**
868 * AJAX handler for saving onboarding wizard settings
869 */
870 public function save_onboarding_settings() {
871 if ( ! current_user_can( 'manage_options' ) ) {
872 wp_send_json_error( [ 'message' => 'Insufficient permissions.' ] );
873 }
874
875 if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'embedpress_onboarding_nonce' ) ) {
876 wp_send_json_error( [ 'message' => 'Security check failed.' ] );
877 }
878
879 $settings = (array) get_option( EMBEDPRESS_PLG_NAME, [] );
880 $elements = (array) get_option( EMBEDPRESS_PLG_NAME . ':elements', [] );
881
882 // Element toggles — enable/disable all blocks/widgets at once
883 $all_gutenberg_blocks = [
884 'embedpress', 'document', 'embedpress-pdf', 'embedpress-calendar',
885 'youtube-block', 'google-docs-block', 'google-slides-block',
886 'google-sheets-block', 'google-forms-block', 'google-drawings-block',
887 'google-maps-block', 'twitch-block', 'wistia-block', 'vimeo-block',
888 ];
889 $all_elementor_widgets = [
890 'embedpress', 'embedpress-document', 'embedpress-pdf', 'embedpress-calendar',
891 ];
892
893 if ( isset( $_POST['gutenberg_block'] ) ) {
894 if ( sanitize_text_field( $_POST['gutenberg_block'] ) === '1' ) {
895 foreach ( $all_gutenberg_blocks as $block ) {
896 $elements['gutenberg'][ $block ] = $block;
897 }
898 } else {
899 $elements['gutenberg'] = [];
900 }
901 }
902 if ( isset( $_POST['elementor_widget'] ) ) {
903 if ( sanitize_text_field( $_POST['elementor_widget'] ) === '1' ) {
904 foreach ( $all_elementor_widgets as $widget ) {
905 $elements['elementor'][ $widget ] = $widget;
906 }
907 } else {
908 $elements['elementor'] = [];
909 }
910 }
911
912 // Global settings toggles
913 if ( isset( $_POST['analytics_tracking'] ) ) {
914 update_option( 'embedpress_analytics_tracking_enabled', intval( $_POST['analytics_tracking'] ) ? true : false );
915 }
916 if ( isset( $_POST['g_lazyload'] ) ) {
917 $settings['g_lazyload'] = intval( $_POST['g_lazyload'] );
918 }
919 if ( isset( $_POST['embedpress_document_powered_by'] ) ) {
920 $settings['embedpress_document_powered_by'] = intval( $_POST['embedpress_document_powered_by'] ) ? 'yes' : 'no';
921 }
922 // Pro feature toggles
923 if ( isset( $_POST['social_share'] ) ) {
924 $settings['social_share'] = intval( $_POST['social_share'] );
925 }
926 if ( isset( $_POST['custom_branding'] ) ) {
927 $settings['custom_branding'] = intval( $_POST['custom_branding'] );
928 }
929 if ( isset( $_POST['custom_ads'] ) ) {
930 $settings['custom_ads'] = intval( $_POST['custom_ads'] );
931 }
932 if ( isset( $_POST['content_protection'] ) ) {
933 $settings['content_protection'] = intval( $_POST['content_protection'] );
934 }
935 // Mark onboarding as complete
936 if ( ! empty( $_POST['complete'] ) ) {
937 update_option( 'embedpress_onboarding_complete', true );
938 }
939
940 // Data consent — enable usage tracking via WPInsights
941 if ( ! empty( $_POST['data_consent'] ) && ! get_option( 'embedpress_data_consent', false ) ) {
942 update_option( 'embedpress_data_consent', true );
943
944 $allow_tracking = get_option( 'wpins_allow_tracking', [] );
945 if ( ! is_array( $allow_tracking ) ) {
946 $allow_tracking = [];
947 }
948 $allow_tracking['embedpress'] = 'embedpress';
949 update_option( 'wpins_allow_tracking', $allow_tracking );
950
951 // Suppress the legacy opt-in notice now that consent was captured via the wizard
952 $block_notice = get_option( 'wpins_block_notice', [] );
953 if ( ! is_array( $block_notice ) ) {
954 $block_notice = [];
955 }
956 $block_notice['embedpress'] = 'embedpress';
957 update_option( 'wpins_block_notice', $block_notice );
958
959 // Register the daily cron and fire an initial payload so data
960 // reaches wpinsight.com without waiting for the first cron tick.
961 $tracker = EmbedPress_Plugin_Usage_Tracker::get_instance( EMBEDPRESS_FILE, [
962 'opt_in' => true,
963 'goodbye_form' => true,
964 'item_id' => '98ba0ac16a4f7b3b940d',
965 ] );
966 $tracker->schedule_tracking();
967 $tracker->do_tracking( true );
968 }
969
970 update_option( EMBEDPRESS_PLG_NAME, $settings );
971 update_option( EMBEDPRESS_PLG_NAME . ':elements', $elements );
972
973 wp_send_json_success( [ 'message' => 'Onboarding settings saved.' ] );
974 }
975
976 /**
977 * Reorder submenu items into the canonical order:
978 * 1. Dashboard, 2. Analytics, 3. Player & Engagement, 4. Branding,
979 * 5. Custom Ads, 6. Shortcode, 7. Settings, 8. Setup Wizard, 9. License.
980 *
981 * The label match strips out the trailing PRO badge span (if any) so
982 * upsell items keep their position regardless of badge markup.
983 */
984 public function reorder_submenu_items() {
985 global $submenu;
986
987 if (!isset($submenu[$this->page_slug])) {
988 return;
989 }
990
991 // Canonical priority by label (lower = earlier).
992 $priority = [
993 // Overview
994 __('Dashboard', 'embedpress') => 10,
995 __('Analytics', 'embedpress') => 20,
996 // Feature pages. Google Reviews — our exclusive flagship feature —
997 // caps the feature group (last feature, before the config items) so
998 // it's prominent and easy to find without being buried at the very
999 // bottom by License (QA #4).
1000 __('Player & Engagement', 'embedpress') => 30,
1001 __('Branding', 'embedpress') => 40,
1002 __('Custom Ads', 'embedpress') => 50,
1003 __('Google Reviews', 'embedpress') => 55,
1004 // Tools / configuration
1005 __('Shortcode', 'embedpress') => 60,
1006 __('Settings', 'embedpress') => 70,
1007 __('Setup Wizard', 'embedpress') => 80,
1008 __('License', 'embedpress') => 90,
1009 ];
1010
1011 $items = $submenu[$this->page_slug];
1012
1013 // Stable sort: pair each item with its original index so unknown
1014 // labels keep their relative order while known ones snap to priority.
1015 $indexed = [];
1016 foreach ($items as $i => $item) {
1017 $label_raw = isset($item[0]) ? $item[0] : '';
1018 // Strip the trailing PRO/badge span and tags so labels with
1019 // inline markup still match the priority map.
1020 $label = trim(wp_strip_all_tags($label_raw));
1021 $rank = isset($priority[$label]) ? $priority[$label] : 1000 + $i;
1022 $indexed[] = [$rank, $i, $item];
1023 }
1024
1025 usort($indexed, function ($a, $b) {
1026 if ($a[0] === $b[0]) {
1027 return $a[1] - $b[1];
1028 }
1029 return $a[0] - $b[0];
1030 });
1031
1032 $submenu[$this->page_slug] = array_map(function ($row) {
1033 return $row[2];
1034 }, $indexed);
1035 }
1036 }
1037