PluginProbe
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 2.1.3
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v2.1.3
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 All 189 releases
← All changes | EmbedPress/Core.php +134 -788 trunk2.1.3 View file →
@@ -1,31 +1,25 @@
1 1 <?php
2 -
3 2 namespace EmbedPress;
4 3
5 -use EmbedPress\Ends\Back\Handler as EndHandlerAdmin;
6 -use EmbedPress\Ends\Back\Settings\EmbedpressSettings;
7 -use EmbedPress\Ends\Front\Handler as EndHandlerPublic;
8 -use EmbedPress\Includes\Traits\Shared;
9 -use EmbedPress\Includes\Classes\FeatureNotices;
10 -use EmbedPress\Includes\Classes\FeaturePreviewModal;
4 +use \EmbedPress\AutoLoader;
5 +use \EmbedPress\Loader;
6 +use \EmbedPress\Ends\Back\Handler as EndHandlerAdmin;
7 +use \EmbedPress\Ends\Front\Handler as EndHandlerPublic;
11 8
12 -
13 9 (defined('ABSPATH') && defined('EMBEDPRESS_IS_LOADED')) or die("No direct script access allowed.");
14 10
15 11 /**
16 - * Entity that glues together all pieces that the plugin is made of, for WordPress 5+.
12 + * Entity that glues together all pieces that the plugin is made of.
17 13 *
18 14 * @package EmbedPress
19 15 * @author EmbedPress <help@embedpress.com>
20 - * @copyright Copyright (C) 2021 WPDeveloper. All rights reserved.
21 - * @license GPLv3 or later
16 + * @copyright Copyright (C) 2018 EmbedPress. All rights reserved.
17 + * @license GPLv2 or later
22 18 * @since 1.0.0
23 19 */
24 20 class Core
25 21 {
26 - use Shared;
27 -
28 22 /**
29 23 * The name of the plugin.
30 24 *
31 25 * @since 1.0.0
@@ -30,9 +24,9 @@
30 24 *
31 25 * @since 1.0.0
32 26 * @access protected
33 27 *
34 - * @var string $pluginName The name of the plugin.
28 + * @var string $pluginName The name of the plugin.
35 29 */
36 30 protected $pluginName;
37 31
38 32 /**
@@ -40,9 +34,9 @@
40 34 *
41 35 * @since 1.0.0
42 36 * @access protected
43 37 *
44 - * @var string $pluginVersion The version of the plugin.
38 + * @var string $pluginVersion The version of the plugin.
45 39 */
46 40 protected $pluginVersion;
47 41
48 42 /**
@@ -50,9 +44,9 @@
50 44 *
51 45 * @since 1.0.0
52 46 * @access protected
53 47 *
54 - * @var Loader $pluginVersion The version of the plugin.
48 + * @var \EmbedPress\Loader $pluginVersion The version of the plugin.
55 49 */
56 50 protected $loaderInstance;
57 51
58 52 /**
@@ -63,39 +57,31 @@
63 57 * @static
64 58 *
65 59 * @var array
66 60 */
67 - private static $plugins = [];
61 + private static $plugins = array();
68 62
69 63 /**
70 64 * Initialize the plugin and set its properties.
71 65 *
72 - * @return void
73 66 * @since 1.0.0
74 67 *
68 + * @return void
75 69 */
76 70 public function __construct()
77 71 {
78 72 $this->pluginName = EMBEDPRESS_PLG_NAME;
79 - $this->pluginVersion = EMBEDPRESS_VERSION;
73 + $this->pluginVersion = EMBEDPRESS_PLG_VERSION;
80 74
81 75 $this->loaderInstance = new Loader();
82 -
83 - add_action('in_admin_header', [$this, 'remove_admin_notice'], 99);
84 - add_action('ep_admin_notices', [$this, 'embedpress_admin_notice']);
85 - add_action('ep_admin_notices', [$this, 'admin_notice']);
86 -
87 - add_filter('upload_mimes', [$this, 'extended_mime_types']);
88 -
89 - add_action('wp_mail_failed', [$this, 'capture_mail_error'], 10, 1);
90 76 }
91 77
92 78 /**
93 79 * Method that retrieves the plugin name.
94 80 *
95 - * @return string
96 81 * @since 1.0.0
97 82 *
83 + * @return string
98 84 */
99 85 public function getPluginName()
100 86 {
101 87 return $this->pluginName;
@@ -103,11 +89,11 @@
103 89
104 90 /**
105 91 * Method that retrieves the plugin version.
106 92 *
107 - * @return string
108 93 * @since 1.0.0
109 94 *
95 + * @return string
110 96 */
111 97 public function getPluginVersion()
112 98 {
113 99 return $this->pluginVersion;
@@ -115,11 +101,11 @@
115 101
116 102 /**
117 103 * Method that retrieves the loader instance.
118 104 *
119 - * @return Loader
120 105 * @since 1.0.0
121 106 *
107 + * @return \EmbedPress\Loader
122 108 */
123 109 public function getLoader()
124 110 {
125 111 return $this->loaderInstance;
@@ -127,830 +113,138 @@
127 113
128 114 /**
129 115 * Method responsible to connect all required hooks in order to make the plugin work.
130 116 *
131 - * @return void
132 117 * @since 1.0.0
133 118 *
119 + * @return void
134 120 */
135 121 public function initialize()
136 122 {
137 123 global $wp_actions;
138 - add_filter('oembed_providers', [$this, 'addOEmbedProviders']);
139 - add_action('rest_api_init', [$this, 'registerOEmbedRestRoutes']);
140 - add_action('rest_api_init', ['\\EmbedPress\\Includes\\Classes\\GoogleReviewsRestController', 'register']);
141 - add_action('enqueue_block_editor_assets', ['\\EmbedPress\\Includes\\Classes\\GoogleReviewsRenderer', 'enqueue_editor_assets']);
142 - add_action('elementor/preview/enqueue_styles', ['\\EmbedPress\\Includes\\Classes\\GoogleReviewsRenderer', 'enqueue_editor_assets']);
143 - \EmbedPress\Includes\Classes\GoogleReviewsAdminPage::register();
144 - // Apify-backed review fetching (the heavy "fetch all reviews" job + the
145 - // sync ≤5 fallback) lives in free so the picker → refetch flow works
146 - // without Pro. Pro extends this via filters (multi-place merge,
147 - // advanced layouts, filtering, theme, schema) — see
148 - // embedpress-pro/includes/Filters/Google_Reviews_Pro.php.
149 - new \EmbedPress\Includes\Classes\GoogleReviewsApify();
150 - // Hosted-proxy review fetch (api.embedpress.com/google-reviews/v1).
151 - // Lowest-priority handler on the same filters — Apify (user token) wins
152 - // when configured; managed runs as the zero-setup fallback.
153 - new \EmbedPress\Includes\Classes\GoogleReviewsManaged();
154 124
155 - // just disabled rating and feedback
156 - // add_action('rest_api_init', [$this, 'register_feedback_email_endpoint']);
157 -
158 -
159 - $this->start_plugin_tracking();
160 -
161 125 if (is_admin()) {
162 - new EmbedpressSettings();
126 + $plgSettings = self::getSettings();
163 127
164 - add_action('init', [$this, 'admin_notice']);
128 + $settingsClassNamespace = '\EmbedPress\Ends\Back\Settings';
129 + add_action('admin_menu', array($settingsClassNamespace, 'registerMenuItem'));
130 + add_action('admin_init', array($settingsClassNamespace, 'registerActions'));
131 + unset($settingsClassNamespace);
165 132
166 - // Initialize Feature Notices from separate file
167 - FeatureNotices::get_instance();
133 + add_filter('plugin_action_links_embedpress/embedpress.php', array('\EmbedPress\Core', 'handleActionLinks'), 10, 2);
168 134
169 - // Initialize the post-update "What's New" feature preview modal.
170 - // Its dismiss AJAX + enqueue/render hooks self-register; release
171 - // feature sets are registered from FeatureNotices::register_all_notices().
172 - FeaturePreviewModal::get_instance();
135 + add_action('admin_enqueue_scripts', array('\EmbedPress\Ends\Back\Handler', 'enqueueStyles'));
173 136
174 - add_filter(
175 - 'plugin_action_links_embedpress/embedpress.php',
176 - ['\\EmbedPress\\Core', 'handleActionLinks'],
177 - 10,
178 - 2
179 - );
137 + add_action('init', array('\EmbedPress\Disabler', 'run'), 1);
138 + add_action('init', array($this, 'configureTinyMCE'), 1);
180 139
181 - // Old enqueue handlers removed - now handled by AssetManager
182 - add_action('wp_ajax_embedpress_notice_dismiss', ['\\EmbedPress\\Ends\\Back\\Handler', 'embedpress_notice_dismiss']);
183 - new EndHandlerAdmin($this->getPluginName(), $this->getPluginVersion());
184 - // Asset enqueuing now handled by AssetManager - keeping only non-asset functionality
185 - } else {
186 - // Asset enqueuing now handled by AssetManager - keeping only non-asset functionality
187 - new EndHandlerPublic($this->getPluginName(), $this->getPluginVersion());
188 - }
140 + $plgHandlerAdminInstance = new EndHandlerAdmin($this->getPluginName(), $this->getPluginVersion());
189 141
190 - // Add support for embeds on AMP pages
191 - add_filter('pp_embed_parsed_content', ['\\EmbedPress\\AMP\\EmbedHandler', 'processParsedContent'], 10, 3);
192 -
193 - // Add support for our embeds on Beaver Builder. Without this it only run the native embeds.
194 - add_filter(
195 - 'fl_builder_before_render_shortcodes',
196 - ['\\EmbedPress\\ThirdParty\\BeaverBuilder', 'before_render_shortcodes']
197 - );
198 - $this->loaderInstance->run();
199 - }
200 -
201 - /**
202 - * Initialize minimal plugin functionality without script handlers
203 - * Used when the new block system is active to avoid conflicts
204 - *
205 - * @return void
206 - * @since 4.2.7
207 - */
208 - public function initialize_minimal()
209 - {
210 -
211 - add_filter('oembed_providers', [$this, 'addOEmbedProviders']);
212 - add_action('rest_api_init', [$this, 'registerOEmbedRestRoutes']);
213 -
214 - // just disabled rating and feedback
215 - // add_action('rest_api_init', [$this, 'register_feedback_email_endpoint']);
216 -
217 - $this->start_plugin_tracking();
218 -
219 - // Skip the admin and frontend handlers that enqueue scripts
220 - // Only initialize core functionality
221 -
222 -
223 - // Add support for embeds on AMP pages
224 - add_filter('pp_embed_parsed_content', ['\\EmbedPress\\AMP\\EmbedHandler', 'processParsedContent'], 10, 3);
225 -
226 - // Add support for our embeds on Beaver Builder
227 - add_filter(
228 - 'fl_builder_before_render_shortcodes',
229 - ['\\EmbedPress\\ThirdParty\\BeaverBuilder', 'before_render_shortcodes']
230 - );
231 -
232 - $this->loaderInstance->run();
233 - }
234 -
235 - /**
236 - * @param $providers
237 - *
238 - * @return mixed
239 - */
240 - public function addOEmbedProviders($providers)
241 - {
242 - $newProviders = [
243 - // Viddler
244 - '#https?://(.+\.)?viddler\.com/v/.+#i' => 'viddler',
245 -
246 - // Deviantart.com (http://www.deviantart.com)
247 - // '#https?://(.+\.)?deviantart\.com/art/.+#i' => 'devianart',
248 - // '#https?://(.+\.)?deviantart\.com/.+#i' => 'devianart',
249 - // '#https?://(.+\.)?deviantart\.com/.*/d.+#i' => 'devianart',
250 - // '#https?://(.+\.)?fav\.me/.+#i' => 'devianart',
251 - // '#https?://(.+\.)?sta\.sh/.+#i' => 'devianart',
252 -
253 - // chirbit.com (http://www.chirbit.com/)
254 - //'#https?://(.+\.)?chirb\.it/.+#i' => 'chirbit',
255 -
256 -
257 - // nfb.ca (http://www.nfb.ca/)
258 - //'#https?://(.+\.)?nfb\.ca/film/.+#i' => 'nfb',
259 -
260 - // Dotsub (http://dotsub.com/)
261 - //'#https?://(.+\.)?dotsub\.com/view/.+#i' => 'dotsub',
262 -
263 - // Rdio (http://rdio.com/)
264 - '#https?://(.+\.)?rdio\.com/(artist|people)/.+#i' => 'rdio',
265 -
266 - // Sapo Videos (http://videos.sapo.pt)
267 - //'#https?://(.+\.)?videos\.sapo\.pt/.+#i' => 'sapo',
268 -
269 - // Official FM (http://official.fm)
270 - '#https?://(.+\.)?official\.fm/(tracks|playlists)/.+#i' => 'officialfm',
271 -
272 - // HuffDuffer (http://huffduffer.com)
273 - //'#https?://(.+\.)?huffduffer\.com/.+#i' => 'huffduffer',
274 -
275 - // Shoudio (http://shoudio.com)
276 - //'#https?://(.+\.)?shoudio\.(com|io)/.+#i' => 'shoudio',
277 -
278 - // Moby Picture (http://www.mobypicture.com)
279 - '#https?://(.+\.)?mobypicture\.com/user/.+/view/.+#i' => 'mobypicture',
280 - '#https?://(.+\.)?moby\.to/.+#i' => 'mobypicture',
281 -
282 - // 23HQ (http://www.23hq.com)
283 - //'#https?://(.+\.)?23hq\.com/.+/photo/.+#i' => '23hq',
284 -
285 - // Cacoo (https://cacoo.com)
286 - '#https?://(.+\.)?cacoo\.com/diagrams/.+#i' => 'cacoo',
287 -
288 - // Dipity (http://www.dipity.com)
289 - '#https?://(.+\.)?dipity\.com/.+#i' => 'dipity',
290 -
291 - // Roomshare (http://roomshare.jp)
292 - //'#https?://(.+\.)?roomshare\.jp/(en/)?post/.+#i' => 'roomshare',
293 -
294 - // Crowd Ranking (http://crowdranking.com)
295 - '#https?://(.+\.)?c9ng\.com/.+#i' => 'crowd',
296 -
297 - // CircuitLab (https://www.circuitlab.com/)
298 - //'#https?://(.+\.)?circuitlab\.com/circuit/.+#i' => 'circuitlab',
299 -
300 - // Coub (http://coub.com/)
301 - //'#https?://(.+\.)?coub\.com/(view|embed)/.+#i' => 'coub',
302 -
303 - // Ustream (http://www.ustream.tv)
304 - //'#https?://(.+\.)?ustream\.(tv|com)/.+#i' => 'ustream',
305 -
306 - // Daily Mile (http://www.dailymile.com)
307 - '#https?://(.+\.)?dailymile\.com/people/.+/entries/.+#i' => 'daily',
308 -
309 - // Sketchfab (http://sketchfab.com)
310 - '#https?://(.+\.)?sketchfab\.com/models/.+#i' => 'sketchfab',
311 - '#https?://(.+\.)?sketchfab\.com/.+/folders/.+#i' => 'sketchfab',
312 -
313 - // AudioSnaps (http://audiosnaps.com)
314 - '#https?://(.+\.)?audiosnaps\.com/k/.+#i' => 'audiosnaps',
315 -
316 - // RapidEngage (https://rapidengage.com)
317 - '#https?://(.+\.)?rapidengage\.com/s/.+#i' => 'rapidengage',
318 -
319 - // Getty Images (http://www.gettyimages.com/)
320 - //'#https?://(.+\.)?gty\.im/.+#i' => 'gettyimages',
321 - //'#https?://(.+\.)?gettyimages\.com/detail/photo/.+#i' => 'gettyimages',
322 -
323 - // amCharts Live Editor (http://live.amcharts.com/)
324 - //'#https?://(.+\.)?live\.amcharts\.com/.+#i' => 'amcharts',
325 -
326 - // Infogram (https://infogr.am/)
327 - //'#https?://(.+\.)?infogr\.am/.+#i' => 'infogram',
328 - //(https://infogram.com/)
329 - //'#https?://(.+\.)?infogram\.com/.+#i' => 'infogram',
330 -
331 - // ChartBlocks (http://www.chartblocks.com/)
332 - //'#https?://(.+\.)?public\.chartblocks\.com/c/.+#i' => 'chartblocks',
333 -
334 - // ReleaseWire (http://www.releasewire.com/)
335 - //'#https?://(.+\.)?rwire\.com/.+#i' => 'releasewire',
336 -
337 - // ShortNote (https://www.shortnote.jp/)
338 - //'#https?://(.+\.)?shortnote\.jp/view/notes/.+#i' => 'shortnote',
339 -
340 - // EgliseInfo (http://egliseinfo.catholique.fr/)
341 - '#https?://(.+\.)?egliseinfo\.catholique\.fr/.+#i' => 'egliseinfo',
342 -
343 - // Silk (http://www.silk.co/)
344 - '#https?://(.+\.)?silk\.co/explore/.+#i' => 'silk',
345 - '#https?://(.+\.)?silk\.co/s/embed/.+#i' => 'silk',
346 -
347 - // http://bambuser.com
348 - '#https?://(.+\.)?bambuser\.com/v/.+#i' => 'bambuser',
349 -
350 - // https://clyp.it
351 - //'#https?://(.+\.)?clyp\.it/.+#i' => 'clyp',
352 -
353 - // https://gist.github.com
354 - // '#https?://(.+\.)?gist\.github\.com/.+#i' => 'github',
355 -
356 - // https://portfolium.com
357 - //'#https?://(.+\.)?portfolium\.com/.+#i' => 'portfolium',
358 -
359 - // http://rutube.ru
360 - '#https?://(.+\.)?rutube\.ru/video/.+#i' => 'rutube',
361 -
362 - // http://www.videojug.com
363 - '#https?://(.+\.)?videojug\.com/.+#i' => 'videojug',
364 -
365 - // https://vine.com
366 - //'#https?://(.+\.)?vine\.co/v/.+#i' => 'vine',
367 -
368 - // Google Shortened Url
369 - '#https?://(.+\.)?goo\.gl/.+#i' => 'google',
370 -
371 - // Google Maps
372 - //'#https?://(.+\.)?google\.com/maps/.+#i' => 'googlemaps',
373 - //'#https?://(.+\.)?maps\.google\.com/.+#i' => 'googlemaps',
374 -
375 - // Google Docs
376 - //'#https?://(.+\.)?docs\.google\.com/(.+/)?(document|presentation|spreadsheets|forms|drawings)/.+#i' => 'googledocs',
377 -
378 - // Twitch.tv
379 - //'#https?://(.+\.)?twitch\.tv/.+#i' => 'twitch',
380 -
381 - // Giphy
382 - //'#https?://(.+\.)?giphy\.com/gifs/.+#i' => 'giphy',
383 - //'#https?://(.+\.)?i\.giphy\.com/.+#i' => 'giphy',
384 - //'#https?://(.+\.)?gph\.is/.+#i' => 'giphy',
385 -
386 - // Wistia
387 - //'#https?://(.+\.)?wistia\.com/medias/.+#i' => 'wistia',
388 - //'#https?://(.+\.)?fast\.wistia\.com/embed/medias/.+#i\.jsonp' => 'wistia',
389 - ];
390 -
391 - /**
392 - * ========================================
393 - * Make sure the $wp_write global is set.
394 - * This fix compatibility with JetPack, Classical Editor and Disable Gutenberg. JetPack makes
395 - * the oembed_providers filter be called and this activates our class too, but one dependency
396 - * of the rest_url method is not loaded yet.
397 - */
398 - global $wp_rewrite;
399 -
400 - if (!class_exists('\\WP_Rewrite')) {
401 - $path = ABSPATH . WPINC . '/class-wp-rewrite.php';
402 - if (file_exists($path)) {
403 - require_once $path;
142 + if ((bool)$plgSettings->enablePluginInAdmin) {
143 + $this->loaderInstance->add_action('admin_enqueue_scripts', $plgHandlerAdminInstance, 'enqueueScripts');
404 144 }
405 - }
406 145
407 - if (!is_object($wp_rewrite)) {
408 - $wp_rewrite = new \WP_Rewrite();
409 - $_GLOBALS['wp_write'] = $wp_rewrite;
410 - }
411 - /*========================================*/
146 + $onAjaxCallbackName = "doShortcodeReceivedViaAjax";
147 + $this->loaderInstance->add_action('wp_ajax_embedpress_do_ajax_request', $plgHandlerAdminInstance, $onAjaxCallbackName);
148 + $this->loaderInstance->add_action('wp_ajax_nopriv_embedpress_do_ajax_request', $plgHandlerAdminInstance, $onAjaxCallbackName);
412 149
413 - foreach ($newProviders as $url => &$data) {
414 - $data = [
415 - rest_url('embedpress/v1/oembed/' . $data),
416 - true,
417 - ];
418 - }
150 + $this->loaderInstance->add_action('wp_ajax_embedpress_get_embed_url_info', $plgHandlerAdminInstance, "getUrlInfoViaAjax");
419 151
420 - $providers = array_merge($providers, $newProviders);
421 -
422 - return $providers;
423 - }
424 -
425 - /**
426 - * Register OEmbed Rest Routes
427 - */
428 - public function registerOEmbedRestRoutes()
429 - {
430 - register_rest_route(
431 - 'embedpress/v1',
432 - '/oembed/(?P<provider>[a-zA-Z0-9\-]+)',
433 - [
434 - 'methods' => \WP_REST_Server::READABLE,
435 - 'callback' => ['\\EmbedPress\\RestAPI', 'oembed'],
436 - // This endpoint fetches an arbitrary user-supplied URL server-side
437 - // (oEmbed discovery). Its only legitimate caller is the block editor
438 - // preview, which always runs as a logged-in editor. Requiring
439 - // edit_posts prevents unauthenticated SSRF via this route.
440 - 'permission_callback' => function () {
441 - return current_user_can('edit_posts');
442 - },
443 - ]
444 - );
445 - register_rest_route(
446 - 'embedpress/v1',
447 - '/oembed/(?P<provider>[a-zA-Z0-9\-]+)',
448 - [
449 - 'methods' => \WP_REST_Server::CREATABLE,
450 - 'callback' => ['\\EmbedPress\\RestAPI', 'oembed'],
451 - 'permission_callback' => function () {
452 - return current_user_can('edit_posts');
453 - },
454 - ]
455 - );
456 -
457 - // Queue infinite-scroll: returns a batch of rendered <li.ep-yt-queue__item>
458 - // for the next page of a YouTube playlist.
459 - register_rest_route(
460 - 'embedpress/v1',
461 - '/youtube-playlist-items',
462 - [
463 - 'methods' => \WP_REST_Server::READABLE,
464 - 'callback' => ['\\EmbedPress\\RestAPI', 'youtube_playlist_items'],
465 - 'permission_callback' => '__return_true',
466 - 'args' => [
467 - 'playlist_id' => ['required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field'],
468 - 'page_token' => ['required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field'],
469 - 'page_size' => ['required' => false, 'type' => 'integer', 'sanitize_callback' => 'absint'],
470 - 'offset' => ['required' => false, 'type' => 'integer', 'sanitize_callback' => 'absint'],
471 - 'layout' => ['required' => false, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field'],
472 - ],
473 - ]
474 - );
475 -
476 - // Dynamic-source field enumerator (fbs-81736). Inspector drop-down
477 - // calls this to populate field choices for the selected provider
478 - // instead of asking the user to type the field key by hand.
479 - register_rest_route(
480 - 'embedpress/v1',
481 - '/dynamic-fields',
482 - [
483 - 'methods' => \WP_REST_Server::READABLE,
484 - 'callback' => ['\\EmbedPress\\Includes\\Classes\\DynamicFieldResolver', 'rest_list_fields'],
485 - 'permission_callback' => function () {
486 - return current_user_can('edit_posts')
487 - && \EmbedPress\Includes\Classes\Helper::is_pro_features_enabled();
488 - },
489 - 'args' => [
490 - 'source' => ['type' => 'string', 'required' => true],
491 - ],
492 - ]
493 - );
494 -
495 - // Dynamic-source value resolver (fbs-81736). The block editor calls this
496 - // to live-preview the resolved custom-field URL instead of the saved
497 - // placeholder, so the canvas matches the front-end render.
498 - register_rest_route(
499 - 'embedpress/v1',
500 - '/dynamic-resolve',
501 - [
502 - 'methods' => \WP_REST_Server::READABLE,
503 - 'callback' => ['\\EmbedPress\\Includes\\Classes\\DynamicFieldResolver', 'rest_resolve_field'],
504 - 'permission_callback' => function () {
505 - return current_user_can('edit_posts')
506 - && \EmbedPress\Includes\Classes\Helper::is_pro_features_enabled();
507 - },
508 - 'args' => [
509 - 'source' => ['type' => 'string', 'required' => true],
510 - 'field' => ['type' => 'string', 'required' => true],
511 - 'post_id' => ['type' => 'integer', 'required' => false],
512 - ],
513 - ]
514 - );
515 - }
516 -
517 - public function send_user_feedback_email($request)
518 - {
519 - // Ensure we have a valid REST request object
520 - if (!($request instanceof \WP_REST_Request)) {
521 - return new \WP_REST_Response(['message' => 'Invalid request'], 400);
522 - }
523 -
524 - // CRITICAL: Check if feedback was already sent FIRST to prevent spam
525 - $is_feedback_already_sent = get_option('embedpress_feedback_submited');
526 - if ($is_feedback_already_sent) {
527 - return new \WP_REST_Response(['message' => 'Feedback already submitted'], 200);
528 - }
529 -
530 - // Rate limiting: Only allow one request per IP per minute
531 - $user_ip = $this->get_user_ip();
532 - $rate_limit_key = 'embedpress_feedback_rate_limit_' . md5($user_ip);
533 - if (get_transient($rate_limit_key)) {
534 - return new \WP_REST_Response(['message' => 'Too many requests. Please try again later.'], 429);
535 - }
536 - set_transient($rate_limit_key, 2, MINUTE_IN_SECONDS);
537 -
538 - // Verify user is logged in and has admin capabilities
539 - if (!is_user_logged_in()) {
540 - return new \WP_REST_Response(['message' => 'Unauthorized. You must be logged in.'], 401);
541 - }
542 -
543 - if (!current_user_can('manage_options')) {
544 - return new \WP_REST_Response(['message' => 'Forbidden. Insufficient permissions.'], 403);
545 - }
546 -
547 - // Verify nonce for CSRF protection
548 - $nonce = $request->get_header('X-WP-Nonce');
549 -
550 - if (!$nonce || !wp_verify_nonce($nonce, 'wp_rest')) {
551 - return new \WP_REST_Response(['message' => 'Invalid security token. Please refresh the page and try again.'], 403);
552 - }
553 -
554 -
555 - $params = $request->get_params();
556 -
557 - // Safely extract and sanitize incoming params to avoid undefined index notices
558 - $params = is_array($params) ? $params : [];
559 - $user_email = isset($params['email']) ? sanitize_email($params['email']) : '';
560 - $user_name = isset($params['name']) ? sanitize_text_field($params['name']) : '';
561 - $user_rating = isset($params['rating']) ? intval($params['rating']) : 0;
562 - $user_msg = isset($params['message']) ? sanitize_textarea_field($params['message']) : '';
563 -
564 - // Validate rating is within acceptable range
565 - if ($user_rating < 1 || $user_rating > 5) {
566 - return new \WP_REST_Response(['message' => 'Invalid rating value. Must be between 1 and 5.'], 400);
567 - }
568 -
569 - // Prevent submissions with empty/invalid user data (prevents N/A spam)
570 - if (empty($user_email) || !is_email($user_email)) {
571 - return new \WP_REST_Response(['message' => 'Valid email address is required.'], 400);
572 - }
573 -
574 - if (empty($user_name) || strlen(trim($user_name)) < 2) {
575 - return new \WP_REST_Response(['message' => 'Valid name is required.'], 400);
576 - }
577 -
578 - // If the payload is completely empty, ignore to prevent blank/spam emails
579 - $has_meaningful_input = false;
580 -
581 - if ($user_rating > 0) {
582 - if ($user_rating < 5) {
583 - // description required
584 - if (trim($user_msg) !== '') {
585 - $has_meaningful_input = true;
586 - }
587 - } else {
588 - // rating is 5, description not required
589 - $has_meaningful_input = true;
590 - }
591 - }
592 -
593 - if (!$has_meaningful_input) {
594 - return new \WP_REST_Response(['message' => 'No feedback content provided; ignored.'], 200);
595 - }
596 -
597 - // Prevent accidental duplicate submissions (double-clicks, quick retries)
598 - $payload_hash = md5(json_encode([$user_email, $user_name, $user_rating, $user_msg]));
599 - if (get_transient('embedpress_feedback_dupe_' . $payload_hash)) {
600 - return new \WP_REST_Response(['message' => 'Duplicate feedback detected; already processed.'], 200);
601 - }
602 - set_transient('embedpress_feedback_dupe_' . $payload_hash, 1, 5 * MINUTE_IN_SECONDS);
603 -
604 - $email_html = $user_email ? '<a href="mailto:' . esc_attr($user_email) . '">' . esc_html($user_email) . '</a>' : 'N/A';
605 - $rating_html = $user_rating ? esc_html($user_rating) . ' ⭐️' : 'N/A';
606 - $message_html = $user_msg !== '' ? nl2br(esc_html($user_msg)) : 'N/A';
607 -
608 -
609 - $site_name = get_bloginfo('name');
610 - $site_url = get_site_url();
611 - $admin_email = get_option('admin_email');
612 - $wp_version = get_bloginfo('version');
613 -
614 - $admin_user = get_user_by('ID', 1);
615 - if ($admin_user) {
616 - $first_name = get_user_meta($admin_user->ID, 'first_name', true);
617 - $last_name = get_user_meta($admin_user->ID, 'last_name', true);
618 -
619 - $admin_full_name = trim("$first_name $last_name");
620 -
621 - // Fallback to display name if full name is not set
622 - if (empty($admin_full_name)) {
623 - $admin_full_name = $admin_user->display_name;
624 - }
152 + unset($onAjaxCallbackName, $plgHandlerAdminInstance);
625 153 } else {
626 - $admin_full_name = 'Unknown';
627 - }
154 + add_action('init', array('\EmbedPress\Disabler', 'run'), 1);
628 155
629 - $to = 'akash@wpdeveloper.com, rasel@wpdeveloper.com, nahid@wpdeveloper.com, md-nahid-hasan@wpdeveloper.com'; // Replace with the recipient's email
630 - $subject = '[IMPORTANT] New feedback received from an EmbedPress user.';
156 + $plgHandlerPublicInstance = new EndHandlerPublic($this->getPluginName(), $this->getPluginVersion());
631 157
632 - // HTML Email Template
633 - $message = '<html><body style="font-family: Arial, sans-serif; padding: 20px;">';
634 - $message .= '<div style="max-width: 600px; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin: auto;">';
635 - $message .= '<div style="text-align: center; padding-bottom: 20px; border-bottom: 1px solid #ddd">';
636 - $message .= '<img src="https://embedpress.com/wp-content/uploads/2025/03/logo.png" alt="EmbedPress" style="max-width: 150px;">';
637 - $message .= '</div>';
638 - $message .= '<h2 style="font-family: system-ui; color: #333; text-align: center;">Feedback Overview</h2>';
639 - $message .= '<table style="font-family: system-ui; width: 100%; border-collapse: collapse; border: 1px solid #ddd">';
158 + $enqueueScriptsHookName = "wp_enqueue_scripts";
159 + $this->loaderInstance->add_action($enqueueScriptsHookName, $plgHandlerPublicInstance, 'enqueueScripts');
160 + $this->loaderInstance->add_action($enqueueScriptsHookName, $plgHandlerPublicInstance, 'enqueueStyles');
640 161
641 - // Email
642 - $message .= '<tr><td style="padding: 10px; font-weight: bold; width: 100px; border-bottom: 1px solid #ddd;">Email :</td>';
643 - $message .= '<td style="padding: 10px; border-bottom: 1px solid #ddd;">' . $email_html . '</td></tr>';
644 -
645 - // Rating
646 - $message .= '<tr><td style="padding: 10px; font-weight: bold; width: 100px; border-bottom: 1px solid #ddd;">Rating :</td>';
647 - $message .= '<td style="padding: 10px; border-bottom: 1px solid #ddd;">' . $rating_html . '</td></tr>';
648 -
649 - // User
650 - $message .= '<tr><td style="padding: 10px; font-weight: bold; width: 100px; border-bottom: 1px solid #ddd;">Name :</td>';
651 - $message .= '<td style="padding: 10px; border-bottom: 1px solid #ddd; font-weight: 500;">' . esc_html($admin_full_name) . '</td></tr>';
652 -
653 - // Pack
654 - $message .= '<tr><td style="padding: 10px; font-weight: bold; width: 100px; border-bottom: 1px solid #ddd;">Site Url :</td>';
655 - $message .= '<td style="padding: 10px; border-bottom: 1px solid #ddd;"><a target="_blank" href="' . esc_url($site_url) . '" style="color: blue;">' . esc_html($site_url) . '</a></td></tr>';
656 -
657 - // Feedback
658 - $message .= '<tr><td style="padding: 10px; font-weight: bold; width: 100px; display: flex;">Feedback :</td>';
659 - $message .= '<td style="padding: 10px;">' . $message_html . '</td></tr>';
660 -
661 - $message .= '</table>';
662 - $message .= '</div></body></html>';
663 -
664 - $headers = [
665 - 'Content-Type: text/html; charset=UTF-8',
666 - 'From: ' . esc_html($site_name) . ' <' . sanitize_email($admin_email) . '>'
667 - ];
668 - if ($user_email) {
669 - $reply_to = $user_name ? esc_html($user_name) . ' <' . sanitize_email($user_email) . '>' : sanitize_email($user_email);
670 - $headers[] = 'Reply-To: ' . $reply_to;
162 + unset($enqueueScriptsHookName, $plgHandlerPublicInstance);
671 163 }
672 164
673 - // Send the email
674 - $sent = wp_mail($to, $subject, $message, $headers);
165 + // Add support for embeds on AMP pages
166 + add_filter('pp_embed_parsed_content', array('\EmbedPress\AMP\EmbedHandler', 'processParsedContent'), 10, 3);
675 167
676 - if ($sent) {
677 - update_option('embedpress_feedback_submited', true);
678 -
679 - return new \WP_REST_Response(['message' => 'Email sent successfully!'], 200);
680 - } else {
681 - // Retrieve last error
682 - $last_error = get_transient('embedpress_last_mail_error');
683 - $error_message = 'Failed to send email.';
684 - if ($last_error instanceof \WP_Error) {
685 - $error_message = $last_error->get_error_message();
686 - }
687 -
688 - return new \WP_REST_Response([
689 - 'message' => $error_message
690 - ], 422); // using 422 instead of 500
691 - }
168 + $this->loaderInstance->run();
692 169 }
693 170
694 - public function capture_mail_error($wp_error)
695 - {
696 - if ($wp_error instanceof \WP_Error) {
697 - set_transient('embedpress_last_mail_error', $wp_error, 60);
698 - }
699 - }
700 -
701 171 /**
702 - * Get user IP address safely
703 - *
704 - * @return string
705 - */
706 - private function get_user_ip()
707 - {
708 - $ip_keys = [
709 - 'HTTP_CF_CONNECTING_IP', // CloudFlare
710 - 'HTTP_X_FORWARDED_FOR',
711 - 'HTTP_X_REAL_IP',
712 - 'REMOTE_ADDR'
713 - ];
714 -
715 - foreach ($ip_keys as $key) {
716 - if (!empty($_SERVER[$key])) {
717 - $ip = sanitize_text_field(wp_unslash($_SERVER[$key]));
718 - // Handle comma-separated IPs (from proxies)
719 - if (strpos($ip, ',') !== false) {
720 - $ip = trim(explode(',', $ip)[0]);
721 - }
722 - if (filter_var($ip, FILTER_VALIDATE_IP)) {
723 - return $ip;
724 - }
725 - }
726 - }
727 -
728 - return '0.0.0.0';
729 - }
730 -
731 - /**
732 - * Permission callback for feedback endpoint
733 - *
734 - * We return true here to allow the request to reach our handler,
735 - * where we perform detailed authentication and authorization checks
736 - * with custom error messages.
737 - *
738 - * @return bool
739 - */
740 - public function feedback_permission_callback()
741 - {
742 - // Return true to allow request to reach handler
743 - // Actual auth checks are done in send_user_feedback_email()
744 - return true;
745 - }
746 -
747 -
748 - public function register_feedback_email_endpoint()
749 - {
750 - register_rest_route('embedpress/v1', '/send-feedback', [
751 - 'methods' => 'POST',
752 - 'callback' => [$this, 'send_user_feedback_email'],
753 - 'permission_callback' => [$this, 'feedback_permission_callback'],
754 - 'args' => [
755 - 'email' => [
756 - 'required' => false,
757 - 'type' => 'string',
758 - 'sanitize_callback' => 'sanitize_email',
759 - ],
760 - 'name' => [
761 - 'required' => false,
762 - 'type' => 'string',
763 - 'sanitize_callback' => 'sanitize_text_field',
764 - ],
765 - 'rating' => [
766 - 'required' => true,
767 - 'type' => 'integer',
768 - 'validate_callback' => function($param) {
769 - return is_numeric($param) && $param >= 1 && $param <= 5;
770 - }
771 - ],
772 - 'message' => [
773 - 'required' => false,
774 - 'type' => 'string',
775 - 'sanitize_callback' => 'sanitize_textarea_field',
776 - ],
777 - ]
778 - ]);
779 - }
780 -
781 -
782 -
783 - /**
784 172 * Callback called right after the plugin has been activated.
785 173 *
786 - * @return void
787 174 * @since 1.0.0
788 175 * @static
789 176 *
177 + * @return void
790 178 */
791 179 public static function onPluginActivationCallback()
792 180 {
793 - $dirname = wp_get_upload_dir()['basedir'] . '/embedpress';
794 - if (!file_exists($dirname)) {
795 - mkdir($dirname, 0777);
796 - }
181 + add_filter('rewrite_rules_array', array('\EmbedPress\Disabler', 'disableDefaultEmbedRewriteRules'));
797 182 flush_rewrite_rules();
798 - embedpress_schedule_cache_cleanup();
799 -
800 - // Trigger the setup wizard redirect only on a true fresh install. The
801 - // 'embedpress_install_type' marker is set in EmbedpressSettings::__construct
802 - // before any default settings are written, so it reliably distinguishes
803 - // first-ever installs from re-activations after a plugin update.
804 - $pro_active = apply_filters( 'embedpress/is_allow_rander', false );
805 - $install_type = get_option( 'embedpress_install_type', false );
806 -
807 - if ( ! $pro_active && $install_type !== 'existing' ) {
808 - $settings = get_option( EMBEDPRESS_PLG_NAME, [] );
809 - $settings['need_first_time_redirect'] = true;
810 - update_option( EMBEDPRESS_PLG_NAME, $settings );
811 -
812 - // Clear any previous redirect done flag
813 - delete_option( 'embedpress_activation_redirect_done' );
814 -
815 - }
816 -
817 - // "What's New" modal: show ONLY after an update from an older version,
818 - // never on a brand-new install (a first-time user has nothing "new").
819 - //
820 - // Trust the 'embedpress_install_type' marker here — do NOT re-derive
821 - // "prior data" from EMBEDPRESS_PLG_NAME. EmbedpressSettings::__construct
822 - // runs during initialize() EARLIER in this same activation request and
823 - // (a) computes install_type before writing anything, then (b) seeds
824 - // default settings (turn_off_rating_help / turn_off_milestone / …) into
825 - // EMBEDPRESS_PLG_NAME. So by the time this callback runs that option is
826 - // ALWAYS non-empty — the old !empty() check made every fresh install look
827 - // "existing" and wrongly fired the modal on top of the onboarding wizard.
828 - //
829 - // On a fresh install we stamp the current version as already seen so both
830 - // the modal and the menu "New" badge stay suppressed; on an update we
831 - // leave the markers unset and the modal fires once.
832 - $seen_option = \EmbedPress\Includes\Classes\FeaturePreviewModal::SEEN_VERSION_OPTION;
833 - if ( get_option( $seen_option, false ) === false ) {
834 - if ( $install_type === 'existing' ) {
835 - // Known existing user (update / re-activate) → let the modal fire once.
836 - $is_fresh_install = false;
837 - } elseif ( $install_type === 'fresh' ) {
838 - // Known fresh install → suppress.
839 - $is_fresh_install = true;
840 - } else {
841 - // install_type not computed this request (e.g. WP-CLI activation,
842 - // where EmbedpressSettings didn't run and so has NOT polluted
843 - // EMBEDPRESS_PLG_NAME) → direct data detection is reliable here.
844 - $is_fresh_install = ! (
845 - (bool) get_option( 'embedpress_elements_updated', false )
846 - || ! empty( get_option( EMBEDPRESS_PLG_NAME, [] ) )
847 - || ! empty( get_option( EMBEDPRESS_PLG_NAME . ':elements', [] ) )
848 - );
849 - }
850 -
851 - if ( $is_fresh_install ) {
852 - $current_version = defined( 'EMBEDPRESS_VERSION' ) ? EMBEDPRESS_VERSION : '0.0.0';
853 - // Suppress the modal (seen) AND the menu "New" badge (opened) — a
854 - // first-time user has nothing "new" to be announced.
855 - update_option( $seen_option, $current_version );
856 - update_option(
857 - \EmbedPress\Includes\Classes\FeaturePreviewModal::OPENED_VERSION_OPTION,
858 - $current_version
859 - );
860 - }
861 - }
862 183 }
863 184
864 185 /**
865 186 * Callback called right after the plugin has been deactivated.
866 187 *
867 - * @return void
868 188 * @since 1.0.0
869 189 * @static
870 190 *
191 + * @return void
871 192 */
872 193 public static function onPluginDeactivationCallback()
873 194 {
195 + remove_filter('rewrite_rules_array', array('\EmbedPress\Disabler', 'disableDefaultEmbedRewriteRules'));
874 196 flush_rewrite_rules();
875 - embedpress_cache_cleanup();
876 - $timestamp = wp_next_scheduled('embedpress_backup_cleanup_action');
877 - if ($timestamp) {
878 - wp_unschedule_event($timestamp, 'embedpress_backup_cleanup_action');
879 - }
880 197 }
881 198
882 199 /**
883 200 * Method that retrieves all additional service providers defined in the ~<plugin_root_path>/providers.php file.
884 201 *
885 - * @return array
886 202 * @since 1.0.0
887 203 * @static
888 204 *
205 + * @return array
889 206 */
890 207 public static function getAdditionalServiceProviders()
891 208 {
892 - $additionalProvidersFilePath = EMBEDPRESS_PATH_BASE . 'providers.php';
209 + $additionalProvidersFilePath = EMBEDPRESS_PATH_BASE .'providers.php';
893 210 if (file_exists($additionalProvidersFilePath)) {
894 211 include $additionalProvidersFilePath;
895 212
896 213 if (isset($additionalServiceProviders)) {
897 - return apply_filters('embedpress_additional_service_providers', $additionalServiceProviders);
214 + return $additionalServiceProviders;
898 215 }
899 216 }
900 217
901 - return apply_filters('embedpress_additional_service_providers', []);
218 + return array();
902 219 }
903 220
904 221 /**
905 222 * Method that checks if an embed of a given service provider can be responsive.
906 223 *
907 - * @param string $serviceProviderAlias The service's slug.
908 - *
909 - * @return boolean
910 224 * @since 1.0.0
911 225 * @static
912 226 *
227 + * @param string $serviceProviderAlias The service's slug.
228 + * @return boolean
913 229 */
914 230 public static function canServiceProviderBeResponsive($serviceProviderAlias)
915 231 {
916 - return in_array($serviceProviderAlias, [
917 - "dailymotion",
918 - "kickstarter",
919 - "rutube",
920 - "ted",
921 - "vimeo",
922 - "youtube",
923 - "ustream",
924 - "google-docs",
925 - "animatron",
926 - "amcharts",
927 - "on-aol-com",
928 - "animoto",
929 - "videojug",
930 - 'issuu',
931 - ]);
232 + return in_array($serviceProviderAlias, array("dailymotion", "kickstarter", "rutube", "ted", "vimeo", "youtube", "ustream", "google-docs", "animatron", "amcharts", "on-aol-com", "animoto", "videojug", 'issuu'));
932 233 }
933 234
934 235 /**
935 236 * Method that retrieves the plugin settings defined by the user.
936 237 *
937 - * @return object
938 238 * @since 1.0.0
939 239 * @static
940 240 *
241 + * @return object
941 242 */
942 243 public static function getSettings()
943 244 {
944 - // Fetch settings from the database
945 245 $settings = get_option(EMBEDPRESS_PLG_NAME);
946 246
947 - // If the settings are not an array (it might return false), initialize as an empty array
948 - if (!is_array($settings)) {
949 - $settings = [];
950 - }
951 -
952 - // Default values if settings are missing
953 247 if (!isset($settings['enablePluginInAdmin'])) {
954 248 $settings['enablePluginInAdmin'] = true;
955 249 }
956 250
@@ -957,30 +251,59 @@
957 251 if (!isset($settings['enablePluginInFront'])) {
958 252 $settings['enablePluginInFront'] = true;
959 253 }
960 254
961 - if (!isset($settings['enableGlobalEmbedResize'])) {
962 - $settings['enableGlobalEmbedResize'] = false;
255 + return (object)$settings;
256 + }
257 +
258 + /**
259 + * Method that register an EmbedPress plugin.
260 + *
261 + * @since 1.4.0
262 + * @static
263 + *
264 + * @param array $pluginMeta Associative array containing plugin's name, slug and namespace
265 + * @return void
266 + */
267 + public static function registerPlugin($pluginMeta)
268 + {
269 + $pluginMeta = json_decode(json_encode($pluginMeta));
270 +
271 + if (empty($pluginMeta->name) || empty($pluginMeta->slug) || empty($pluginMeta->namespace)) {
272 + return;
963 273 }
964 274
965 - if (!isset($settings['enableEmbedResizeHeight'])) {
966 - $settings['enableEmbedResizeHeight'] = 550; // old 552
967 - }
275 + if (!isset(self::$plugins[$pluginMeta->slug])) {
276 + AutoLoader::register($pluginMeta->namespace, WP_PLUGIN_DIR .'/'. EMBEDPRESS_PLG_NAME .'-'. $pluginMeta->slug .'/'. $pluginMeta->name);
968 277
969 - if (!isset($settings['enableEmbedResizeWidth'])) {
970 - $settings['enableEmbedResizeWidth'] = 600; // old 652
278 + $plugin = "{$pluginMeta->namespace}\Plugin";
279 + if (\defined("{$plugin}::SLUG") && $plugin::SLUG !== null) {
280 + self::$plugins[$pluginMeta->slug] = $pluginMeta->namespace;
281 +
282 + $bsFilePath = $plugin::PATH . EMBEDPRESS_PLG_NAME .'-'. $plugin::SLUG .'.php';
283 +
284 + register_activation_hook($bsFilePath, array($plugin::NAMESPACE_STRING, 'onActivationCallback'));
285 + register_deactivation_hook($bsFilePath, array($plugin::NAMESPACE_STRING, 'onDeactivationCallback'));
286 +
287 + add_action('admin_init', array($plugin, 'onLoadAdminCallback'));
288 +
289 + add_action(EMBEDPRESS_PLG_NAME .':'. $plugin::SLUG .':settings:register', array($plugin, 'registerSettings'));
290 + add_action(EMBEDPRESS_PLG_NAME .':settings:render:tab', array($plugin, 'renderTab'));
291 +
292 + add_filter('plugin_action_links_embedpress-'. $plugin::SLUG .'/embedpress-'. $plugin::SLUG .'.php', array($plugin, 'handleActionLinks'), 10, 2);
293 +
294 + $plugin::registerEvents();
295 + }
971 296 }
972 -
973 - return (object) $settings;
974 297 }
975 298
976 299 /**
977 300 * Retrieve all registered plugins.
978 301 *
979 - * @return array
980 302 * @since 1.4.0
981 303 * @static
982 304 *
305 + * @return array
983 306 */
984 307 public static function getPlugins()
985 308 {
986 309 return self::$plugins;
@@ -988,39 +311,33 @@
988 311
989 312 /**
990 313 * Handle links displayed below the plugin name in the WordPress Installed Plugins page.
991 314 *
992 - * @return array
993 315 * @since 1.4.0
994 316 * @static
995 317 *
318 + * @return array
996 319 */
997 320 public static function handleActionLinks($links, $file)
998 321 {
999 - $settingsLink = '<a href="' . admin_url('admin.php?page=embedpress') . '" aria-label="' . __(
1000 - 'Open settings page',
1001 - 'embedpress'
1002 - ) . '">' . __('Settings', 'embedpress') . '</a>';
322 + $settingsLink = '<a href="'. admin_url('admin.php?page=embedpress') .'" aria-label="'. __('Open settings page', 'embedpress') .'">'. __('Settings', 'embedpress') .'</a>';
1003 323
1004 324 array_unshift($links, $settingsLink);
1005 - if (!apply_filters('embedpress/is_allow_rander', false)) {
1006 - $links[] = '<a href="https://wpdeveloper.com/in/upgrade-embedpress" target="_blank" class="embedpress-go-pro-action" style="color: green">' . __('Go Pro', 'embedpress') . '</a>';
1007 - }
325 +
1008 326 return $links;
1009 327 }
1010 328
1011 -
1012 329 /**
1013 330 * Method that ensures the API's url are whitelisted to WordPress external requests.
1014 331 *
1015 - * @param boolean $isAllowed
1016 - * @param string $host
1017 - * @param string $url
1018 - *
1019 - * @return boolean
1020 332 * @since 1.4.0
1021 333 * @static
1022 334 *
335 + * @param boolean $isAllowed
336 + * @param string $host
337 + * @param string $url
338 + *
339 + * @return boolean
1023 340 */
1024 341 public static function allowApiHost($isAllowed, $host, $url)
1025 342 {
1026 343 if ($host === EMBEDPRESS_LICENSES_API_HOST) {
@@ -1029,10 +346,39 @@
1029 346
1030 347 return $isAllowed;
1031 348 }
1032 349
1033 - public function extended_mime_types($mimes)
350 + /**
351 + * Add filters to configure the TinyMCE editor.
352 + *
353 + * @since 1.6.2
354 + */
355 + public function configureTinyMCE()
1034 356 {
1035 - $mimes['ppsx'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
1036 - return $mimes;
357 + add_filter('teeny_mce_before_init', array($this, 'hookOnPaste'));
358 + add_filter('tiny_mce_before_init', array($this, 'hookOnPaste'));
359 + }
360 +
361 + /**
362 + * Hook the onPaste methof to the paste_preprocess config in the editor.
363 + *
364 + * @since 1.6.2
365 + *
366 + * @param array $mceInit
367 + *
368 + * @return array
369 + */
370 + public function hookOnPaste($mceInit)
371 + {
372 + $settings = self::getSettings();
373 +
374 + if (isset($settings->enablePluginInAdmin) && $settings->enablePluginInAdmin) {
375 + // We hook here because the onPaste is sometimes called after the content was already added to the editor.
376 + // If you copy text from the editor and paste there, it will give no way to use a normal onPaste event hook
377 + // to modify the input since it was already injected.
378 + $mceInit['paste_preprocess'] = 'function (plugin, args) {EmbedPress.onPaste(plugin, args);}';
379 + }
380 +
381 +
382 + return $mceInit;
1037 383 }
1038 384 }