first commit
This commit is contained in:
@@ -0,0 +1,344 @@
|
||||
<?php
|
||||
/**
|
||||
* ET_Theme_Builder_Local_Library_Item class
|
||||
*
|
||||
* @package Builder
|
||||
* @subpackage ThemeBuilder
|
||||
* @since ??
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class used to implement local library in the theme builder.
|
||||
* */
|
||||
class ET_Theme_Builder_Local_Library_Item {
|
||||
|
||||
/**
|
||||
* Data util.
|
||||
*
|
||||
* @var ET_Core_Data_Utils
|
||||
*/
|
||||
protected static $_;
|
||||
|
||||
/**
|
||||
* The library item post.
|
||||
*
|
||||
* @var WP_Post|null
|
||||
*/
|
||||
public $item_post = null;
|
||||
|
||||
/**
|
||||
* The library item type. i.e template and preset.
|
||||
*
|
||||
* @deprecated Use get_item_type() instead. This should be private variable, eventually.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $item_type;
|
||||
|
||||
/**
|
||||
* The contructor.
|
||||
*
|
||||
* @since ??
|
||||
*
|
||||
* @param integer|null $item_id Iem post id.
|
||||
*/
|
||||
public function __construct( $item_id = null ) {
|
||||
if ( $item_id ) {
|
||||
$this->init_item( $item_id );
|
||||
}
|
||||
|
||||
self::$_ = ET_Core_Data_Utils::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Library Item type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_item_type() {
|
||||
return $this->item_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init item.
|
||||
*
|
||||
* @param integer $item_id Item post id.
|
||||
*/
|
||||
public function init_item( $item_id ) {
|
||||
// Initalize item post.
|
||||
$item_post = et_theme_builder_get_library_item_post( $item_id );
|
||||
|
||||
if ( is_wp_error( $item_post ) ) {
|
||||
return new WP_Error( 'et_library_item_not_exists', __( 'Library Item does not exist.', 'et_builder' ) );
|
||||
}
|
||||
|
||||
$this->item_post = $item_post;
|
||||
|
||||
$item_type = et_theme_builder_get_library_item_type( $item_post );
|
||||
|
||||
if ( is_wp_error( $item_post ) ) {
|
||||
return $item_type;
|
||||
}
|
||||
|
||||
$this->item_type = $item_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the local library item.
|
||||
*
|
||||
* @param array $args Item details.
|
||||
*/
|
||||
public function use_library_item( $args = [] ) {
|
||||
if ( ! $this->item_post || ! $this->item_type ) {
|
||||
return new WP_Error(
|
||||
'no_library_item_found',
|
||||
esc_html__( 'No library item found', 'et_builder' ),
|
||||
array(
|
||||
'status' => 400,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
switch ( $this->item_type ) {
|
||||
case ET_THEME_BUILDER_ITEM_TEMPLATE:
|
||||
return $this->use_template();
|
||||
case ET_THEME_BUILDER_ITEM_SET:
|
||||
return $this->use_preset( $args );
|
||||
// `default` case is already handled in the above `if` statement.
|
||||
}
|
||||
}
|
||||
|
||||
// phpcs:disable Squiz.Commenting.FunctionComment.ParamCommentFullStop -- Respecting punctuation.
|
||||
/**
|
||||
* Use local library template.
|
||||
*
|
||||
* @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.
|
||||
* ]
|
||||
*/
|
||||
public function use_template( $global_layouts = [] ) {
|
||||
$template_data = array(
|
||||
'layouts' => et_theme_builder_create_layouts_from_library_template( $this->item_post, $global_layouts ),
|
||||
'settings' => et_theme_builder_get_template_settings( $this->item_post->ID, true ),
|
||||
);
|
||||
|
||||
return $template_data;
|
||||
}
|
||||
// phpcs:enable
|
||||
|
||||
/**
|
||||
* Populate Data to implement Use Preset functionality in TB.
|
||||
*
|
||||
* @param array $args Additional arguments.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function use_preset( $args = [] ) {
|
||||
$preset = [];
|
||||
$_ = et_();
|
||||
|
||||
$override_default_website_template = $_->array_get( $args, 'override_default_website_template' );
|
||||
$incoming_layout_duplicate_decision = $_->array_get( $args, 'incoming_layout_duplicate_decision' );
|
||||
$global_layouts = [];
|
||||
$default_template_id = 0;
|
||||
|
||||
$maybe_default_template_id = get_post_meta( $this->item_post->ID, '_et_default_template_id', true );
|
||||
$default_template_id = is_string( $maybe_default_template_id ) ? absint( $maybe_default_template_id ) : 0;
|
||||
|
||||
if ( 'duplicate' === $incoming_layout_duplicate_decision || $override_default_website_template ) {
|
||||
|
||||
if ( $default_template_id > 0 ) {
|
||||
// $context is raw, because get_post()->post_content by default uses `raw`.
|
||||
$default_template = get_post( $default_template_id );
|
||||
$global_layouts = et_theme_builder_create_layouts_from_library_template( $default_template );
|
||||
|
||||
$preset[ $default_template_id ] = [
|
||||
'layouts' => $global_layouts,
|
||||
'settings' => et_theme_builder_get_template_settings( $default_template_id, true ),
|
||||
];
|
||||
}
|
||||
|
||||
if ( ! $override_default_website_template ) {
|
||||
// Layouts should be created for each templates when `Import as static layouts` is clicked.
|
||||
$global_layouts = [];
|
||||
}
|
||||
}
|
||||
|
||||
$template_ids = get_post_meta( $this->item_post->ID, '_et_template_id', false );
|
||||
|
||||
foreach ( $template_ids as $maybe_template_id ) {
|
||||
$template_id = absint( $maybe_template_id );
|
||||
|
||||
if ( $default_template_id === $template_id && 'relink' !== $incoming_layout_duplicate_decision ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $default_template_id === $template_id && 'relink' === $incoming_layout_duplicate_decision ) {
|
||||
foreach ( [ 'header', 'body', 'footer' ] as $layout_type ) {
|
||||
if ( '1' === get_post_meta( $template_id, "_et_{$layout_type}_layout_global", true ) ) {
|
||||
$global_layouts[ $layout_type ] = 'use_global';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$library_item = new self( $template_id );
|
||||
$preset[ $template_id ] = $library_item->use_template( $global_layouts );
|
||||
}
|
||||
|
||||
return $preset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE when the given Preset ID contains a global layout.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_global_layouts() {
|
||||
if ( ET_THEME_BUILDER_ITEM_SET !== $this->item_type ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$has_global_layouts = '1' === get_post_meta( $this->item_post->ID, '_et_has_global_layouts', true );
|
||||
|
||||
return $has_global_layouts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE when the given Preset ID contains a default template.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_default_template() {
|
||||
if ( ET_THEME_BUILDER_ITEM_SET !== $this->item_type ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$has_default_template = '1' === get_post_meta( $this->item_post->ID, '_et_has_default_template', true );
|
||||
|
||||
return $has_default_template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default template ID when the $item_type is preset.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_default_template_id() {
|
||||
if ( ! $this->has_default_template() ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$template_ids = get_post_meta( $this->item_post->ID, '_et_template_id', false );
|
||||
$default_template_id = 0;
|
||||
|
||||
foreach ( $template_ids as $template_id ) {
|
||||
$is_default = (bool) get_post_meta( $template_id, '_et_default', true );
|
||||
|
||||
if ( $is_default ) {
|
||||
$default_template_id = $template_id;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $default_template_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the theme builder id.
|
||||
*
|
||||
* @since ??
|
||||
*
|
||||
* @return int The theme builder id.
|
||||
*/
|
||||
public function get_theme_builder_id() {
|
||||
return $this->theme_builder_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item field.
|
||||
*
|
||||
* @param string $field_name Database field name.
|
||||
* @param string $context Refer get_post_field() for context.
|
||||
* @param string $default Default value to return when actual value does not exist.
|
||||
* @return string
|
||||
*/
|
||||
public function get_item_field( $field_name = 'post_title', $context = 'display', $default = '' ) {
|
||||
if ( is_a( $this->item_post, 'WP_Post' ) ) {
|
||||
return get_post_field( $field_name, $this->item_post->ID, $context );
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item title field.
|
||||
*
|
||||
* @param string $context Refer get_post_field() for context.
|
||||
* @param string $default Default value to return when actual value does not exist.
|
||||
* @return string
|
||||
*/
|
||||
public function get_item_title( $context = 'display', $default = '' ) {
|
||||
return $this->get_item_field( 'post_title', $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item title field formatted to be displayed in Theme Builder.
|
||||
*
|
||||
* @return int|WP_Error Valid Post ID on success. 0 or WP_Error on failure.
|
||||
*/
|
||||
public function duplicate_template_item() {
|
||||
$template_meta_keys = array(
|
||||
'_et_autogenerated_title',
|
||||
'_et_enabled',
|
||||
'_et_header_layout_enabled',
|
||||
'_et_body_layout_enabled',
|
||||
'_et_footer_layout_enabled',
|
||||
'_et_template_title',
|
||||
'_et_use_on',
|
||||
'_et_exclude_from',
|
||||
'_et_header_layout_global',
|
||||
'_et_body_layout_global',
|
||||
'_et_footer_layout_global',
|
||||
'_et_set_template',
|
||||
'_et_default',
|
||||
);
|
||||
|
||||
foreach ( $template_meta_keys as $key ) {
|
||||
$post_meta_value = get_post_meta( $this->item_post->ID, $key, true );
|
||||
|
||||
// `empty()` must NOT be used because meta value may contain '0' and the post meta will be skipped during duplication.
|
||||
if ( isset( $post_meta_value ) && '' !== $post_meta_value ) {
|
||||
$template_meta_input[ $key ] = $post_meta_value;
|
||||
}
|
||||
}
|
||||
|
||||
$new_item = array(
|
||||
'post_title' => $this->item_post->post_title,
|
||||
'post_content' => wp_slash( $this->item_post->post_content ),
|
||||
'post_status' => 'publish',
|
||||
'post_type' => $this->item_post->post_type,
|
||||
'meta_input' => $template_meta_input,
|
||||
'tax_input' => array(
|
||||
'et_tb_item_type' => ET_THEME_BUILDER_ITEM_TEMPLATE,
|
||||
),
|
||||
);
|
||||
|
||||
return wp_insert_post( $new_item );
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates the Library Item.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function duplicate_item() {
|
||||
$item_duplication_function = "duplicate_{$this->get_item_type()}_item";
|
||||
$duplicated_item_id = $this->$item_duplication_function();
|
||||
|
||||
return $duplicated_item_id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing Local Library Item Editor class.
|
||||
*
|
||||
* @package Builder
|
||||
* @subpackage ThemeBuilder
|
||||
* @since ??
|
||||
*/
|
||||
|
||||
/**
|
||||
* Local Library Item Editor class.
|
||||
*/
|
||||
class ET_Theme_Builder_Local_Library_Item_Editor {
|
||||
/**
|
||||
* Hold the class instance.
|
||||
*
|
||||
* @var ET_Theme_Builder_Local_Library_Item_Editor[]
|
||||
*/
|
||||
private static $_instances;
|
||||
|
||||
/**
|
||||
* Interim Theme Builder Id.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $_theme_builder_id;
|
||||
|
||||
/**
|
||||
* Library Item.
|
||||
*
|
||||
* @var ET_Theme_Builder_Local_Library_Item
|
||||
*/
|
||||
public $item;
|
||||
|
||||
/**
|
||||
* Class contructor.
|
||||
*
|
||||
* @param int $item_id Item Id.
|
||||
*/
|
||||
public function __construct( $item_id ) {
|
||||
if ( ! self::$_theme_builder_id ) {
|
||||
self::$_theme_builder_id = et_theme_builder_insert_library_theme_builder();
|
||||
}
|
||||
|
||||
$this->item = new ET_Theme_Builder_Local_Library_Item( $item_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton instance.
|
||||
*
|
||||
* @param int $item_id Item Id.
|
||||
*
|
||||
* @return ET_Theme_Builder_Local_Library_Item_Editor
|
||||
*/
|
||||
public static function instance( $item_id ) {
|
||||
if ( ! isset( self::$_instances[ $item_id ] ) ) {
|
||||
self::$_instances[ $item_id ] = new ET_Theme_Builder_Local_Library_Item_Editor( $item_id );
|
||||
}
|
||||
|
||||
return self::$_instances[ $item_id ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the interim Theme Builder Id for the current request.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_interim_theme_builder_id() {
|
||||
return self::$_theme_builder_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init Library Template Item.
|
||||
*/
|
||||
public function init_library_template_item_editor() {
|
||||
if ( ! isset( self::$_theme_builder_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert template.
|
||||
$template_id = et_theme_builder_create_template_from_library_template( $this->item->item_post );
|
||||
|
||||
if ( ! $template_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
add_post_meta( self::$_theme_builder_id, '_et_template', $template_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Init Library Template Item.
|
||||
*/
|
||||
public function init_library_set_item_editor() {
|
||||
if ( ! isset( self::$_theme_builder_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$template_ids = get_post_meta( $this->item->item_post->ID, '_et_template_id', false );
|
||||
$default_template_item_id = (int) get_post_meta( $this->item->item_post->ID, '_et_default_template_id', true );
|
||||
$global_layouts = array();
|
||||
|
||||
foreach ( $template_ids as $maybe_template_id ) {
|
||||
$template_item_id = absint( $maybe_template_id );
|
||||
$template_item = new ET_Theme_Builder_Local_Library_Item( $template_item_id );
|
||||
|
||||
if ( ! isset( $template_item->item_post ) || ! is_a( $template_item->item_post, 'WP_Post' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Insert template.
|
||||
$template_id = et_theme_builder_create_template_from_library_template( $template_item->item_post, $global_layouts );
|
||||
|
||||
if ( ! $template_id ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $template_item_id === $default_template_item_id ) {
|
||||
$global_layouts = array(
|
||||
'body' => (int) get_post_meta( $template_id, '_et_body_layout_id', true ),
|
||||
'header' => (int) get_post_meta( $template_id, '_et_header_layout_id', true ),
|
||||
'footer' => (int) get_post_meta( $template_id, '_et_footer_layout_id', true ),
|
||||
);
|
||||
}
|
||||
|
||||
add_post_meta( self::$_theme_builder_id, '_et_template', $template_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init Library Item.
|
||||
*/
|
||||
public function init_library_item_editor() {
|
||||
if ( ! is_a( $this->item, 'ET_Theme_Builder_Local_Library_Item' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$item_type = $this->item->get_item_type();
|
||||
|
||||
if ( ET_THEME_BUILDER_ITEM_TEMPLATE === $item_type ) {
|
||||
$this->init_library_template_item_editor();
|
||||
} elseif ( ET_THEME_BUILDER_ITEM_SET === $item_type ) {
|
||||
$this->init_library_set_item_editor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item title field formatted to be displayed in Theme Builder.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_library_item_editor_item_title() {
|
||||
if ( ET_THEME_BUILDER_ITEM_SET === $this->item->get_item_type() ) {
|
||||
return sprintf(
|
||||
'%1$s: %2$s',
|
||||
esc_html_x( 'Edit Set', 'Edit Set using Theme Builder', 'et_builder' ),
|
||||
$this->item->get_item_title()
|
||||
);
|
||||
} elseif ( ET_THEME_BUILDER_ITEM_TEMPLATE === $this->item->get_item_type() ) {
|
||||
return sprintf(
|
||||
'%1$s: %2$s',
|
||||
esc_html_x( 'Edit Template', 'Edit Template using Theme Builder', 'et_builder' ),
|
||||
$this->item->get_item_title()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
* Divi Theme Builder Item Library.
|
||||
*
|
||||
* @since ??
|
||||
*
|
||||
* @package Builder
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core class used to implement TB Item library.
|
||||
*
|
||||
* Register TB Item post type and its taxonomies.
|
||||
*/
|
||||
class ET_Builder_TBItem_Library {
|
||||
|
||||
/**
|
||||
* Instance of `ET_Builder_TBItem_Library`.
|
||||
*
|
||||
* @var ET_Builder_TBItem_Library
|
||||
*/
|
||||
private static $_instance;
|
||||
|
||||
/**
|
||||
* Instance of `ET_Core_Data_Utils`.
|
||||
*
|
||||
* @var ET_Core_Data_Utils
|
||||
*/
|
||||
protected static $_;
|
||||
|
||||
/**
|
||||
* List of i18n strings.
|
||||
*
|
||||
* @var mixed[]
|
||||
*/
|
||||
protected static $_i18n;
|
||||
|
||||
/**
|
||||
* ET_Builder_Post_Taxonomy_TBItemCategory instance.
|
||||
*
|
||||
* Shall be used for querying `et_tb_item` taxonomy.
|
||||
*
|
||||
* @var ET_Builder_Post_Taxonomy_TBItemCategory
|
||||
*/
|
||||
public $item_categories;
|
||||
|
||||
/**
|
||||
* ET_Builder_Post_Taxonomy_TBItemTag instance.
|
||||
*
|
||||
* Shall be used for querying `et_tb_item` taxonomy .
|
||||
*
|
||||
* @var ET_Builder_Post_Taxonomy_TBItemTag
|
||||
*/
|
||||
public $item_tags;
|
||||
|
||||
/**
|
||||
* ET_Builder_Post_Taxonomy_TBItemType instance.
|
||||
*
|
||||
* Shall be used for querying `et_tb_item` taxonomy .
|
||||
*
|
||||
* @var ET_Builder_Post_Taxonomy_TBItemType
|
||||
*/
|
||||
public $item_types;
|
||||
|
||||
/**
|
||||
* ET_Builder_Post_Type_TBItem instance.
|
||||
*
|
||||
* Shall be used for querying `et_tb_item` posts .
|
||||
*
|
||||
* @var ET_Builder_Post_Type_TBItem
|
||||
*/
|
||||
public $items;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->_instance_check();
|
||||
$this->_register_cpt_and_taxonomies();
|
||||
|
||||
self::$_ = ET_Core_Data_Utils::instance();
|
||||
|
||||
$root_directory = defined( 'ET_BUILDER_PLUGIN_ACTIVE' ) ? ET_BUILDER_PLUGIN_DIR : get_template_directory();
|
||||
|
||||
self::$_i18n = require $root_directory . '/cloud/i18n/library.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a translated string from {@see self::$_i18n}.
|
||||
*
|
||||
* @param string $string The untranslated string.
|
||||
* @param string $path Optional path for nested strings.
|
||||
*
|
||||
* @return string The translated string if found, the original string otherwise.
|
||||
*/
|
||||
public static function __( $string, $path = '' ) {
|
||||
$path .= $path ? ".{$string}" : $string;
|
||||
|
||||
return self::$_->array_get( self::$_i18n, $path, $string );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dies if an instance already exists.
|
||||
*/
|
||||
protected function _instance_check() {
|
||||
if ( self::$_instance ) {
|
||||
et_error( 'Multiple instances are not allowed!' );
|
||||
wp_die();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the Theme Builder Library's custom post type and its taxonomies.
|
||||
*/
|
||||
protected function _register_cpt_and_taxonomies() {
|
||||
$files = [
|
||||
ET_THEME_BUILDER_DIR . 'post/type/TBItem.php',
|
||||
ET_THEME_BUILDER_DIR . 'post/taxonomy/TBItemType.php',
|
||||
ET_THEME_BUILDER_DIR . 'post/query/TBItems.php',
|
||||
ET_BUILDER_DIR . 'post/type/Layout.php',
|
||||
ET_BUILDER_DIR . 'post/taxonomy/LayoutCategory.php',
|
||||
ET_BUILDER_DIR . 'post/taxonomy/LayoutTag.php',
|
||||
ET_BUILDER_DIR . 'post/query/Layouts.php',
|
||||
];
|
||||
|
||||
if ( ! $files ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $files as $file ) {
|
||||
require_once $file;
|
||||
}
|
||||
|
||||
$this->items = ET_Builder_Post_Type_TBItem::instance();
|
||||
$this->item_categories = ET_Builder_Post_Taxonomy_LayoutCategory::instance();
|
||||
$this->item_tags = ET_Builder_Post_Taxonomy_LayoutTag::instance();
|
||||
$this->item_types = ET_Builder_Post_Taxonomy_TBItemType::instance();
|
||||
|
||||
// We manually call register_all() now to ensure the CPT and taxonomies are registered
|
||||
// at exactly the same point during the request that they were in prior releases.
|
||||
ET_Builder_Post_Type_TBItem::register_all( 'builder' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ET_Builder_TBItem_Library instance.
|
||||
*
|
||||
* @return ET_Builder_TBItem_Library
|
||||
*/
|
||||
public static function instance() {
|
||||
if ( ! self::$_instance ) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ET_Builder_TBItem_Library::instance();
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
class ET_Theme_Builder_Api_Errors {
|
||||
const UNKNOWN = 'unknown';
|
||||
const PORTABILITY_INCORRECT_CONTEXT = 'incorrect_context';
|
||||
const PORTABILITY_REQUIRE_INCOMING_LAYOUT_DUPLICATE_DECISION = 'require_incoming_layout_duplicate_decision';
|
||||
const PORTABILITY_IMPORT_PRESETS_FAILURE = 'import_presets_failure';
|
||||
const PORTABILITY_IMPORT_INVALID_FILE = 'invalid_file';
|
||||
|
||||
/**
|
||||
* Get map of all error codes.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getMap() {
|
||||
return array(
|
||||
'unknown' => self::UNKNOWN,
|
||||
'portabilityIncorrectContext' => self::PORTABILITY_INCORRECT_CONTEXT,
|
||||
'portabilityRequireIncomingLayoutDuplicateDecision' => self::PORTABILITY_REQUIRE_INCOMING_LAYOUT_DUPLICATE_DECISION,
|
||||
'portabilityImportPresetsFailure' => self::PORTABILITY_IMPORT_PRESETS_FAILURE,
|
||||
'portabilityImportInvalidFile' => self::PORTABILITY_IMPORT_INVALID_FILE,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,444 @@
|
||||
<?php
|
||||
|
||||
class ET_Theme_Builder_Request {
|
||||
/**
|
||||
* Type constants.
|
||||
*/
|
||||
const TYPE_FRONT_PAGE = 'front_page';
|
||||
const TYPE_404 = '404';
|
||||
const TYPE_SEARCH = 'search';
|
||||
const TYPE_SINGULAR = 'singular';
|
||||
const TYPE_POST_TYPE_ARCHIVE = 'archive';
|
||||
const TYPE_TERM = 'term';
|
||||
const TYPE_AUTHOR = 'author';
|
||||
const TYPE_DATE = 'date';
|
||||
|
||||
/**
|
||||
* Requested object type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = '';
|
||||
|
||||
/**
|
||||
* Requested object subtype.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $subtype = '';
|
||||
|
||||
/**
|
||||
* Requested object id.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $id = 0;
|
||||
|
||||
/**
|
||||
* Create a request object based on the current request.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @return ET_Theme_Builder_Request|null
|
||||
*/
|
||||
public static function from_current() {
|
||||
$is_extra_layout_home = 'layout' === get_option( 'show_on_front' ) && is_home();
|
||||
|
||||
if ( $is_extra_layout_home || is_front_page() ) {
|
||||
return new self( self::TYPE_FRONT_PAGE, '', get_queried_object_id() );
|
||||
}
|
||||
|
||||
if ( is_404() ) {
|
||||
return new self( self::TYPE_404, '', 0 );
|
||||
}
|
||||
|
||||
if ( is_search() ) {
|
||||
return new self( self::TYPE_SEARCH, '', 0 );
|
||||
}
|
||||
|
||||
$id = get_queried_object_id();
|
||||
$object = get_queried_object();
|
||||
$page_for_posts = (int) get_option( 'page_for_posts' );
|
||||
$is_blog_page = 0 !== $page_for_posts && is_page( $page_for_posts );
|
||||
|
||||
if ( is_singular() ) {
|
||||
return new self( self::TYPE_SINGULAR, get_post_type( $id ), $id );
|
||||
}
|
||||
|
||||
if ( $is_blog_page || is_home() ) {
|
||||
return new self( self::TYPE_POST_TYPE_ARCHIVE, 'post', $id );
|
||||
}
|
||||
|
||||
if ( is_category() || is_tag() || is_tax() ) {
|
||||
return new self( self::TYPE_TERM, $object->taxonomy, $id );
|
||||
}
|
||||
|
||||
if ( is_post_type_archive() ) {
|
||||
return new self( self::TYPE_POST_TYPE_ARCHIVE, $object->name, $id );
|
||||
}
|
||||
|
||||
if ( is_author() ) {
|
||||
return new self( self::TYPE_AUTHOR, '', $id );
|
||||
}
|
||||
|
||||
if ( is_date() ) {
|
||||
return new self( self::TYPE_DATE, '', 0 );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a request object based on a post id.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $post_id
|
||||
*
|
||||
* @return ET_Theme_Builder_Request
|
||||
*/
|
||||
public static function from_post( $post_id ) {
|
||||
if ( (int) get_option( 'page_on_front' ) === $post_id ) {
|
||||
return new self( self::TYPE_FRONT_PAGE, '', $post_id );
|
||||
}
|
||||
|
||||
if ( (int) get_option( 'page_for_posts' ) === $post_id ) {
|
||||
return new self( self::TYPE_POST_TYPE_ARCHIVE, 'post', $post_id );
|
||||
}
|
||||
|
||||
return new self( self::TYPE_SINGULAR, get_post_type( $post_id ), $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
*/
|
||||
public function __construct( $type, $subtype, $id ) {
|
||||
$this->type = $type;
|
||||
$this->subtype = $subtype;
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the requested object type.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_type() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the requested object subtype.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_subtype() {
|
||||
return $this->subtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the requested object id.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_id() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the top ancestor of a setting based on its id. Takes the setting itself
|
||||
* if it has no ancestors.
|
||||
* Returns an empty array if the setting is not found.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param array $flat_settings Flat settings.
|
||||
* @param string $setting_id Setting ID.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _get_template_setting_ancestor( $flat_settings, $setting_id ) {
|
||||
$id = $setting_id;
|
||||
|
||||
if ( ! isset( $flat_settings[ $id ] ) ) {
|
||||
// If the setting is not found, check if a valid parent exists.
|
||||
$parent_id = explode( ET_THEME_BUILDER_SETTING_SEPARATOR, $id );
|
||||
array_pop( $parent_id );
|
||||
$parent_id[] = '';
|
||||
$parent_id = implode( ET_THEME_BUILDER_SETTING_SEPARATOR, $parent_id );
|
||||
$id = $parent_id;
|
||||
}
|
||||
|
||||
if ( ! isset( $flat_settings[ $id ] ) ) {
|
||||
// The setting is still not found - bail.
|
||||
return array();
|
||||
}
|
||||
|
||||
return $flat_settings[ $id ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get $a or $b depending on which template setting has a higher priority.
|
||||
* Handles cases such as category settings with equal priority but in a ancestor-child relationship.
|
||||
* Returns an empty string if neither setting is found.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param array $flat_settings Flat settings.
|
||||
* @param string $a First template setting.
|
||||
* @param string $b Second template setting.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _get_higher_priority_template_setting( $flat_settings, $a, $b ) {
|
||||
$map = array_flip( array_keys( $flat_settings ) );
|
||||
$a_ancestor = $this->_get_template_setting_ancestor( $flat_settings, $a );
|
||||
$b_ancestor = $this->_get_template_setting_ancestor( $flat_settings, $b );
|
||||
$a_found = ! empty( $a_ancestor );
|
||||
$b_found = ! empty( $b_ancestor );
|
||||
|
||||
if ( ! $a_found || ! $b_found ) {
|
||||
if ( $a_found ) {
|
||||
return $a;
|
||||
}
|
||||
|
||||
if ( $b_found ) {
|
||||
return $b;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( $a_ancestor['priority'] !== $b_ancestor['priority'] ) {
|
||||
// Priorities are not equal - use a simple comparison.
|
||||
return $a_ancestor['priority'] >= $b_ancestor['priority'] ? $a : $b;
|
||||
}
|
||||
|
||||
if ( $a_ancestor['id'] !== $b_ancestor['id'] ) {
|
||||
// Equal priorities, but the ancestors are not the same - use the order in $flat_settings
|
||||
// so we have a deterministic result even if $a and $b are swapped.
|
||||
return $map[ $a_ancestor['id'] ] <= $map[ $b_ancestor['id'] ] ? $a : $b;
|
||||
}
|
||||
|
||||
// Equal priorities, same ancestor.
|
||||
$ancestor = $a_ancestor;
|
||||
$a_pieces = explode( ET_THEME_BUILDER_SETTING_SEPARATOR, $a );
|
||||
$b_pieces = explode( ET_THEME_BUILDER_SETTING_SEPARATOR, $b );
|
||||
$separator = preg_quote( ET_THEME_BUILDER_SETTING_SEPARATOR, '/' );
|
||||
|
||||
// Hierarchical post types are a special case by spec since we have to take hierarchy into account.
|
||||
// Test if the ancestor matches "singular:post_type:<post_type>:children:id:".
|
||||
$id_pieces = array( 'singular', 'post_type', '[^' . $separator . ']+', 'children', 'id', '' );
|
||||
$term_regex = '/^' . implode( $separator, $id_pieces ) . '$/';
|
||||
|
||||
if ( preg_match( $term_regex, $ancestor['id'] ) && is_post_type_hierarchical( $a_pieces[2] ) ) {
|
||||
$a_post_id = (int) $a_pieces[5];
|
||||
$b_post_id = (int) $b_pieces[5];
|
||||
|
||||
$a_post_ancestors = get_post_ancestors( $a_post_id );
|
||||
$b_post_ancestors = get_post_ancestors( $b_post_id );
|
||||
|
||||
if ( in_array( $a_post_id, $b_post_ancestors, true ) ) {
|
||||
// $b is a child of $a so it should take priority.
|
||||
return $b;
|
||||
}
|
||||
|
||||
if ( in_array( $b_post_id, $a_post_ancestors, true ) ) {
|
||||
// $a is a child of $b so it should take priority.
|
||||
return $a;
|
||||
}
|
||||
|
||||
// neither $a nor $b is an ancestor to the other - continue the comparisons.
|
||||
}
|
||||
|
||||
// Term archive listings are a special case by spec since we have to take hierarchy into account.
|
||||
// Test if the ancestor matches "archive:taxonomy:<taxonomy>:term:id:".
|
||||
$id_pieces = array( 'archive', 'taxonomy', '[^' . $separator . ']+', 'term', 'id', '' );
|
||||
$term_regex = '/^' . implode( $separator, $id_pieces ) . '$/';
|
||||
|
||||
if ( preg_match( $term_regex, $ancestor['id'] ) && is_taxonomy_hierarchical( $a_pieces[2] ) ) {
|
||||
$a_term_id = $a_pieces[5];
|
||||
$b_term_id = $b_pieces[5];
|
||||
|
||||
if ( term_is_ancestor_of( $a_term_id, $b_term_id, $a_pieces[2] ) ) {
|
||||
// $b is a child of $a so it should take priority.
|
||||
return $b;
|
||||
}
|
||||
|
||||
if ( term_is_ancestor_of( $b_term_id, $a_term_id, $a_pieces[2] ) ) {
|
||||
// $a is a child of $b so it should take priority.
|
||||
return $a;
|
||||
}
|
||||
|
||||
// neither $a nor $b is an ancestor to the other - continue the comparisons.
|
||||
}
|
||||
|
||||
// Find the first difference in the settings and compare it.
|
||||
// The difference should be representing an id or a slug.
|
||||
foreach ( $a_pieces as $index => $a_piece ) {
|
||||
$b_piece = $b_pieces[ $index ];
|
||||
|
||||
if ( $b_piece === $a_piece ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( is_numeric( $a_piece ) ) {
|
||||
$prioritized = (float) $a_piece <= (float) $b_piece ? $a : $b;
|
||||
} else {
|
||||
$prioritized = strcmp( $a, $b ) <= 0 ? $a : $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the higher prioritized setting in a given pair that
|
||||
* has equal built-in priority.
|
||||
*
|
||||
* @since 4.2
|
||||
*
|
||||
* @param string $prioritized_setting
|
||||
* @param string $setting_a
|
||||
* @param string $setting_b
|
||||
* @param ET_Theme_Builder_Request $request
|
||||
*/
|
||||
return apply_filters( 'et_theme_builder_prioritized_template_setting', $prioritized, $a, $b, $this );
|
||||
}
|
||||
|
||||
// We should only reach this point if $a and $b are equal so it doesn't
|
||||
// matter which we return.
|
||||
return $a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this request fulfills a template setting.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param array $flat_settings Flat settings.
|
||||
* @param string $setting_id Setting ID.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function _fulfills_template_setting( $flat_settings, $setting_id ) {
|
||||
$ancestor = $this->_get_template_setting_ancestor( $flat_settings, $setting_id );
|
||||
$fulfilled = false;
|
||||
|
||||
if ( ! empty( $ancestor ) && isset( $ancestor['validate'] ) && is_callable( $ancestor['validate'] ) ) {
|
||||
// @phpcs:ignore Generic.PHP.ForbiddenFunctions.Found
|
||||
$fulfilled = call_user_func(
|
||||
$ancestor['validate'],
|
||||
$this->get_type(),
|
||||
$this->get_subtype(),
|
||||
$this->get_id(),
|
||||
explode( ET_THEME_BUILDER_SETTING_SEPARATOR, $setting_id )
|
||||
);
|
||||
}
|
||||
|
||||
return $fulfilled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce callback for self::get_template() to get the highest priority template from all applicable ones.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param array $carry
|
||||
* @param array $applicable_template
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function reduce_get_template( $carry, $applicable_template ) {
|
||||
global $__et_theme_builder_request_flat_settings;
|
||||
|
||||
if ( empty( $carry ) ) {
|
||||
return $applicable_template;
|
||||
}
|
||||
|
||||
$higher = $this->_get_higher_priority_template_setting(
|
||||
$__et_theme_builder_request_flat_settings,
|
||||
$carry['top_setting_id'],
|
||||
$applicable_template['top_setting_id']
|
||||
);
|
||||
|
||||
return $carry['top_setting_id'] !== $higher ? $applicable_template : $carry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the highest-priority template that should be applied for this request, if any.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param array $templates
|
||||
* @param array $flat_settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_template( $templates, $flat_settings ) {
|
||||
// Use a global variable to pass data to the reduce callback as we support PHP 5.2.
|
||||
global $__et_theme_builder_request_flat_settings;
|
||||
|
||||
$applicable_templates = array();
|
||||
|
||||
foreach ( $templates as $template ) {
|
||||
if ( ! $template['enabled'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $template['exclude_from'] as $setting_id ) {
|
||||
if ( $this->_fulfills_template_setting( $flat_settings, $setting_id ) ) {
|
||||
// The setting is explicitly excluded - bail from testing the template any further.
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
$highest_priority = '';
|
||||
|
||||
foreach ( $template['use_on'] as $setting_id ) {
|
||||
if ( $this->_fulfills_template_setting( $flat_settings, $setting_id ) ) {
|
||||
$highest_priority = $this->_get_higher_priority_template_setting( $flat_settings, $highest_priority, $setting_id );
|
||||
}
|
||||
}
|
||||
|
||||
if ( '' !== $highest_priority ) {
|
||||
$applicable_templates[] = array(
|
||||
'template' => $template,
|
||||
'top_setting_id' => $highest_priority,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$__et_theme_builder_request_flat_settings = $flat_settings;
|
||||
$applicable_template = array_reduce( $applicable_templates, array( $this, 'reduce_get_template' ), array() );
|
||||
$__et_theme_builder_request_flat_settings = array();
|
||||
|
||||
if ( ! empty( $applicable_template ) ) {
|
||||
// Found the highest priority applicable template - return it.
|
||||
return $applicable_template['template'];
|
||||
}
|
||||
|
||||
$default_templates = et_()->array_pick( $templates, array( 'default' => true ) );
|
||||
|
||||
if ( ! empty( $default_templates ) ) {
|
||||
$default_template = $default_templates[0];
|
||||
|
||||
if ( $default_template['enabled'] ) {
|
||||
// Return the first default template. We don't expect there to be multiple ones but
|
||||
// it is technically possible with direct database edits, for example.
|
||||
return $default_template;
|
||||
}
|
||||
}
|
||||
|
||||
// No templates found at all - probably never used the Theme Builder.
|
||||
return array();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder
|
||||
*
|
||||
* Variable product class extension for displaying WooCommerce placeholder on Theme Builder
|
||||
*/
|
||||
class ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder extends WC_Product_Variable {
|
||||
/**
|
||||
* Cached upsells id
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $tb_upsells_id;
|
||||
|
||||
/**
|
||||
* Cached product category ids
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $tb_category_ids;
|
||||
|
||||
/**
|
||||
* Cached product tag ids
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $tb_tag_ids;
|
||||
|
||||
/**
|
||||
* Cached attributes
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $tb_attributes;
|
||||
|
||||
/**
|
||||
* Create pre-filled WC Product (variable) object which acts as placeholder generator in TB
|
||||
*
|
||||
* @since 4.0.10 Instead of empty product object that is set later, pre-filled default data properties
|
||||
*
|
||||
* @param int|WC_Product|object $product Product to init.
|
||||
*/
|
||||
public function __construct( $product = 0 ) {
|
||||
// Pre-filled default data with placeholder value so everytime this product class is
|
||||
// initialized, it already has sufficient data to be displayed on Theme Builder
|
||||
$this->data = array(
|
||||
'name' => esc_html( 'Product name', 'et_builder' ),
|
||||
'slug' => 'product-name',
|
||||
'date_created' => current_time( 'timestamp' ),
|
||||
'date_modified' => null,
|
||||
'status' => 'publish',
|
||||
'featured' => false,
|
||||
'catalog_visibility' => 'visible',
|
||||
'description' => esc_html( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris bibendum eget dui sed vehicula. Suspendisse potenti. Nam dignissim at elit non lobortis. Cras sagittis dui diam, a finibus nibh euismod vestibulum. Integer sed blandit felis. Maecenas commodo ante in mi ultricies euismod. Morbi condimentum interdum luctus. Mauris iaculis interdum risus in volutpat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent cursus odio eget cursus pharetra. Aliquam lacinia lectus a nibh ullamcorper maximus. Quisque at sapien pulvinar, dictum elit a, bibendum massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris non pellentesque urna.', 'et_builder' ),
|
||||
'short_description' => esc_html( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris bibendum eget dui sed vehicula. Suspendisse potenti. Nam dignissim at elit non lobortis.', 'et_builder' ),
|
||||
'sku' => 'product-name',
|
||||
'price' => '75',
|
||||
'regular_price' => '80',
|
||||
'sale_price' => '65',
|
||||
'date_on_sale_from' => null,
|
||||
'date_on_sale_to' => null,
|
||||
'total_sales' => '0',
|
||||
'tax_status' => 'taxable',
|
||||
'tax_class' => '',
|
||||
'manage_stock' => true,
|
||||
'stock_quantity' => 50,
|
||||
'stock_status' => 'instock',
|
||||
'backorders' => 'no',
|
||||
'low_stock_amount' => 2,
|
||||
'sold_individually' => false,
|
||||
'weight' => 2,
|
||||
'length' => '',
|
||||
'width' => 2,
|
||||
'height' => 2,
|
||||
'upsell_ids' => array(),
|
||||
'cross_sell_ids' => array(),
|
||||
'parent_id' => 0,
|
||||
'reviews_allowed' => true,
|
||||
'purchase_note' => '',
|
||||
'attributes' => array(),
|
||||
'default_attributes' => array(),
|
||||
'menu_order' => 0,
|
||||
'post_password' => '',
|
||||
'virtual' => false,
|
||||
'downloadable' => false,
|
||||
'category_ids' => array(),
|
||||
'tag_ids' => array(),
|
||||
'shipping_class_id' => 0,
|
||||
'downloads' => array(),
|
||||
'image_id' => '',
|
||||
'gallery_image_ids' => array(),
|
||||
'download_limit' => -1,
|
||||
'download_expiry' => -1,
|
||||
'rating_counts' => array(
|
||||
4 => 2,
|
||||
),
|
||||
'average_rating' => '4.00',
|
||||
'review_count' => 2,
|
||||
'recent_product_ids' => null,
|
||||
);
|
||||
|
||||
parent::__construct( $product );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get internal type.
|
||||
* Define custom internal type so custom data store can be used to bypass database value retrieval
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_type() {
|
||||
return 'tb-placeholder';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get placeholder product as available variation. The method is basically identical to
|
||||
* `WC_Product_Variable->get_available_variation()` except for the checks which are removed
|
||||
* so placeholder value can be passed
|
||||
*
|
||||
* @since 4.3.3
|
||||
*
|
||||
* @param int|object $variation not needed since it will be overwritten by placeholder variation
|
||||
* but it needs to be kept for compatibility with base class' method
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_available_variation( $variation = 0 ) {
|
||||
$variation = new ET_Theme_Builder_Woocommerce_Product_Variation_Placeholder();
|
||||
$show_variation_price = apply_filters( 'woocommerce_show_variation_price', $variation->get_price() === '' || $this->get_variation_sale_price( 'min' ) !== $this->get_variation_sale_price( 'max' ) || $this->get_variation_regular_price( 'min' ) !== $this->get_variation_regular_price( 'max' ), $this, $variation );
|
||||
|
||||
// Set variation id; Prevent $product->get_id() returns falsey which usually triggers wc_product_get()
|
||||
// in WC add ons; Valid $product->get_id() makes global $product being used most of the time
|
||||
$variation->set_id( $this->get_id() );
|
||||
|
||||
// Set current product id as variation parent id so $product->get_parent_id() returns
|
||||
// valid value (mostly when being called by WC add-ons). The absence of this value (in TB)
|
||||
// triggers new `wc_get_product()` which most likely returned unwanted output
|
||||
$variation->set_prop( 'parent_id', $this->get_id() );
|
||||
|
||||
// Returned array properties are identical to `WC_Product_Variable->get_available_variation()`
|
||||
return apply_filters(
|
||||
'woocommerce_available_variation',
|
||||
array(
|
||||
'attributes' => $variation->get_variation_attributes(),
|
||||
'availability_html' => wc_get_stock_html( $variation ),
|
||||
'backorders_allowed' => $variation->backorders_allowed(),
|
||||
'dimensions' => $variation->get_dimensions( false ),
|
||||
'dimensions_html' => wc_format_dimensions( $variation->get_dimensions( false ) ),
|
||||
'display_price' => wc_get_price_to_display( $variation ),
|
||||
'display_regular_price' => wc_get_price_to_display( $variation, array( 'price' => $variation->get_regular_price() ) ),
|
||||
'image' => wc_get_product_attachment_props( $variation->get_image_id() ),
|
||||
'image_id' => $variation->get_image_id(),
|
||||
'is_downloadable' => $variation->is_downloadable(),
|
||||
'is_in_stock' => $variation->is_in_stock(),
|
||||
'is_purchasable' => $variation->is_purchasable(),
|
||||
'is_sold_individually' => $variation->is_sold_individually() ? 'yes' : 'no',
|
||||
'is_virtual' => $variation->is_virtual(),
|
||||
'max_qty' => 0 < $variation->get_max_purchase_quantity() ? $variation->get_max_purchase_quantity() : '',
|
||||
'min_qty' => $variation->get_min_purchase_quantity(),
|
||||
'price_html' => $show_variation_price ? '<span class="price">' . $variation->get_price_html() . '</span>' : '',
|
||||
'sku' => $variation->get_sku(),
|
||||
'variation_description' => wc_format_content( $variation->get_description() ),
|
||||
'variation_id' => $variation->get_id(),
|
||||
'variation_is_active' => $variation->variation_is_active(),
|
||||
'variation_is_visible' => $variation->variation_is_visible(),
|
||||
'weight' => $variation->get_weight(),
|
||||
'weight_html' => wc_format_weight( $variation->get_weight() ),
|
||||
),
|
||||
$this,
|
||||
$variation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to cart's <select> requires variable product type and get_available_variations() method
|
||||
* outputting product->children value. Filtering get_available_variations() can't be done so
|
||||
* extending WC_Product_Variable and set fixed value for get_available_variations() method
|
||||
*
|
||||
* @since 4.5.7 Introduced $return arg to fix compatibility issue {@link https://github.com/elegantthemes/Divi/issues/20985}
|
||||
* @since 4.3.3 `Replaced ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder` with
|
||||
* `ET_Theme_Builder_Woocommerce_Product_Variation_Placeholder` (which is now
|
||||
* called at `get_available_variations()` method and similar to
|
||||
* `WC_Product_Variation`'s method with no check). It has all variation-required
|
||||
* methods and properties which makes it more reliable when WC add-ons are used
|
||||
* @since 4.0.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_available_variations( $return = 'array' ) {
|
||||
return array(
|
||||
$this->get_available_variation(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Divi's placeholder image in WC image in TB
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @param string not used but need to be declared to prevent incompatible declaration error
|
||||
* @param array not used but need to be declared to prevent incompatible declaration error
|
||||
* @param bool not used but need to be declared to prevent incompatible declaration error
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_image( $size = 'woocommerce_thumbnail', $attr = array(), $placeholder = true ) {
|
||||
return et_builder_wc_placeholder_img();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set product upsells id for TB's woocommerceComponent. This can't be called during class
|
||||
* initialization and need to be called BEFORE `woocommerce_product_class` filter callback
|
||||
* to avoid infinite loop
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @param array $args
|
||||
*/
|
||||
public static function set_tb_upsells_ids( $args = array() ) {
|
||||
$defaults = array(
|
||||
'limit' => 4,
|
||||
);
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
// Get recent products for upsells product; Any product will do since its purpose is
|
||||
// for visual preview only
|
||||
$recent_products_query = new WC_Product_Query( $args );
|
||||
$recent_product_ids = array();
|
||||
|
||||
foreach ( $recent_products_query->get_products() as $recent_product ) {
|
||||
$recent_product_ids[] = $recent_product->get_id();
|
||||
}
|
||||
|
||||
// Set up upsells id product
|
||||
self::$tb_upsells_id = $recent_product_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get upsells id
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @param string not used but need to be declared to prevent incompatible declaration error
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_upsell_ids( $context = 'view' ) {
|
||||
// Bypass database value retrieval and simply pulled cached value from property
|
||||
return is_array( self::$tb_upsells_id ) ? self::$tb_upsells_id : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attributes
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @param string not used but need to be declared to prevent incompatible declaration error
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_attributes( $context = 'view' ) {
|
||||
if ( ! is_null( self::$tb_attributes ) ) {
|
||||
return self::$tb_attributes;
|
||||
}
|
||||
|
||||
// Initialize color attribute
|
||||
$colors = new WC_Product_Attribute();
|
||||
$colors->set_id( 1 );
|
||||
$colors->set_name( 'color' );
|
||||
$colors->set_options( array( 'Black', 'White', 'Gray' ) );
|
||||
$colors->set_position( 1 );
|
||||
$colors->set_visible( 1 );
|
||||
$colors->set_variation( 1 );
|
||||
|
||||
// Initialize size attribute
|
||||
$sizes = new WC_Product_Attribute();
|
||||
$sizes->set_id( 2 );
|
||||
$sizes->set_name( 'size' );
|
||||
$sizes->set_options( array( 'S', 'M', 'L', 'XL' ) );
|
||||
$sizes->set_position( 1 );
|
||||
$sizes->set_visible( 1 );
|
||||
$sizes->set_variation( 1 );
|
||||
|
||||
self::$tb_attributes = array(
|
||||
'pa_color' => $colors,
|
||||
'pa_size' => $sizes,
|
||||
);
|
||||
|
||||
return self::$tb_attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get variation price
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @param bool not used but need to be declared to prevent incompatible declaration error
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_variation_prices( $for_display = false ) {
|
||||
return array(
|
||||
'price' => array( $this->data['price'] ),
|
||||
'regular_price' => array( $this->data['regular_price'] ),
|
||||
'sale_price' => array( $this->data['sale_price'] ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render default product variable add to cart UI for tb-placeholder product type
|
||||
*
|
||||
* @since 4.0.10
|
||||
*/
|
||||
add_action( 'woocommerce_tb-placeholder_add_to_cart', 'woocommerce_variable_add_to_cart', 30 );
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Register data store for ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder_Data_Store_CPT
|
||||
* which aims to bypass database value retrieval and simply returns default value as placeholder
|
||||
*
|
||||
* @since 4.0.10
|
||||
*/
|
||||
class ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder_Data_Store_CPT extends WC_Product_Variable_Data_Store_CPT implements WC_Object_Data_Store_Interface, WC_Product_Variable_Data_Store_Interface {
|
||||
/**
|
||||
* Basically the original read() method with one exception: retruns default value (which is
|
||||
* placeholder value) and remove all database value retrieval mechanism so any add-ons
|
||||
* on TB refers to TB placeholder product data
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @param WC_Product $product Product object.
|
||||
*/
|
||||
public function read( &$product ) {
|
||||
$product->set_defaults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register product type data store
|
||||
*
|
||||
* @since 4.0.10
|
||||
* @since 4.3.3 register the store for tb-placeholder-variation product
|
||||
*
|
||||
* @param array $stores
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function register_store( $stores ) {
|
||||
$stores['product-tb-placeholder'] = 'ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder_Data_Store_CPT';
|
||||
|
||||
// Placeholder variation store requirement is identical to placeholder variable, which is
|
||||
// loading defaults as value and skipping database value retrieval; thus best keep thing
|
||||
// simple and reuse it for tb-placeholder-variation
|
||||
$stores['product-tb-placeholder-variation'] = 'ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder_Data_Store_CPT';
|
||||
|
||||
return $stores;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register product tb-placeholder's store
|
||||
*
|
||||
* @since 4.0.10
|
||||
*/
|
||||
add_filter(
|
||||
'woocommerce_data_stores',
|
||||
array( 'ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder_Data_Store_CPT', 'register_store' )
|
||||
);
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ET_Theme_Builder_Woocommerce_Product_Variation_Placeholder
|
||||
*
|
||||
* Display variation (child of variable) placeholder product on Theme Builder. This needs to be
|
||||
* explicitly defined in case WC add-ons relies on any of variation's method.
|
||||
*/
|
||||
class ET_Theme_Builder_Woocommerce_Product_Variation_Placeholder extends WC_Product_Variation {
|
||||
/**
|
||||
* Get internal type.
|
||||
* Define custom internal type so custom data store can be used to bypass database value retrieval
|
||||
*
|
||||
* @since 4.3.3
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_type() {
|
||||
return 'tb-placeholder-variation';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
/**
|
||||
* Load portability used in the Theme Builder admin page.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_load_portability() {
|
||||
if ( ! et_pb_is_allowed( 'theme_builder' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
et_core_load_component( 'portability' );
|
||||
et_core_portability_register(
|
||||
'et_theme_builder',
|
||||
array(
|
||||
'name' => esc_html__( 'Divi Theme Builder', 'et_builder' ),
|
||||
'type' => 'theme_builder',
|
||||
'view' => 'et_theme_builder' === et_()->array_get( $_GET, 'page' ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No need to use nonce.
|
||||
)
|
||||
);
|
||||
}
|
||||
add_action( 'admin_init', 'et_theme_builder_load_portability' );
|
||||
|
||||
/**
|
||||
* Register the Theme Builder admin page.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $parent
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_add_admin_page( $parent ) {
|
||||
if ( ! et_pb_is_allowed( 'theme_builder' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We register the page with the 'edit_others_posts' capability since it's the lowest
|
||||
// requirement to use VB and we already checked for the theme_builder ET cap.
|
||||
add_submenu_page(
|
||||
$parent,
|
||||
esc_html__( 'Theme Builder', 'et_builder' ),
|
||||
esc_html__( 'Theme Builder', 'et_builder' ),
|
||||
'edit_others_posts',
|
||||
'et_theme_builder',
|
||||
'et_theme_builder_admin_page'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue Theme Builder assets.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_enqueue_scripts() {
|
||||
if ( ! et_builder_is_tb_admin_screen() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$role_capabilities = et_pb_get_role_settings();
|
||||
$user_role = et_pb_get_current_user_role();
|
||||
|
||||
et_builder_enqueue_open_sans();
|
||||
|
||||
et_fb_enqueue_bundle( 'et-theme-builder', 'theme-builder.css', array( 'et-core-admin' ) );
|
||||
|
||||
et_builder_enqueue_assets_head();
|
||||
et_builder_enqueue_assets_main();
|
||||
|
||||
global $wp_version;
|
||||
|
||||
$ver = ET_BUILDER_VERSION;
|
||||
$root = ET_BUILDER_URI;
|
||||
|
||||
if ( version_compare( substr( $wp_version, 0, 3 ), '4.5', '<' ) ) {
|
||||
$dep = array( 'jquery-ui-compat' );
|
||||
wp_register_script( 'jquery-ui-compat', "{$root}/scripts/ext/jquery-ui-1.10.4.custom.min.js", array( 'jquery' ), $ver, true );
|
||||
} else {
|
||||
$dep = array( 'jquery-ui-datepicker' );
|
||||
}
|
||||
|
||||
wp_register_script( 'jquery-ui-datepicker-addon', "{$root}/scripts/ext/jquery-ui-timepicker-addon.js", $dep, $ver, true );
|
||||
wp_register_script( 'react-tiny-mce', "{$root}/frontend-builder/assets/vendors/tinymce.min.js" );
|
||||
|
||||
$asset_ver = ET_BUILDER_VERSION;
|
||||
|
||||
$frame_helpers_id = 'et-frame-helpers';
|
||||
$frame_helpers_path = ET_BUILDER_DIR . '/frontend-builder/build/frame-helpers.js';
|
||||
$frame_helpers_url = ET_BUILDER_URI . '/frontend-builder/build/frame-helpers.js';
|
||||
|
||||
if ( ! file_exists( $frame_helpers_path ) ) {
|
||||
// Load "hot" from webpack-dev-server.
|
||||
$site_url = wp_parse_url( get_site_url() );
|
||||
$frame_helpers_url = "{$site_url['scheme']}://{$site_url['host']}:31495/frame-helpers.js";
|
||||
}
|
||||
|
||||
wp_register_script( $frame_helpers_id, $frame_helpers_url, array(), $asset_ver );
|
||||
|
||||
$asset_id = 'et-theme-builder';
|
||||
$asset_path = ET_BUILDER_DIR . '/frontend-builder/build/theme-builder.js';
|
||||
$asset_uri = ET_BUILDER_URI . '/frontend-builder/build/theme-builder.js';
|
||||
$dependencies = array(
|
||||
'jquery',
|
||||
'jquery-ui-sortable',
|
||||
'jquery-ui-datepicker-addon',
|
||||
'react',
|
||||
'react-dom',
|
||||
'react-tiny-mce',
|
||||
'et-core-admin',
|
||||
'wp-hooks',
|
||||
'et-frame-helpers',
|
||||
);
|
||||
|
||||
if ( ! wp_script_is( 'wp-hooks', 'registered' ) ) {
|
||||
// Use bundled wp-hooks script when WP < 5.0
|
||||
wp_enqueue_script( 'wp-hooks', ET_BUILDER_URI . '/frontend-builder/assets/backports/hooks.js', array(), $asset_ver, false );
|
||||
}
|
||||
|
||||
et_fb_enqueue_react();
|
||||
|
||||
if ( ! file_exists( $asset_path ) ) {
|
||||
// Load "hot" from webpack-dev-server.
|
||||
$site_url = wp_parse_url( get_site_url() );
|
||||
$asset_uri = "{$site_url['scheme']}://{$site_url['host']}:31495/theme-builder.js";
|
||||
}
|
||||
|
||||
wp_enqueue_script( $asset_id, $asset_uri, $dependencies, $asset_ver, true );
|
||||
|
||||
// Strip 'validate' key from settings as it is used server-side only.
|
||||
$default_settings = et_theme_builder_get_template_settings_options();
|
||||
foreach ( $default_settings as $group_key => $group ) {
|
||||
foreach ( $group['settings'] as $setting_key => $setting ) {
|
||||
unset( $default_settings[ $group_key ]['settings'][ $setting_key ]['validate'] );
|
||||
}
|
||||
}
|
||||
|
||||
// Library item editor.
|
||||
$theme_builder_id = 0;
|
||||
$library_item_title = '';
|
||||
$is_item_editor = et_theme_builder_library_is_item_editor();
|
||||
|
||||
if ( $is_item_editor ) {
|
||||
$item_id = et_theme_builder_get_item_id();
|
||||
$item_editor = ET_Theme_Builder_Local_Library_Item_Editor::instance( $item_id );
|
||||
if ( null !== $item_editor->item->item_post ) {
|
||||
$theme_builder_id = $item_editor->get_interim_theme_builder_id();
|
||||
$library_item_title = $item_editor->get_library_item_editor_item_title();
|
||||
}
|
||||
}
|
||||
|
||||
$preloaded_settings = et_theme_builder_get_template_settings_options_for_preloading( $theme_builder_id );
|
||||
foreach ( $preloaded_settings as $setting_key => $setting ) {
|
||||
unset( $preloaded_settings[ $setting_key ]['validate'] );
|
||||
}
|
||||
|
||||
$preferences = et_fb_app_preferences();
|
||||
$animation = et_()->array_get( $preferences, 'builder_animation.value', 'true' );
|
||||
$animation = true === $animation || 'true' === $animation;
|
||||
$i18n = require ET_BUILDER_DIR . 'frontend-builder/i18n.php';
|
||||
|
||||
wp_localize_script(
|
||||
'et-theme-builder',
|
||||
'et_theme_builder_bundle',
|
||||
array(
|
||||
'config' => array(
|
||||
'distPath' => ET_BUILDER_URI . '/frontend-builder/build/',
|
||||
'api' => admin_url( 'admin-ajax.php' ),
|
||||
'apiErrors' => ET_Theme_Builder_Api_Errors::getMap(),
|
||||
'themeBuilderURL' => admin_url( 'admin.php?page=et_theme_builder' ),
|
||||
'diviLibraryCustomTabs' => apply_filters( 'et_builder_library_modal_custom_tabs', array(), 'theme-builder' ),
|
||||
// phpcs:disable WordPress.Arrays.MultipleStatementAlignment -- It fails to correctly identify the required spaces before double arrow in the nonces list`.
|
||||
'nonces' => array(
|
||||
'et_builder_library_get_layouts_data' => wp_create_nonce( 'et_builder_library_get_layouts_data' ),
|
||||
'et_theme_builder_library_get_items_data' => wp_create_nonce( 'et_theme_builder_library_get_items_data' ),
|
||||
'et_theme_builder_library_update_terms' => wp_create_nonce( 'et_theme_builder_library_update_terms' ),
|
||||
'et_theme_builder_library_get_item' => wp_create_nonce( 'et_theme_builder_library_get_item' ),
|
||||
'et_theme_builder_api_duplicate_layout' => wp_create_nonce( 'et_theme_builder_api_duplicate_layout' ),
|
||||
'et_theme_builder_api_create_layout' => wp_create_nonce( 'et_theme_builder_api_create_layout' ),
|
||||
'et_theme_builder_api_get_layout_url' => wp_create_nonce( 'et_theme_builder_api_get_layout_url' ),
|
||||
'et_theme_builder_api_save' => wp_create_nonce( 'et_theme_builder_api_save' ),
|
||||
'et_theme_builder_api_drop_autosave' => wp_create_nonce( 'et_theme_builder_api_drop_autosave' ),
|
||||
'et_theme_builder_api_get_template_settings' => wp_create_nonce( 'et_theme_builder_api_get_template_settings' ),
|
||||
'et_theme_builder_api_reset' => wp_create_nonce( 'et_theme_builder_api_reset' ),
|
||||
'et_theme_builder_api_export_theme_builder' => wp_create_nonce( 'et_theme_builder_api_export_theme_builder' ),
|
||||
'et_theme_builder_api_import_theme_builder' => wp_create_nonce( 'et_theme_builder_api_import_theme_builder' ),
|
||||
'et_builder_library_update_account' => wp_create_nonce( 'et_builder_library_update_account' ),
|
||||
'et_theme_builder_library_update_item' => wp_create_nonce( 'et_theme_builder_library_update_item' ),
|
||||
'et_theme_builder_library_save_temp_layout' => wp_create_nonce( 'et_theme_builder_library_save_temp_layout' ),
|
||||
'et_theme_builder_library_remove_temp_layout' => wp_create_nonce( 'et_theme_builder_library_remove_temp_layout' ),
|
||||
'et_theme_builder_library_toggle_cloud_status' => wp_create_nonce( 'et_theme_builder_library_toggle_cloud_status' ),
|
||||
'et_theme_builder_api_save_template_to_library' => wp_create_nonce( 'et_theme_builder_api_save_template_to_library' ),
|
||||
'et_theme_builder_api_save_preset_to_library' => wp_create_nonce( 'et_theme_builder_api_save_preset_to_library' ),
|
||||
'et_theme_builder_api_get_terms' => wp_create_nonce( 'et_theme_builder_api_get_terms' ),
|
||||
'et_theme_builder_api_use_library_item' => wp_create_nonce( 'et_theme_builder_api_use_library_item' ),
|
||||
'et_theme_builder_trash_theme_builder' => wp_create_nonce( 'et_theme_builder_trash_theme_builder' ),
|
||||
'et_theme_builder_library_item_edit' => wp_create_nonce( 'et_theme_builder_library_item_edit' ),
|
||||
'et_theme_builder_api_get_library_item' => wp_create_nonce( 'et_theme_builder_api_get_library_item' ),
|
||||
'et_pb_preview_nonce' => wp_create_nonce( 'et_pb_preview_nonce' ),
|
||||
'et_theme_builder_library_get_set_items' => wp_create_nonce( 'et_theme_builder_library_get_set_items' ),
|
||||
'et_theme_builder_get_preset_default_template_id' => wp_create_nonce( 'et_theme_builder_get_preset_default_template_id' ),
|
||||
'saveDomainToken' => wp_create_nonce( 'et_builder_ajax_save_domain_token' ),
|
||||
'et_theme_builder_library_clear_temp_data' => wp_create_nonce( 'et_theme_builder_library_clear_temp_data' ),
|
||||
'et_theme_builder_library_get_cloud_token' => wp_create_nonce( 'et_theme_builder_library_get_cloud_token' ),
|
||||
),
|
||||
// phpcs:enable
|
||||
'site_url' => get_site_url(),
|
||||
'rtl' => is_rtl(),
|
||||
'animation' => $animation,
|
||||
'templateSettings' => array(
|
||||
'default' => $default_settings,
|
||||
'preloaded' => $preloaded_settings,
|
||||
),
|
||||
'etAccount' => et_core_get_et_account(),
|
||||
'capabilities' => isset( $role_capabilities[ $user_role ] ) ? $role_capabilities[ $user_role ] : array(),
|
||||
'templates' => array(
|
||||
'hasDraft' => ! $theme_builder_id && 0 !== et_theme_builder_get_theme_builder_post_id( false, false ),
|
||||
'live' => et_theme_builder_get_theme_builder_templates( true, $theme_builder_id ),
|
||||
'draft' => et_theme_builder_get_theme_builder_templates( false, $theme_builder_id ),
|
||||
),
|
||||
'localLibrary' => array(
|
||||
'templateCategories' => et_theme_builder_get_terms( 'layout_category' ),
|
||||
'templateTags' => et_theme_builder_get_terms( 'layout_tag' ),
|
||||
'themeBuilderId' => $theme_builder_id,
|
||||
'libraryItemTitle' => ! empty( $library_item_title ) ? $library_item_title : '',
|
||||
),
|
||||
'site_domain' => isset( $home_url['host'] ) ? untrailingslashit( $home_url['host'] ) : '/',
|
||||
'domainToken' => get_option( 'et_server_domain_token', '' ),
|
||||
'verticalMenu' => array(
|
||||
'showTooltip' => false,
|
||||
),
|
||||
),
|
||||
'i18n' => array(
|
||||
'generic' => $i18n['generic'],
|
||||
'portability' => $i18n['portability'],
|
||||
'library' => $i18n['library'],
|
||||
'themeBuilder' => $i18n['themeBuilder'],
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Load Library and Cloud.
|
||||
et_builder_load_library();
|
||||
|
||||
ET_Cloud_App::load_js();
|
||||
}
|
||||
add_action( 'admin_enqueue_scripts', 'et_theme_builder_enqueue_scripts' );
|
||||
|
||||
/**
|
||||
* Render the Theme Builder admin page.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_admin_page() {
|
||||
echo '<div id="et-theme-builder"></div>';
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* Theme Builder Library constants.
|
||||
*
|
||||
* @package Builder
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
if ( ! defined( 'ET_THEME_BUILDER_ITEM_SET' ) ) {
|
||||
define( 'ET_THEME_BUILDER_ITEM_SET', 'set' );
|
||||
}
|
||||
|
||||
if ( ! defined( 'ET_THEME_BUILDER_ITEM_TEMPLATE' ) ) {
|
||||
define( 'ET_THEME_BUILDER_ITEM_TEMPLATE', 'template' );
|
||||
}
|
||||
|
||||
if ( ! defined( 'ET_THEME_BUILDER_EDITOR_STANDARD' ) ) {
|
||||
define( 'ET_THEME_BUILDER_EDITOR_STANDARD', 'standard' );
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/**
|
||||
* Resolve placeholder content for built-in dynamic content fields for Theme Builder layouts.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $content Content.
|
||||
* @param string $name Name.
|
||||
* @param array $settings Settings.
|
||||
* @param integer $post_id Post ID.
|
||||
* @param string $context Context.
|
||||
* @param array $overrides Overrides.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function et_theme_builder_filter_resolve_default_dynamic_content( $content, $name, $settings, $post_id, $context, $overrides ) {
|
||||
$post_type = get_post_type( $post_id );
|
||||
|
||||
if ( ! et_theme_builder_is_layout_post_type( $post_type ) && ! is_et_theme_builder_template_preview() ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$placeholders = array(
|
||||
'post_title' => __( 'Your Dynamic Post Title Will Display Here', 'et_builder' ),
|
||||
'post_excerpt' => __( 'Your dynamic post excerpt will display here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus auctor urna eleifend diam eleifend sollicitudin a fringilla turpis. Curabitur lectus enim.', 'et_builder' ),
|
||||
'post_date' => time(),
|
||||
'post_comment_count' => 12,
|
||||
'post_categories' => array(
|
||||
__( 'Category 1', 'et_builder' ),
|
||||
__( 'Category 2', 'et_builder' ),
|
||||
__( 'Category 3', 'et_builder' ),
|
||||
),
|
||||
'post_tags' => array(
|
||||
__( 'Tag 1', 'et_builder' ),
|
||||
__( 'Tag 2', 'et_builder' ),
|
||||
__( 'Tag 3', 'et_builder' ),
|
||||
),
|
||||
'post_author' => array(
|
||||
'display_name' => __( 'John Doe', 'et_builder' ),
|
||||
'first_last_name' => __( 'John Doe', 'et_builder' ),
|
||||
'last_first_name' => __( 'Doe, John', 'et_builder' ),
|
||||
'first_name' => __( 'John', 'et_builder' ),
|
||||
'last_name' => __( 'Doe', 'et_builder' ),
|
||||
'nickname' => __( 'John', 'et_builder' ),
|
||||
'username' => __( 'johndoe', 'et_builder' ),
|
||||
),
|
||||
'post_author_bio' => __( 'Your dynamic author bio will display here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus auctor urna eleifend diam eleifend sollicitudin a fringilla turpis. Curabitur lectus enim.', 'et_builder' ),
|
||||
'post_featured_image' => ET_BUILDER_PLACEHOLDER_LANDSCAPE_IMAGE_DATA,
|
||||
'term_description' => __( 'Your dynamic category description will display here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus auctor urna eleifend diam eleifend sollicitudin a fringilla turpis. Curabitur lectus enim.', 'et_builder' ),
|
||||
'site_logo' => 'https://www.elegantthemes.com/img/divi.png',
|
||||
);
|
||||
|
||||
$_ = et_();
|
||||
$def = 'et_builder_get_dynamic_attribute_field_default';
|
||||
$wrapped = false;
|
||||
|
||||
switch ( $name ) {
|
||||
case 'post_title':
|
||||
$content = esc_html( $placeholders[ $name ] );
|
||||
break;
|
||||
|
||||
case 'post_excerpt':
|
||||
$words = (int) $_->array_get( $settings, 'words', $def( $post_id, $name, 'words' ) );
|
||||
$read_more = $_->array_get( $settings, 'read_more_label', $def( $post_id, $name, 'read_more_label' ) );
|
||||
$content = esc_html( $placeholders[ $name ] );
|
||||
|
||||
if ( $words > 0 ) {
|
||||
$content = wp_trim_words( $content, $words );
|
||||
}
|
||||
|
||||
if ( ! empty( $read_more ) ) {
|
||||
$content .= sprintf(
|
||||
' <a href="%1$s">%2$s</a>',
|
||||
'#',
|
||||
esc_html( $read_more )
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'post_date':
|
||||
$format = $_->array_get( $settings, 'date_format', $def( $post_id, $name, 'date_format' ) );
|
||||
$custom_format = $_->array_get( $settings, 'custom_date_format', $def( $post_id, $name, 'custom_date_format' ) );
|
||||
|
||||
if ( 'default' === $format ) {
|
||||
$format = strval( get_option( 'date_format' ) );
|
||||
}
|
||||
|
||||
if ( 'custom' === $format ) {
|
||||
$format = $custom_format;
|
||||
}
|
||||
|
||||
$content = esc_html( date( $format, $placeholders[ $name ] ) );
|
||||
break;
|
||||
|
||||
case 'post_comment_count':
|
||||
$link = $_->array_get( $settings, 'link_to_comments_page', $def( $post_id, $name, 'link_to_comments_page' ) );
|
||||
$link = 'on' === $link;
|
||||
$content = esc_html( $placeholders[ $name ] );
|
||||
|
||||
if ( $link ) {
|
||||
$content = sprintf(
|
||||
'<a href="%1$s">%2$s</a>',
|
||||
'#',
|
||||
et_core_esc_previously( et_builder_wrap_dynamic_content( $post_id, $name, $content, $settings ) )
|
||||
);
|
||||
$wrapped = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'post_categories': // Intentional fallthrough.
|
||||
case 'post_tags':
|
||||
$link = $_->array_get( $settings, 'link_to_term_page', $def( $post_id, $name, 'link_to_category_page' ) );
|
||||
$link = 'on' === $link;
|
||||
$url = '#';
|
||||
$separator = $_->array_get( $settings, 'separator', $def( $post_id, $name, 'separator' ) );
|
||||
$separator = ! empty( $separator ) ? $separator : $def( $post_id, $name, 'separator' );
|
||||
$content = $placeholders[ $name ];
|
||||
|
||||
foreach ( $content as $index => $item ) {
|
||||
$content[ $index ] = esc_html( $item );
|
||||
|
||||
if ( $link ) {
|
||||
$content[ $index ] = sprintf(
|
||||
'<a href="%1$s" target="%2$s">%3$s</a>',
|
||||
esc_url( $url ),
|
||||
esc_attr( '_blank' ),
|
||||
et_core_esc_previously( $content[ $index ] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$content = implode( esc_html( $separator ), $content );
|
||||
break;
|
||||
|
||||
case 'post_link':
|
||||
$text = $_->array_get( $settings, 'text', $def( $post_id, $name, 'text' ) );
|
||||
$custom_text = $_->array_get( $settings, 'custom_text', $def( $post_id, $name, 'custom_text' ) );
|
||||
$label = 'custom' === $text ? $custom_text : $placeholders['post_title'];
|
||||
$content = sprintf(
|
||||
'<a href="%1$s">%2$s</a>',
|
||||
'#',
|
||||
esc_html( $label )
|
||||
);
|
||||
break;
|
||||
|
||||
case 'post_author':
|
||||
$name_format = $_->array_get( $settings, 'name_format', $def( $post_id, $name, 'name_format' ) );
|
||||
$link = $_->array_get( $settings, 'link', $def( $post_id, $name, 'link' ) );
|
||||
$link = 'on' === $link;
|
||||
$label = isset( $placeholders[ $name ][ $name_format ] ) ? $placeholders[ $name ][ $name_format ] : '';
|
||||
$url = '#';
|
||||
|
||||
$content = esc_html( $label );
|
||||
|
||||
if ( $link && ! empty( $url ) ) {
|
||||
$content = sprintf(
|
||||
'<a href="%1$s" target="%2$s">%3$s</a>',
|
||||
esc_url( $url ),
|
||||
esc_attr( '_blank' ),
|
||||
et_core_esc_previously( $content )
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'post_author_bio':
|
||||
$content = esc_html( $placeholders[ $name ] );
|
||||
break;
|
||||
|
||||
case 'term_description':
|
||||
$content = esc_html( $placeholders[ $name ] );
|
||||
break;
|
||||
|
||||
case 'post_link_url':
|
||||
$content = '#';
|
||||
break;
|
||||
|
||||
case 'post_author_url':
|
||||
$content = '#';
|
||||
break;
|
||||
|
||||
case 'post_featured_image':
|
||||
$content = et_core_intentionally_unescaped( $placeholders[ $name ], 'fixed_string' );
|
||||
break;
|
||||
|
||||
case 'site_logo':
|
||||
if ( empty( $content ) ) {
|
||||
$content = esc_url( $placeholders[ $name ] );
|
||||
} else {
|
||||
$wrapped = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Avoid unhandled cases being wrapped twice by the default resolve and this one.
|
||||
$wrapped = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $_->starts_with( $name, 'custom_meta_' ) ) {
|
||||
$meta_key = substr( $name, strlen( 'custom_meta_' ) );
|
||||
$meta_value = get_post_meta( $post_id, $meta_key, true );
|
||||
if ( empty( $meta_value ) ) {
|
||||
$content = et_builder_get_dynamic_content_custom_field_label( $meta_key );
|
||||
} else {
|
||||
$wrapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $wrapped ) {
|
||||
$content = et_builder_wrap_dynamic_content( $post_id, $name, $content, $settings );
|
||||
$wrapped = true;
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
add_filter( 'et_builder_resolve_dynamic_content', 'et_theme_builder_filter_resolve_default_dynamic_content', 11, 6 );
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
$layouts = et_theme_builder_get_template_layouts();
|
||||
?>
|
||||
<?php get_header(); ?>
|
||||
|
||||
<?php
|
||||
et_theme_builder_frontend_render_body(
|
||||
$layouts[ ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE ]['id'],
|
||||
$layouts[ ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE ]['enabled'],
|
||||
$layouts[ ET_THEME_BUILDER_TEMPLATE_POST_TYPE ]
|
||||
);
|
||||
?>
|
||||
|
||||
<?php
|
||||
get_footer();
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
$layouts = et_theme_builder_get_template_layouts();
|
||||
?>
|
||||
<?php
|
||||
et_theme_builder_frontend_render_footer(
|
||||
$layouts[ ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE ]['id'],
|
||||
$layouts[ ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE ]['enabled'],
|
||||
$layouts[ ET_THEME_BUILDER_TEMPLATE_POST_TYPE ]
|
||||
);
|
||||
?>
|
||||
|
||||
<?php if ( et_core_is_fb_enabled() && et_theme_builder_is_layout_post_type( get_post_type() ) ) : ?>
|
||||
<?php // Hide the footer when we are editing a TB layout. ?>
|
||||
<div class="et-tb-fb-footer" style="display: none;">
|
||||
<?php wp_footer(); ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php wp_footer(); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! et_is_builder_plugin_active() && 'on' === et_get_option( 'divi_back_to_top', 'false' ) ) : ?>
|
||||
<span class="et_pb_scroll_top et-pb-icon"></span>
|
||||
<?php endif; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
$layouts = et_theme_builder_get_template_layouts();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html <?php language_attributes(); ?>>
|
||||
<head>
|
||||
<?php echo $tb_theme_head; ?>
|
||||
|
||||
<?php do_action( 'et_theme_builder_template_head' ); ?>
|
||||
|
||||
<?php wp_head(); ?>
|
||||
</head>
|
||||
<body <?php body_class(); ?>>
|
||||
<?php
|
||||
|
||||
wp_body_open();
|
||||
|
||||
et_theme_builder_frontend_render_header(
|
||||
$layouts[ ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE ]['id'],
|
||||
$layouts[ ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE ]['enabled'],
|
||||
$layouts[ ET_THEME_BUILDER_TEMPLATE_POST_TYPE ]
|
||||
);
|
||||
?>
|
||||
@@ -0,0 +1,671 @@
|
||||
<?php
|
||||
/**
|
||||
* Remove the admin bar from the VB when used from the Theme Builder.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_frontend_disable_admin_bar() {
|
||||
if ( et_builder_tb_enabled() ) {
|
||||
add_filter( 'show_admin_bar', '__return_false' );
|
||||
}
|
||||
}
|
||||
add_filter( 'wp', 'et_theme_builder_frontend_disable_admin_bar' );
|
||||
|
||||
/**
|
||||
* Add body classes depending on which areas are overridden by TB.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param array $classes
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
function et_theme_builder_frontend_add_body_classes( $classes ) {
|
||||
if ( et_builder_bfb_enabled() ) {
|
||||
// Do not add any classes in BFB.
|
||||
return $classes;
|
||||
}
|
||||
|
||||
$layouts = et_theme_builder_get_template_layouts();
|
||||
|
||||
if ( ! empty( $layouts ) ) {
|
||||
$classes[] = 'et-tb-has-template';
|
||||
|
||||
if ( $layouts[ ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE ]['override'] ) {
|
||||
$classes[] = 'et-tb-has-header';
|
||||
|
||||
if ( ! $layouts[ ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE ]['enabled'] ) {
|
||||
$classes[] = 'et-tb-header-disabled';
|
||||
}
|
||||
}
|
||||
|
||||
if ( $layouts[ ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE ]['override'] ) {
|
||||
$classes[] = 'et-tb-has-body';
|
||||
|
||||
if ( ! $layouts[ ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE ]['enabled'] ) {
|
||||
$classes[] = 'et-tb-body-disabled';
|
||||
}
|
||||
}
|
||||
|
||||
if ( $layouts[ ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE ]['override'] ) {
|
||||
$classes[] = 'et-tb-has-footer';
|
||||
|
||||
if ( ! $layouts[ ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE ]['enabled'] ) {
|
||||
$classes[] = 'et-tb-footer-disabled';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
add_filter( 'body_class', 'et_theme_builder_frontend_add_body_classes', 9 );
|
||||
|
||||
/**
|
||||
* Conditionally override the template being loaded by WordPress based on what the user
|
||||
* has created in their Theme Builder.
|
||||
* The header and footer are always dealt with as a pair - if the header is replaced the footer is replaced a well.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $template
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function et_theme_builder_frontend_override_template( $template ) {
|
||||
$layouts = et_theme_builder_get_template_layouts();
|
||||
$page_template = locate_template( 'page.php' );
|
||||
$override_header = et_theme_builder_overrides_layout( ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE );
|
||||
$override_body = et_theme_builder_overrides_layout( ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE );
|
||||
$override_footer = et_theme_builder_overrides_layout( ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE );
|
||||
$is_visual_builder = isset( $_GET['et_fb'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Value is not used
|
||||
$is_theme_builder = et_builder_tb_enabled();
|
||||
|
||||
if ( ( $override_header || $override_body || $override_footer ) && et_core_is_fb_enabled() ) {
|
||||
// When cached assets/definitions do not exist, a VB/BFB page will generate them inline.
|
||||
// This would normally happen later but not in the case of TB because, due to early
|
||||
// `the_content()` calls, `maybe_rebuild_option_template()` would be invoked before
|
||||
// saving definitions/assets resulting in them including resolved option templates instead
|
||||
// of placeholders.
|
||||
$post_type = get_post_type();
|
||||
et_fb_get_dynamic_asset( 'helpers', $post_type );
|
||||
et_fb_get_dynamic_asset( 'definitions', $post_type );
|
||||
}
|
||||
|
||||
if ( $override_header || $override_footer ) {
|
||||
// wp-version >= 5.2
|
||||
remove_action( 'wp_body_open', 'wp_admin_bar_render', 0 );
|
||||
|
||||
add_action( 'get_header', 'et_theme_builder_frontend_override_header' );
|
||||
add_action( 'get_footer', 'et_theme_builder_frontend_override_footer' );
|
||||
}
|
||||
|
||||
et_theme_builder_frontend_enqueue_styles( $layouts );
|
||||
|
||||
// For other themes than Divi, use 'frontend-body-template.php'.
|
||||
if ( $override_body && ! function_exists( 'et_divi_fonts_url' ) ) {
|
||||
return ET_THEME_BUILDER_DIR . 'frontend-body-template.php';
|
||||
}
|
||||
|
||||
if ( $override_body && ( $is_theme_builder || ! $is_visual_builder || ! $layouts['et_template'] || ! et_pb_is_allowed( 'theme_builder' ) ) ) {
|
||||
return ET_THEME_BUILDER_DIR . 'frontend-body-template.php';
|
||||
}
|
||||
|
||||
if ( $override_body && ! is_home() ) {
|
||||
return $page_template;
|
||||
}
|
||||
|
||||
return $template;
|
||||
}
|
||||
// Priority of 98 so it can be overridden by BFB.
|
||||
add_filter( 'template_include', 'et_theme_builder_frontend_override_template', 98 );
|
||||
|
||||
/**
|
||||
* Enqueue any necessary TB layout styles.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param array $layouts
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_frontend_enqueue_styles( $layouts ) {
|
||||
if ( empty( $layouts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! is_singular() && ! et_core_is_fb_enabled() ) {
|
||||
// Create styles managers so they can enqueue styles early enough.
|
||||
// What styles are created and how they are enqueued:
|
||||
// - In FE, singular post view:
|
||||
// -> TB + Post Styles are combined into et-*-tb-{HEADER_ID}-tb-{BODY_ID}-tb-{FOOTER_ID}-{POST_ID}-*.css
|
||||
//
|
||||
// - In FE, non-singular post view:
|
||||
// -> TB styles are separate with the usual filename: et-*-{LAYOUT_ID}-*.css
|
||||
//
|
||||
// - In FE, singular post view in VB so post-specific DC works:
|
||||
// -> TB styles are separate with the current post ID prepended: et-*-tb-for-{POST_ID}-{LAYOUT_ID}-*.css.
|
||||
|
||||
if ( $layouts[ ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE ]['override'] ) {
|
||||
ET_Builder_Element::setup_advanced_styles_manager( $layouts[ ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE ]['id'] );
|
||||
}
|
||||
|
||||
if ( $layouts[ ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE ]['override'] ) {
|
||||
ET_Builder_Element::setup_advanced_styles_manager( $layouts[ ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE ]['id'] );
|
||||
}
|
||||
|
||||
if ( $layouts[ ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE ]['override'] ) {
|
||||
ET_Builder_Element::setup_advanced_styles_manager( $layouts[ ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE ]['id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a custom partial overriding the original one.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $partial
|
||||
* @param string $action
|
||||
* @param string $name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_frontend_override_partial( $partial, $name, $action = '' ) {
|
||||
global $wp_filter;
|
||||
|
||||
$tb_theme_head = '';
|
||||
|
||||
/**
|
||||
* Slightly adjusted version of WordPress core code in order to mimic behavior.
|
||||
*
|
||||
* @link https://core.trac.wordpress.org/browser/tags/5.0.3/src/wp-includes/general-template.php#L33
|
||||
*/
|
||||
$templates = array();
|
||||
$name = (string) $name;
|
||||
if ( '' !== $name ) {
|
||||
$templates[] = "{$partial}-{$name}.php";
|
||||
}
|
||||
$templates[] = "{$partial}.php";
|
||||
|
||||
// Buffer and discard the original partial forcing a require_once so it doesn't load again later.
|
||||
$buffered = ob_start();
|
||||
if ( $buffered ) {
|
||||
$actions = array();
|
||||
|
||||
if ( ! empty( $action ) ) {
|
||||
// Skip any partial-specific actions so they don't run twice.
|
||||
$actions = et_()->array_get( $wp_filter, $action, array() );
|
||||
unset( $wp_filter[ $action ] );
|
||||
}
|
||||
|
||||
locate_template( $templates, true, true );
|
||||
$html = ob_get_clean();
|
||||
|
||||
if ( 'wp_head' === $action ) {
|
||||
$tb_theme_head = et_theme_builder_extract_head( $html );
|
||||
}
|
||||
|
||||
if ( ! empty( $action ) ) {
|
||||
// Restore skipped actions.
|
||||
$wp_filter[ $action ] = $actions;
|
||||
}
|
||||
}
|
||||
|
||||
require_once ET_THEME_BUILDER_DIR . "frontend-{$partial}-template.php";
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract <head> tag contents.
|
||||
*
|
||||
* @since 4.0.8
|
||||
*
|
||||
* @param string $html
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function et_theme_builder_extract_head( $html ) {
|
||||
// We could use DOMDocument here to guarantee proper parsing but we need
|
||||
// the most performant solution since we cannot reliably cache the result.
|
||||
$head = array();
|
||||
preg_match( '/^[\s\S]*?<head[\s\S]*?>([\s\S]*?)<\/head>[\s\S]*$/i', $html, $head );
|
||||
|
||||
return ! empty( $head[1] ) ? trim( $head[1] ) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default header template.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_frontend_override_header( $name ) {
|
||||
et_theme_builder_frontend_override_partial( 'header', $name, 'wp_head' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default footer template.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_frontend_override_footer( $name ) {
|
||||
et_theme_builder_frontend_override_partial( 'footer', $name, 'wp_footer' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter builder content wrapping as Theme Builder Layouts are wrapped collectively instead of individually.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param bool $wrap
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_frontend_filter_add_outer_content_wrap( $wrap ) {
|
||||
$override_header = et_theme_builder_overrides_layout( ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE );
|
||||
$override_footer = et_theme_builder_overrides_layout( ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE );
|
||||
|
||||
// Theme Builder layouts must not be individually wrapped as they are wrapped
|
||||
// collectively, with the exception of the BFB or body layout.
|
||||
if ( ( $override_header || $override_footer ) && ! et_builder_bfb_enabled() ) {
|
||||
$wrap = false;
|
||||
}
|
||||
|
||||
return $wrap;
|
||||
}
|
||||
add_filter( 'et_builder_add_outer_content_wrap', 'et_theme_builder_frontend_filter_add_outer_content_wrap' );
|
||||
|
||||
/**
|
||||
* Render a template builder layout.
|
||||
*
|
||||
* Wrapper cases:
|
||||
* 1. Header/Footer are replaced.
|
||||
* => Common is open and closed. Header/Footer do not get opened/closed because
|
||||
* Common is opened before them.
|
||||
*
|
||||
* 2. Body is replaced.
|
||||
* => Common is NOT opened/closed. Body is open/closed.
|
||||
*
|
||||
* 3. Header/Body/Footer are replaced.
|
||||
* => Common is open and closed. Header/Body/Footer do not get opened/closed because
|
||||
* Common is opened before them.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $layout_type Layout Type.
|
||||
* @param integer $layout_id Layout ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_frontend_render_layout( $layout_type, $layout_id ) {
|
||||
if ( $layout_id <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$layout = get_post( $layout_id );
|
||||
|
||||
if ( null === $layout || $layout->post_type !== $layout_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
et_theme_builder_frontend_render_common_wrappers( $layout_type, true );
|
||||
|
||||
/**
|
||||
* Fires after Theme Builder layout opening wrappers have been output but before any
|
||||
* other processing has been done (e.g. replacing the current post).
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @param string $layout_type
|
||||
* @param integer $layout_id
|
||||
*/
|
||||
do_action( 'et_theme_builder_after_layout_opening_wrappers', $layout_type, $layout_id );
|
||||
|
||||
ET_Builder_Element::begin_theme_builder_layout( $layout_id );
|
||||
|
||||
ET_Post_Stack::replace( $layout );
|
||||
|
||||
$is_visual_builder = isset( $_GET['et_fb'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Value is not used
|
||||
$theme_builder_layouts = array( 'et_header_layout', 'et_footer_layout' );
|
||||
|
||||
// Do not pass header and footer content here if visual builder is loaded,
|
||||
// they will be loaded inside the builder itself.
|
||||
if ( et_pb_is_allowed( 'theme_builder' ) && $is_visual_builder && in_array( $layout_type, $theme_builder_layouts, true ) ) {
|
||||
$post_content = '';
|
||||
} else {
|
||||
$post_content = get_the_content();
|
||||
}
|
||||
|
||||
echo et_core_intentionally_unescaped( et_builder_render_layout( $post_content ), 'html' );
|
||||
|
||||
// Get dynamic content.
|
||||
$has_dynamic_content = et_builder_get_dynamic_contents( get_the_content() );
|
||||
|
||||
// Handle style output.
|
||||
if ( is_singular() && ! et_core_is_fb_enabled() ) {
|
||||
$result = ET_Builder_Element::setup_advanced_styles_manager( ET_Post_Stack::get_main_post_id() );
|
||||
} elseif ( is_tax() && ! empty( $has_dynamic_content ) ) {
|
||||
// Set post id to 0 if its a taxonomy page.
|
||||
// This is because of the dynamic content not working properly,
|
||||
// With the theme builder cache.
|
||||
$result = ET_Builder_Element::setup_advanced_styles_manager( 0 );
|
||||
} else {
|
||||
$result = ET_Builder_Element::setup_advanced_styles_manager( $layout->ID );
|
||||
}
|
||||
|
||||
$advanced_styles_manager = $result['manager'];
|
||||
if ( isset( $result['deferred'] ) ) {
|
||||
$deferred_styles_manager = $result['deferred'];
|
||||
}
|
||||
|
||||
// Pass styles to page resource which will handle their output.
|
||||
/**
|
||||
* Filters whether Critical CSS feature is enabled or not.
|
||||
*
|
||||
* @since 4.10.0
|
||||
*
|
||||
* @param bool $enabled Critical CSS enabled value.
|
||||
*/
|
||||
$is_critical_enabled = apply_filters( 'et_builder_critical_css_enabled', false );
|
||||
|
||||
if ( ET_Builder_Element::$forced_inline_styles || ! $advanced_styles_manager->has_file() || $advanced_styles_manager->forced_inline ) {
|
||||
$custom = et_pb_get_page_custom_css( $layout->ID );
|
||||
|
||||
$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_Post_Stack::restore();
|
||||
|
||||
ET_Builder_Element::end_theme_builder_layout();
|
||||
|
||||
/**
|
||||
* Fires before Theme Builder layout closing wrappers have been output and after any
|
||||
* other processing has been done (e.g. replacing the current post).
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @param string $layout_type
|
||||
* @param integer $layout_id
|
||||
*/
|
||||
do_action( 'et_theme_builder_before_layout_closing_wrappers', $layout_type, $layout_id );
|
||||
|
||||
et_theme_builder_frontend_render_common_wrappers( $layout_type, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a header layout.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param boolean $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_frontend_render_header( $layout_id, $layout_enabled, $template_id ) {
|
||||
/**
|
||||
* Fires before theme builder page wrappers are output.
|
||||
* Example use case is to add opening wrapping html tags for the entire page.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param bool $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*/
|
||||
do_action( 'et_theme_builder_template_before_page_wrappers', $layout_id, $layout_enabled, $template_id );
|
||||
|
||||
et_theme_builder_frontend_render_common_wrappers( 'common', true );
|
||||
|
||||
/**
|
||||
* Fires before theme builder template header is output.
|
||||
* Example use case is to add opening wrapping html tags for the header and/or the entire page.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param bool $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*/
|
||||
do_action( 'et_theme_builder_template_before_header', $layout_id, $layout_enabled, $template_id );
|
||||
|
||||
if ( $layout_enabled ) {
|
||||
et_theme_builder_frontend_render_layout( ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE, $layout_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires after theme builder template header is output.
|
||||
* Example use case is to add closing wrapping html tags for the header.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param bool $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*/
|
||||
do_action( 'et_theme_builder_template_after_header', $layout_id, $layout_enabled, $template_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a body layout.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param boolean $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_frontend_render_body( $layout_id, $layout_enabled, $template_id ) {
|
||||
/**
|
||||
* Fires before theme builder template body is output.
|
||||
* Example use case is to add opening wrapping html tags for the body.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param bool $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
do_action( 'et_theme_builder_template_before_body', $layout_id, $layout_enabled, $template_id );
|
||||
|
||||
if ( $layout_enabled ) {
|
||||
et_theme_builder_frontend_render_layout( ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE, $layout_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires after theme builder template body is output.
|
||||
* Example use case is to add closing wrapping html tags for the body.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param bool $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
do_action( 'et_theme_builder_template_after_body', $layout_id, $layout_enabled, $template_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a footer layout.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param boolean $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function et_theme_builder_frontend_render_footer( $layout_id, $layout_enabled, $template_id ) {
|
||||
/**
|
||||
* Fires before theme builder template footer is output.
|
||||
* Example use case is to add opening wrapping html tags for the footer.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param bool $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
do_action( 'et_theme_builder_template_before_footer', $layout_id, $layout_enabled, $template_id );
|
||||
|
||||
if ( $layout_enabled ) {
|
||||
et_theme_builder_frontend_render_layout( ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE, $layout_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires after theme builder template footer is output.
|
||||
* Example use case is to add closing wrapping html tags for the footer and/or the entire page.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param bool $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
do_action( 'et_theme_builder_template_after_footer', $layout_id, $layout_enabled, $template_id );
|
||||
|
||||
et_theme_builder_frontend_render_common_wrappers( 'common', false );
|
||||
|
||||
/**
|
||||
* Fires after theme builder page wrappers are output.
|
||||
* Example use case is to add closing wrapping html tags for the entire page.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param integer $layout_id The layout id or 0.
|
||||
* @param bool $layout_enabled
|
||||
* @param integer $template_id The template id or 0.
|
||||
*/
|
||||
do_action( 'et_theme_builder_template_after_page_wrappers', $layout_id, $layout_enabled, $template_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Open or close common builder wrappers (e.g. #et-boc) in order to avoid having triple wrappers - one for every layout.
|
||||
*
|
||||
* Useful
|
||||
*
|
||||
* @param $area
|
||||
* @param $open
|
||||
*/
|
||||
function et_theme_builder_frontend_render_common_wrappers( $area, $open ) {
|
||||
static $wrapper = '';
|
||||
|
||||
if ( $open ) {
|
||||
// Open wrappers only if there are no other open wrappers already.
|
||||
if ( '' === $wrapper ) {
|
||||
$wrapper = $area;
|
||||
echo et_builder_get_builder_content_opening_wrapper();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( '' === $wrapper || $area !== $wrapper ) {
|
||||
// Do not close wrappers if the opener does not match the current area.
|
||||
return;
|
||||
}
|
||||
|
||||
echo et_builder_get_builder_content_closing_wrapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the html representing the post content for the current post.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function et_theme_builder_frontend_render_post_content() {
|
||||
static $__prevent_recursion = false;
|
||||
global $wp_query;
|
||||
|
||||
if ( is_et_theme_builder_template_preview() ) {
|
||||
return et_theme_builder_get_post_content_placeholder();
|
||||
}
|
||||
|
||||
if ( ET_Builder_Element::get_theme_builder_layout_type() !== ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE ) {
|
||||
// Prevent usage on non-body layouts.
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( ! is_singular() ) {
|
||||
// Do not output anything on non-singular pages.
|
||||
return '';
|
||||
}
|
||||
|
||||
$main_query_post = ET_Post_Stack::get_main_post();
|
||||
|
||||
if ( ! $main_query_post ) {
|
||||
// Bail if there is no current post.
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( true === $__prevent_recursion ) {
|
||||
// Failsafe just in case.
|
||||
return '';
|
||||
}
|
||||
|
||||
$__prevent_recursion = true;
|
||||
$html = '';
|
||||
$buffered = ob_start();
|
||||
|
||||
if ( $buffered ) {
|
||||
ET_Post_Stack::replace( $main_query_post );
|
||||
|
||||
ET_Builder_Element::begin_theme_builder_layout( get_the_ID() );
|
||||
|
||||
do_action_ref_array( 'loop_start', array( &$wp_query ) );
|
||||
the_content();
|
||||
do_action_ref_array( 'loop_end', array( &$wp_query ) );
|
||||
|
||||
ET_Builder_Element::end_theme_builder_layout();
|
||||
|
||||
ET_Post_Stack::restore();
|
||||
|
||||
$html = ob_get_clean();
|
||||
}
|
||||
|
||||
$__prevent_recursion = false;
|
||||
|
||||
return $html;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* Implement ET_Builder_Post_Query_TBItems to query `et_tb_item`.
|
||||
*
|
||||
* @since ??
|
||||
*
|
||||
* @package Builder
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to handle `et_tb_item` query.
|
||||
*
|
||||
* Think of this class as WP_Query for ET_TB_ITEM_POST_TYPE.
|
||||
*/
|
||||
class ET_Builder_Post_Query_TBItems extends ET_Core_Post_Query {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param string $taxonomy The taxonomy name.
|
||||
* @param array $terms Taxonomy terms.
|
||||
* @param bool $negate Whether to negate this tax query.
|
||||
*/
|
||||
protected function _add_tax_query( $taxonomy, $terms, $negate = null ) {
|
||||
$args = self::$_->array_flatten( $terms );
|
||||
$negate = $this->_reset_negate();
|
||||
|
||||
if ( ! $args ) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
parent::_add_tax_query( $taxonomy, $args, $negate );
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* Init `et_tb_item` taxonomy.
|
||||
*
|
||||
* @since ??
|
||||
*
|
||||
* @package Builder
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to handle `et_tb_item` taxonomy.
|
||||
*
|
||||
* Registers TB Item's Category taxonomy.
|
||||
*/
|
||||
class ET_Builder_Post_Taxonomy_TBItemCategory extends ET_Core_Post_Taxonomy {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_owner = 'builder';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'et_tb_item_category';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected function _get_args() {
|
||||
return array(
|
||||
'hierarchical' => true,
|
||||
'show_ui' => false,
|
||||
'show_admin_column' => true,
|
||||
'query_var' => true,
|
||||
'show_in_nav_menus' => false,
|
||||
'publicly_queryable' => ET_Builder_Post_Type_TBItem::is_publicly_queryable(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function _get_labels() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class instance.
|
||||
*
|
||||
* @param string $type See {@see self::$wp_type} for accepted values. Default is 'taxonomy'.
|
||||
* @param string $name The name/slug of the post object. Default is {@see self::$name}.
|
||||
*
|
||||
* @return ET_Builder_Post_Taxonomy_TBItemCategory|null
|
||||
*/
|
||||
public static function instance( $type = 'taxonomy', $name = 'et_tb_item_category' ) {
|
||||
$instance = parent::instance( $type, $name );
|
||||
if ( ! $instance ) {
|
||||
$instance = new self();
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* Init `et_tb_item` taxonomy.
|
||||
*
|
||||
* @since ??
|
||||
*
|
||||
* @package Builder
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to handle `et_tb_item` taxonomy.
|
||||
*
|
||||
* Registers TB Item's Tag taxonomy.
|
||||
*/
|
||||
class ET_Builder_Post_Taxonomy_TBItemTag extends ET_Core_Post_Taxonomy {
|
||||
|
||||
/**
|
||||
* Taxonomy key.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'et_tb_item_tag';
|
||||
/**
|
||||
* Owner name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_owner = 'builder';
|
||||
|
||||
/**
|
||||
* Get the class instance.
|
||||
*
|
||||
* @param string $type See {@see self::$wp_type} for accepted values. Default is 'taxonomy'.
|
||||
* @param string $name The name/slug of the post object. Default is {@see self::$name}.
|
||||
*
|
||||
* @return ET_Builder_Post_Taxonomy_TBItemTag|null
|
||||
*/
|
||||
public static function instance( $type = 'taxonomy', $name = 'et_tb_item_tag' ) {
|
||||
$instance = parent::instance( $type, $name );
|
||||
|
||||
if ( ! $instance ) {
|
||||
$instance = new self();
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function _get_args() {
|
||||
return array(
|
||||
'hierarchical' => false,
|
||||
'show_ui' => false,
|
||||
'show_admin_column' => true,
|
||||
'query_var' => true,
|
||||
'show_in_nav_menus' => false,
|
||||
'publicly_queryable' => ET_Builder_Post_Type_TBItem::is_publicly_queryable(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function _get_labels() {
|
||||
return array(
|
||||
'name' => esc_html__( 'Tags', 'et_builder' ),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* Init `et_tb_item` taxonomy.
|
||||
*
|
||||
* @since ??
|
||||
*
|
||||
* @package Builder
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to handle `et_tb_item` taxonomy.
|
||||
*
|
||||
* Registers TB Item's Type taxonomy.
|
||||
*/
|
||||
class ET_Builder_Post_Taxonomy_TBItemType extends ET_Core_Post_Taxonomy {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_owner = 'builder';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'et_tb_item_type';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function _get_args() {
|
||||
return array(
|
||||
'hierarchical' => false,
|
||||
'show_ui' => false,
|
||||
'show_admin_column' => true,
|
||||
'query_var' => true,
|
||||
'show_in_nav_menus' => false,
|
||||
'publicly_queryable' => ET_Builder_Post_Type_TBItem::is_publicly_queryable(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function _get_labels() {
|
||||
return array(
|
||||
'name' => esc_html__( 'Type', 'et_builder' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class instance.
|
||||
*
|
||||
* @param string $type See {@see self::$wp_type} for accepted values. Default is 'taxonomy'.
|
||||
* @param string $name The name/slug of the post object. Default is {@see self::$name}.
|
||||
*
|
||||
* @return ET_Builder_Post_Taxonomy_TBItemType|null
|
||||
*/
|
||||
public static function instance( $type = 'taxonomy', $name = 'et_tb_item_type' ) {
|
||||
$instance = parent::instance( $type, $name );
|
||||
if ( ! $instance ) {
|
||||
$instance = new self();
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
/**
|
||||
* Init `et_tb_item` taxonomy.
|
||||
*
|
||||
* @since ??
|
||||
*
|
||||
* @package Builder
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ET_TB_ITEM_POST_TYPE' ) ) {
|
||||
define( 'ET_TB_ITEM_POST_TYPE', 'et_tb_item' );
|
||||
}
|
||||
|
||||
require_once ET_THEME_BUILDER_DIR . 'post/query/TBItems.php';
|
||||
|
||||
/**
|
||||
* Class to handle `et_tb_item` post type.
|
||||
*
|
||||
* Registers TB Item.
|
||||
*/
|
||||
class ET_Builder_Post_Type_TBItem extends ET_Core_Post_Type {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_category_tax = 'layout_category';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_owner = 'builder';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_tag_tax = 'layout_tag';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = ET_TB_ITEM_POST_TYPE;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function _get_args() {
|
||||
return array(
|
||||
'can_export' => true,
|
||||
'capability_type' => 'post',
|
||||
'has_archive' => false,
|
||||
'hierarchical' => false,
|
||||
'map_meta_cap' => true,
|
||||
'public' => false,
|
||||
'publicly_queryable' => self::is_publicly_queryable(),
|
||||
'query_var' => false,
|
||||
'show_in_menu' => false,
|
||||
'show_ui' => false,
|
||||
'supports' => array(
|
||||
'editor',
|
||||
'excerpt',
|
||||
'revisions',
|
||||
'thumbnail',
|
||||
'title',
|
||||
),
|
||||
'taxonomies' => array(
|
||||
'layout_category',
|
||||
'layout_tag',
|
||||
'et_tb_item_type',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function _get_labels() {
|
||||
return array(
|
||||
'add_new' => esc_html_x( 'Add New', 'Layout', 'et_builder' ),
|
||||
'add_new_item' => esc_html__( 'Add New Theme Builder Item', 'et_builder' ),
|
||||
'all_items' => esc_html__( 'All Theme Builder Items', 'et_builder' ),
|
||||
'edit_item' => esc_html__( 'Edit Theme Builder Item', 'et_builder' ),
|
||||
'name' => esc_html__( 'Theme Builder Items', 'et_builder' ),
|
||||
'new_item' => esc_html__( 'New Theme Builder Item', 'et_builder' ),
|
||||
'not_found' => esc_html__( 'Nothing found', 'et_builder' ),
|
||||
'not_found_in_trash' => esc_html__( 'Nothing found in Trash', 'et_builder' ),
|
||||
'parent_item_colon' => '',
|
||||
'search_items' => esc_html__( 'Search Theme Builder Items', 'et_builder' ),
|
||||
'singular_name' => et_builder_i18n( 'Theme Builder Item' ),
|
||||
'view_item' => esc_html__( 'View Theme Builder Item', 'et_builder' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class instance.
|
||||
*
|
||||
* @param string $type See {@see self::$wp_type} for accepted values. Default is 'cpt'.
|
||||
* @param string $name The name/slug of the post object. Default is {@see self::$name}.
|
||||
*
|
||||
* @return self|null
|
||||
*/
|
||||
public static function instance( $type = 'cpt', $name = ET_TB_ITEM_POST_TYPE ) {
|
||||
$instance = parent::instance( $type, $name );
|
||||
if ( ! $instance ) {
|
||||
$instance = new self();
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE when a layout is Favorite.
|
||||
*
|
||||
* @param string $post_id Post ID.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_favorite( $post_id ) {
|
||||
return 'favorite' === get_post_meta( $post_id, 'favorite_status', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if TB Item Library's CPT and its taxonomies are publicly queryable for the current request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_publicly_queryable() {
|
||||
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification -- Nonce not required.
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Nonce not required.
|
||||
$get = $_GET;
|
||||
|
||||
// phpcs:ignore ET.Sniffs.ValidVariableName.VariableNotSnakeCase -- TB is an acronym.
|
||||
$is_TB = ( 'et_theme_builder' === self::$_->array_get( $get, 'page' ) || wp_doing_ajax() );
|
||||
// phpcs:enable
|
||||
|
||||
// phpcs:ignore ET.Sniffs.ValidVariableName.VariableNotSnakeCase -- TB is an acronym.
|
||||
return $is_TB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of ET_Builder_Post_Query_TBItems.
|
||||
*
|
||||
* The instance can then be used to get results.
|
||||
*
|
||||
* @see ET_Builder_Post_Query_TBItems::run()
|
||||
*
|
||||
* @return ET_Builder_Post_Query_TBItems
|
||||
*/
|
||||
public function query() {
|
||||
return new ET_Builder_Post_Query_TBItems( $this->name, $this->_category_tax, $this->_tag_tax );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
/**
|
||||
* Filters an object id for use in template settings validation functions.
|
||||
*
|
||||
* @since 4.2
|
||||
*
|
||||
* @param integer $id Object ID.
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
function et_theme_builder_template_setting_filter_validation_object_id( $id, $type, $subtype ) {
|
||||
/**
|
||||
* Filters template settings object id for validation use.
|
||||
*
|
||||
* @since 4.2
|
||||
*
|
||||
* @param integer $id
|
||||
* @param string $type
|
||||
* @param string $subtype
|
||||
*/
|
||||
return apply_filters( 'et_theme_builder_template_setting_filter_validation_id', $id, $type, $subtype );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate homepage.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_homepage( $type, $subtype, $id, $setting ) {
|
||||
return ET_Theme_Builder_Request::TYPE_FRONT_PAGE === $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate singular:post_type:<post_type>:all.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_singular_post_type_all( $type, $subtype, $id, $setting ) {
|
||||
if ( ET_Theme_Builder_Request::TYPE_FRONT_PAGE === $type && 'page' === $setting[2] && $id === (int) get_option( 'page_on_front' ) ) {
|
||||
// Cover the homepage as well.
|
||||
return true;
|
||||
}
|
||||
|
||||
return ET_Theme_Builder_Request::TYPE_SINGULAR === $type && $subtype === $setting[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate archive:post_type:<post_type>.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_archive_post_type( $type, $subtype, $id, $setting ) {
|
||||
return ET_Theme_Builder_Request::TYPE_POST_TYPE_ARCHIVE === $type && $subtype === $setting[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate singular:post_type:<post_type>:id:<id>.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_singular_post_type_id( $type, $subtype, $id, $setting ) {
|
||||
$object_id = et_theme_builder_template_setting_filter_validation_object_id( (int) $setting[4], 'post', $setting[2] );
|
||||
|
||||
return (
|
||||
// Cover the special case where the post selected is assigned as the website homepage.
|
||||
( ET_Theme_Builder_Request::TYPE_FRONT_PAGE === $type && $id === $object_id )
|
||||
||
|
||||
( ET_Theme_Builder_Request::TYPE_SINGULAR === $type && $id === $object_id )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate singular:post_type:<post_type>:children:id:<id>.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_singular_post_type_children_id( $type, $subtype, $id, $setting ) {
|
||||
if ( ET_Theme_Builder_Request::TYPE_SINGULAR !== $type ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$object_id = et_theme_builder_template_setting_filter_validation_object_id( (int) $setting[5], 'post', $setting[2] );
|
||||
|
||||
return in_array( $object_id, get_post_ancestors( $id ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate singular:taxonomy:<taxonomy>:term:id:<id>.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_singular_taxonomy_term_id( $type, $subtype, $id, $setting ) {
|
||||
if ( ET_Theme_Builder_Request::TYPE_SINGULAR !== $type ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$taxonomy = $setting[2];
|
||||
$object_id = et_theme_builder_template_setting_filter_validation_object_id( (int) $setting[5], 'taxonomy', $taxonomy );
|
||||
|
||||
return has_term( $object_id, $taxonomy, $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate archive:all.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_archive_all( $type, $subtype, $id, $setting ) {
|
||||
$archives = array(
|
||||
ET_Theme_Builder_Request::TYPE_POST_TYPE_ARCHIVE,
|
||||
ET_Theme_Builder_Request::TYPE_TERM,
|
||||
ET_Theme_Builder_Request::TYPE_AUTHOR,
|
||||
ET_Theme_Builder_Request::TYPE_DATE,
|
||||
);
|
||||
|
||||
return in_array( $type, $archives, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate archive:taxonomy:<taxonomy>:all.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_archive_taxonomy_all( $type, $subtype, $id, $setting ) {
|
||||
return ET_Theme_Builder_Request::TYPE_TERM === $type && $subtype === $setting[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate archive:taxonomy:<taxonomy>:term:id:<id>.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_archive_taxonomy_term_id( $type, $subtype, $id, $setting ) {
|
||||
$taxonomy = $setting[2];
|
||||
$object_id = et_theme_builder_template_setting_filter_validation_object_id( (int) $setting[5], 'post', $taxonomy );
|
||||
|
||||
if ( ET_Theme_Builder_Request::TYPE_TERM === $type && $subtype === $taxonomy ) {
|
||||
// Exact match.
|
||||
if ( $id === $object_id ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Specified setting term id is an ancestor of the request term id ($id).
|
||||
if ( term_is_ancestor_of( $object_id, $id, $taxonomy ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate archive:user:all.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_archive_user_all( $type, $subtype, $id, $setting ) {
|
||||
return ET_Theme_Builder_Request::TYPE_AUTHOR === $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate archive:user:id:<id>.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_archive_user_id( $type, $subtype, $id, $setting ) {
|
||||
return ET_Theme_Builder_Request::TYPE_AUTHOR === $type && $id === (int) $setting[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate archive:user:role:<role>.
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_archive_user_role( $type, $subtype, $id, $setting ) {
|
||||
$user = get_userdata( $id );
|
||||
|
||||
if ( ! $user ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( 'administrator' === $setting[3] && is_super_admin( $user->ID ) ) {
|
||||
// Superadmins may:
|
||||
// - have a low-level role assigned in the current site
|
||||
// - not be added to the site at all
|
||||
// in either case they are treated as administrators so we have to handle this edge case.
|
||||
return true;
|
||||
}
|
||||
|
||||
return ET_Theme_Builder_Request::TYPE_AUTHOR === $type && in_array( $setting[3], $user->roles, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate archive:date:all.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_archive_date_all( $type, $subtype, $id, $setting ) {
|
||||
return ET_Theme_Builder_Request::TYPE_DATE === $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate search.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_search( $type, $subtype, $id, $setting ) {
|
||||
return ET_Theme_Builder_Request::TYPE_SEARCH === $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate 404.
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
* @param integer $id ID.
|
||||
* @param string[] $setting Setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function et_theme_builder_template_setting_validate_404( $type, $subtype, $id, $setting ) {
|
||||
return ET_Theme_Builder_Request::TYPE_404 === $type;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
/**
|
||||
* Get placeholders for WooCommerce module in Theme Builder
|
||||
*
|
||||
* @since 4.0.1
|
||||
* @since 4.0.10 Product placeholders is initialized as TB placeholder product's default props
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function et_theme_builder_wc_placeholders() {
|
||||
return array(
|
||||
'title' => esc_html__( 'Product name', 'et_builder' ),
|
||||
'slug' => 'product-name',
|
||||
'short_description' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris bibendum eget dui sed vehicula. Suspendisse potenti. Nam dignissim at elit non lobortis.', 'et_builder' ),
|
||||
'description' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris bibendum eget dui sed vehicula. Suspendisse potenti. Nam dignissim at elit non lobortis. Cras sagittis dui diam, a finibus nibh euismod vestibulum. Integer sed blandit felis. Maecenas commodo ante in mi ultricies euismod. Morbi condimentum interdum luctus. Mauris iaculis interdum risus in volutpat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent cursus odio eget cursus pharetra. Aliquam lacinia lectus a nibh ullamcorper maximus. Quisque at sapien pulvinar, dictum elit a, bibendum massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris non pellentesque urna.', 'et_builder' ),
|
||||
'status' => 'publish',
|
||||
'comment_status' => 'open',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force set product's class to ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder in TB's woocommerceComponent
|
||||
* rendering. This product classname is specifically filled and will returned TB placeholder data
|
||||
* without retrieving actual value from database
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function et_theme_builder_wc_product_class() {
|
||||
return 'ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get review placeholder for WooCommerce module in Theme Builder. This can't be included at
|
||||
* `et_theme_builder_wc_placeholders()` due to dependability on global $post value and
|
||||
* `et_theme_builder_wc_placeholders()`'s returned value being cached on static variable
|
||||
*
|
||||
* @since 4.0.1
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
function et_theme_builder_wc_review_placeholder() {
|
||||
global $post;
|
||||
|
||||
$review = new stdClass();
|
||||
$review->comment_ID = 1;
|
||||
$review->comment_author = 'John Doe';
|
||||
$review->comment_author_email = 'john@doe.com';
|
||||
$review->comment_date = '2019-10-15 16:13:13';
|
||||
$review->comment_date_gmt = '2019-10-15 16:13:13';
|
||||
$review->comment_content = 'Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cum sociis natoque penatibus et magnis dis parturient montes; nascetur ridiculus mus.';
|
||||
$review->comment_post_ID = $post->ID;
|
||||
$review->user_id = null;
|
||||
|
||||
return new WP_Comment( $review );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set global objects needed to manipulate `ETBuilderBackend.currentPage.woocommerceComponents` on
|
||||
* theme builder into displaying WooCommerce module placeholder (even though TB's CPT is not
|
||||
* WooCommerce's product CPT)
|
||||
*
|
||||
* @since 4.0.1
|
||||
*
|
||||
* @param array $conditional_tags evaluate conditional tags when current request is AJAX request
|
||||
*/
|
||||
function et_theme_builder_wc_set_global_objects( $conditional_tags = array() ) {
|
||||
$is_tb = et_()->array_get( $conditional_tags, 'is_tb', false );
|
||||
$is_use_placeholder = $is_tb || is_et_pb_preview();
|
||||
|
||||
// Check if current request is theme builder (direct page / AJAX request)
|
||||
if ( ! et_builder_tb_enabled() && ! $is_use_placeholder ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Global variable that affects WC module rendering
|
||||
global $product, $post, $tb_original_product, $tb_original_post, $tb_wc_post, $tb_wc_product;
|
||||
|
||||
// Making sure correct comment template is loaded on WC tabs' review tab
|
||||
add_filter( 'comments_template', array( 'ET_Builder_Module_Woocommerce_Tabs', 'comments_template_loader' ), 20 );
|
||||
|
||||
// Force display related posts; technically sets all products as related
|
||||
add_filter( 'woocommerce_product_related_posts_force_display', '__return_true' );
|
||||
|
||||
// Make sure review's form is opened
|
||||
add_filter( 'comments_open', '__return_true' );
|
||||
|
||||
// Save original $post for reset later
|
||||
$tb_original_post = $post;
|
||||
|
||||
// Save original $product for reset later
|
||||
$tb_original_product = $product;
|
||||
|
||||
// If modified global existed, use it for efficiency
|
||||
if ( ! is_null( $tb_wc_post ) && ! is_null( $tb_wc_product ) ) {
|
||||
$post = $tb_wc_post;
|
||||
$product = $tb_wc_product;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get placeholders
|
||||
$placeholders = et_theme_builder_wc_placeholders();
|
||||
|
||||
if ( $is_use_placeholder ) {
|
||||
$placeholder_src = wc_placeholder_img_src( 'full' );
|
||||
$placeholder_id = attachment_url_to_postid( $placeholder_src );
|
||||
|
||||
if ( absint( $placeholder_id ) > 0 ) {
|
||||
$placeholders['gallery_image_ids'] = array( $placeholder_id );
|
||||
}
|
||||
} else {
|
||||
$placeholders['gallery_image_ids'] = array();
|
||||
}
|
||||
|
||||
// $post might be null if current request is computed callback (ie. WC gallery)
|
||||
if ( is_null( $post ) ) {
|
||||
$post = new stdClass();
|
||||
}
|
||||
|
||||
// Overwrite $post global
|
||||
$post->post_title = $placeholders['title'];
|
||||
$post->post_slug = $placeholders['slug'];
|
||||
$post->post_excerpt = $placeholders['short_description'];
|
||||
$post->post_content = $placeholders['description'];
|
||||
$post->post_status = $placeholders['status'];
|
||||
$post->comment_status = $placeholders['comment_status'];
|
||||
|
||||
// Overwrite global $product
|
||||
$product = new ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder();
|
||||
|
||||
// Set current post ID as product's ID. `ET_Theme_Builder_Woocommerce_Product_Variable_Placeholder`
|
||||
// handles all placeholder related value but product ID need to be manually set to match current
|
||||
// post's ID. This is especially needed when add-ons is used and accessing get_id() method.
|
||||
if ( isset( $post->ID ) ) {
|
||||
$product->set_id( $post->ID );
|
||||
}
|
||||
|
||||
// Save modified global for later use
|
||||
$tb_wc_post = $post;
|
||||
$tb_wc_product = $product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset global objects needed to manipulate `ETBuilderBackend.currentPage.woocommerceComponents`
|
||||
*
|
||||
* @since 4.0.1
|
||||
* @since 4.14.5 Add conditional tags parameter to evaluate AJAX request.
|
||||
*
|
||||
* @param array $conditional_tags Evaluate conditional tags when current request is AJAX request.
|
||||
*/
|
||||
function et_theme_builder_wc_reset_global_objects( $conditional_tags = array() ) {
|
||||
$is_tb = et_()->array_get( $conditional_tags, 'is_tb', false );
|
||||
$is_use_placeholder = $is_tb || is_et_pb_preview();
|
||||
|
||||
// Check if current request is theme builder (direct page / AJAX request).
|
||||
if ( ! et_builder_tb_enabled() && ! $is_use_placeholder ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $product, $post, $tb_original_product, $tb_original_post;
|
||||
|
||||
remove_filter( 'comments_template', array( 'ET_Builder_Module_Woocommerce_Tabs', 'comments_template_loader' ), 20 );
|
||||
remove_filter( 'woocommerce_product_related_posts_force_display', '__return_true' );
|
||||
remove_filter( 'comments_open', '__return_true' );
|
||||
|
||||
$post = $tb_original_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Need override the post with the theme builder post.
|
||||
$product = $tb_original_product; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Need override the product with the theme builder product.
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify reviews output on WooCommerce's review and tabs' review module in TB
|
||||
*
|
||||
* @since 4.0.1
|
||||
*
|
||||
* @param array $comments
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function et_theme_builder_wc_set_review_objects( $comments ) {
|
||||
// Return early if it isn't theme builder
|
||||
if ( ! et_builder_tb_enabled() ) {
|
||||
return $comments;
|
||||
}
|
||||
|
||||
$placeholder = et_theme_builder_wc_review_placeholder();
|
||||
|
||||
// Add two placeholder reviews
|
||||
$comments = array(
|
||||
$placeholder,
|
||||
$placeholder,
|
||||
);
|
||||
|
||||
// When comment metadata is modified via `get_comment_metadata` filter, the $comment param
|
||||
// passed into template functions is int instead of WP_Comment object which triggers
|
||||
// `get_comment()` which triggers error because there's no real review/comment saved in database
|
||||
// to fix it, modify cache to short-circuit and prevent full `get_comment()` execution
|
||||
wp_cache_set( $placeholder->comment_ID, $placeholder, 'comment' );
|
||||
|
||||
return $comments;
|
||||
}
|
||||
|
||||
// Modify review output on WooCommerce Tabs module
|
||||
add_filter( 'comments_array', 'et_theme_builder_wc_set_review_objects' );
|
||||
|
||||
// Modify review output on WooCommerce Review module
|
||||
add_filter( 'the_comments', 'et_theme_builder_wc_set_review_objects' );
|
||||
|
||||
/**
|
||||
* Modify review rating output on WooCommerce review and tabs review module in TB
|
||||
*
|
||||
* @since 4.0.1
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param int $object_id
|
||||
* @param string $meta_key
|
||||
* @param bool $single
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function et_theme_builder_wc_set_review_metadata( $value, $object_id, $meta_key, $single ) {
|
||||
$is_tb = et_builder_tb_enabled();
|
||||
|
||||
// Modify rating metadata
|
||||
if ( $is_tb && 'rating' === $meta_key ) {
|
||||
global $product;
|
||||
return $product->get_average_rating();
|
||||
}
|
||||
|
||||
// Modify verified metadata
|
||||
if ( $is_tb && 'verified' === $meta_key ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
add_filter( 'get_comment_metadata', 'et_theme_builder_wc_set_review_metadata', 10, 4 );
|
||||
|
||||
/**
|
||||
* Filter `get_the_terms()` output for Theme Builder layout usage. `get_the_term()` is used for
|
||||
* product tags and categories in WC meta module and relies on current post's ID to output product's
|
||||
* tags and categories. In TB settings, post ID is irrelevant as the current layout can be used in
|
||||
* various pages. Thus, simply get the first tags and cats then output it for visual preview purpose
|
||||
*
|
||||
* @since 4.0.10
|
||||
*
|
||||
* @param WP_Term[]|WP_Error $terms Array of attached terms, or WP_Error on failure.
|
||||
* @param int $post_id Post ID.
|
||||
* @param string $taxonomy Name of the taxonomy.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
function et_theme_builder_wc_terms( $terms, $post_id, $taxonomy ) {
|
||||
// Only modify product_cat and product_tag taxonomies; This function is only called in TB's
|
||||
// woocommerceComponent output for current product setting
|
||||
if ( in_array( $taxonomy, array( 'product_cat', 'product_tag' ) ) && empty( $terms ) ) {
|
||||
$tags = get_categories( array( 'taxonomy' => $taxonomy ) );
|
||||
|
||||
if ( isset( $tags[0] ) ) {
|
||||
$terms = array( $tags[0] );
|
||||
}
|
||||
}
|
||||
|
||||
return $terms;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
* Disable language filtering of terms in TB.
|
||||
*
|
||||
* @since 4.2
|
||||
*
|
||||
* @param string $parent_id
|
||||
* @param string $child_type
|
||||
* @param string $child_value
|
||||
*/
|
||||
function et_theme_builder_wpml_disable_term_filters( $parent_id, $child_type, $child_value ) {
|
||||
global $sitepress;
|
||||
|
||||
if ( ! $sitepress || 'taxonomy' !== $child_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove_filter( 'terms_clauses', array( $sitepress, 'terms_clauses' ), 10 );
|
||||
remove_filter( 'get_terms_args', array( $sitepress, 'get_terms_args_filter' ), 10 );
|
||||
remove_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1 );
|
||||
}
|
||||
add_action( 'et_theme_builder_before_get_template_setting_child_options', 'et_theme_builder_wpml_disable_term_filters', 10, 3 );
|
||||
|
||||
/**
|
||||
* Enable language filtering of terms in TB.
|
||||
*
|
||||
* @since 4.2
|
||||
*
|
||||
* @param string $parent_id
|
||||
* @param string $child_type
|
||||
* @param string $child_value
|
||||
*/
|
||||
function et_theme_builder_wpml_enable_term_filters( $parent_id, $child_type, $child_value ) {
|
||||
global $sitepress;
|
||||
|
||||
if ( ! $sitepress || 'taxonomy' !== $child_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter( 'terms_clauses', array( $sitepress, 'terms_clauses' ), 10, 3 );
|
||||
add_filter( 'get_terms_args', array( $sitepress, 'get_terms_args_filter' ), 10, 2 );
|
||||
add_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1, 1 );
|
||||
}
|
||||
add_action( 'et_theme_builder_after_get_template_setting_child_options', 'et_theme_builder_wpml_enable_term_filters', 10, 3 );
|
||||
|
||||
/**
|
||||
* Normalize an object ID to it's base language ID if it is a translation.
|
||||
*
|
||||
* @since 4.2
|
||||
*
|
||||
* @param integer $id WPML object ID.
|
||||
* @param string $type Type.
|
||||
* @param string $subtype Subtype.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
function et_theme_builder_wpml_normalize_object_id( $id, $type, $subtype ) {
|
||||
return apply_filters( 'wpml_object_id', $id, $subtype, true );
|
||||
}
|
||||
add_filter( 'et_theme_builder_template_setting_filter_validation_id', 'et_theme_builder_wpml_normalize_object_id', 10, 3 );
|
||||
|
||||
/**
|
||||
* Prioritize IDs for the current active language over translated IDs
|
||||
* when comparing template settings priority.
|
||||
*
|
||||
* @since 4.2
|
||||
*
|
||||
* @param string $prioritized_setting Prioritized setting.
|
||||
* @param string $a First translated id.
|
||||
* @param string $b Second translated id.
|
||||
* @param ET_Theme_Builder_Request $request
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function et_theme_builder_wpml_prioritize_translated_id( $prioritized_setting, $a, $b, $request ) {
|
||||
$a_id = '';
|
||||
$a_id_translated = '';
|
||||
$b_id = '';
|
||||
$b_id_translated = '';
|
||||
$a_matches = array();
|
||||
$b_matches = array();
|
||||
|
||||
// Match singular:post_type:<post_type>:id:<id>
|
||||
$singular = '/^singular:post_type:([^:]+):id:(\d+)$/i';
|
||||
// Match singular:post_type:<post_type>:children:id:<id>
|
||||
$singular_children = '/^singular:post_type:([^:]+):children:id:(\d+)$/i';
|
||||
// Match singular:taxonomy:<taxonomy>:term:id:<id>
|
||||
$singular_term = '/^singular:taxonomy:([^:]+):term:id:(\d+)$/i';
|
||||
// Match archive:taxonomy:<taxonomy>:term:id:<id>
|
||||
$archive_term = '/^archive:taxonomy:([^:]+):term:id:(\d+)$/i';
|
||||
|
||||
if ( preg_match( $singular, $a, $a_matches ) && preg_match( $singular, $b, $b_matches ) ) {
|
||||
$a_id = (int) $a_matches[2];
|
||||
$a_id_translated = et_theme_builder_wpml_normalize_object_id( $a_id, 'post', $a_matches[1] );
|
||||
$b_id = (int) $b_matches[2];
|
||||
$b_id_translated = et_theme_builder_wpml_normalize_object_id( $b_id, 'post', $b_matches[1] );
|
||||
} elseif ( preg_match( $singular_children, $a, $a_matches ) && preg_match( $singular_children, $b, $b_matches ) ) {
|
||||
$a_id = (int) $a_matches[2];
|
||||
$a_id_translated = et_theme_builder_wpml_normalize_object_id( $a_id, 'post', $a_matches[1] );
|
||||
$b_id = (int) $b_matches[2];
|
||||
$b_id_translated = et_theme_builder_wpml_normalize_object_id( $b_id, 'post', $b_matches[1] );
|
||||
} elseif ( preg_match( $singular_term, $a, $a_matches ) && preg_match( $singular_term, $b, $b_matches ) ) {
|
||||
$a_id = (int) $a_matches[2];
|
||||
$a_id_translated = et_theme_builder_wpml_normalize_object_id( $a_id, 'taxonomy', $a_matches[1] );
|
||||
$b_id = (int) $b_matches[2];
|
||||
$b_id_translated = et_theme_builder_wpml_normalize_object_id( $b_id, 'taxonomy', $b_matches[1] );
|
||||
} elseif ( preg_match( $archive_term, $a, $a_matches ) && preg_match( $archive_term, $b, $b_matches ) ) {
|
||||
$a_id = (int) $a_matches[2];
|
||||
$a_id_translated = et_theme_builder_wpml_normalize_object_id( $a_id, 'taxonomy', $a_matches[1] );
|
||||
$b_id = (int) $b_matches[2];
|
||||
$b_id_translated = et_theme_builder_wpml_normalize_object_id( $b_id, 'taxonomy', $b_matches[1] );
|
||||
}
|
||||
|
||||
if ( $a_id && $a_id_translated && $a_id_translated === $a_id ) {
|
||||
// $a is an exact match for the current request and not a translated match so we prioritize it.
|
||||
return $a;
|
||||
}
|
||||
|
||||
if ( $b_id && $b_id_translated && $b_id_translated === $b_id ) {
|
||||
// $b is an exact match for the current request and not a translated match so we prioritize it.
|
||||
return $b;
|
||||
}
|
||||
|
||||
// Neither $a nor $b are exact matches so don't prioritize either.
|
||||
return $prioritized_setting;
|
||||
}
|
||||
add_filter( 'et_theme_builder_prioritized_template_setting', 'et_theme_builder_wpml_prioritize_translated_id', 10, 6 );
|
||||
Reference in New Issue
Block a user