982 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			982 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * Save (template and preset) to the local library functionality.
 | 
						|
 *
 | 
						|
 * @package Builder.
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * Gets the Library Item name.
 | 
						|
 *
 | 
						|
 * @param array  $preferences Preferences set in the Save Builder Preset/Template modals.
 | 
						|
 * @param string $item_type Preset / Template item type.
 | 
						|
 *
 | 
						|
 * @return string
 | 
						|
 */
 | 
						|
function et_theme_builder_local_library_get_item_name( $preferences, $item_type ) {
 | 
						|
	$_         = et_();
 | 
						|
	$item_name = '';
 | 
						|
 | 
						|
	if ( ! is_array( $preferences ) ) {
 | 
						|
		$preferences = [];
 | 
						|
	}
 | 
						|
 | 
						|
	switch ( trim( $item_type ) ) {
 | 
						|
		case ET_THEME_BUILDER_ITEM_SET:
 | 
						|
			$item_name = isset( $preferences['set_name'] ) && '' !== $preferences['set_name']
 | 
						|
			? sanitize_text_field( $preferences['set_name'] )
 | 
						|
			: esc_html__( 'Divi Theme Builder Set', 'et_builder' );
 | 
						|
 | 
						|
			break;
 | 
						|
		case ET_THEME_BUILDER_ITEM_TEMPLATE:
 | 
						|
			$item_name = isset( $preferences['template_name'] ) && '' !== $preferences['template_name']
 | 
						|
			? sanitize_text_field( $preferences['template_name'] )
 | 
						|
			: esc_html__( 'Divi Theme Builder Template', 'et_builder' );
 | 
						|
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	return $item_name;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Gets the layouts(shortcodes from header/body/footer area) information.
 | 
						|
 *
 | 
						|
 * @param array $template Template information from Save Builder Preset/Template modals.
 | 
						|
 *
 | 
						|
 * @return array
 | 
						|
 */
 | 
						|
function et_theme_builder_local_library_get_layouts( $template ) {
 | 
						|
	$_ = et_();
 | 
						|
 | 
						|
	$header_id = (int) $_->array_get( $template, 'layouts.header.id', 0 );
 | 
						|
	$body_id   = (int) $_->array_get( $template, 'layouts.body.id', 0 );
 | 
						|
	$footer_id = (int) $_->array_get( $template, 'layouts.footer.id', 0 );
 | 
						|
 | 
						|
	// get_post_field returns empty string on failure.
 | 
						|
	$header_content = get_post_field( 'post_content', $header_id );
 | 
						|
	$body_content   = get_post_field( 'post_content', $body_id );
 | 
						|
	$footer_content = get_post_field( 'post_content', $footer_id );
 | 
						|
 | 
						|
	return [
 | 
						|
		'header' => $header_content,
 | 
						|
		'body'   => $body_content,
 | 
						|
		'footer' => $footer_content,
 | 
						|
	];
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Save a Theme Builder template to the local library.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 * @param array $template Template.
 | 
						|
 * @param array $preferences Preferences for the save template.
 | 
						|
 *
 | 
						|
 * @return (integer|false) Return false on failure.
 | 
						|
 */
 | 
						|
function et_theme_builder_save_template_to_library( $template, $preferences = array() ) {
 | 
						|
	if ( ! current_user_can( 'edit_others_posts' ) ) {
 | 
						|
		wp_die();
 | 
						|
	}
 | 
						|
 | 
						|
	$_               = et_();
 | 
						|
	$is_set_template = false;
 | 
						|
 | 
						|
	if ( ! is_array( $preferences ) ) {
 | 
						|
		$preferences = [];
 | 
						|
	}
 | 
						|
 | 
						|
	// Preferences.
 | 
						|
	if ( ! array_key_exists( 'item_type', $preferences ) ) {
 | 
						|
		$preferences = array_merge( $preferences, [ 'item_type' => ET_THEME_BUILDER_ITEM_TEMPLATE ] );
 | 
						|
	}
 | 
						|
 | 
						|
	$template_name       = sanitize_text_field( et_theme_builder_local_library_get_item_name( $preferences, ET_THEME_BUILDER_ITEM_TEMPLATE ) );
 | 
						|
	$title               = sanitize_text_field( $_->array_get( $template, 'title', '' ) );
 | 
						|
	$enabled             = (bool) $_->array_get( $template, 'enabled', true );
 | 
						|
	$header_enabled      = (bool) $_->array_get( $template, 'layouts.header.enabled', true );
 | 
						|
	$body_enabled        = (bool) $_->array_get( $template, 'layouts.body.enabled', true );
 | 
						|
	$footer_enabled      = (bool) $_->array_get( $template, 'layouts.footer.enabled', true );
 | 
						|
	$autogenerated_title = (bool) $_->array_get( $template, 'autogenerated_title', true );
 | 
						|
	$use_on              = array_map( 'sanitize_text_field', $_->array_get( $template, 'use_on', array() ) );
 | 
						|
	$exclude_from        = array_map( 'sanitize_text_field', $_->array_get( $template, 'exclude_from', array() ) );
 | 
						|
	$is_default          = (bool) $_->array_get( $template, 'default', false );
 | 
						|
	$preset_id           = intval( $_->array_get( $preferences, 'preset_id', 0 ) );
 | 
						|
	$item_id             = intval( $_->array_get( $template, 'item_id', 0 ) );
 | 
						|
	$status              = sanitize_text_field( $_->array_get( $template, 'status', 'publish' ) );
 | 
						|
 | 
						|
	// Layout's shortcode.
 | 
						|
	$layout_types       = array( 'header', 'body', 'footer' );
 | 
						|
	$layout_shortcodes  = array();
 | 
						|
	$global_layout_meta = array();
 | 
						|
	$layout_meta        = array();
 | 
						|
 | 
						|
	$update = false; // Editing the saved template?.
 | 
						|
	if ( $item_id ) {
 | 
						|
		$item   = get_post( $item_id );
 | 
						|
		$update = $item && ET_TB_ITEM_POST_TYPE === $item->post_type && ( 'publish' === $item->post_status || $_->array_get( $preferences, 'force_update', false ) );
 | 
						|
	}
 | 
						|
 | 
						|
	foreach ( $layout_types as $layout_type ) {
 | 
						|
		$layout_id        = (int) $_->array_get( $template, "layouts.$layout_type.id", 0 );
 | 
						|
		$global_layout_id = (int) $_->array_get( $template, "global_layouts.$layout_type.id", 0 );
 | 
						|
		$is_global_layout = $layout_id && $global_layout_id && $layout_id === $global_layout_id;
 | 
						|
 | 
						|
		if ( $is_default && ET_THEME_BUILDER_ITEM_SET === $_->array_get( $preferences, 'item_type', '' ) ) {
 | 
						|
			if ( $preset_id && $global_layout_id ) {
 | 
						|
				update_post_meta( $preset_id, '_et_has_global_layouts', '1' );
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Mark whether layout is global layout.
 | 
						|
		$global_layout_meta[ "_et_{$layout_type}_layout_global" ] = $is_global_layout ? '1' : '0';
 | 
						|
		$layout_meta[ "_et_{$layout_type}_layout_id" ]            = $layout_id;
 | 
						|
 | 
						|
		// Do not save the global layout conent if template is not a Default Website Template.
 | 
						|
		$layout_post = get_post( $layout_id );
 | 
						|
		if ( $layout_post ) {
 | 
						|
			$layout_content = $layout_post->post_content;
 | 
						|
			if ( ! empty( $layout_content ) ) {
 | 
						|
				$layout_shortcodes[ $layout_type ] = array(
 | 
						|
					'post_content' => $layout_content,
 | 
						|
					'post_meta'    => et_core_get_post_builder_meta( $layout_id ),
 | 
						|
				);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	$post_content = ! empty( $layout_shortcodes ) ? wp_slash( wp_json_encode( $layout_shortcodes ) ) : '';
 | 
						|
 | 
						|
	if ( $update ) {
 | 
						|
		// Update template into the local library.
 | 
						|
		$post_id = wp_update_post(
 | 
						|
			array(
 | 
						|
				'ID'           => $item_id,
 | 
						|
				'post_title'   => $title,
 | 
						|
				'post_content' => $post_content,
 | 
						|
			)
 | 
						|
		);
 | 
						|
	} else {
 | 
						|
		// Insert template into the local library.
 | 
						|
		$is_set_template = ET_THEME_BUILDER_ITEM_SET === $_->array_get( $preferences, 'item_type', '' );
 | 
						|
 | 
						|
		$post_id = wp_insert_post(
 | 
						|
			array(
 | 
						|
				'post_type'    => ET_TB_ITEM_POST_TYPE,
 | 
						|
				'post_status'  => $status,
 | 
						|
				'post_title'   => $is_set_template ? $title : $template_name,
 | 
						|
				'post_content' => $post_content,
 | 
						|
			)
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	if ( 0 === $post_id || is_wp_error( $post_id ) ) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	$item_type = $_->array_get( $preferences, 'item_type', '' );
 | 
						|
 | 
						|
	// Taxonomy: TB item type and selected category and tags.
 | 
						|
	if ( ET_THEME_BUILDER_ITEM_TEMPLATE === $item_type ) {
 | 
						|
		et_local_library_set_item_taxonomy( $post_id, $preferences );
 | 
						|
	} elseif ( ET_THEME_BUILDER_ITEM_SET === $item_type ) {
 | 
						|
		$template_preferences = [
 | 
						|
			'item_type' => ET_THEME_BUILDER_ITEM_TEMPLATE,
 | 
						|
		];
 | 
						|
 | 
						|
		$is_set_template = true;
 | 
						|
 | 
						|
		if ( $is_default && $preset_id > 0 ) {
 | 
						|
			update_post_meta( $preset_id, '_et_has_default_template', '1' );
 | 
						|
		}
 | 
						|
 | 
						|
		et_local_library_set_item_taxonomy( $post_id, $template_preferences );
 | 
						|
	}
 | 
						|
 | 
						|
	// Template meta.
 | 
						|
	$metas = array_merge(
 | 
						|
		array(
 | 
						|
			'_et_autogenerated_title'   => $autogenerated_title ? '1' : '0',
 | 
						|
			'_et_default'               => $is_default ? '1' : '0',
 | 
						|
			'_et_enabled'               => $enabled ? '1' : '0',
 | 
						|
			'_et_header_layout_enabled' => $header_enabled ? '1' : '0',
 | 
						|
			'_et_body_layout_enabled'   => $body_enabled ? '1' : '0',
 | 
						|
			'_et_footer_layout_enabled' => $footer_enabled ? '1' : '0',
 | 
						|
			'_et_template_title'        => $title,
 | 
						|
		),
 | 
						|
		$global_layout_meta
 | 
						|
	);
 | 
						|
 | 
						|
	if ( $is_set_template ) {
 | 
						|
		$metas = array_merge(
 | 
						|
			$metas,
 | 
						|
			[
 | 
						|
				'_et_set_template' => '1',
 | 
						|
			]
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	foreach ( $metas as $key => $value ) {
 | 
						|
		update_post_meta( $post_id, $key, $value );
 | 
						|
	}
 | 
						|
 | 
						|
	// In a case of update, delete existing meta `_et_use_on` and `_et_exclude_from` before adding new.
 | 
						|
	if ( $update ) {
 | 
						|
		delete_post_meta( $post_id, '_et_use_on' );
 | 
						|
		delete_post_meta( $post_id, '_et_exclude_from' );
 | 
						|
	}
 | 
						|
 | 
						|
	if ( $use_on ) {
 | 
						|
		$use_on_unique = array_unique( $use_on );
 | 
						|
 | 
						|
		foreach ( $use_on_unique as $condition ) {
 | 
						|
			add_post_meta( $post_id, '_et_use_on', $condition );
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if ( $exclude_from ) {
 | 
						|
		$exclude_from_unique = array_unique( $exclude_from );
 | 
						|
 | 
						|
		foreach ( $exclude_from_unique as $condition ) {
 | 
						|
			add_post_meta( $post_id, '_et_exclude_from', $condition );
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if ( $is_default ) {
 | 
						|
		update_post_meta( $preset_id, '_et_default_template_id', $post_id );
 | 
						|
	}
 | 
						|
 | 
						|
	return $post_id;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Save a Theme Builder preset to the local library.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 * @param array $templates List of templates.
 | 
						|
 * @param array $preferences Preset preferences.
 | 
						|
 *
 | 
						|
 * @return (integer|false) Returns Post ID on success and FALSE on failure.
 | 
						|
 */
 | 
						|
function et_theme_builder_save_preset_to_library( $templates, $preferences ) {
 | 
						|
	if ( ! current_user_can( 'edit_others_posts' ) ) {
 | 
						|
		wp_die();
 | 
						|
	}
 | 
						|
 | 
						|
	if ( ! is_array( $templates ) ) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	$_                 = et_();
 | 
						|
	$template_post_ids = [];
 | 
						|
 | 
						|
	// Preferences.
 | 
						|
	if ( is_array( $preferences ) ) {
 | 
						|
		$preferences = array_merge( $preferences, [ 'item_type' => ET_THEME_BUILDER_ITEM_SET ] );
 | 
						|
	} else {
 | 
						|
		// Returning FALSE sends back wp_send_json_error().
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * List of all Template IDs as part of this preset.
 | 
						|
	 *
 | 
						|
	 * The following hierarchy will explain the relation between Presets, Templates & Layouts.
 | 
						|
	 *
 | 
						|
	 * - Preset
 | 
						|
	 *     - Templates
 | 
						|
	 *         - Layouts
 | 
						|
	 *
 | 
						|
	 * Each Template pertaining to this preset will be stored as `_et_template_id` post meta.
 | 
						|
	 *
 | 
						|
	 * SELECT post_id, meta_key, meta_value
 | 
						|
	 * FROM wp_postmeta
 | 
						|
	 * WHERE
 | 
						|
	 * meta_key='_et_template_id' AND post_id={post_id};
 | 
						|
	 */
 | 
						|
	$template_post_ids = [];
 | 
						|
 | 
						|
	$preset_name = et_theme_builder_local_library_get_item_name( $preferences, ET_THEME_BUILDER_ITEM_SET );
 | 
						|
 | 
						|
	$post_id = wp_insert_post(
 | 
						|
		array(
 | 
						|
			'post_type'   => ET_TB_ITEM_POST_TYPE,
 | 
						|
			'post_status' => et_()->array_get( $preferences, 'post_status', 'publish' ),
 | 
						|
			'post_title'  => $preset_name,
 | 
						|
		)
 | 
						|
	);
 | 
						|
 | 
						|
	if ( 0 === $post_id || is_wp_error( $post_id ) ) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	$preferences = array_merge( $preferences, [ 'preset_id' => $post_id ] );
 | 
						|
 | 
						|
	// Insert template into the local library.
 | 
						|
	foreach ( $templates as $template ) {
 | 
						|
		$template_post_ids[] = et_theme_builder_save_template_to_library( $template, $preferences );
 | 
						|
	}
 | 
						|
 | 
						|
	// Taxonomy: TB item type and selected category and tags.
 | 
						|
	et_local_library_set_item_taxonomy( $post_id, $preferences );
 | 
						|
	et_theme_builder_add_template_to_preset( $post_id, $template_post_ids );
 | 
						|
 | 
						|
	return $post_id;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Add template to the saved preset.
 | 
						|
 *
 | 
						|
 * @param int   $preset_id The preset id.
 | 
						|
 * @param array $template_post_ids List of the template post ids.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 */
 | 
						|
function et_theme_builder_add_template_to_preset( $preset_id, $template_post_ids ) {
 | 
						|
	foreach ( $template_post_ids as $template_post_id ) {
 | 
						|
		if ( 0 === absint( $template_post_id ) ) {
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		// `add_post_meta` used to create new { key: value } pair using the same key.
 | 
						|
		add_post_meta( $preset_id, '_et_template_id', $template_post_id );
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Retrieves an array of the terms in a given taxonomy in following format:
 | 
						|
 *
 | 
						|
 *   $terms = array(
 | 
						|
 *       '1' => array(
 | 
						|
 *           'id'    => 1,
 | 
						|
 *           'name'  => 'Uncategorized',
 | 
						|
 *           'slug'  => 'uncategorized',
 | 
						|
 *           'count' => 10,
 | 
						|
 *       ),
 | 
						|
 *   );
 | 
						|
 *
 | 
						|
 * @param string $tax_name Taxonomy name.
 | 
						|
 */
 | 
						|
function et_theme_builder_get_terms( $tax_name ) {
 | 
						|
	$terms       = get_terms( $tax_name, array( 'hide_empty' => false ) );
 | 
						|
	$terms_by_id = array();
 | 
						|
 | 
						|
	if ( is_wp_error( $terms ) || empty( $terms ) ) {
 | 
						|
		return array();
 | 
						|
	}
 | 
						|
 | 
						|
	foreach ( $terms as $term ) {
 | 
						|
		$term_id = $term->term_id;
 | 
						|
 | 
						|
		$terms_by_id[ $term_id ]['id']    = $term_id;
 | 
						|
		$terms_by_id[ $term_id ]['name']  = $term->name;
 | 
						|
		$terms_by_id[ $term_id ]['slug']  = $term->slug;
 | 
						|
		$terms_by_id[ $term_id ]['count'] = $term->count;
 | 
						|
	}
 | 
						|
 | 
						|
	return $terms_by_id;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Retrieves the library item type attached with library item.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 *
 | 
						|
 * @param int|WP_Post $item Library item post ID or object.
 | 
						|
 * @return string|WP_Error The library item type. WP_Error on failure.
 | 
						|
 */
 | 
						|
function et_theme_builder_get_library_item_type( $item ) {
 | 
						|
	// Initalize item type.
 | 
						|
	$terms = get_the_terms( $item, 'et_tb_item_type' );
 | 
						|
 | 
						|
	if ( ! $terms || is_wp_error( $terms ) ) {
 | 
						|
		return new WP_Error( 'et_theme_builder_no_item_type_attached', __( 'The library item type is not attached to a given item.', 'et_builder' ) );
 | 
						|
	}
 | 
						|
 | 
						|
	$item_type = $terms[0]->slug;
 | 
						|
 | 
						|
	// Allowed item types, i.e template and preset.
 | 
						|
	if ( ! in_array( $item_type, array( ET_THEME_BUILDER_ITEM_SET, ET_THEME_BUILDER_ITEM_TEMPLATE ), true ) ) {
 | 
						|
		return new WP_Error( 'et_theme_builder_invalid_item_type', __( 'Invalid library item type.', 'et_builder' ) );
 | 
						|
	}
 | 
						|
 | 
						|
	return $item_type;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Retrieves library item post given a library post ID or post object.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 *
 | 
						|
 * @param int|WP_Post $item Library item's post ID or WP_Post object.
 | 
						|
 * @return WP_Post|WP_Error The library item post object. WP_Error on failure.
 | 
						|
 */
 | 
						|
function et_theme_builder_get_library_item_post( $item ) {
 | 
						|
	// Initalize item post.
 | 
						|
	$item_post = get_post( $item );
 | 
						|
 | 
						|
	if ( ! $item_post ) {
 | 
						|
		return new WP_Error( 'et_theme_builder_item_not_found', __( 'Library item not found', 'et_builder' ) );
 | 
						|
	}
 | 
						|
 | 
						|
	$item_type = et_theme_builder_get_library_item_type( $item_post );
 | 
						|
 | 
						|
	if ( is_wp_error( $item_type ) ) {
 | 
						|
		return $item_type;
 | 
						|
	}
 | 
						|
 | 
						|
	return $item_post;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Create interim theme builder post for the local library editor.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 *
 | 
						|
 * @return int|bool The post ID on success. The value false on failure.
 | 
						|
 */
 | 
						|
function et_theme_builder_insert_library_theme_builder() {
 | 
						|
	if ( ! current_user_can( 'edit_others_posts' ) ) {
 | 
						|
		wp_die();
 | 
						|
	}
 | 
						|
 | 
						|
	$post_id = wp_insert_post(
 | 
						|
		array(
 | 
						|
			'post_type'   => ET_THEME_BUILDER_THEME_BUILDER_POST_TYPE,
 | 
						|
			'post_status' => 'publish',
 | 
						|
			'post_title'  => 'Library Theme Builder',
 | 
						|
		)
 | 
						|
	);
 | 
						|
 | 
						|
	if ( ! $post_id || is_wp_error( $post_id ) ) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	// Mark the theme builder to use during template editing.
 | 
						|
	update_post_meta( $post_id, '_et_library_theme_builder', '1' );
 | 
						|
 | 
						|
	return $post_id;
 | 
						|
}
 | 
						|
 | 
						|
// phpcs:disable Squiz.Commenting.FunctionComment.ParamCommentFullStop -- Respecting punctuation.
 | 
						|
/**
 | 
						|
 * Create a theme builder layouts from the template saved in the local library.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 *
 | 
						|
 * @param WP_Post $template_post The template post.
 | 
						|
 * @param array   $global_layouts Optional. Array containing the necessary params.
 | 
						|
 *    $params = [
 | 
						|
 *      'header' => (int|string) Header Layout ID. `use_global` string when TB global layout (relink option) is to be used.
 | 
						|
 *      'body'   => (int|string) Body Layout ID. `use_global` string when TB global layout (relink option) is to be used.
 | 
						|
 *      'footer' => (int|string) Footer Layout ID. `use_global` string when TB global layout (relink option) is to be used.
 | 
						|
 *    ]
 | 
						|
 *
 | 
						|
 * @return array|WP_Error An array of the created layout post ids. WP_Error on failure.
 | 
						|
 */
 | 
						|
function et_theme_builder_create_layouts_from_library_template( $template_post, $global_layouts = [] ) {
 | 
						|
 | 
						|
	if ( ! $template_post instanceof WP_Post || empty( $template_post->post_content ) ) {
 | 
						|
		return array();
 | 
						|
	}
 | 
						|
 | 
						|
	$layouts             = (array) json_decode( $template_post->post_content, true );
 | 
						|
	$template_settings   = et_theme_builder_get_template_settings( $template_post->ID, false );
 | 
						|
	$is_default_template = '1' === $template_settings['_et_default'];
 | 
						|
 | 
						|
	if ( empty( $layouts ) ) {
 | 
						|
		return new WP_Error(
 | 
						|
			'et_theme_builder_invalid_json',
 | 
						|
			esc_html__(
 | 
						|
				'Incorrect JSON string.',
 | 
						|
				'et-builder'
 | 
						|
			)
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	$new_layout_ids = array();
 | 
						|
 | 
						|
	foreach ( $layouts as $layout_type => $layout ) {
 | 
						|
		$layout_post_content = et_()->array_get( $layout, 'post_content', '' );
 | 
						|
 | 
						|
		// Skip if the layout `post_content` value is empty.
 | 
						|
		if ( empty( $layout_post_content ) ) {
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if ( ! $is_default_template && '1' === $template_settings[ "_et_{$layout_type}_layout_global" ] && array_key_exists( $layout_type, $global_layouts ) ) {
 | 
						|
			$new_layout_ids[ $layout_type ] = $global_layouts[ $layout_type ];
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		// Insert layout.
 | 
						|
		$post_id = et_theme_builder_insert_layout(
 | 
						|
			array(
 | 
						|
				'post_type'    => et_theme_builder_get_valid_layout_post_type( $layout_type ),
 | 
						|
				'post_content' => $layout_post_content,
 | 
						|
			)
 | 
						|
		);
 | 
						|
 | 
						|
		if ( $post_id && ! is_wp_error( $post_id ) ) {
 | 
						|
			$new_layout_ids[ $layout_type ] = $post_id;
 | 
						|
 | 
						|
			// Add post meta in the new layout from the layout `post_meta` value.
 | 
						|
			$layout_post_meta = et_()->array_get( $layout, 'post_meta', array() );
 | 
						|
			foreach ( $layout_post_meta as $post_meta ) {
 | 
						|
				update_post_meta( $post_id, $post_meta['key'], $post_meta['value'] );
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return $new_layout_ids;
 | 
						|
}
 | 
						|
// phpcs:enable
 | 
						|
 | 
						|
/**
 | 
						|
 * Create template from the library item post.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 *
 | 
						|
 * @param WP_Post $item_post The library item post object.
 | 
						|
 * @param array   $global_layouts Array of global layouts.
 | 
						|
 * @return int|bool The template id on success. false on failure.
 | 
						|
 */
 | 
						|
function et_theme_builder_create_template_from_library_template( $item_post, $global_layouts = array() ) {
 | 
						|
	if ( ! current_user_can( 'edit_others_posts' ) ) {
 | 
						|
		wp_die();
 | 
						|
	}
 | 
						|
 | 
						|
	// Insert template.
 | 
						|
	$template_id = wp_insert_post(
 | 
						|
		array(
 | 
						|
			'post_type'   => ET_THEME_BUILDER_TEMPLATE_POST_TYPE,
 | 
						|
			'post_status' => 'publish',
 | 
						|
			'post_title'  => $item_post->post_title,
 | 
						|
		)
 | 
						|
	);
 | 
						|
 | 
						|
	if ( ! $template_id || is_wp_error( $template_id ) ) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	// Insert layouts.
 | 
						|
	$new_layouts_ids = et_theme_builder_create_layouts_from_library_template( $item_post, $global_layouts );
 | 
						|
 | 
						|
	if ( is_wp_error( $new_layouts_ids ) ) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	foreach ( array( 'body', 'header', 'footer' ) as $layout_type ) {
 | 
						|
		$layout_post_id = et_()->array_get( $new_layouts_ids, $layout_type, 0 );
 | 
						|
		update_post_meta( $template_id, "_et_{$layout_type}_layout_id", $layout_post_id );
 | 
						|
	}
 | 
						|
 | 
						|
	// Add template settings.
 | 
						|
	$template_settings = et_theme_builder_get_template_settings( $item_post->ID, false );
 | 
						|
	foreach ( $template_settings as $meta_key => $meta_value ) {
 | 
						|
		if ( is_array( $meta_value ) ) {
 | 
						|
			foreach ( $meta_value as $value ) {
 | 
						|
				if ( ! empty( $value ) ) {
 | 
						|
					add_post_meta( $template_id, $meta_key, $value );
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			add_post_meta( $template_id, $meta_key, $meta_value );
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	add_post_meta( $template_id, '_et_library_item_id', $item_post->ID );
 | 
						|
 | 
						|
	return $template_id;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Retrive template settings.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 *
 | 
						|
 * @param int  $item_id The library item post ID.
 | 
						|
 * @param bool $formatted Whether to remove "_et" prefix from setting keys.
 | 
						|
 *
 | 
						|
 * @return array An array of template settings.
 | 
						|
 */
 | 
						|
function et_theme_builder_get_template_settings( $item_id, $formatted ) {
 | 
						|
	// Template settings meta.
 | 
						|
	$metas = array(
 | 
						|
		'_et_template_title'        => true,
 | 
						|
		'_et_autogenerated_title'   => true,
 | 
						|
		'_et_default'               => true,
 | 
						|
		'_et_enabled'               => true,
 | 
						|
		'_et_header_layout_enabled' => true,
 | 
						|
		'_et_body_layout_enabled'   => true,
 | 
						|
		'_et_footer_layout_enabled' => true,
 | 
						|
		'_et_use_on'                => false,
 | 
						|
		'_et_exclude_from'          => false,
 | 
						|
		'_et_header_layout_global'  => true,
 | 
						|
		'_et_body_layout_global'    => true,
 | 
						|
		'_et_footer_layout_global'  => true,
 | 
						|
	);
 | 
						|
 | 
						|
	$settings = array();
 | 
						|
 | 
						|
	foreach ( $metas as $meta_key => $is_single ) {
 | 
						|
		$key = $formatted ? substr( $meta_key, 4 ) : $meta_key;
 | 
						|
 | 
						|
		$settings[ $key ] = get_post_meta( $item_id, $meta_key, $is_single );
 | 
						|
	}
 | 
						|
 | 
						|
	return $settings;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Intalize the library item editor.
 | 
						|
 */
 | 
						|
function et_theme_builder_init_library_item_editor() {
 | 
						|
	if ( ! et_theme_builder_library_is_item_editor() ) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	$tb_item_id  = et_theme_builder_get_item_id();
 | 
						|
	$item_editor = ET_Theme_Builder_Local_Library_Item_Editor::instance( $tb_item_id );
 | 
						|
	$item_editor->init_library_item_editor();
 | 
						|
}
 | 
						|
 | 
						|
add_action( 'admin_init', 'et_theme_builder_init_library_item_editor', 10 );
 | 
						|
 | 
						|
/**
 | 
						|
 * Return custom style from the passed layout meta.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 *
 | 
						|
 * @param array  $layout_meta All layout meta saved in the local library.
 | 
						|
 * @param string $layout_type The layout type i.e body, header, footer.
 | 
						|
 * @return string Page custom style.
 | 
						|
 */
 | 
						|
function et_theme_builder_get_preview_custom_css( $layout_meta, $layout_type ) {
 | 
						|
	$overflow        = et_pb_overflow();
 | 
						|
	$selector_prefix = '.et-l--post';
 | 
						|
 | 
						|
	switch ( $layout_type ) {
 | 
						|
		case 'header':
 | 
						|
			$selector_prefix = '.et-l--header';
 | 
						|
			break;
 | 
						|
 | 
						|
		case 'body':
 | 
						|
			$selector_prefix = '.et-l--body';
 | 
						|
			break;
 | 
						|
 | 
						|
		case 'footer':
 | 
						|
			$selector_prefix = '.et-l--footer';
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	$page_settings = array();
 | 
						|
	foreach ( $layout_meta as $post_meta ) {
 | 
						|
		$page_settings[ $post_meta->key ] = $post_meta->value;
 | 
						|
	}
 | 
						|
 | 
						|
	$selector_prefix = ' ' . ET_BUILDER_CSS_PREFIX . $selector_prefix;
 | 
						|
	$output          = isset( $page_settings['_et_pb_custom_css'] ) ? $page_settings['_et_pb_custom_css'] : '';
 | 
						|
 | 
						|
	if ( isset( $page_settings['_et_pb_light_text_color'] ) ) {
 | 
						|
		$output .= sprintf(
 | 
						|
			'%2$s .et_pb_bg_layout_dark { color: %1$s !important; }',
 | 
						|
			esc_html( $page_settings['_et_pb_light_text_color'] ),
 | 
						|
			esc_html( $selector_prefix )
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	if ( isset( $page_settings['_et_pb_dark_text_color'] ) ) {
 | 
						|
		$output .= sprintf(
 | 
						|
			'%2$s .et_pb_bg_layout_light { color: %1$s !important; }',
 | 
						|
			esc_html( $page_settings['_et_pb_dark_text_color'] ),
 | 
						|
			esc_html( $selector_prefix )
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	if ( isset( $page_settings['_et_pb_content_area_background_color'] ) ) {
 | 
						|
		$content_area_bg_selector = et_is_builder_plugin_active() ? $selector_prefix : ' .page.et_pb_pagebuilder_layout #main-content';
 | 
						|
		$output                  .= sprintf(
 | 
						|
			'%1$s { background-color: %2$s; }',
 | 
						|
			esc_html( $content_area_bg_selector ),
 | 
						|
			esc_html( $page_settings['_et_pb_content_area_background_color'] )
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	if ( isset( $page_settings['_et_pb_section_background_color'] ) ) {
 | 
						|
		$output .= sprintf(
 | 
						|
			'%2$s > .et_builder_inner_content > .et_pb_section { background-color: %1$s; }',
 | 
						|
			esc_html( $page_settings['_et_pb_section_background_color'] ),
 | 
						|
			esc_html( $selector_prefix )
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	$overflow_x = $overflow->get_value_x( $page_settings, '', '_et_pb_' );
 | 
						|
	$overflow_y = $overflow->get_value_y( $page_settings, '', '_et_pb_' );
 | 
						|
 | 
						|
	if ( ! empty( $overflow_x ) ) {
 | 
						|
		$output .= sprintf(
 | 
						|
			'%2$s .et_builder_inner_content { overflow-x: %1$s; }',
 | 
						|
			esc_html( $overflow_x ),
 | 
						|
			esc_html( $selector_prefix )
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	if ( ! empty( $overflow_y ) ) {
 | 
						|
		$output .= sprintf(
 | 
						|
			'%2$s .et_builder_inner_content { overflow-y: %1$s; }',
 | 
						|
			esc_html( $overflow_y ),
 | 
						|
			esc_html( $selector_prefix )
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	if ( isset( $page_settings['_et_pb_page_z_index'] ) && '' !== $page_settings['_et_pb_page_z_index'] ) {
 | 
						|
		$output .= sprintf(
 | 
						|
			'%2$s .et_builder_inner_content { z-index: %1$s; }',
 | 
						|
			esc_html( $page_settings['et_pb_page_z_index'] ),
 | 
						|
			esc_html( '.et-db #et-boc .et-l' . $selector_prefix )
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Filters page custom css.
 | 
						|
	 *
 | 
						|
	 * @since 4.18.0
 | 
						|
	 *
 | 
						|
	 * @param string $output
 | 
						|
	 */
 | 
						|
	return apply_filters( 'et_pb_page_custom_css', $output );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Render the saved template.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 *
 | 
						|
 * @param int $item_id The saved library item id.
 | 
						|
 * @retun void
 | 
						|
 */
 | 
						|
function et_theme_builder_render_library_template_preview( $item_id ) {
 | 
						|
	$item          = new ET_Theme_Builder_Local_Library_Item( $item_id );
 | 
						|
	$layouts       = json_decode( $item->item_post->post_content );
 | 
						|
	$template_html = '';
 | 
						|
 | 
						|
	$layout_post_types = [
 | 
						|
		'header' => ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE,
 | 
						|
		'body'   => ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE,
 | 
						|
		'footer' => ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE,
 | 
						|
	];
 | 
						|
 | 
						|
	foreach ( $layouts as $layout_type => $layout ) {
 | 
						|
		$layout_meta      = $layout->post_meta;
 | 
						|
		$layout_post_type = $layout_post_types[ $layout_type ];
 | 
						|
		$layout_id        = 0;
 | 
						|
 | 
						|
		et_theme_builder_frontend_render_common_wrappers( $layout_type, true );
 | 
						|
 | 
						|
		$template_html .= et_builder_get_layout_opening_wrapper( $layout_post_type );
 | 
						|
		ET_Builder_Element::begin_theme_builder_layout( $layout_id );
 | 
						|
 | 
						|
		$template_html .= et_core_intentionally_unescaped( et_builder_render_layout( $layout->post_content ), 'html' );
 | 
						|
 | 
						|
		$result                                 = ET_Builder_Element::setup_advanced_styles_manager( $layout_id );
 | 
						|
		$advanced_styles_manager                = $result['manager'];
 | 
						|
		$advanced_styles_manager->forced_inline = true;
 | 
						|
 | 
						|
		if ( isset( $result['deferred'] ) ) {
 | 
						|
			$deferred_styles_manager = $result['deferred'];
 | 
						|
		}
 | 
						|
 | 
						|
		$is_critical_enabled = apply_filters( 'et_builder_critical_css_enabled', false );
 | 
						|
		$custom              = et_theme_builder_get_preview_custom_css( $layout_meta, $layout_type );
 | 
						|
		$critical            = $is_critical_enabled ? ET_Builder_Element::get_style( false, $layout_id, true ) . ET_Builder_Element::get_style( true, $layout_id, true ) : [];
 | 
						|
		$styles              = ET_Builder_Element::get_style( false, $layout_id ) . ET_Builder_Element::get_style( true, $layout_id );
 | 
						|
 | 
						|
		if ( empty( $critical ) ) {
 | 
						|
			// No critical styles defined, just enqueue everything as usual.
 | 
						|
			$styles = $custom . $styles;
 | 
						|
			if ( ! empty( $styles ) ) {
 | 
						|
				if ( isset( $deferred_styles_manager ) ) {
 | 
						|
					$deferred_styles_manager->set_data( $styles, 40 );
 | 
						|
				} else {
 | 
						|
					$advanced_styles_manager->set_data( $styles, 40 );
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			// Add page css to the critical section.
 | 
						|
			$critical = $custom . $critical;
 | 
						|
			$advanced_styles_manager->set_data( $critical, 40 );
 | 
						|
			if ( ! empty( $styles ) ) {
 | 
						|
				// Defer everything else.
 | 
						|
				$deferred_styles_manager->set_data( $styles, 40 );
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		ET_Builder_Element::end_theme_builder_layout();
 | 
						|
		$template_html .= et_builder_get_layout_closing_wrapper( $layout_post_type );
 | 
						|
	}
 | 
						|
 | 
						|
	return $template_html;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Check whether current page is library template preview page.
 | 
						|
 *
 | 
						|
 * @return bool
 | 
						|
 */
 | 
						|
function is_et_theme_builder_template_preview() {
 | 
						|
	global $wp_query;
 | 
						|
	// phpcs:ignore WordPress.Security.NonceVerification -- This function does not change any state, and is therefore not susceptible to CSRF.
 | 
						|
	return ( 'true' === $wp_query->get( 'et_pb_preview' ) && isset( $_GET['et_pb_preview_nonce'] ) && isset( $_GET['item_id'] ) );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Get updated global layouts by incoming layout duplicate decision.
 | 
						|
 *
 | 
						|
 * @param string $incoming_layout_duplicate_decision Layout duplicate decision opted by User.
 | 
						|
 * @param array  $global_layouts                     Global layouts.
 | 
						|
 * @return array
 | 
						|
 */
 | 
						|
function et_theme_builder_get_global_layouts_by_incoming_layout_duplicate_decision( $incoming_layout_duplicate_decision, $global_layouts ) {
 | 
						|
	$updated_global_layouts = [];
 | 
						|
 | 
						|
	if ( 0 === count( $global_layouts ) && 'relink' === $incoming_layout_duplicate_decision ) {
 | 
						|
		$theme_builder_templates = et_theme_builder_get_theme_builder_templates( true, false );
 | 
						|
		$layouts                 = [];
 | 
						|
 | 
						|
		foreach ( $theme_builder_templates as $template ) {
 | 
						|
			if ( ! $template['default'] ) {
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			$layouts = $template['layouts'];
 | 
						|
		}
 | 
						|
 | 
						|
		foreach ( $layouts as $layout_type => $layout ) {
 | 
						|
			$updated_global_layouts[ $layout_type ] = $layout['id'];
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		foreach ( $global_layouts as $layout_type => $layout_id ) {
 | 
						|
			$layout_post = get_post( $layout_id );
 | 
						|
 | 
						|
			if ( ! $layout_post ) {
 | 
						|
				$updated_global_layouts[ $layout_type ] = 0;
 | 
						|
			} else {
 | 
						|
				$created_layout_id = wp_insert_post(
 | 
						|
					[
 | 
						|
						'post_content' => $layout_post->post_content,
 | 
						|
						'post_title'   => $layout_post->post_title,
 | 
						|
						'post_type'    => $layout_post->post_type,
 | 
						|
						'post_status'  => $layout_post->post_status,
 | 
						|
						'post_name'    => $layout_post->post_name,
 | 
						|
					]
 | 
						|
				);
 | 
						|
 | 
						|
				$updated_global_layouts[ $layout_type ] = $created_layout_id;
 | 
						|
 | 
						|
				$meta = et_core_get_post_builder_meta( $layout_id );
 | 
						|
 | 
						|
				foreach ( $meta as $entry ) {
 | 
						|
					update_post_meta( $created_layout_id, $entry['key'], $entry['value'] );
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return $updated_global_layouts;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Retrieve the item id from query parameters.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 *
 | 
						|
 * @return int The template id or preset id.
 | 
						|
 */
 | 
						|
function et_theme_builder_get_item_id() {
 | 
						|
	// Editing library template.
 | 
						|
	$item_id = (int) et_()->array_get( $_GET, 'tb_template', 0 ); // phpcs:ignore WordPress.Security.NonceVerification -- Nonce verified in `et_builder_security_check`.
 | 
						|
 | 
						|
	if ( $item_id ) {
 | 
						|
		return $item_id;
 | 
						|
	}
 | 
						|
 | 
						|
	$item_id = (int) et_()->array_get( $_GET, 'tb_set', 0 ); // phpcs:ignore WordPress.Security.NonceVerification -- Nonce verified in `et_builder_security_check`.
 | 
						|
 | 
						|
	return $item_id;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Update library items.
 | 
						|
 *
 | 
						|
 * @since 4.18.0
 | 
						|
 *
 | 
						|
 * @param int   $item_id The item id.
 | 
						|
 * @param array $templates List of template ids.
 | 
						|
 */
 | 
						|
function et_theme_builder_update_library_item( $item_id, $templates ) {
 | 
						|
	$item_type = et_theme_builder_get_library_item_type( $item_id );
 | 
						|
 | 
						|
	$global_layouts = array();
 | 
						|
	if ( ET_THEME_BUILDER_ITEM_SET === $item_type ) {
 | 
						|
		// Remove the templates from preset.
 | 
						|
		$old_template_ids = get_post_meta( $item_id, '_et_template_id' );
 | 
						|
		delete_post_meta( $item_id, '_et_template_id' );
 | 
						|
 | 
						|
		// Find global layouts.
 | 
						|
		foreach ( $templates as $template ) {
 | 
						|
			if ( isset( $template['default'] ) && '1' === $template['default'] ) {
 | 
						|
				$global_layouts = $template['layouts'];
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Save templates to library.
 | 
						|
	$template_post_ids = array();
 | 
						|
	foreach ( $templates as $template ) {
 | 
						|
		$template['global_layouts'] = $global_layouts;
 | 
						|
 | 
						|
		$preferences = array(
 | 
						|
			'template_name' => $template['title'],
 | 
						|
			'force_update'  => true,
 | 
						|
		);
 | 
						|
 | 
						|
		$template_post_ids[] = et_theme_builder_save_template_to_library( $template, $preferences );
 | 
						|
	}
 | 
						|
 | 
						|
	if ( ET_THEME_BUILDER_ITEM_SET === $item_type ) {
 | 
						|
		// Trash the removed template.
 | 
						|
		$removed_template_ids = array_diff( $old_template_ids, $template_post_ids );
 | 
						|
		if ( ! empty( $removed_template_ids ) ) {
 | 
						|
			foreach ( $removed_template_ids as $removed_template_id ) {
 | 
						|
				if ( current_user_can( 'delete_post', $removed_template_id ) && ET_TB_ITEM_POST_TYPE === get_post_type( $removed_template_id ) ) {
 | 
						|
					wp_trash_post( $removed_template_id );
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Add saved templates to preset.
 | 
						|
		et_theme_builder_add_template_to_preset( $item_id, $template_post_ids );
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Determines if the library item editor is open.
 | 
						|
 *
 | 
						|
 * @return bool
 | 
						|
 */
 | 
						|
function et_theme_builder_library_is_item_editor() {
 | 
						|
	if ( ! et_builder_is_tb_admin_screen() ) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	$item_id = et_theme_builder_get_item_id();
 | 
						|
 | 
						|
	if ( ! $item_id || ET_TB_ITEM_POST_TYPE !== get_post_type( $item_id ) ) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 |