| Server IP : 65.109.86.83 / Your IP : 216.73.217.65 Web Server : nginx/1.14.1 System : Linux libra 4.18.0-553.51.1.el8_10.x86_64 #1 SMP Wed Apr 30 20:24:04 UTC 2025 x86_64 User : root ( 0) PHP Version : 8.3.31 Disable Function : exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file,show_source MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /var/www/html/wp-content/plugins/thrive-leads/tcb/landing-page/inc/ |
Upload File : |
<?php
/**
* folder where we keep the landing pages downloaded from the cloud, relative to the wp-uploads folder
*/
defined( 'TVE_CLOUD_LP_FOLDER' ) || define( 'TVE_CLOUD_LP_FOLDER', 'tcb_lp_templates' );
/**
* handles the communication with the landing pages API located at TCB_Landing_Page_Cloud_Templates_Api::API_URL
*
*
* Class TCB_Landing_Page_Cloud_Templates_Api
*/
class TCB_Landing_Page_Cloud_Templates_Api {
const API_KEY = '@(#$*%)^SDFKNgjsdi870234521SADBNC#';
const API_PASS = '!!@#ThriveIsTheBest123$$@#';
const DEBUG_LOCAL = false;
const API_URL = 'https://landingpages.thrivethemes.com/cloud-api/index-api.php';
const API_SERVICE = 'https://service-api.thrivethemes.com/cloud-templates-api';
/**
* @var TCB_Landing_Page_Cloud_Templates_Api
*/
protected static $_instance = null;
protected $received_auth_header = '';
protected $secret_key = '@#$()%*%$^&*(#@$%@#$%93827456MASDFJIK3245';
/**
* holds the last response from the API server
*
* @var array
*/
protected $response = [];
/**
* holds the last request sent to the API server.
*
* @var array
*/
protected $request = [];
/**
* singleton
*
* @return TCB_Landing_Page_Cloud_Templates_Api
*/
public static function getInstance() {
if ( ! static::$_instance instanceof static ) {
static::$_instance = new static();
}
return static::$_instance;
}
/**
* constructor - use getInstance
*/
protected function __construct() {
}
/**
* get the template list
*
* @return array
* @throws Exception if response data and success properties does not have expected values
*
* @deprecated. use self::get_template_list()
*
*/
public function getTemplateList() {
return call_user_func( [ $this, 'get_template_list' ], func_get_args() );
}
/**
* Get a list of Landing Page templates from the cloud, filterable by using $filters
*
* @param array $filters
*
* @return mixed|void
* @throws Exception
*/
public function get_template_list( $filters = [] ) {
$params = apply_filters( 'tcb_get_cloud_templates_default_args', array(
'route' => 'getAll',
'tar_version' => defined( 'TCB_CLOUD_DEBUG' ) && TCB_CLOUD_DEBUG ? '10' : TVE_VERSION,
'tar_cloud_debug' => defined( 'TCB_CLOUD_DEBUG' ) && TCB_CLOUD_DEBUG ? '1' : '0',
) );
if ( ! empty( $filters ) ) {
$params['filters'] = $filters; // allow filtering
}
$response = $this->_request( $params, 2 );
$data = json_decode( $response, true );
if ( empty( $data['success'] ) ) {
return [ 'error' => $data['error_message'] ];
}
if ( ! isset( $data['data'] ) ) {
return [ 'error' => 'Could not fetch templates.' ];
}
$this->_validateReceivedHeader( $data );
return $data['data'];
}
/**
* download the zip file for a template
*
* @param string|array $template If array, it must contain [key] and [uid] keys
*
* @return string the new template name (with the cloud prefix prepended)
*
* @throws Exception
*/
public function download( $template ) {
$uid = '';
if ( is_array( $template ) ) {
$uid = $template['uid']; // unique identifier from cloud
$template = $template['key'];
}
/**
* first make sure we can save the downloaded template
*/
$upload = wp_upload_dir();
if ( ! empty( $upload['error'] ) ) {
throw new Exception( $upload['error'] );
}
/* create folders in uploads - make sure all of the required folders exist */
$this->createFolders( $upload, $template );
$params = [
'route' => 'download',
'tar_version' => TVE_VERSION,
'tpl' => $template,
'uid' => $uid,
];
// LP v2 pages
$version = 2;
$body = $this->_request( $params, $version );
$control = [
'auth' => $this->request['headers']['X-Thrive-Authenticate'],
'tpl' => $template,
];
/**
* this means an error -> error message is json_encoded
*/
if ( empty( $this->received_auth_header ) ) {
$data = json_decode( $body, true );
throw new Exception( isset( $data['error_message'] ) ? $data['error_message'] : 'Invalid response: ' . $body );
}
$this->_validateReceivedHeader( $control );
/**
* at this point, $body holds the contents of the zip file
*/
$zip_path = trailingslashit( $upload['basedir'] ) . TVE_CLOUD_LP_FOLDER . '/' . $template . '.zip';
tve_wp_upload_bits( $zip_path, $body );
$transfer = new TCB_Landing_Page_Transfer();
$result = $transfer->importFromCloud( $zip_path, $template );
/* unlink the zip archive and the configuration file */
@unlink( $zip_path );
@unlink( trailingslashit( dirname( $zip_path ) ) . $template . '.json' );
return $result;
}
/**
* send an API request
*
* @param array $params body params to be sent in POST data
* @param mixed $version new LP version or TCB1.5 version (null)
*
* @return string the response body
*
* @throws Exception
*/
protected function _request( $params, $version = null ) {
$params = array_merge( $params, TD_TTW_Connection::get_instance()->get_connection_data() );
/**
* filter params before sending them to cloud
*/
$params = apply_filters( 'tcb_cloud_request_params', $params, $version );
/* make sure each param is a string - this makes sure the encoding / decoding does not cause API validation error */
foreach ( $params as $key => $param ) {
if ( $param === null || ( ! is_string( $param ) && is_scalar( $param ) ) ) {
$params[ $key ] = (string) $param;
}
}
$params['pw'] = self::API_PASS;
$headers = array(
'X-Thrive-Authenticate' => $this->_buildAuthString( $params ),
);
$this->request = [
'headers' => $headers,
'body' => $params,
];
$url = defined( 'TCB_CLOUD_API_LOCAL' ) && TCB_CLOUD_API_LOCAL ? TCB_CLOUD_API_LOCAL : self::API_SERVICE;
$url = add_query_arg( array(
'p' => $this->calc_hash( $params ),
), $url );
if ( ! empty( $version ) ) {
$url = add_query_arg( [
'v' => $version,
], $url );
}
$response = tve_dash_api_remote_post( $url, [
'headers' => $headers,
'body' => $params,
] );
if ( $response instanceof WP_Error ) {
throw new Exception( $response->get_error_message() );
}
$this->received_auth_header = wp_remote_retrieve_header( $response, 'X-Thrive-Authenticate' );
/**
* also try lowercased, just in case this will be dependent of server
*/
if ( empty( $this->received_auth_header ) ) {
$this->received_auth_header = wp_remote_retrieve_header( $response, 'x-thrive-authenticate' );
}
$this->response = $response;
return wp_remote_retrieve_body( $response );
}
/**
* build an authentication string, from each of the POST (or $data) values, concatenated with self::API_KEY between '|'
*
* @param array $data
*
* @return string md5 hash of the string above
*/
protected function _buildAuthString( $data = null ) {
$string = '';
if ( null === $data ) {
$data = $_POST;
}
foreach ( $data as $field => $value ) {
if ( is_array( $value ) ) {
$value = serialize( $value );
}
$string .= $field . '=' . $value;
$string .= '|' . self::API_KEY . '|';
}
return md5( $string );
}
/**
* Calculates the has that signs the requests for service.thrivethemes.com
*
* @param $data
*
* @return string
*/
public function calc_hash( $data ) {
return md5( $this->secret_key . serialize( $data ) . $this->secret_key );
}
/**
* validate the received header containing authentication data
*
*
* @param array $data
*
* @throws Exception
*/
protected function _validateReceivedHeader( $data ) {
if ( $this->received_auth_header != $this->_buildAuthString( $data ) ) {
throw new Exception( 'Invalid data received from the API' );
}
}
/**
* create all the necessary folders inside a tcb_lp_templates folder in the wp-uploads dir
* required folders are:
*
* - js
* - lightboxes
* - menu
* - templates
* - css
* - fonts
* - images
* - thumbnails
*
*
* @param array $wp_upload
* @param string $template_key
*/
public function createFolders( $wp_upload, $template_key ) {
$folder_list = [
'js',
'lightboxes',
'menu',
'templates',
'templates/css',
'templates/css/fonts',
'templates/css/fonts/' . $template_key,
'templates/css/images',
'templates/thumbnails',
];
/**
* this filter would allow adding some extra custom folders (if needed in the future)
*
*/
$folder_list = apply_filters( 'tcb_lp_extra_folders_create', $folder_list );
$base = trailingslashit( $wp_upload['basedir'] ) . TVE_CLOUD_LP_FOLDER . '/';
foreach ( $folder_list as $folder ) {
if ( false === wp_mkdir_p( $base . $folder ) ) {
throw new Exception( 'Could not create the templates folder' );
}
}
}
}
/**
* Import / Export functionality for landing pages
*
*/
class TCB_Landing_Page_Transfer {
/**
* holds ids of the exported lightboxes, to make sure we don't create an infinite loop
*
* @var array
*/
private $exported_lightboxes = [];
/**
* flag that will be true when the icon pack needs to be included in the export
*
* @var bool
*/
private $export_icon_pack = false;
/**
* holds the current WP Page (or landing page) that will be replaced with the imported landing page, OR the one that is being exported right now
*
* @var WP_Post
*/
private $current_page = null;
/**
*
* @var array wordpress uploads folder
*/
private $wp_upload_dir = null;
/**
* hold a copy of the config array for the import process
*
* @var array
*/
private $import_config = [];
/**
* Zip data
*
* @var string
*/
protected $cfg_name = 'lp.json';
protected $html_file_name = 'lp.html';
protected $archive_prefix = 'tve-lp-';
protected $thumbnail_prefix = 'lp-';
/**
* Whether LP vars should be replaced by their values on export
*/
protected $allow_lp_vars = false;
/**
* @var array
*/
public $image_map;
public $export_symbol_ids;
public function __construct() {
$this->image_map = [];
$this->export_symbol_ids = [];
}
/**
* get the wp upload dir info
*
* @return array
*
* @throws Exception
*/
protected function getUploadDir() {
if ( ! is_null( $this->wp_upload_dir ) ) {
return $this->wp_upload_dir;
}
$this->wp_upload_dir = wp_upload_dir();
if ( ! empty( $this->wp_upload_dir['error'] ) ) {
throw new Exception( sprintf( __( 'Could not determine uploads folder (%s)', 'thrive-cb' ), $this->wp_upload_dir['error'] ) );
}
return $this->wp_upload_dir;
}
/**
* Get symbol IDs that should be exported
*
* @param $content
*
* @return void
*/
public function parse_content_symbols( $content ) {
preg_match_all( TCB_Symbol_Template::SYMBOL_CONFIG_REGEX, $content, $matches );
if ( ! empty( $matches ) && count( $matches ) === 2 ) {
$this->export_symbol_ids = array_merge( $this->export_symbol_ids, $matches[1] );
}
preg_match_all( TCB_Symbol_Template::SYMBOL_SHORTCODE_REGEX, $content, $matches );
if ( ! empty( $matches ) && count( $matches ) === 2 ) {
$this->export_symbol_ids = array_merge( $this->export_symbol_ids, $matches[1] );
}
$this->export_symbol_ids = array_unique( $this->export_symbol_ids );
}
/**
* Export lp sections - header + footer and maybe top & bottom theme sections
*
* @param $page_id
*
* @return mixed|void
*/
public function export_sections( $page_id ) {
$sections = [];
foreach ( [ 'header', 'footer' ] as $section ) {
$key = "_tve_$section";
$section_id = (int) get_post_meta( $page_id, $key, true );
if ( ! empty( $section_id ) ) {
$symbol = TCB_Symbol_Template::get_instance( $section_id )->export();
add_filter( 'tve_should_minify_css', '__return_false' );
$symbol['meta_input']['tve_custom_css'] = tve_prepare_global_variables_for_front( $symbol['meta_input']['tve_custom_css'], true );
remove_filter( 'tve_should_minify_css', '__return_false' );
$this->parse_content_symbols( $symbol['meta_input']['tve_updated_post'] );
$symbol = json_encode( $symbol );
$symbol = static::replace_ids_on_export( $symbol );
$this->exportParseImages( $symbol );
$sections [ $section ] = json_decode( $symbol, true );
}
}
/**
* Filter sections to export for the lp
*
* @param array $sections
* @param int $page_id
* @param TCB_Landing_Page_Transfer
*
* @return array
*/
return apply_filters( 'tcb_lp_sections_export', $sections, $page_id, $this );
}
/**
* Export symbols used in the content
*
* @param $page_id
*
* @return mixed|void
*/
public function export_symbols( $page_id ) {
$symbols = [];
foreach ( $this->export_symbol_ids as $symbol_id ) {
$symbol = TCB_Symbol_Template::get_instance( $symbol_id )->export();
add_filter( 'tve_should_minify_css', '__return_false' );
$symbol['meta_input']['tve_custom_css'] = tve_prepare_global_variables_for_front( $symbol['meta_input']['tve_custom_css'], true );
remove_filter( 'tve_should_minify_css', '__return_false' );
$symbol = json_encode( $symbol );
$symbol = static::replace_ids_on_export( $symbol );
$this->exportParseImages( $symbol );
$symbols [ $symbol_id ] = json_decode( $symbol, true );
}
/**
* Filter sections to export for the lp
*
* @param array $sections
* @param int $page_id
* @param TCB_Landing_Page_Transfer
*
* @return array
*/
return apply_filters( 'tcb_lp_symbols_export', $symbols, $page_id, $this );
}
/**
* create a zip file containing the landing page export
*
* @param int $page_id
* @param string $template_name
* @param int $thumbnail_attachment_id the id of the attachment to use as a thumbnail
* @param bool $return_data whether or not to just return the generated data or archive it in a zip file
*
* @return mixed|array with information about the zip file:
* (
* 'path' => full path to the zip file
* 'url' => web-accessible url to the zip file
* )
*
* @throws Exception
*
*/
public function export( $page_id, $template_name, $thumbnail_attachment_id = 0, $return_data = false ) {
/* first, some general checks */
if ( ! class_exists( 'ZipArchive' ) ) {
throw new Exception( __( 'The PHP ZipArchive extension must be enabled in order to use this functionality. Please contact your hosting provider.', 'thrive-cb' ) );
}
$template_name = sanitize_title( $template_name );
/* build the meta-values config for the landing page */
$config = $this->getTCBMeta( $page_id );
$config['cloud_template'] = tve_is_cloud_template( $config['tve_landing_page'] );
$config['tve_version'] = TVE_VERSION; /* just to be able to validate imports later on, if we'll need some kind of compatibility checks */
$config['tve_original_post_type'] = get_post_type( $page_id ); /* just in case we need it to prevent imports to other post types */
$page_content = apply_filters( 'tcb.export_page_content', $config['tve_updated_post'], $page_id );
unset( $config['tve_updated_post'] ); // we do not need these in the config file
$page_content = static::replace_ids_on_export( $page_content );
$this->parse_content_symbols( $page_content );
/* parse and replace all image urls (both from img src and background: url(...) */
$this->exportImageMap( $page_content, $config );
$config['sections'] = $this->export_sections( $page_id );
/* handle any possible included lightboxes */
$config['lightbox'] = [];
/* include any lightbox that's setup as a page-level event */
if ( ! empty( $config['tve_page_events'] ) ) {
foreach ( $config['tve_page_events'] as $event ) {
$this->exportLightboxFromEvent( $event, $config );
}
}
/* parse the page contents to include any lightbox that's setup inside the html contents, e.g. from a link / button */
$this->exportParseLightboxes( $page_content, $config );
if ( $return_data ) {
return [
'page_meta' => $config,
'page_content' => $page_content,
'image_map' => $this->image_map,
'export_symbol_ids' => $this->export_symbol_ids,
];
}
if ( ! empty( $this->export_symbol_ids ) ) {
$config['symbols'] = $this->export_symbols( $page_id );
}
$uploads_dir = $this->getUploadDir();
$zip_filename = $this->archive_prefix . $template_name . '.zip';
@unlink( $uploads_dir['path'] . $zip_filename );
WP_Filesystem();
$old_umask = umask( 0 );
$zip = new ZipArchive();
if ( $zip->open( trailingslashit( $uploads_dir['path'] ) . $zip_filename, ZipArchive::CREATE ) !== true ) {
throw new Exception( 'Could not create zip archive' );
}
/* add images directly to the zip archive, in the images/ folder */
$zip->addEmptyDir( 'images' );
foreach ( $this->image_map as $key => $info ) {
$config['image_map'][ $key ] = $info['name'];
$zip->addFile( $info['path'], 'images/' . $key . '.img_file' );
}
/* check if the icon pack needs to be exported and include it in the archive file */
$this->exportIconPack( $zip, $config );
/* check if there is any font added through the Font Import Manager */
$this->exportFontPack( $zip, $config );
/* add lightbox template html to the lightboxes/ folder */
if ( ! empty( $config['lightbox'] ) ) {
$zip->addEmptyDir( 'lightboxes' );
foreach ( $config['lightbox'] as $id => $data ) {
$zip->addFromString( 'lightboxes/' . $id . '.html', $data['tve_updated_post'] );
unset( $config['lightbox'][ $id ]['tve_updated_post'] );
/* any extra icon_packs that might be included in the lightbox */
$this->exportExtraIconPacks( $zip, $config['lightbox'][ $id ] );
$this->exportFontPack( $zip, $config['lightbox'][ $id ] );
}
}
/* add the font_pack config to the configuration array, if it has been included */
$config['font_pack'] = isset( $this->exported_font_pack ) ? $this->exported_font_pack : [];
/* add the contents of the page, in a separate file */
$zip->addFromString( $this->html_file_name, $page_content );
/* it's possible that this landing page or some of it's lightboxes have some extra icon packs (added from previous imports) */
$this->exportExtraIconPacks( $zip, $config );
/* also include the thumbnail for the landing page, if any */
if ( ! empty( $thumbnail_attachment_id ) ) {
$this->exportThumbnail( $thumbnail_attachment_id, $zip, $config );
} else {
$exported = $this->exportGeneratedThumbnail( $page_id, $zip );
if ( $exported ) {
$config['thumbnail'] = $this->thumbnail_prefix . $page_id . '.png';
}
}
/* add the json config file */
$zip->addFromString( $this->cfg_name, json_encode( $config ) );
if ( ! @$zip->close() ) {
throw new Exception( 'Could not write the zip file' );
}
umask( $old_umask );
return array(
'path' => trailingslashit( $uploads_dir['path'] ) . $zip_filename,
'url' => trailingslashit( $uploads_dir['url'] ) . $zip_filename,
);
}
/**
* also include the thumbnail chosen by the user, if empty => the default LP thumbnail will be used
*
* @param int $thumbnail_attachment_id
* @param ZipArchive $zip
* @param array $config
*/
protected function exportThumbnail( $thumbnail_attachment_id, ZipArchive $zip, &$config ) {
if ( empty( $thumbnail_attachment_id ) || ! wp_attachment_is_image( $thumbnail_attachment_id ) ) {
return;
}
$file = get_attached_file( $thumbnail_attachment_id, true );
if ( ! is_file( $file ) ) {
return;
}
$thumb_name = basename( $file );
$zip->addEmptyDir( 'thumbnail' );
if ( false === $zip->addFile( $file, 'thumbnail/' . $thumb_name ) ) {
$zip->deleteName( 'thumbnail' );
return;
}
$config['thumbnail'] = $thumb_name;
}
/**
* Get the generated preview of the LP(it's previously done on save)
*
* @param $page_id
* @param $zip
*
* @return false
*/
protected function exportGeneratedThumbnail( $page_id, $zip ) {
$upload = tve_filter_landing_page_preview_location( wp_upload_dir() );
$path = $upload['path'] . '/' . $this->thumbnail_prefix . $page_id . '.png';
$zip->addEmptyDir( 'thumbnail' );
if ( is_file( $path ) && $zip->addFile( $path, 'thumbnail/' . $this->thumbnail_prefix . $page_id . '.png' ) === false ) {
$zip->deleteName( 'thumbnail' );
return false;
}
return true;
}
/**
*
* parse the HTML content, search for local images (stored on the server) AND images used in inline styles, retrieve the image paths and copy them to the $dest folder for each encountered image
* it will also replace the image srcs in HTML to a list of keys
*
* @param string $content
*/
public function exportParseImages( &$content ) {
$site_url = str_replace( [ 'http://', 'https://', '//' ], '', site_url() );
/* regular expression that finds image links that point to the current server */
$image_regexp = '#(http:|https:)?(\\\?/\\\?/)(' . preg_quote( $site_url, '#' ) . ')([^ "\']+?)(\.[png|svg|webp|gif|jpg|jpeg]+)#is';
if ( preg_match_all( $image_regexp, $content, $matches ) ) {
foreach ( $matches[4] as $index => $src ) {
$img_path = $src . $matches[5][ $index ];
$img_src = $matches[3][ $index ] . $img_path;
$no_qstring = explode( '?', $img_src );
$img_src = $no_qstring[0];
$unslashed_img_src = wp_unslash( $img_src );
$full_image_path = untrailingslashit( ABSPATH ) . $img_path;
if ( ! file_exists( $full_image_path ) ) {
continue;
}
$replacement = md5( $unslashed_img_src );
$protocol = ( empty( $matches[1][ $index ] ) ? '' : $matches[1][ $index ] ) . $matches[2][ $index ];
$this->image_map[ $replacement ] = array(
'name' => basename( $img_src ),
'path' => $full_image_path,
'url' => wp_unslash( $protocol ) . $unslashed_img_src,
);
$content = str_replace( [
'https:' . $matches[0][ $index ],
'http:' . $matches[0][ $index ],
$matches[0][ $index ],
], '{{img=' . $replacement . '}}', $content );
}
}
/* return the current image map so the function can be used as a standalone function without the export one */
return $this->image_map;
}
/**
* get all the meta fields used by TCB for a page / lightbox
*
* @param int $post_id
*
* @return array
*/
protected function getTCBMeta( $post_id ) {
$config = [];
$non_lp_dependent_keys = [ 'tve_landing_page', 'tve_disable_theme_dependency', TCB_LP_Palettes::LP_PALETTES, TCB_LP_Palettes::LP_PALETTES_CONFIG ];
foreach ( tve_get_used_meta_keys() as $key ) {
$config[ $key ] = in_array( $key, $non_lp_dependent_keys ) ? get_post_meta( $post_id, $key, true ) : tve_get_post_meta( $post_id, $key );
}
unset( $config['tve_content_before_more'], $config['tve_save_post'] );
if ( ! empty( $config['thrive_icon_pack'] ) ) {
$this->export_icon_pack = true;
}
$post = get_post( $post_id );
$config['post_title'] = $post->post_title;
if ( apply_filters( 'tcb_allow_landing_page_set_data', true ) ) {
$this->prepare_global_data_for_export( $config );
}
return apply_filters( 'tcb_lp_transfer_meta', $config, $post_id );
}
/**
* replace all image links from $post_content and both global configuration (e.g. page background, lightbox background)
*
* @param string $post_content
* @param array $config
*/
protected function exportImageMap( &$post_content, &$config ) {
$this->exportParseImages( $post_content );
/* global setting for page background - pattern */
if ( ! empty( $config['tve_globals']['lp_bgp'] ) ) {
$this->exportParseImages( $config['tve_globals']['lp_bgp'] );
}
/* global setting for page background - image */
if ( ! empty( $config['tve_globals']['lp_bgi'] ) ) {
$this->exportParseImages( $config['tve_globals']['lp_bgi'] );
}
/* lightbox - global setting - content background */
if ( ! empty( $config['tve_globals']['l_cimg'] ) ) {
$this->exportParseImages( $config['tve_globals']['l_cimg'] );
unset( $config['tve_globals']['l_cpat'] );
} elseif ( ! empty( $config['tve_globals']['l_cpat'] ) ) {
$this->exportParseImages( $config['tve_globals']['l_cpat'] );
}
/**
* User custom CSS styles - background images
*/
if ( ! empty( $config['tve_custom_css'] ) ) {
$this->exportParseImages( $config['tve_custom_css'] );
}
}
/**
* parse the contents and include in the export file any lightboxes that are used in event managers for individual elements
*
* @param string $content
* @param array $config
*/
protected function exportParseLightboxes( $content, &$config ) {
$events = $this->getRelevantEvents( $content );
foreach ( $events as $event ) {
$this->exportLightboxFromEvent( $event, $config );
}
}
/**
* parses $content for any events registered from the TCB event manager that have as actions "thrive_lightbox"
* and retrieves an array of all such events
*
* @param string $content
*
* @return array array of registered events
*/
protected function getRelevantEvents( $content ) {
/* bail early if no event is defined */
if ( strpos( $content, '__TCB_EVENT_' ) === false ) {
return [];
}
$event_pattern = "#data-tcb-events=('|\")__TCB_EVENT_(.+?)_TNEVE_BCT__('|\")#";
if ( ! preg_match_all( $event_pattern, $content, $matches ) ) {
return [];
}
$events = [];
foreach ( $matches[2] as $i => $str ) {
$str = htmlspecialchars_decode( $str ); // the actual matched regexp group
if ( ! ( $elem_events = json_decode( $str, true ) ) ) {
$elem_events = [];
}
if ( empty( $elem_events ) ) {
continue;
}
foreach ( $elem_events as $event ) {
if ( empty( $event ) || $event['a'] !== 'thrive_lightbox' ) {
continue;
}
$events [] = $event;
}
}
return $events;
}
/**
* add a lightbox to the exported landing page
*
* @param array $event
* @param array $config
*/
protected function exportLightboxFromEvent( $event, &$config ) {
if ( empty( $event ) || ! is_array( $event ) || empty( $event['a'] ) || $event['a'] !== 'thrive_lightbox' ) {
return;
}
if ( empty( $event['config'] ) || empty( $event['config']['l_id'] ) ) {
return;
}
$lb_id = $event['config']['l_id'];
if ( isset( $this->exported_lightboxes[ $lb_id ] ) || get_post_type( $lb_id ) !== 'tcb_lightbox' ) {
return;
}
$this->exported_lightboxes[ $lb_id ] = true;
if ( empty( $config['lightbox'][ $lb_id ] ) ) {
$lb_config = $this->getTCBMeta( $lb_id );
$lb_config['tve_lp_lightbox'] = get_post_meta( $lb_id, 'tve_lp_lightbox', true );
// parse images
$this->exportImageMap( $lb_config['tve_updated_post'], $lb_config );
/* also handle the "lightbox in lightbox" cases */
$this->exportParseLightboxes( $lb_config['tve_updated_post'], $config );
$config['lightbox'][ $lb_id ] = $lb_config;
}
}
/**
* check if the export archive needs to contain the icon pack also and include the css and fonts for the icon pack
*
* @param ZipArchive $zip
* @param array $config
*/
public function exportIconPack( ZipArchive $zip, &$config ) {
if ( ! $this->export_icon_pack ) {
return;
}
$thrive_icon_pack = get_option( 'thrive_icon_pack' );
if ( empty( $thrive_icon_pack ) ) {
return;
}
if ( ! is_dir( $thrive_icon_pack['folder'] ) || ! is_file( trailingslashit( $thrive_icon_pack['folder'] ) . 'style.css' ) ) {
return;
}
$zip->addEmptyDir( 'icon-pack' );
$zip->addFile( trailingslashit( $thrive_icon_pack['folder'] ) . 'style.css', 'icon-pack/style.css' );
/* add all font files */
$zip->addEmptyDir( 'icon-pack/fonts' );
/**
* TCB-1683 php < 5.3 does not have support for ZipArchive::addGlob()
*/
$icon_files = glob( trailingslashit( $thrive_icon_pack['folder'] ) . 'fonts/*', GLOB_BRACE );
foreach ( $icon_files as $file ) {
$zip->addFile( $file, 'icon-pack/fonts/' . basename( $file ) );
}
$config['icon_pack'] = [
'font-family' => $thrive_icon_pack['fontFamily'],
'icons' => $thrive_icon_pack['icons'],
];
}
/**
*
* if this is a previously imported landing page, it can have any number of extra icon packs associated. we need to include those in the export archive
*
* export any extra icon packs that might be associated with this landing page
* there can by any number of icon packs
*
* @param ZipArchive $zip
* @param array $config
*/
public function exportExtraIconPacks( ZipArchive $zip, &$config ) {
if ( empty( $config['tve_globals']['extra_icons'] ) || empty( $config['tve_globals']['used_icon_packs'] ) ) {
return;
}
$used_icon_packs = $config['tve_globals']['used_icon_packs'];
foreach ( $config['tve_globals']['extra_icons'] as $i => $icon_pack ) {
if ( empty( $icon_pack ) || ! in_array( $icon_pack['font-family'], $used_icon_packs ) ) {
unset( $config['tve_globals']['extra_icons'][ $i ] );
continue;
}
if ( ! is_dir( $icon_pack['folder'] ) || ! is_file( trailingslashit( $icon_pack['folder'] ) . 'style.css' ) ) {
unset( $config['tve_globals']['extra_icons'][ $i ] );
continue;
}
$icon_zip_folder = $icon_pack['font-family'];
$zip->addEmptyDir( $icon_zip_folder );
$zip->addFile( trailingslashit( $icon_pack['folder'] ) . 'style.css', $icon_zip_folder . '/style.css' );
$zip->addEmptyDir( $icon_zip_folder . '/fonts' );
/**
* TCB-1683 php < 5.3 does not have support for ZipArchive::addGlob()
*/
$icon_files = glob( trailingslashit( $icon_pack['folder'] ) . 'fonts/*', GLOB_BRACE );
foreach ( $icon_files as $icon_file ) {
$zip->addFile( $icon_file, $icon_zip_folder . '/fonts/' . basename( $icon_file ) );
}
unset( $config['tve_globals']['extra_icons'][ $i ]['folder'], $config['tve_globals']['extra_icons'][ $i ]['css'] );
}
$config['tve_globals']['extra_icons'] = array_values( $config['tve_globals']['extra_icons'] );
}
/**
* check if the export archive needs to contain the custom font pack, or any user-defined fonts
*
* @param ZipArchive $zip
* @param array $config
*/
public function exportFontPack( ZipArchive $zip, &$config ) {
if ( empty( $config['thrive_tcb_post_fonts'] ) && empty( $config['tve_globals']['extra_fonts'] ) ) {
return;
}
/* grab all the used fonts */
$used_font_classes = isset( $config['tve_globals']['font_cls'] ) ? $config['tve_globals']['font_cls'] : [];
$included = [];
$all_fonts = $this->getThriveFonts();
foreach ( $used_font_classes as $font_class ) {
$font_index = $this->findFontByProps( [ 'font_class' => $font_class ], $all_fonts, [ 'font_class' ] );
if ( false === $font_index ) {
continue;
}
$font = $all_fonts[ $font_index ];
if ( Tve_Dash_Font_Import_Manager::isImportedFont( $font['font_name'] ) ) {
$font['imported'] = true;
$export_font_pack = true; // export the files included in the font pack
}
$included [] = $font;
}
$config['thrive_tcb_post_fonts'] = $included;
if ( isset( $export_font_pack ) && ! isset( $this->exported_font_pack ) ) {
$this->exported_font_pack = [];
$font_pack = $this->getImportedFontPack();
if ( ! empty( $font_pack ) && ! empty( $font_pack['folder'] ) && ! empty( $font_pack['css_file'] ) ) {
$css_file = basename( $font_pack['css_file'] );
$this->exportAddFontToZip( $zip, $font_pack['folder'], $font_pack['css_file'] );
$this->exported_font_pack = array(
'name' => basename( $font_pack['folder'] ),
'css' => $css_file,
);
}
}
/* finally, check for any extra fonts (that might exist from previous imports of landing pages)*/
if ( empty( $config['tve_globals']['extra_fonts'] ) ) {
return;
}
foreach ( $config['tve_globals']['extra_fonts'] as $i => $font ) {
if ( ! empty( $font['ignore'] ) ) { // if not used, do not include it
unset( $config['tve_globals']['extra_fonts'][ $i ] );
continue;
}
$this->exportAddFontToZip( $zip, $font['font_folder'], basename( $font['font_url'] ) );
$config['tve_globals']['extra_fonts'][ $i ]['font_folder'] = basename( $font['font_folder'] );
}
$config['tve_globals']['extra_fonts'] = array_values( $config['tve_globals']['extra_fonts'] );
}
/**
* add a font folder to the zip archive
*
* @param ZipArchive $zip
* @param string $folder_path
* @param string $css_file
* @param string $zip_folder_name if empty, it will take basename($folder_path)
*/
protected function exportAddFontToZip( ZipArchive $zip, $folder_path, $css_file, $zip_folder_name = null ) {
$css_file = basename( $css_file );
$css_path = trailingslashit( $folder_path ) . $css_file;
if ( ! is_dir( $folder_path ) || ! is_file( $css_path ) ) {
return;
}
$name = $zip_folder_name !== null ? $zip_folder_name : basename( $folder_path );
$zip->addEmptyDir( 'font-pack/' . $name );
$zip->addFile( $css_path, 'font-pack/' . $name . '/' . $css_file );
/* add all font files */
/**
* TCB-1683 php < 5.3 does not have support for ZipArchive::addGlob()
*/
$font_files = glob( trailingslashit( $folder_path ) . '*.{woff,WOFF,eot,EOT,woff2,WOFF2,ttf,TTF,svg,SVG}', GLOB_BRACE );
foreach ( $font_files as $font_file ) {
$zip->addFile( $font_file, 'font-pack/' . $name . '/' . basename( $font_file ) );
}
}
/**
* get the path to a writable folder in this WP install
*
* @return string the path to a writable (temp) folder
* @throws Exception
*
*/
protected function getTempFolder() {
$folder = get_temp_dir();
if ( ! wp_is_writable( $folder ) ) {
$folder = wp_upload_dir();
}
if ( ! wp_is_writable( $folder ) ) {
throw new Exception( 'Could not find a writable folder to create the archive in. Does your wp-content/uploads folder exist?', 'thrive-cb' );
}
return $folder;
}
/** --------------------------------------- IMPORT methods --------------------------------------- */
/**
* import a landing page from a zip file located in the attachment received as parameter
*
* @param mixed $file
* @param int $page_id - the existing page which will be transformed into a landing page
*
* @return array $page_id the ID of the landing page
*
* @throws Exception
*/
public function import( $file, $page_id ) {
$template_name = $this->importValidateFile( $file );
$zip = new ZipArchive();
if ( $zip->open( $file ) !== true ) {
throw new Exception( __( 'Could not open the archive file', 'thrive-cb' ) );
}
$config = $this->importReadConfig( $zip );
$this->import_config = $config;
$this->current_page = get_post( $page_id );
/**
* if this is a cloud template, we need to make sure the user has the cloud template files downloaded
*/
if ( ! empty( $config['cloud_template'] ) ) {
$existing = tve_get_downloaded_templates();
if ( ! isset( $existing[ $config['tve_landing_page'] ] ) ) {
try {
TCB_Landing_Page_Cloud_Templates_Api::getInstance()->download( $config['tve_landing_page'] );
} catch ( Exception $e ) {
// this means the LP is not available in the cloud anymore.
}
}
}
/* Import any extra icon_packs that might be associated with the landing page */
$this->importExtraIconPacks( $config, $zip );
/* Import any fonts that might be included in the export file, for the landing page */
/* the $font_class_map will hold a mapping between old classes (.ttfmx) and newly created classes */
$font_class_map = $this->importFonts( $config, $zip );
$config = static::replace_ids_on_import( $config );
/* if any landing page fonts have been setup, we need to replace the font_classes for the selectors, with the values from font_class_map */
if ( ! empty( $config['tve_globals']['landing_fonts'] ) ) {
foreach ( $config['tve_globals']['landing_fonts'] as $key => $data ) {
if ( ! isset( $font_class_map[ $data['css_class'] ] ) ) {
continue;
}
$config['tve_globals']['landing_fonts'][ $key ]['css_class'] = $font_class_map[ $data['css_class'] ];
}
}
/* also for any of the lightboxes */
if ( ! empty( $config['lightbox'] ) ) {
foreach ( $config['lightbox'] as $id => $item ) {
$this->importExtraIconPacks( $config['lightbox'][ $id ], $zip );
$font_class_map = array_merge( $font_class_map, $this->importFonts( $config['lightbox'][ $id ], $zip ) );
}
}
/* 1b. include the icon pack as an extra resource to be saved in the landing page */
if ( ! empty( $config['icon_pack'] ) ) {
$new_icon_pack = $this->importIconPack( $config, $zip );
if ( ! empty( $new_icon_pack ) && ! empty( $config['icon_pack']['icons'] ) && count( $config['icon_pack']['icons'] ) === count( $new_icon_pack['icons'] ) && $new_icon_pack['icons'][0] !== $config['icon_pack']['icons'][0] ) {
$icon_search = $config['icon_pack']['icons'];
$icon_replace = $new_icon_pack['icons'];
}
/* the default icons should not be included anymore in the LP or any of the lightboxes */
if ( ! empty( $config['thrive_icon_pack'] ) ) {
$config['thrive_icon_pack'] = 0;
$config['tve_globals']['used_icon_packs'] = empty( $config['tve_globals']['used_icon_packs'] ) ? [] : $config['tve_globals']['used_icon_packs'];
$config['tve_globals']['extra_icons'] = empty( $config['tve_globals']['extra_icons'] ) ? [] : $config['tve_globals']['extra_icons'];
$config['tve_globals']['extra_icons'] [] = $new_icon_pack;
$config['tve_globals']['used_icon_packs'] [] = $new_icon_pack['font-family'];
}
foreach ( $config['lightbox'] as $id => $item ) {
if ( ! empty( $item['thrive_icon_pack'] ) ) {
$config['lightbox'][ $id ]['thrive_icon_pack'] = 0;
$config['lightbox'][ $id ]['tve_globals']['used_icon_packs'] = empty( $config['lightbox'][ $id ]['tve_globals']['used_icon_packs'] ) ? [] : $config['lightbox'][ $id ]['tve_globals']['used_icon_packs'];
$config['lightbox'][ $id ]['tve_globals']['extra_icons'] = empty( $config['lightbox'][ $id ]['tve_globals']['extra_icons'] ) ? [] : $config['lightbox'][ $id ]['tve_globals']['extra_icons'];
$config['lightbox'][ $id ]['tve_globals']['extra_icons'] [] = $new_icon_pack;
$config['lightbox'][ $id ]['tve_globals']['used_icon_packs'] [] = $new_icon_pack['font-family'];
}
}
}
/* 2. import all the images (add them as attachments) and store the links in the config array */
$this->importImages( $config, $zip );
/* 3. import all lightboxes (create new posts with type tcb_lightbox) */
$lightbox_id_map = $this->importLightboxes( $config );
/* 3. page-level events - check if we have a lightbox there and replace its ID */
if ( ! empty( $config['tve_page_events'] ) ) {
foreach ( $config['tve_page_events'] as $index => $evt ) {
if ( $evt['a'] !== 'thrive_lightbox' || empty( $evt['config']['l_id'] ) || ! isset( $lightbox_id_map[ $evt['config']['l_id'] ] ) ) {
continue;
}
$config['tve_page_events'][ $index ]['config']['l_id'] = $lightbox_id_map[ $evt['config']['l_id'] ];
}
}
/* 4. set all post-meta values to the lightbox */
$this->importParseImageLinks( $config );
update_post_meta( $page_id, 'tve_landing_page', $config['tve_landing_page'] );
if ( ! empty( $config['tve_disable_theme_dependency'] ) ) {
//Options that disable the CSS from theme. Can be 1 if activated or 0 if not activated
update_post_meta( $page_id, 'tve_disable_theme_dependency', $config['tve_disable_theme_dependency'] );
}
foreach ( tve_get_used_meta_keys() as $meta_key ) {
if ( ! isset( $config[ $meta_key ] ) || $meta_key === 'tve_landing_page' ) {
continue;
}
$data = $this->replace_content_symbols_on_insert( $config[ $meta_key ] );
tve_update_post_meta( $page_id, $meta_key, $data );
}
/* 5. update the meta-field for TCB content - we need to parse the content and replace lightbox ids inside the event manager parameters */
$page_content = $zip->getFromName( $this->html_file_name );
$page_content = static::replace_ids_on_import( $page_content );
$this->importParseImageLinks( $page_content );
$this->importReplaceLightboxIds( $page_content, $lightbox_id_map );
if ( isset( $icon_search, $icon_replace ) ) {
$page_content = str_replace( $icon_search, $icon_replace, $page_content );
}
$page_content = $this->importReplaceFontClasses( $font_class_map, $page_content );
$this->import_symbols( $config );
$page_content = $this->replace_content_symbols_on_insert( $page_content );
tve_update_post_meta( $page_id, 'tve_updated_post', $page_content );
/* 6. search inside the lightboxes for event manager actions that trigger other lightboxes and replace those also */
if ( ! empty( $config['lightbox'] ) ) {
foreach ( $config['lightbox'] as $old_id => $data ) {
$lb_content = $zip->getFromName( 'lightboxes/' . $old_id . '.html' );
$this->importReplaceLightboxIds( $lb_content, $lightbox_id_map );
$this->importParseImageLinks( $lb_content );
if ( isset( $icon_search, $icon_replace ) ) {
$lb_content = str_replace( $icon_search, $icon_replace, $lb_content );
}
$lb_content = $this->importReplaceFontClasses( $font_class_map, $lb_content );
update_post_meta( $lightbox_id_map[ $old_id ], 'tve_updated_post', $lb_content );
}
}
/* import header, footer and maybe theme sections */
$config = $this->import_sections( $page_id, $config );
/* finally, save this import also as a landing page template */
$template_name = str_replace( $this->archive_prefix, '', $template_name );
/**
* Change imported lps name before saving as template
*
*/
$template_name = apply_filters( 'tve_imported_lp_name', $template_name );
/**
* For smart Landing Pages, we need to make sure that keys needed for smart landing pages exists inside the json file
*/
$smart_lp_keys = [ 'page_vars', 'page_styles', 'page_palettes' ];
foreach ( $smart_lp_keys as $smart_lp_key ) {
if ( ! isset( $config[ $smart_lp_key ] ) ) {
$config[ $smart_lp_key ] = [];
}
}
$template_data = [
'content' => $page_content,
'inline_css' => preg_replace( '/\.page-id-\d*/m', ".page-id-$page_id", $config['tve_custom_css'] ),
'custom_css' => $config['tve_user_custom_css'],
'tve_globals' => $config['tve_globals'],
'tve_global_scripts' => $config['tve_global_scripts'],
'name' => $template_name,
'template' => $config['tve_landing_page'],
'tags' => 'imported-template',
'date' => gmdate( 'Y-m-d' ),
'imported' => 1,
'zip_filesize' => filesize( $file ),
'thumbnail' => $this->importThumbnail( $config, $zip ),
'sections' => isset( $config['sections'] ) ? $config['sections'] : [],
'tpl_skin_tag' => isset( $config['skin_tag'] ) ? $config['skin_tag'] : '',
];
//save page colors & elements for saved template too
if ( ! empty( $config['page_vars']['colors'] ) ) {
$template_data['tpl_colours'] = $config['page_vars']['colors'];
}
if ( ! empty( $config['page_vars']['gradients'] ) ) {
$template_data['tpl_gradients'] = $config['page_vars']['gradients'];
}
if ( ! empty( $config['page_palettes'] ) ) {
$template_data['tpl_palettes'] = $config['page_palettes'];
}
if ( ! empty( $config[ TCB_LP_Palettes::LP_PALETTES ] ) ) {
$template_data['tpl_palettes_v2'] = $config[ TCB_LP_Palettes::LP_PALETTES ];
}
if ( ! empty( $config[ TCB_LP_Palettes::LP_PALETTES_CONFIG ] ) ) {
$template_data['tpl_palettes_config_v2'] = $config[ TCB_LP_Palettes::LP_PALETTES_CONFIG ];
}
$elements = [
'button',
'section',
'contentbox',
];
foreach ( $elements as $element ) {
if ( ! empty( $config['page_styles'][ $element ] ) ) {
$template_data[ 'tpl_' . $element ] = $config['page_styles'][ $element ];
}
}
$template_id = \TCB\SavedLandingPages\Saved_Lp::insert( $template_data );
if ( $page_id ) {
$landing_page = tcb_landing_page( $page_id );
$landing_page->set_lp_cloud_template_action( $config );
$landing_page->update_template_css_variables( $config['page_vars'] );
$landing_page->update_template_global_styles( $config['page_styles'] );
$landing_page->update_template_palettes( $config['page_palettes'], true );
}
return compact( 'page_id', 'template_id' );
}
/**
* Import header and footer if present in archive
*
* @param $page_id
* @param $config
*
* @return array
*/
public function import_sections( $page_id, $config ) {
foreach ( [ 'header', 'footer' ] as $section ) {
if ( ! empty( $config['sections'][ $section ] ) ) {
$old_id = $config['sections'][ $section ]['ID'];
$data = json_encode( $config['sections'][ $section ] );
$data = $this->replace_image_hash( $data );
$data = $this->replace_content_symbols_on_insert( $data );
$data = json_decode( $data, true );
if ( empty( $GLOBALS['tcb_symbol_map'][ $old_id ] ) ) {
$section_id = TCB_Symbol_Template::import( $data, $section );
} else {
$section_id = $GLOBALS['tcb_symbol_map'][ $old_id ];
}
if ( ! empty( $section_id ) ) {
update_post_meta( $page_id, "_tve_$section", $section_id );
$GLOBALS['tcb_symbol_map'][ $old_id ] = $section_id;
$config['sections'][ $section ]['ID'] = $section_id;
}
$config['sections'][ $section ]['meta_input'] = $data['meta_input'];
}
}
/**
* Filter config after importing sections
*
* @param array $sections
* @param int $page_id
* @param TCB_Landing_Page_Transfer
*
* @return array
*/
return apply_filters( 'tcb_lp_sections_import', $config, $page_id, $this );
}
/**
* Insert the symbols and set their mapping
*
* @param $config
*
* @return void
*/
public function import_symbols( $config ) {
if ( ! empty( $config['symbols'] ) ) {
foreach ( $config['symbols'] as $symbol ) {
$old_symbol_id = $symbol['ID'];
if ( empty( $GLOBALS['tcb_symbol_map'][ $old_symbol_id ] ) ) {
$data = json_encode( $symbol );
$data = $this->replace_image_hash( $data );
$data = json_decode( $data, true );
$symbol_id = TCB_Symbol_Template::import( $data );
$GLOBALS['tcb_symbol_map'][ $old_symbol_id ] = $symbol_id;
}
}
}
}
/**
* Get existing symbols from the content and replace them with the new ones
*
* @param $content
*
* @return mixed
*/
public function replace_content_symbols_on_insert( $content ) {
if ( ! empty( $GLOBALS['tcb_symbol_map'] ) && is_string( $content ) ) {
preg_match_all( TCB_Symbol_Template::SYMBOL_CONFIG_REGEX, $content, $cfg_matches );
preg_match_all( TCB_Symbol_Template::SYMBOL_SHORTCODE_REGEX, $content, $shortcode_matches );
$content = $this->replace_symbols_in_matches( $content, $cfg_matches );
$content = $this->replace_symbols_in_matches( $content, $shortcode_matches );
foreach ( $GLOBALS['tcb_symbol_map'] as $old_symbol_id => $new_symbol_id ) {
$content = str_replace( 'thrv_symbol_' . $old_symbol_id, 'thrv_symbol_' . $new_symbol_id, $content );
}
}
return $content;
}
/**
* Replace old symbols with new ones based on the mapping
*
* @param $content
* @param $matches
*
* @return array|mixed|string|string[]
*/
public function replace_symbols_in_matches( $content, $matches ) {
if ( ! empty( $matches ) && count( $matches ) === 2 ) {
foreach ( $matches[1] as $match_index => $symbol_id ) {
if ( isset( $GLOBALS['tcb_symbol_map'][ $symbol_id ] ) ) {
$old_symbol = $matches[0][ $match_index ];
$new_symbol = str_replace( $symbol_id, $GLOBALS['tcb_symbol_map'][ $symbol_id ], $old_symbol );
$content = str_replace( $old_symbol, $new_symbol, $content );
}
}
}
return $content;
}
/**
* validate if the file exists and it is a zip archive
*
* @param string $file
*
* @return string the file name without extension
*
* @throws Exception
*/
protected function importValidateFile( $file ) {
if ( ! is_file( $file ) ) {
throw new Exception( __( 'Could not find the archive file on the server. Please make sure the file exists.', 'thrive-cb' ) );
}
$name = basename( $file );
$info = pathinfo( $name );
if ( $info['extension'] !== 'zip' && $info['extension'] !== 'ZIP' ) {
throw new Exception( __( 'Invalid file specified', 'thrive-cb' ) );
}
if ( ! class_exists( 'ZipArchive' ) ) {
throw new Exception( __( 'The PHP ZipArchive extension must be enabled in order to use this functionality. Please contact your hosting provider.', 'thrive-cb' ) );
}
return str_ireplace( '.zip', '', $name );
}
/**
* check if all the required files are inside the zip archive
*
* @param ZipArchive $zip
*
* @return array the decoded configuration array
*
* @throws Exception
*/
protected function importReadConfig( ZipArchive $zip ) {
/* 1. check if json exists in the archive */
if ( false === $zip->locateName( $this->cfg_name ) ) {
throw new Exception( __( 'This archive does not seem to be generated from Thrive Architect - unable to find the config file', 'thrive-cb' ) );
}
/* 2. check if html exists - the Landing Page contents */
if ( false === $zip->locateName( $this->html_file_name ) ) {
throw new Exception( __( 'This archive does not seem to be generated from Thrive Architect - unable to find the content file', 'thrive-cb' ) );
}
/* 3. extract the config array from the json config file */
$contents = trim( $zip->getFromName( $this->cfg_name ) );
$config = json_decode( $zip->getFromName( $this->cfg_name ), true );
/**
* Also support the base64-encoded config files
*/
if ( empty( $config ) ) {
$config = @unserialize( @base64_decode( $contents ) );
}
if ( empty( $config ) ) {
throw new Exception( __( 'This archive does not seem to be generated from Thrive Architect - could not decode the configuration', 'thrive-cb' ) );
}
if ( $this->should_check_lp_page() && empty( $config['tve_landing_page'] ) ) {
throw new Exception( __( 'This archive does not seem to be generated from Thrive Architect - configuration file is invalid', 'thrive-cb' ) );
}
/* 4. check for all lightboxes to exist as files */
if ( ! empty( $config['lightbox'] ) ) {
foreach ( $config['lightbox'] as $id => $data ) {
if ( false == $zip->locateName( 'lightboxes/' . $id . '.html' ) ) {
throw new Exception( __( 'Could not locate the lightbox #' . $id, 'thrive-cb' ) );
}
if ( ! array_key_exists( 'post_title', $data ) ) {
throw new Exception( __( 'Values are missing from the configuration (post_title)', 'thrive-cb' ) );
}
}
}
/* 5. check that all images included in the config are also included as files in the archive */
if ( ! empty( $config['image_map'] ) ) {
foreach ( $config['image_map'] as $hash => $original_name ) {
if ( false === $zip->locateName( 'images/' . $hash . '.img_file' ) ) {
throw new Exception( __( 'Image is missing from the archive: ' . $original_name, 'thrive-cb' ) );
}
}
}
return $config;
}
/**
* Whether or not we expect a LP to be imported
*
* @return bool
*/
protected function should_check_lp_page() {
return true;
}
/**
* save all images as attachments
*
* @param array $config
* @param ZipArchive $zip
*
* @throws Exception
*/
protected function importImages( $config, ZipArchive $zip ) {
if ( empty( $config['image_map'] ) ) {
$this->image_map = [];
} else {
foreach ( $config['image_map'] as $hash => $image_name ) {
$this->image_map[ $hash ] = $this->insertAttachment( $image_name, $zip->getFromName( 'images/' . $hash . '.img_file' ) );
}
}
}
/**
* uploads an image to the wp media folder and insert it as an attachment
*
* @param string $image_name
* @param string $image_content full content of the image file
*
* @return string the url to the uploaded image
*
* @throws Exception
*/
protected function insertAttachment( $image_name, $image_content ) {
$upload = wp_upload_bits( $image_name, null, $image_content );
if ( ! empty( $upload['error'] ) ) {
throw new Exception( sprintf( __( 'Could not upload the image: %s', 'thrive-cb' ), $image_name ) );
}
/* add the image to the media library, as an attachment */
$wp_filetype = wp_check_filetype( $image_name, null );
$attachment = array(
'post_mime_type' => $wp_filetype['type'],
'post_parent' => 0,
'post_title' => preg_replace( '/\.[^.]+$/', '', $image_name ),
'post_content' => '',
'post_status' => 'inherit',
);
$attachment_id = wp_insert_attachment( $attachment, $upload['file'] );
if ( ! is_wp_error( $attachment_id ) ) {
/* if we leave these filters in, the generate_attachment_metadata will run forever */
remove_all_filters( 'wp_generate_attachment_metadata' );
remove_all_filters( 'intermediate_image_sizes' );
/* some themes / plugins fill this directly. empty it so that no extra size is generated */
global $_wp_additional_image_sizes;
$_wp_additional_image_sizes = [];
require_once ABSPATH . 'wp-admin/includes/image.php';
$attachment_data = wp_generate_attachment_metadata( $attachment_id, $upload['file'] );
wp_update_attachment_metadata( $attachment_id, $attachment_data );
}
return $upload['url'];
}
/**
* return $string with all occurrences of {{img=hash}} replace with the new image links
*
* @param string $string
*
* @return string
*/
public function replace_image_hash( $string ) {
$search = [];
$replace = [];
foreach ( $this->image_map as $hash => $url ) {
$search [] = '{{img=' . $hash . '}}';
$replace [] = $url;
}
return str_replace( $search, $replace, $string );
}
/**
* replace all occurrences of {img=hash} with the generated URLs for the new images
*
* @param string|array $content the post content (or the configuration the lightbox / landing page - to replace background images and stuff)
*/
protected function importParseImageLinks( &$content ) {
if ( is_array( $content ) ) {
/* global setting for page background - image */
if ( ! empty( $content['tve_globals']['lp_bgi'] ) ) {
$content['tve_globals']['lp_bgi'] = $this->replace_image_hash( $content['tve_globals']['lp_bgi'] );
}
if ( ! empty( $content['tve_globals']['lp_bgp'] ) ) {
$content['tve_globals']['lp_bgp'] = $this->replace_image_hash( $content['tve_globals']['lp_bgp'] );
}
/* lightbox - global setting - content background */
if ( ! empty( $content['tve_globals']['l_cimg'] ) ) {
$content['tve_globals']['l_cimg'] = $this->replace_image_hash( $content['tve_globals']['l_cimg'] );
} elseif ( ! empty( $content['tve_globals']['l_cpat'] ) ) {
$content['tve_globals']['l_cpat'] = $this->replace_image_hash( $content['tve_globals']['l_cpat'] );
}
/* CSS - head_css rules */
if ( ! empty( $content['tve_custom_css'] ) ) {
$content['tve_custom_css'] = $this->replace_image_hash( $content['tve_custom_css'] );
}
return;
}
$content = $this->replace_image_hash( $content );
}
/**
* import (create) the lightboxes included in the export file
* this does not import the lb contents yet
*
* @param array $config
*
* @return array map of old_id => new_id for each lightbox
*/
protected function importLightboxes( &$config ) {
if ( empty( $config['lightbox'] ) ) {
return [];
}
$lightbox_id_map = [];
foreach ( $config['lightbox'] as $id => $lb_data ) {
$this->importParseImageLinks( $lb_data );
$globals = $lb_data['tve_globals'];
unset( $lb_data['tve_globals'] );
$lightbox_id_map[ $id ] = TCB_Lightbox::create( str_replace( '(Imported)', '', $lb_data['post_title'] ) . '(Imported)', '', $globals, $lb_data );
}
return $lightbox_id_map;
}
/**
* parse the content for event manager configurations and replace old lightbox ids with new ones
*
* @param string $content
* @param array $lightbox_id_map
*/
protected function importReplaceLightboxIds( &$content, $lightbox_id_map ) {
if ( empty( $lightbox_id_map ) ) {
return;
}
$search = $replace = [];
foreach ( $lightbox_id_map as $old_id => $new_id ) {
$search [] = '"l_id":"' . $old_id . '"';
$replace [] = '"l_id":"' . $new_id . '"';
}
$content = str_replace( $search, $replace, $content );
}
/**
* import the main icon pack (the main Thrive Icon Pack setup on the site where the user made the export)
*
* @param array $config
* @param ZipArchive $zip
*
* @return array with new icon classes.
*
* @throws Exception
*/
protected function importIconPack( $config, ZipArchive $zip ) {
if ( empty( $config['icon_pack']['icons'] ) ) {
return [];
}
if ( false === $zip->locateName( 'icon-pack/style.css' ) || false === $zip->locateName( 'icon-pack/fonts/' ) ) {
return [];
}
$font_css = $zip->getFromName( 'icon-pack/style.css' );
$old_font_family = $config['icon_pack']['font-family'];
$new_font_family = uniqid( 'tve-ff-' . $this->current_page->ID . '-' );
/* create a new folder in the uploads_dir for the font-pack */
$upload_dir = $this->getUploadDir();
$font_dir_path = trailingslashit( $upload_dir['basedir'] ) . $new_font_family . '/fonts';
if ( ! wp_mkdir_p( $font_dir_path ) ) {
throw new Exception( __( 'Could not create the folder for the Icon Pack', 'thrive-cb' ) );
}
$icon_pack = [
'font-family' => $new_font_family,
];
$new_cls_prefix = uniqid( 'tve-icm-' ) . '-';
/* replace the font-family declaration AND all the class names with a prefix */
$font_css = preg_replace( '#font-family:(.*?)' . preg_quote( $old_font_family, '#' ) . '(.*)$#m', 'font-family:$1' . $new_font_family . '$2', $font_css );
/* replace all the CSS classes with the new cls prefix */
/*
do a preg_match do find the icon class. usually this is how the icomoon css file declares its classes:
[class^="icon2-"], [class*=" icon2-"] {...}
if we cannot find this pattern, there is no point in going forward, we cannot determine the global class selector
*/
if ( preg_match_all( '#\[class(.*?)("|\')(.+?)("|\')#m', $font_css, $matches ) ) {
$old_cls_prefix = $matches[3][0];
$font_css = preg_replace( '#\[class(.*?)("|\')(.+?)("|\')#m', '[class$1$2' . $new_cls_prefix . '$4', $font_css );
}
$new_icons = $config['icon_pack']['icons'];
if ( isset( $old_cls_prefix ) ) {
$font_css = str_replace( '.' . $old_cls_prefix, '.' . $new_cls_prefix, $font_css );
foreach ( $new_icons as $i => $icon ) {
$new_icons[ $i ] = str_replace( $old_cls_prefix, $new_cls_prefix, $icon );
}
}
$icon_pack['icons'] = $new_icons;
/* upload the font css file */
tve_wp_upload_bits( trailingslashit( dirname( $font_dir_path ) ) . 'style.css', $font_css );
/* save the URL to the uploaded css file */
$icon_pack['css'] = trailingslashit( $upload_dir['baseurl'] ) . $new_font_family . '/style.css';
/* save the folder path to the saved icon pack */
$icon_pack['folder'] = str_replace( '\\', '\\\\', trailingslashit( $upload_dir['basedir'] ) . $new_font_family );
/* go through the zip contents and grab all the font files - upload them to the fonts folder ($font_dir_path) */
$i = 0;
while ( $info = $zip->statIndex( $i ) ) {
if ( strpos( $info['name'], 'icon-pack/fonts/' ) === 0 && ! empty( $info['size'] ) ) {
$pathinfo = pathinfo( $info['name'] );
if ( empty( $pathinfo['extension'] )
|| ! in_array( strtolower( $pathinfo['extension'] ), [
'woff',
'woff2',
'ttf',
'svg',
'eot',
] )
) {
$i ++;
continue;
}
tve_wp_upload_bits( trailingslashit( $font_dir_path ) . basename( $info['name'] ), $zip->getFromIndex( $i ) );
}
$i ++;
}
return $icon_pack;
}
/**
* import any extra icon_packs that might be existing in the $config array from a previous import
*
* @param array $config
* @param ZipArchive $zip
*
* @return mixed
*
* @throws Exception
*/
protected function importExtraIconPacks( &$config, ZipArchive $zip ) {
if ( empty( $config['tve_globals']['extra_icons'] ) ) {
return;
}
foreach ( $config['tve_globals']['extra_icons'] as $i => $icon_pack ) {
$family = $icon_pack['font-family'];
if ( false === $zip->locateName( $family . '/style.css' ) || false === $zip->locateName( $family . '/fonts/' ) ) {
unset( $config['tve_globals']['extra_icons'][ $i ] );
continue;
}
/* create a new folder in the uploads_dir for the font-pack */
$upload_dir = $this->getUploadDir();
$font_dir_path = trailingslashit( $upload_dir['basedir'] ) . $family . '/fonts';
if ( ! wp_mkdir_p( $font_dir_path ) ) {
throw new Exception( __( 'Could not create the folder for the Icon Pack', 'thrive-cb' ) );
}
/* upload the font css file */
tve_wp_upload_bits( trailingslashit( dirname( $font_dir_path ) ) . 'style.css', $zip->getFromName( $family . '/style.css' ) );
/* save the URL to the uploaded css file */
$icon_pack['css'] = trailingslashit( $upload_dir['baseurl'] ) . $family . '/style.css';
/* save the folder path to the saved icon pack */
$icon_pack['folder'] = str_replace( '\\', '\\\\', trailingslashit( $upload_dir['basedir'] ) . $family );
/* go through the zip contents and grab all the font files - upload them to the fonts folder ($font_dir_path) */
$zip_index = 0;
while ( $info = $zip->statIndex( $zip_index ) ) {
if ( strpos( $info['name'], $family . '/fonts/' ) === 0 && ! empty( $info['size'] ) ) {
$pathinfo = pathinfo( $info['name'] );
if ( empty( $pathinfo['extension'] )
|| ! in_array( strtolower( $pathinfo['extension'] ), [
'woff',
'ttf',
'svg',
'eot',
] )
) {
$zip_index ++;
continue;
}
tve_wp_upload_bits( trailingslashit( $font_dir_path ) . basename( $info['name'] ), $zip->getFromIndex( $zip_index ) );
}
$zip_index ++;
}
$config['tve_globals']['extra_icons'][ $i ] = $icon_pack;
}
$config['tve_globals']['extra_icons'] = array_values( $config['tve_globals']['extra_icons'] );
}
/**
* create new fonts from the exported ones, return a class map in the form of .ttfmx => .ttfmy - to be used to replace occurences of ttfmx with ttfmy in the page / lightbox contents
*
* @param array $config
* @param ZipArchive $zip
*
* @return array
*/
public function importFonts( &$config, ZipArchive $zip ) {
if ( empty( $config['thrive_tcb_post_fonts'] ) && empty( $config['tve_globals']['extra_fonts'] ) ) {
return [];
}
$class_map = [];
$config['tve_globals']['font_cls'] = [];
$config['tve_globals']['extra_fonts'] = isset( $config['tve_globals']['extra_fonts'] ) ? $config['tve_globals']['extra_fonts'] : [];
$this->import_config['imported_font_index'] = isset( $this->import_config['imported_font_index'] ) ? $this->import_config['imported_font_index'] : 0;
$this->import_config['imported_font_index'] ++;
$this->import_config['imported_fonts'] = isset( $this->import_config['imported_fonts'] ) ? $this->import_config['imported_fonts'] : [];
/* check for any extra_fonts included in the import file */
if ( ! empty( $config['tve_globals']['extra_fonts'] ) ) {
foreach ( $config['tve_globals']['extra_fonts'] as $i => $font ) {
$location = $this->importFontPack( $zip, $font['font_folder'], basename( $font['font_url'] ), $font['font_folder'] ); // use the same folder name
if ( empty( $location ) ) {
unset( $config['tve_globals']['extra_fonts'][ $i ] );
continue;
}
$already_imported_index = $this->findFontByProps( $font, $this->import_config['imported_fonts'] );
if ( false === $already_imported_index ) {
$font['font_url'] = $location['url'];
$font['font_folder'] = str_replace( '\\', '\\\\', $location['path'] );
$font['font_id'] = $this->import_config['imported_font_index'] ++;
$new_css_class = 'ttfm-i-' . $font['font_id'];
$class_map[ $font['font_class'] ] = $new_css_class;
$font['font_class'] = $new_css_class;
$this->import_config['imported_fonts'] [] = $font;
} else {
$font = $this->import_config['imported_fonts'][ $already_imported_index ];
}
$config['tve_globals']['extra_fonts'][ $i ] = $font;
}
}
$config['tve_globals']['extra_fonts'] = array_values( $config['tve_globals']['extra_fonts'] );
$all_fonts = $this->getThriveFonts();
foreach ( $config['thrive_tcb_post_fonts'] as $index => $font_data ) {
if ( empty( $font_data['imported'] ) ) {
$font_index = $this->findFontByProps( $font_data, $all_fonts );
if ( $font_index === false ) {
$new_font = $this->addThriveFont( $font_data, $all_fonts );
} else {
$new_font = $all_fonts[ $font_index ];
}
if ( $font_data['font_class'] != $new_font['font_class'] ) {
$class_map[ $font_data['font_class'] ] = $new_font['font_class'];
}
if ( tve_is_safe_font( $new_font ) ) {
/* it does not require an URL */
unset( $config['thrive_tcb_post_fonts'][ $index ] );
} else {
$config['thrive_tcb_post_fonts'][ $index ] = tve_custom_font_get_link( $new_font );
}
/* add the font class to the global font_cls field */
$config['tve_globals']['font_cls'][] = $new_font['font_class'];
continue;
}
if ( empty( $this->import_config['font_pack'] ) ) {
unset( $config['thrive_tcb_post_fonts'][ $index ] );
continue;
}
/* at this point, the included font was imported using the thrive font import manager */
$location = $this->importFontPack( $zip, $this->import_config['font_pack']['name'], $this->import_config['font_pack']['css'] );
if ( empty( $location ) ) { // nothing we can do here, the archive seems corrupted
unset( $config['thrive_tcb_post_fonts'][ $index ] );
continue;
}
$already_imported_index = $this->findFontByProps( $font_data, $this->import_config['imported_fonts'] );
/* search and see if this has already been imported in this run */
if ( false === $already_imported_index ) {
$font_data['font_url'] = $location['url'];
$font_data['font_folder'] = str_replace( '\\', '\\\\', $location['path'] );
$font_data['font_id'] = $this->import_config['imported_font_index'] ++;
$new_css_class = 'ttfm-i-' . $font_data['font_id'];
$class_map[ $font_data['font_class'] ] = $new_css_class;
$font_data['font_class'] = $new_css_class;
unset( $font_data['imported'] );
$this->import_config['imported_fonts'][] = $font_data;
} else {
$font_data = $this->import_config['imported_fonts'][ $already_imported_index ];
}
$config['tve_globals']['extra_fonts'][] = $font_data;
/* this can be removed from here at the moment */
unset( $config['thrive_tcb_post_fonts'][ $index ] );
}
/* reorder the array, to skip non-consecutive indexes */
$config['thrive_tcb_post_fonts'] = array_values( $config['thrive_tcb_post_fonts'] );
return $class_map;
}
/**
* import the actual files for the font pack included in the archive
*
* @param ZipArchive $zip
* @param string $folder_name folder name where the font files are stored in the zip archive
* @param string $css_file name of the css file from the font folder
* @param string $new_folder_name if empty, a random folder name will be generated
*
* @return array|false
* url -> the full url to the css font definition file
* path -> the full path to the folder containing the font files
*
* @throws Exception
*/
public function importFontPack( $zip, $folder_name, $css_file, $new_folder_name = null ) {
if ( ! empty( $this->import_config['font_pack_imported'][ $folder_name ] ) ) {
return $this->import_config['font_pack_imported'][ $folder_name ];
}
$zip_path = 'font-pack/' . $folder_name;
if ( false === $zip->locateName( $zip_path . '/' . $css_file ) ) {
throw new Exception( sprintf( __( 'Could not find the main imported font in the archive file (%s)', 'thrive-cb' ), $zip_path ) );
}
$folder = null === $new_folder_name ? ( substr( $folder_name, 0, 10 ) . uniqid( '-imp-' ) ) : $new_folder_name;
/* create a new folder in the uploads_dir for the font-pack */
$upload_dir = $this->getUploadDir();
$font_dir_path = trailingslashit( $upload_dir['basedir'] ) . $folder;
if ( ! wp_mkdir_p( $font_dir_path ) ) {
throw new Exception( __( 'Could not create the folder for the Custom Font Pack', 'thrive-cb' ) );
}
/* upload the font css file */
tve_wp_upload_bits( trailingslashit( $font_dir_path ) . $css_file, $zip->getFromName( $zip_path . '/' . $css_file ) );
/* save the URL to the uploaded css file */
$this->import_config['font_pack_imported'][ $folder_name ] = array(
'url' => trailingslashit( $upload_dir['baseurl'] ) . $folder . '/' . $css_file,
'path' => $font_dir_path,
);
/* go through the zip contents and grab all the font files - upload them to the fonts folder ($font_dir_path) */
$zip_index = 0;
while ( $info = $zip->statIndex( $zip_index ) ) {
if ( strpos( $info['name'], $folder_name ) === false ) {
$zip_index ++;
continue;
}
if ( ! preg_match( '#\.(woff|eot|woff2|ttf|svg)$#i', $info['name'] ) ) {
$zip_index ++;
continue;
}
tve_wp_upload_bits( trailingslashit( $font_dir_path ) . basename( $info['name'] ), $zip->getFromIndex( $zip_index ) );
$zip_index ++;
}
return $this->import_config['font_pack_imported'][ $folder_name ];
}
/**
* replace all occurences of the array keys of the $class_map with the array values
* the problem here is that we cannot go over the string more than once - it's possible that some of the replacements are identical with some of the searches
*
* @param array $class_map
* @param string $content
*
* @return string
*/
protected function importReplaceFontClasses( $class_map, $content ) {
if ( empty( $class_map ) ) {
return $content;
}
$search = array_keys( $class_map );
/* hold this to be used in the callback function for replacing */
$this->import_temp_replace_map = $class_map;
$pattern = '#(' . implode( '|', $search ) . ')#s';
return preg_replace_callback( $pattern, [ $this, '_importReplaceFontClassCallback' ], $content );
}
private function _importReplaceFontClassCallback( $matches ) {
return $this->import_temp_replace_map[ $matches[0] ];
}
/**
* check if there is a thumbnail included in the archive and import it
*
* @param array $config configuration array
* @param ZipArchive $zip zip archive containing the exported landing page
*
* @return string the url to the uploaded thumbnail file
*/
protected function importThumbnail( $config, ZipArchive $zip ) {
if ( empty( $config['thumbnail'] ) ) {
return '';
}
if ( false === $zip->locateName( 'thumbnail/' . $config['thumbnail'] ) ) {
return '';
}
try {
return $this->insertAttachment( $config['thumbnail'], $zip->getFromName( 'thumbnail/' . $config['thumbnail'] ) );
} catch ( Exception $e ) {
return '';
}
}
/**
* wp_upload_bits does not allow creating subfolders in the upload_dir structure
* we need to upload some things into a grouped manner - e.g. font files for custom icons
*
* @param string $full_path full file path
* @param string $contents
*
* @return true on success
* @throws Exception
*
*/
protected function wpUploadBits( $full_path, $contents ) {
$ifp = @ fopen( $full_path, 'wb' );
if ( ! $ifp ) {
throw new Exception( sprintf( __( 'Could not write file %s', 'thrive-cb' ), basename( $full_path ) ) );
}
@fwrite( $ifp, $contents );
fclose( $ifp );
clearstatcache();
// Set correct file permissions
$stat = @ stat( dirname( $full_path ) );
$perms = $stat['mode'] & 0007777;
$perms = $perms & 0000666;
@ chmod( $full_path, $perms );
clearstatcache();
return true;
}
/**
* get all fonts that are defined from the font manager
*
* @return array
*/
protected function getThriveFonts() {
$fonts = json_decode( get_option( 'thrive_font_manager_options', '[]' ), true );
return empty( $fonts ) ? [] : $fonts;
}
/**
* update (save) the fonts (some new fonts might have been added during the import process)
*
* @param array|string $fonts
*/
protected function updateThriveFonts( $fonts ) {
if ( is_array( $fonts ) ) {
$fonts = json_encode( $fonts );
}
update_option( 'thrive_font_manager_options', $fonts );
}
/**
* check if we can find the font defined by $font properties in the $fonts array
*
* @param array $font font properties
* @param array $fonts array to search in
* @param array $field_search an array of fields which all need to match
*
* @return int|false the index of the match, or false otherwise
*/
protected function findFontByProps( $font, $fonts, $field_search = [ 'font_name', 'font_style', 'font_bold', 'font_color' ] ) {
foreach ( $fonts as $i => $f ) {
$found = true;
foreach ( $field_search as $field ) {
if ( $font[ $field ] !== $f[ $field ] ) {
$found = false;
break;
}
}
if ( $found ) {
return $i;
}
}
return false;
}
/**
* Replace menu id because it won't be valid on next import
*
* @param $content
*
* @return array|string|string[]|null
*/
public static function replace_ids_on_export( $content ) {
$content = preg_replace_callback( '#>__CONFIG_widget_menu__.*(menu_id[^"]*":[^"]*"\d*[^"]*").*__CONFIG_widget_menu__<#mU', static function ( $matches ) {
return str_replace( $matches[1], preg_replace( '/\d+/', '__TVE_EXPORTED_MENU_ID__', $matches[1] ), $matches[0] );
}, $content );
/* remove urls from logo's because they are not relevant for the export */
$content = preg_replace( '#\[tcb_logo href="[^\"]*"#m', '[tcb_logo', $content );
return $content;
}
/**
* Replace menu ids back after import
*
* @param string|array $content
*
* @return array|string|string[]
*/
public static function replace_ids_on_import( $content ) {
$is_string = is_string( $content );
if ( ! $is_string ) {
$content = json_encode( $content );
}
$menu_id = tve_get_default_menu();
$content = str_replace( '__TVE_EXPORTED_MENU_ID__', $menu_id, $content );
if ( ! $is_string ) {
$content = json_decode( $content, true );
}
return $content;
}
/**
* add new font (same functionality as the thrive font manager)
*
* @param array $font
* @param array $fonts
*
* @return array the added font (having a new font_id and a new font_class fields)
*/
protected function addThriveFont( $font, &$fonts ) {
$last = end( $fonts );
$font['font_id'] = empty( $last ) ? 1 : ( $last['font_id'] + 1 );
$font['font_class'] = 'ttfm' . $font['font_id'];
$fonts [] = $font;
$this->updateThriveFonts( $fonts );
return $font;
}
/**
* get the imported font pack metadata, if any
*
* @return array
*/
public function getImportedFontPack() {
return get_option( Tve_Dash_Font_Import_Manager::OPTION_NAME, [] );
}
/** import template from a zip archive that's downloaded from the cloud */
/**
* The zip archive is already downloaded from the cloud and stored in the wp-uploads folder
*
* @param string $zip_file_path
* @param string $template_key
* @param bool $skip_zip_check whether or not to check the zip file for integrity - from templates downloaded directly from the cloud, this can remain true
*
* @return mixed the new template name (with the prefix appended to it)
* @throws Exception
*/
public function importFromCloud( $zip_file_path, $template_key, $skip_zip_check = true ) {
$old_umask = umask( 0 );
defined( 'FS_METHOD' ) || define( 'FS_METHOD', 'direct' );
/** @var $wp_filesystem WP_Filesystem_Base */
global $wp_filesystem;
$upload = $this->getUploadDir();
$wp_uploads_dir = $upload['basedir'];
if ( ! function_exists( 'WP_filesystem' ) ) {
include ABSPATH . 'wp-admin/includes/file.php';
}
if ( FS_METHOD !== 'direct' ) {
WP_Filesystem( array(
'hostname' => defined( 'FTP_HOST' ) ? FTP_HOST : '',
'username' => defined( 'FTP_USER' ) ? FTP_USER : '',
'password' => defined( 'FTP_PASS' ) ? FTP_PASS : '',
) );
if ( FS_METHOD !== 'ssh2' ) {
$wp_uploads_dir = str_replace( ABSPATH, '', $wp_uploads_dir );
}
} else {
WP_Filesystem();
}
if ( ! $wp_filesystem->connect() && $wp_filesystem->errors instanceof WP_Error ) {
throw new Exception( $wp_filesystem->errors->get_error_message() );
}
$folder = trailingslashit( $wp_uploads_dir ) . TVE_CLOUD_LP_FOLDER . '/';
if ( $skip_zip_check ) {
/* this means the template archive is coming directly from the Thrive Template Cloud, we can trust it */
$result = unzip_file( $zip_file_path, $folder );
if ( $result instanceof WP_Error ) {
umask( $old_umask );
throw new Exception( __( 'Could not extract the archive file', 'thrive-cb' ) );
}
}
if ( ! $wp_filesystem->is_readable( $folder . $template_key . '.json' ) ) {
throw new Exception( __( 'Could not read configuration file for the template', 'thrive-cb' ) );
}
$config = json_decode( $wp_filesystem->get_contents( $folder . $template_key . '.json' ), true );
if ( ! isset( $config['check'] ) ) {
throw new Exception( __( 'Could not validate the configuration file for this template', 'thrive-cb' ) );
}
// validate the checksum of the data in the config array
$check = $config['check'];
unset( $config['check'] );
if ( $check != md5( TCB_Landing_Page_Cloud_Templates_Api::API_KEY . serialize( $config ) ) ) {
throw new Exception( __( 'Could not validate the configuration file for this template', 'thrive-cb' ) );
}
$downloaded_templates = tve_get_downloaded_templates();
$config['thumb'] = trailingslashit( $upload['baseurl'] ) . TVE_CLOUD_LP_FOLDER . '/templates/thumbnails/' . $template_key . '.png';
$downloaded_templates[ $template_key ] = $config;
tve_save_downloaded_templates( $downloaded_templates );
return $template_key;
}
/**
* Prepares the page for export
*
* Searches for Global Data (css variables and global styles) and replaces them with their corresponding static data
*
* @param array $config
*/
private function prepare_global_data_for_export( &$config ) {
if ( ! empty( $config['tve_custom_css'] ) ) {
if ( strpos( $config['tve_updated_post'], TVE_GLOBAL_STYLE_CLS_PREFIX ) !== false ) {
if ( ! empty( $_POST['global_styles_css'] ) && is_array( $_POST['global_styles_css'] ) ) {
foreach ( $_POST['global_styles_css'] as $media => $css ) { // phpcs:ignore
$config['tve_custom_css'] = implode( '@media ' . $media . '{' . stripslashes( $_POST['global_styles_css'][ $media ] ), explode( '@media ' . $media . '{', $config['tve_custom_css'] ) ); // phpcs:ignore
}
if ( ! empty( $_POST['global_import_rules'] ) && is_array( $_POST['global_import_rules'] ) ) {
/**
* If there are global import rules, we need to prepend them into custom css
*/
$config['tve_custom_css'] = implode( '', wp_unslash( $_POST['global_import_rules'] ) ) . $config['tve_custom_css'];
}
}
$config['tve_updated_post'] = preg_replace( '#(' . TVE_GLOBAL_STYLE_CLS_PREFIX . '[a-zA-Z0-9]+-(?!tpl_)\w+)#', '$2', $config['tve_updated_post'] );
}
/**
* When using export TAR function
*/
$config['tve_custom_css'] = tve_prepare_global_variables_for_front( $config['tve_custom_css'], true, $this->allow_lp_vars );
}
if ( ! empty( $_REQUEST['post_id'] ) && is_numeric( $_REQUEST['post_id'] ) ) {
$post = tcb_post( absint( $_REQUEST['post_id'] ) );
if ( $post->is_landing_page() ) {
$config = array_merge( $config, tcb_landing_page( absint( $_REQUEST['post_id'] ) )->prepare_landing_page_for_export() );
}
}
}
}
/** various utility functions for handling file operations */
/**
* wp_upload_bits does not allow creating subfolders in the upload_dir structure
* we need to upload some things into a grouped manner - e.g. font files for custom icons
*
* @param string $full_path full file path
* @param string $contents
*
* @return true on success
* @throws Exception
*
*/
function tve_wp_upload_bits( $full_path, $contents ) {
$ifp = @ fopen( $full_path, 'wb' );
if ( ! $ifp ) {
throw new Exception( sprintf( __( 'Could not write file %s', 'thrive-cb' ), basename( $full_path ) ) );
}
@fwrite( $ifp, $contents );
fclose( $ifp );
clearstatcache();
// Set correct file permissions
$stat = @ stat( dirname( $full_path ) );
$perms = $stat['mode'] & 0007777;
$perms = $perms & 0000666;
@ chmod( $full_path, $perms );
clearstatcache();
return true;
}