compatibility.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. <?php
  2. /**
  3. * Misc functions for compatibility with other plugins.
  4. */
  5. /**
  6. * Support for tinyPNG.
  7. *
  8. * Runs cropped photos stored in cache through tinyPNG.
  9. */
  10. function fl_builder_tinypng_support( $cropped_path, $editor ) {
  11. if ( class_exists( 'Tiny_Settings' ) ) {
  12. try {
  13. $settings = new Tiny_Settings();
  14. $settings->xmlrpc_init();
  15. $compressor = $settings->get_compressor();
  16. if ( $compressor ) {
  17. $compressor->compress_file( $cropped_path['path'], false, false );
  18. }
  19. } catch ( Exception $e ) {
  20. //
  21. }
  22. }
  23. }
  24. add_action( 'fl_builder_photo_cropped', 'fl_builder_tinypng_support', 10, 2 );
  25. /**
  26. * Support for WooCommerce Memberships.
  27. *
  28. * Makes sure builder content isn't rendered for protected posts.
  29. */
  30. function fl_builder_wc_memberships_support() {
  31. if ( function_exists( 'wc_memberships_is_post_content_restricted' ) ) {
  32. function fl_builder_wc_memberships_maybe_render_content( $do_render, $post_id ) {
  33. if ( wc_memberships_is_post_content_restricted() ) {
  34. // check if user has access to restricted content
  35. if ( ! current_user_can( 'wc_memberships_view_restricted_post_content', $post_id ) ) {
  36. $do_render = false;
  37. } elseif ( ! current_user_can( 'wc_memberships_view_delayed_post_content', $post_id ) ) {
  38. $do_render = false;
  39. }
  40. }
  41. return $do_render;
  42. }
  43. add_filter( 'fl_builder_do_render_content', 'fl_builder_wc_memberships_maybe_render_content', 10, 2 );
  44. }
  45. }
  46. add_action( 'plugins_loaded', 'fl_builder_wc_memberships_support', 11 );
  47. /**
  48. * Support for Option Tree.
  49. *
  50. * Older versions of Option Tree don't declare the ot_get_media_post_ID
  51. * function on the frontend which is needed for the media uploader and
  52. * throws an error if it doesn't exist.
  53. */
  54. function fl_builder_option_tree_support() {
  55. if ( ! function_exists( 'ot_get_media_post_ID' ) ) {
  56. function ot_get_media_post_ID() { // @codingStandardsIgnoreLine
  57. // Option ID
  58. $option_id = 'ot_media_post_ID';
  59. // Get the media post ID
  60. $post_id = get_option( $option_id, false );
  61. // Add $post_ID to the DB
  62. if ( false === $post_id ) {
  63. global $wpdb;
  64. // Get the media post ID
  65. $post_id = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE `post_title` = 'Media' AND `post_type` = 'option-tree' AND `post_status` = 'private'" );
  66. // Add to the DB
  67. add_option( $option_id, $post_id );
  68. }
  69. return $post_id;
  70. }
  71. }
  72. }
  73. add_action( 'after_setup_theme', 'fl_builder_option_tree_support' );
  74. /**
  75. * If FORCE_SSL_ADMIN is enabled but the frontend is not SSL fixes a CORS error when trying to upload a photo.
  76. * `add_filter( 'fl_admin_ssl_upload_fix', '__return_false' );` will disable.
  77. *
  78. * @since 1.10.2
  79. */
  80. function fl_admin_ssl_upload_fix() {
  81. if ( defined( 'FORCE_SSL_ADMIN' ) && ! is_ssl() && is_admin() && FLBuilderAJAX::doing_ajax() ) {
  82. if ( isset( $_POST['action'] ) && 'upload-attachment' === $_POST['action'] && true === apply_filters( 'fl_admin_ssl_upload_fix', true ) ) {
  83. force_ssl_admin( false );
  84. }
  85. }
  86. }
  87. add_action( 'plugins_loaded', 'fl_admin_ssl_upload_fix', 11 );
  88. /**
  89. * Disable support Buddypress pages since it's causing conflicts with `the_content` filter
  90. *
  91. * @param bool $is_editable Wether the post is editable or not
  92. * @param $post The post to check from
  93. * @return bool
  94. */
  95. function fl_builder_bp_pages_support( $is_editable, $post = false ) {
  96. // Frontend check
  97. if ( ! is_admin() && class_exists( 'BuddyPress' ) && ! bp_is_blog_page() ) {
  98. $is_editable = false;
  99. }
  100. // Admin rows action link check and applies to page list
  101. if ( is_admin() && class_exists( 'BuddyPress' ) && $post && 'page' == $post->post_type ) {
  102. $bp = buddypress();
  103. if ( $bp->pages ) {
  104. foreach ( $bp->pages as $page ) {
  105. if ( $post->ID == $page->id ) {
  106. $is_editable = false;
  107. break;
  108. }
  109. }
  110. }
  111. }
  112. return $is_editable;
  113. }
  114. add_filter( 'fl_builder_is_post_editable', 'fl_builder_bp_pages_support', 11, 2 );
  115. /**
  116. * There is an issue with Jetpack Photon and circle cropped photo module
  117. * returning the wrong image sizes from the bb cache folder.
  118. * This filter disables photon for circle cropped photo module images.
  119. */
  120. function fl_photo_photon_exception( $val, $src, $tag ) {
  121. // Make sure its a bb cached image.
  122. if ( false !== strpos( $src, 'bb-plugin/cache' ) ) {
  123. // now make sure its a circle cropped image.
  124. if ( false !== strpos( basename( $src ), '-circle' ) ) {
  125. return apply_filters( 'fl_photo_photon_exception', true );
  126. }
  127. }
  128. // return original val
  129. return $val;
  130. }
  131. add_filter( 'jetpack_photon_skip_image', 'fl_photo_photon_exception', 10, 3 );
  132. /**
  133. * WordPress pre 4.5 we need to make sure that ui-core|widget|mouse are loaded before sortable.
  134. */
  135. function fl_before_sortable_enqueue_callback() {
  136. if ( version_compare( get_bloginfo( 'version' ), '4.5', '<' ) ) {
  137. wp_deregister_script( 'jquery-ui-widget' );
  138. wp_deregister_script( 'jquery-ui-mouse' );
  139. wp_deregister_script( 'jquery-ui-core' );
  140. wp_enqueue_script( 'jquery-ui-core', site_url( '/wp-includes/js/jquery/ui/core.min.js' ), array( 'jquery' ), '1.8.12' );
  141. wp_enqueue_script( 'jquery-ui-widget', site_url( '/wp-includes/js/jquery/ui/widget.min.js' ), array( 'jquery' ), '1.8.12' );
  142. wp_enqueue_script( 'jquery-ui-mouse', site_url( '/wp-includes/js/jquery/ui/mouse.min.js' ), array( 'jquery' ), '1.8.12' );
  143. }
  144. }
  145. add_action( 'fl_before_sortable_enqueue', 'fl_before_sortable_enqueue_callback' );
  146. /**
  147. * Try to unserialize data normally.
  148. * Uses a preg_callback to fix broken data caused by serialized data that has broken offsets.
  149. *
  150. * @since 1.10.6
  151. * @param string $data unserialized string
  152. * @return array
  153. */
  154. function fl_maybe_fix_unserialize( $data ) {
  155. // @codingStandardsIgnoreStart
  156. $unserialized = @unserialize( $data );
  157. // @codingStandardsIgnoreEnd
  158. if ( ! $unserialized ) {
  159. $unserialized = unserialize( preg_replace_callback( '!s:(\d+):"(.*?)";!', 'fl_maybe_fix_unserialize_callback', $data ) );
  160. }
  161. return $unserialized;
  162. }
  163. /**
  164. * Callback function for fl_maybe_fix_unserialize()
  165. *
  166. * @since 1.10.6
  167. */
  168. function fl_maybe_fix_unserialize_callback( $match ) {
  169. return ( strlen( $match[2] ) == $match[1] ) ? $match[0] : 's:' . strlen( $match[2] ) . ':"' . $match[2] . '";';
  170. }
  171. /**
  172. * Filter rendered module content and if safemode is active safely display a message.
  173. * @since 1.10.7
  174. */
  175. function fl_builder_render_module_content_filter( $contents, $module ) {
  176. if ( isset( $_GET['safemode'] ) && FLBuilderModel::is_builder_active() ) {
  177. return sprintf( '<h3>[%1$s] %2$s %3$s</h3>', __( 'SAFEMODE', 'fl-builder' ), $module->name, __( 'module', 'fl-builder' ) );
  178. } else {
  179. return $contents;
  180. }
  181. }
  182. add_filter( 'fl_builder_render_module_content', 'fl_builder_render_module_content_filter', 10, 2 );
  183. /**
  184. * Duplicate posts plugin fixes when cloning BB template.
  185. *
  186. * @since 1.10.8
  187. * @param int $meta_id The newly added meta ID
  188. * @param int $object_id ID of the object metadata is for.
  189. * @param string $meta_key Metadata key
  190. * @param string $meta_value Metadata value
  191. * @return void
  192. */
  193. function fl_builder_template_meta_add( $meta_id, $object_id, $meta_key, $meta_value ) {
  194. global $pagenow;
  195. if ( 'admin.php' != $pagenow ) {
  196. return;
  197. }
  198. if ( ! isset( $_REQUEST['action'] ) || 'duplicate_post_save_as_new_post' != $_REQUEST['action'] ) {
  199. return;
  200. }
  201. $post_type = get_post_type( $object_id );
  202. if ( 'fl-builder-template' != $post_type || '_fl_builder_template_id' != $meta_key ) {
  203. return;
  204. }
  205. // Generate new template ID;
  206. $template_id = FLBuilderModel::generate_node_id();
  207. update_post_meta( $object_id, '_fl_builder_template_id', $template_id );
  208. }
  209. add_action( 'added_post_meta', 'fl_builder_template_meta_add', 10, 4 );
  210. /**
  211. * Stop bw-minify from optimizing when builder is open.
  212. * @since 1.10.9
  213. */
  214. function fl_bwp_minify_is_loadable_filter( $args ) {
  215. if ( FLBuilderModel::is_builder_active() ) {
  216. return false;
  217. }
  218. return $args;
  219. }
  220. add_filter( 'bwp_minify_is_loadable', 'fl_bwp_minify_is_loadable_filter' );
  221. /**
  222. * Stop autoptimize from optimizing when builder is open.
  223. * @since 1.10.9
  224. */
  225. function fl_autoptimize_filter_noptimize_filter( $args ) {
  226. if ( FLBuilderModel::is_builder_active() ) {
  227. return true;
  228. }
  229. return $args;
  230. }
  231. add_filter( 'autoptimize_filter_noptimize', 'fl_autoptimize_filter_noptimize_filter' );
  232. /**
  233. * Fixes an issue on search archives if one of the results contains same shortcode
  234. * as is currently trying to render.
  235. *
  236. * @since 1.10.9
  237. * @param bool $render Render shortcode.
  238. * @param array $attrs Shortcode attributes.
  239. * @param array $args Passed to FLBuilder::render_query
  240. * @return bool
  241. */
  242. function fl_builder_insert_layout_render_search( $render, $attrs, $args ) {
  243. global $post, $wp_query;
  244. if ( is_search() && is_object( $post ) && is_array( $wp_query->posts ) ) {
  245. foreach ( $wp_query->posts as $queried_post ) {
  246. if ( $post->ID === $queried_post->ID ) {
  247. preg_match( '#(?<=fl_builder_insert_layout).*[id|slug]=[\'"]?([0-9a-z-]+)#', $post->post_content, $matches );
  248. if ( isset( $matches[1] ) ) {
  249. return false;
  250. }
  251. }
  252. }
  253. }
  254. return $render;
  255. }
  256. add_action( 'fl_builder_insert_layout_render', 'fl_builder_insert_layout_render_search', 10, 3 );
  257. /**
  258. * Fixes ajax issues with Event Espresso plugin when builder is open.
  259. * @since 2.1
  260. */
  261. function fl_ee_suppress_notices() {
  262. if ( FLBuilderModel::is_builder_active() ) {
  263. add_filter( 'FHEE__EE_Front_Controller__display_errors', '__return_false' );
  264. }
  265. }
  266. add_action( 'wp', 'fl_ee_suppress_notices' );
  267. /**
  268. * Stops ee from outputting HTML into our ajax responses.
  269. * @since 2.1
  270. */
  271. function fl_ee_before_ajax() {
  272. add_filter( 'FHEE__EE_Front_Controller__display_errors', '__return_false' );
  273. }
  274. add_action( 'fl_ajax_before_call_action', 'fl_ee_before_ajax' );
  275. /**
  276. * Plugin Enjoy Instagram loads its js and css on all frontend pages breaking the builder.
  277. * @since 2.0.1
  278. */
  279. add_action( 'template_redirect', 'fix_aggiungi_script_instafeed_owl', 1000 );
  280. function fix_aggiungi_script_instafeed_owl() {
  281. if ( FLBuilderModel::is_builder_active() ) {
  282. remove_action( 'wp_enqueue_scripts', 'aggiungi_script_instafeed_owl' );
  283. }
  284. }
  285. /**
  286. * Siteground cache captures shutdown and breaks our dynamic js loading.
  287. * @since 2.0.4.2
  288. */
  289. add_action( 'plugins_loaded', 'fl_fix_sg_cache', 9 );
  290. function fl_fix_sg_cache() {
  291. if ( isset( $_GET['fl_builder_load_settings_config'] ) ) {
  292. remove_action( 'plugins_loaded', 'sg_cachepress_start' );
  293. }
  294. }
  295. /**
  296. * Remove Activemember360 shortcodes from saved post content to stop them rendering twice.
  297. * @since 2.0.6
  298. */
  299. add_filter( 'fl_builder_editor_content', 'fl_activemember_shortcode_fix' );
  300. function fl_activemember_shortcode_fix( $content ) {
  301. return preg_replace( '#\[mbr.*?\]#', '', $content );
  302. }
  303. /**
  304. * Remove iMember360 shortcodes from saved post content to stop them rendering twice.
  305. * @since 2.0.6
  306. */
  307. add_filter( 'fl_builder_editor_content', 'fl_imember_shortcode_fix' );
  308. function fl_imember_shortcode_fix( $content ) {
  309. return preg_replace( '#\[i4w.*?\]#', '', $content );
  310. }
  311. /**
  312. * Fix javascript issue caused by nextgen gallery when adding modules in the builder.
  313. * @since 2.0.6
  314. */
  315. add_action( 'plugins_loaded', 'fl_fix_nextgen_gallery' );
  316. function fl_fix_nextgen_gallery() {
  317. if ( isset( $_GET['fl_builder'] ) || isset( $_POST['fl_builder_data'] ) || FLBuilderAJAX::doing_ajax() ) {
  318. define( 'NGG_DISABLE_RESOURCE_MANAGER', true );
  319. }
  320. }
  321. /**
  322. * Fix Tasty Recipes compatibility issues with the builder.
  323. * @since 2.0.6
  324. */
  325. add_action( 'template_redirect', 'fl_fix_tasty_recipes' );
  326. function fl_fix_tasty_recipes() {
  327. if ( FLBuilderModel::is_builder_active() ) {
  328. remove_action( 'wp_enqueue_editor', array( 'Tasty_Recipes\Assets', 'action_wp_enqueue_editor' ) );
  329. remove_action( 'media_buttons', array( 'Tasty_Recipes\Editor', 'action_media_buttons' ) );
  330. }
  331. }
  332. /**
  333. * Dequeue GeneratePress fa5 js when builder is open.
  334. * @since 2.1
  335. */
  336. add_action( 'template_redirect', 'fl_fix_generatepress_fa5' );
  337. function fl_fix_generatepress_fa5() {
  338. if ( FLBuilderModel::is_builder_active() ) {
  339. add_filter( 'generate_fontawesome_essentials', '__return_true' );
  340. }
  341. }
  342. /**
  343. * Try to render Ninja Forms JS templates when rendering an AJAX layout
  344. * in case the layout includes one of their shortcodes. This won't do
  345. * anything if no templates need to be rendered.
  346. * @since 2.1
  347. */
  348. add_filter( 'fl_builder_ajax_layout_response', 'fl_render_ninja_forms_js' );
  349. function fl_render_ninja_forms_js( $response ) {
  350. if ( class_exists( 'NF_Display_Render' ) ) {
  351. ob_start();
  352. NF_Display_Render::output_templates();
  353. $response['html'] .= ob_get_clean();
  354. }
  355. return $response;
  356. }
  357. /**
  358. * Reorder font awesome css.
  359. * @since 2.1
  360. */
  361. function fl_builder_fa_fix() {
  362. global $wp_styles;
  363. $queue = $wp_styles->queue;
  364. $fa4 = array_search( 'font-awesome', $queue );
  365. $fa5 = array_search( 'font-awesome-5', $queue );
  366. // if fa4 is disabled and both are detected, load fa4 FIRST.
  367. if ( false !== $fa4 && false !== $fa5 && $fa4 > $fa5 && ! in_array( 'font-awesome', FLBuilderModel::get_enabled_icons() ) ) {
  368. unset( $wp_styles->queue[ $fa4 ] );
  369. array_unshift( $wp_styles->queue, 'font-awesome' );
  370. }
  371. // If fa4 is detected, add a compatibility layer in the footer.
  372. // This fixes various theme/themer issues.
  373. if ( false !== $fa4 ) {
  374. add_action( 'wp_footer', 'fl_builder_fa_fix_callback' );
  375. }
  376. }
  377. add_action( 'wp_enqueue_scripts', 'fl_builder_fa_fix', 99999 );
  378. function fl_builder_fa_fix_callback() {
  379. echo '<style>[class*="fa fa-"]{font-family: FontAwesome !important;}</style>';
  380. }
  381. /**
  382. * Turn off Hummingbird minification
  383. * @since 2.1
  384. */
  385. add_action( 'template_redirect', 'fl_fix_hummingbird' );
  386. function fl_fix_hummingbird() {
  387. if ( FLBuilderModel::is_builder_active() ) {
  388. add_filter( 'wp_hummingbird_is_active_module_minify', '__return_false', 500 );
  389. }
  390. }
  391. /**
  392. * Fix Enjoy Instagram feed on website with WordPress Widget and Shortcode issues with the builder.
  393. * @since 2.0.6
  394. */
  395. add_action( 'template_redirect', 'fl_fix_enjoy_instagram' );
  396. function fl_fix_enjoy_instagram() {
  397. if ( FLBuilderModel::is_builder_active() ) {
  398. remove_action( 'wp_head', 'funzioni_in_head' );
  399. }
  400. }