Edit File: thrive-visual-editor.php
<?php /* Plugin Name: Thrive Architect Plugin URI: http://www.thrivethemes.com Version: 2.4.6.2 Author: <a href="http://www.thrivethemes.com">Thrive Themes</a> Description: Live front end editor for your WordPress content */ defined( 'TVE_EDITOR_URL' ) || define( 'TVE_EDITOR_URL', plugin_dir_url( __FILE__ ) ); if ( ! defined( 'TVE_TCB_CORE_INCLUDED' ) ) { require_once plugin_dir_path( __FILE__ ) . 'plugin-core.php'; } if ( ! defined( 'TVE_PLUGIN_FILE' ) ) { define( 'TVE_PLUGIN_FILE', __FILE__ ); } defined( 'TVE_IN_ARCHITECT' ) || define( 'TVE_IN_ARCHITECT', true ); /** * Classes that should only be available when TCB is used stand-alone */ if ( ! class_exists( 'TCB_Post' ) ) { /** * Case: TL v1, TCB v2 */ require_once plugin_dir_path( __FILE__ ) . 'inc/classes/class-tcb-post.php'; } /** * Init the UpdateCheck at init action because * Dashboard loads its class at plugins_loaded */ add_action( 'init', 'tve_update_checker' ); /** * admin licensing menu link */ add_action( 'admin_menu', 'tve_add_settings_menu' ); add_action( 'wp_enqueue_scripts', 'tve_frontend_enqueue_scripts' ); // add filter for including the TCB meta into the search functionality - this is only required on the TCB editor add_filter( 'posts_clauses', 'tve_process_search_clauses', null, 2 ); add_filter( 'get_the_content_limit', 'tve_genesis_get_post_excerpt', 10, 4 ); // automatically modify lightbox title if the title of the associated landing page is modified - applies ony to TCB add_action( 'save_post', 'tve_save_post_callback' ); /* filter that allows adding custom icon packs to the "Choose icon" lightbox in the TCB editor */ add_filter( 'tcb_get_extra_icons', 'tve_landing_page_extra_icon_packs', 10, 2 ); /* filter that allows adding custom fonts to the "choose custom font" menu item */ add_filter( 'tcb_extra_custom_fonts', 'tve_get_extra_custom_fonts', 10, 2 ); /* action that fires when the custom fonts css should be included in the page */ add_action( 'tcb_extra_fonts_css', 'tve_output_extra_custom_fonts_css' ); /** fires when all plugins are loaded - used for intermediate filter setup / plugin overrides */ add_action( 'plugins_loaded', 'tve_plugins_loaded_hook' ); //after the plugin is loaded load the dashboard version file add_action( 'plugins_loaded', 'tve_load_dash_version' ); /** * TCB-specific AJAX actions */ add_action( 'wp_ajax_tve_lp_export', 'tve_ajax_landing_page_export' ); add_action( 'wp_ajax_tve_lp_import', 'tve_ajax_landing_page_import' ); /** * AJAX call to return the TCB-added content for a post */ add_action( 'wp_ajax_get_tcb_content', 'tve_ajax_yoast_tcb_post_content' ); add_action( 'wp_head', 'tve_load_custom_css', 100, 0 ); /** * Architect Product must be included only if Architect is active and needs to be added all the time to be able to check external capabilities for access manager */ add_filter( 'tve_dash_installed_products', 'tcb_add_to_dashboard_list' ); /** * output the admin license validation page */ function tve_license_validation() { include( 'tve_settings.php' ); } /** * add the options link to the admin menu */ function tve_add_settings_menu() { add_submenu_page( false, '', '', 'manage_options', 'tve_license_validation', 'tve_license_validation' ); } /** * include the TCB saved meta into query search fields * * WordPress actually allows inserting post META fields in the search query, * but it will always build the clauses with AND (between post content and post meta) e.g.: * WHERE (posts.title LIKE '%xx%' OR posts.post_content) AND (postsmeta.meta_key = 'tve_save_post' AND postsmeta.meta_value LIKE '%xx%') * * - we cannot use this, so we hook into the final pieces of the built SQL query - we need a solution like this: * WHERE ( (posts.title LIKE '%xx%' OR posts.post_content OR (postsmeta.meta_key = 'tve_save_post' AND postsmeta.meta_value LIKE '%xx%') ) * * @param array $pieces * @param WP_Query $wp_query * * @return array */ function tve_process_search_clauses( $pieces, $wp_query ) { if ( is_admin() || empty( $pieces ) || ! $wp_query->is_search() ) { return $pieces; } /** @var wpdb $wpdb */ global $wpdb; $query = ''; $n = ! empty( $q['exact'] ) ? '' : '%'; $q = $wp_query->query_vars; if ( ! empty( $q['search_terms'] ) ) { foreach ( $q['search_terms'] as $term ) { if ( method_exists( $wpdb, 'esc_like' ) ) { // WP4 $term = $wpdb->esc_like( $term ); } else { $term = like_escape( $term ); // like escape is deprecated in WP4 } $like = $n . $term . $n; $query .= "((tve_pm.meta_key = 'tve_updated_post')"; $query .= $wpdb->prepare( " AND (tve_pm.meta_value LIKE %s)) OR ", $like ); } } if ( ! empty( $query ) ) { // add to where clause $pieces['where'] = str_replace( "((({$wpdb->posts}.post_title LIKE '{$n}", "( {$query} (({$wpdb->posts}.post_title LIKE '{$n}", $pieces['where'] ); $pieces['join'] = $pieces['join'] . " LEFT JOIN {$wpdb->postmeta} AS tve_pm ON ({$wpdb->posts}.ID = tve_pm.post_id)"; if ( empty( $pieces['groupby'] ) ) { $pieces['groupby'] = "{$wpdb->posts}.ID"; } } return ( $pieces ); } /** * Handler for "get_the_content_limit" action applied by genesis themes * * Called on pages with posts list * If posts was created with TCB the more_element link is searched. If it is found the content before it is returned. * If more_element is not found the post's content added from admin is appended with TCB content then truncation is applied * * @param string $output Truncated content post by genesis * @param string $content the stripped and truncated genesis content * @param string $link the read more link * @param int $max_characters the maximum number of characters to truncate to * * @return string $content */ function tve_genesis_get_post_excerpt( $output, $content, $link, $max_characters ) { global $post; $post_id = get_the_ID(); if ( ! tve_check_in_loop( $post_id ) ) { tve_load_custom_css( $post_id ); } if ( ! is_singular() ) { $more_found = tve_get_post_meta( get_the_ID(), 'tve_content_more_found', true ); $content_before_more = tve_get_post_meta( get_the_ID(), 'tve_content_before_more', true ); if ( ! empty( $content_before_more ) && $more_found ) { $more_link = apply_filters( 'the_content_more_link', '<a href="' . get_permalink() . '#more-' . $post->ID . '" class="more-link">' . __( 'Continue Reading', 'thrive-cb' ) . '</a>', __( 'Continue Reading', 'thrive-cb' ) ); $content = '<div id="tve_editor" class="tve_shortcode_editor">' . stripslashes( $content_before_more ) . $more_link . '</div>'; return tve_restore_script_tags( tve_do_wp_shortcodes( $content ) ); } $tcb_content = tve_restore_script_tags( tve_do_wp_shortcodes( stripslashes( tve_get_post_meta( get_the_ID(), 'tve_updated_post', true ) ) ) ); if ( ! $tcb_content ) { return $output; } /** * inherited from genesis logic */ $tcb_content = strip_tags( strip_shortcodes( $tcb_content ), apply_filters( 'get_the_content_limit_allowedtags', '<script>,<style>' ) ); $tcb_content = trim( preg_replace( '#<(s(cript|tyle)).*?</\1>#si', '', $tcb_content ) ); // append the original genesis content $tcb_content .= $content; $tcb_content = genesis_truncate_phrase( $tcb_content, $max_characters ); $tcb_content = sprintf( '<p>%s %s</p>', $tcb_content, $link ); return $tcb_content; } return $output; } /** * When a page is edited from admin -> we need to use the same title for the associated lightbox, if the page in question is a landing page * Copy post tve meta to revision meta * * This method is also called when a revision of a post is added * * @param $post_id * * @see defaults-filters.php for add_action("post_updated") * * @see wp_insert_post which is doing: "post_updated", "save_post" */ function tve_save_post_callback( $post_id ) { /** * If $post_id is an ID of a revision POST */ if ( $parent_id = wp_is_post_revision( $post_id ) ) { $meta_keys = tve_get_used_meta_keys(); /** * copy post metas to its revision */ foreach ( $meta_keys as $meta_key ) { if ( $meta_key === 'tve_landing_page' ) { $meta_value = get_post_meta( $parent_id, $meta_key, true ); } else { $meta_value = tve_get_post_meta( $parent_id, $meta_key ); } add_metadata( 'post', $post_id, 'tve_revision_' . $meta_key, $meta_value ); } } $post_type = get_post_type( $post_id ); if ( $post_type != 'page' ) { return; } $is_landing_page = tve_post_is_landing_page( $post_id ); $tve_globals = tve_get_post_meta( $post_id, 'tve_globals' ); if ( ! $is_landing_page || empty( $tve_globals['lightbox_id'] ) ) { return; } $lightbox = get_post( $tve_globals['lightbox_id'] ); if ( ! $lightbox || ! ( $lightbox instanceof WP_Post ) || $lightbox->post_type !== 'tcb_lightbox' ) { return; } wp_update_post( array( 'ID' => $tve_globals['lightbox_id'], 'post_title' => 'Lightbox - ' . get_the_title( $post_id ), ) ); } /** * integration with Wordpress SEO for page analysis. * * @param string $content WP post_content * * @return string $content */ function tve_yoast_seo_integration( $content ) { $post_id = get_the_ID(); if ( $post_id && ! tve_is_post_type_editable( get_post_type( $post_id ) ) ) { return $content; } /** * if the post is actually a Landing Page, we need to reset all previously saved content, as TCB content is the only one shown */ if ( $lp_template = tve_post_is_landing_page( $post_id ) ) { $content = ''; } $tve_saved_content = tve_get_post_meta( get_the_ID(), "tve_updated_post" ); $tve_saved_content = preg_replace( '#<p(.*?)>(.*?)</p>#s', '<p>$2</p>', $tve_saved_content ); $tve_saved_content = str_replace( '<p></p>', '', $tve_saved_content ); $content = $tve_saved_content . " " . $content; return $content; } /** * add TCB content images to the sitemap * * @param array $images * @param $post_id * * @return array */ function tve_yoast_sitemap_images( $images, $post_id ) { $post_type = get_post_type( $post_id ); $p = get_post( $post_id ); if ( ! tve_is_post_type_editable( $post_type, $post_id ) ) { return $images; } $home_url = home_url(); $parsed_home = parse_url( $home_url ); $host = ''; $scheme = 'http'; if ( isset( $parsed_home['host'] ) && ! empty( $parsed_home['host'] ) ) { $host = str_replace( 'www.', '', $parsed_home['host'] ); } if ( isset( $parsed_home['scheme'] ) && ! empty( $parsed_home['scheme'] ) ) { $scheme = $parsed_home['scheme']; } /** * if the post is actually a Landing Page, we need to reset all other images and return just the ones setup in the landing page */ if ( $lp_template = tve_post_is_landing_page( $post_id ) ) { $images = array(); } $content = tve_get_post_meta( $post_id, 'tve_updated_post' ); if ( preg_match_all( '`<img [^>]+>`', $content, $matches ) ) { foreach ( $matches[0] as $img ) { if ( preg_match( '`src=["\']([^"\']+)["\']`', $img, $match ) ) { $src = $match[1]; if ( WPSEO_Utils::is_url_relative( $src ) === true ) { if ( $src[0] !== '/' ) { continue; } else { // The URL is relative, we'll have to make it absolute $src = $home_url . $src; } } elseif ( strpos( $src, 'http' ) !== 0 ) { // Protocol relative url, we add the scheme as the standard requires a protocol $src = $scheme . ':' . $src; } if ( strpos( $src, $host ) === false ) { continue; } if ( $src != esc_url( $src ) ) { continue; } $image = array( 'src' => apply_filters( 'wpseo_xml_sitemap_img_src', $src, $p ), ); if ( preg_match( '`title=["\']([^"\']+)["\']`', $img, $title_match ) ) { $image['title'] = str_replace( array( '-', '_' ), ' ', $title_match[1] ); } unset( $title_match ); if ( preg_match( '`alt=["\']([^"\']+)["\']`', $img, $alt_match ) ) { $image['alt'] = str_replace( array( '-', '_' ), ' ', $alt_match[1] ); } unset( $alt_match ); $image = apply_filters( 'wpseo_xml_sitemap_img', $image, $p ); //search in images for the $image $exists = false; foreach ( $images as $item ) { if ( $item['src'] === $image['src'] ) { $exists = true; break; } } //if already exists do not add it if ( $exists === false ) { $images[] = $image; } } unset( $match, $src ); } } return $images; } /** * export a Landing Page as a Zip file */ function tve_ajax_landing_page_export() { $response = array( 'success' => true, ); if ( empty( $_POST['template_name'] ) || empty( $_POST['post_id'] ) || ! is_numeric( $_POST['post_id'] ) || ! tve_post_is_landing_page( $_POST['post_id'] ) ) { $response['success'] = false; $response['message'] = __( 'Invalid request', 'thrive-cb' ); wp_send_json( $response ); } $transfer = new TCB_Landing_Page_Transfer(); $thumb_attachment_id = empty( $_POST['thumb_id'] ) ? 0 : (int) $_POST['thumb_id']; try { $data = $transfer->export( (int) $_POST['post_id'], $_POST['template_name'], $thumb_attachment_id ); $response['url'] = $data['url']; $response['message'] = __( 'Landing Page exported successfully!', 'thrive-cb' ); } catch ( Exception $e ) { $response['success'] = false; $response['message'] = $e->getMessage(); } wp_send_json( $response ); } /** * import a landing page from an attachment ID received in POST * the attachment should be a .zip file created with the "Export Landing Page" functionality */ function tve_ajax_landing_page_import() { $response = array( 'success' => true, 'message' => '', ); $is_post_type_allowed = apply_filters( 'tve_allowed_post_type', true, get_post_type( $_POST['page_id'] ) ); if ( empty( $_POST['attachment_id'] ) || ! is_numeric( $_POST['attachment_id'] ) || empty( $_POST['page_id'] ) || ! is_numeric( $_POST['page_id'] ) || ! $is_post_type_allowed ) { $response['success'] = false; $response['message'] = __( 'Invalid attachment id', 'thrive-cb' ); wp_send_json( $response ); } $transfer = new TCB_Landing_Page_Transfer(); try { $file = get_attached_file( (int) $_POST['attachment_id'], true ); $landing_page_id = $transfer->import( $file, (int) $_POST['page_id'] ); $response['url'] = tcb_get_editor_url( $landing_page_id ); $response['message'] = __( 'Landing Page imported successfully!', 'thrive-cb' ); } catch ( Exception $e ) { $response['success'] = false; $response['message'] = $e->getMessage(); } wp_send_json( $response ); } /** * checks if any extra icons are attached to the page, and include those also the $icons array * * @param array $icons * @param int $post_id * * @return array */ function tve_landing_page_extra_icon_packs( $icons, $post_id ) { if ( empty( $post_id ) ) { return $icons; } $globals = tve_get_post_meta( $post_id, 'tve_globals' ); if ( empty( $globals['extra_icons'] ) ) { return $icons; } foreach ( $globals['extra_icons'] as $icon_pack ) { if ( empty( $icon_pack['icons'] ) ) { continue; } $icons = array_merge( $icons, $icon_pack['icons'] ); } return $icons; } /** * * check if the current post / page has extra custom fonts associated and output the css needed for each * the extra custom fonts are enqueued from tve_enqueue_extra_resources() * * @param int $post_id * * @see tve_enqueue_extra_resources * */ function tve_output_extra_custom_fonts_css( $post_id = null ) { $fonts = apply_filters( 'tcb_extra_custom_fonts', array(), $post_id ); if ( empty( $fonts ) ) { return; } tve_output_custom_font_css( $fonts ); } /** * * action filter that adds the custom fonts to the $fonts array for a landing page / lightbox * * @param $fonts * @param null $post_id * * @return array */ function tve_get_extra_custom_fonts( $fonts, $post_id = null ) { if ( empty( $post_id ) ) { $post_id = get_the_ID(); } if ( empty( $post_id ) ) { return $fonts; } $globals = tve_get_post_meta( $post_id, 'tve_globals' ); if ( empty( $globals['extra_fonts'] ) ) { return $fonts; } return array_merge( $fonts, $globals['extra_fonts'] ); } /** * called on the 'plugins_loaded' hook */ function tve_plugins_loaded_hook() { if ( defined( 'WPSEO_VERSION' ) ) { // integration with YOAST SEO /* version 3 removed this filter completely - this is handled from javascript from version 3.0 onwards */ if ( version_compare( WPSEO_VERSION, '3.0', '<' ) === true ) { add_filter( 'wpseo_pre_analysis_post_content', 'tve_yoast_seo_integration' ); } else { /* this is handled from javascript */ } // YOAST sitemaps - add image links add_filter( 'wpseo_sitemap_urlimages', 'tve_yoast_sitemap_images', 10, 2 ); } } /** * sends an ajax response containing the TCB-saved post content, stripped of tags for yoast SEO integration * * @return void */ function tve_ajax_yoast_tcb_post_content() { $id = filter_input( INPUT_POST, 'post_id', FILTER_SANITIZE_NUMBER_INT ); /** * mimic the the_content filter on the post - this will return all TCB content */ global $post; $post = get_post( $id ); $wp_content = $post->post_content; /* used ob_start to avoid any output generated by tve_editor_content) */ ob_start(); $tcb_content = tve_editor_content( $post->post_content, 'tcb_content' ); ob_end_clean(); $tcb_post = tcb_post( $post ); if ( $tcb_post->meta( 'tcb2_ready' ) ) { if ( $tcb_post->meta( 'tcb_editor_enabled' ) ) { $wp_content = ''; } elseif ( $tcb_post->meta( 'tcb_editor_disabled' ) ) { $tcb_content = ''; } } wp_send_json( array( 'post_id' => $post->ID, 'content' => $tcb_content . $wp_content, ) ); } /** * resets all stored metadata for downloaded templates * this can be used if some of the template files have been deleted */ function tve_reset_cloud_templates_meta() { tve_save_downloaded_templates( array() ); } /** * Just initialize the PluginUpdateChecker included from dash */ function tve_update_checker() { /** plugin updates script **/ new TVE_PluginUpdateChecker( 'http://service-api.thrivethemes.com/plugin/update', __FILE__, 'thrive-visual-editor', 12, '', 'content_builder' ); /** * Adding icon of the product for update-core page */ add_filter( 'puc_request_info_result-thrive-visual-editor', 'architect_set_product_icon' ); } /** * Adding the product icon for the update core page * * @param $info * * @return mixed */ function architect_set_product_icon( $info ) { $info->icons['1x'] = tve_editor_css() . '/images/thrive-architect-logo.png'; return $info; } /** * Called on plugin activation. * Check for minimum required WordPress version */ function tcb_activation_hook() { if ( ! tcb_wordpress_version_check() ) { /** * Dashboard not loaded yet, force it to load here */ if ( ! function_exists( 'tve_dash_show_activation_error' ) ) { /* Load the dashboard included in this plugin */ tve_load_dash_version(); tve_dash_load(); } tve_dash_show_activation_error( 'wp_version', 'Thrive Architect', TCB_MIN_WP_VERSION ); } } register_activation_hook( __FILE__, 'tcb_activation_hook' ); /** * Enables the script manager during the ajax REST API request * * @param array $features * * @return array */ function tar_enable_script_manager( $features ) { /** * Script manager is only active if TAr is available as a standalone plugin for the current user */ if ( TCB_Product::has_access() ) { $features['script_manager'] = true; } return $features; } add_filter( 'tve_dash_features', 'tar_enable_script_manager' ); /** * always include TD script manager if TAr is active as a stand-alone plugin */ add_filter( 'td_include_script_manager', '__return_true' );
Back