Files
roi-theme/wp-content/plugins/thrive-visual-editor/inc/classes/logo/class-tcb-logo.php
root a22573bf0b Commit inicial - WordPress Análisis de Precios Unitarios
- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 21:04:30 -06:00

515 lines
15 KiB
PHP
Executable File

<?php
/**
* Thrive Themes - https://thrivethemes.com
*
* @package thrive-visual-editor
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Silence is golden!
}
defined( 'TCB_TABLET_THRESHOLD' ) || define( 'TCB_TABLET_THRESHOLD', 768 );
defined( 'TCB_DESKTOP_THRESHOLD' ) || define( 'TCB_DESKTOP_THRESHOLD', 1024 );
/**
* Class TCB_Logo
*
* Implementation of the Logo Element, featuring image optimization and art direction with the <picture> tag - load multiple image versions depending on the device type.
*/
class TCB_Logo {
/* component name */
const COMPONENT = 'logo';
/* identifier used as a class name */
const IDENTIFIER = 'tcb-logo';
/* shortcode tag in which the logo HTML is wrapped */
const SHORTCODE_TAG = 'tcb_logo';
/* name of the option in the DB where the logo data is stored */
const OPTION_NAME = 'tcb_logo_data';
const DELETED_PLACEHOLDER_SRC = 'editor/css/images/logo_deleted_placeholder.png';
/* list of devices that can have their own logo images ( desktop, tablet, mobile were shortened like this in order to work with mediaAttr() in JS ) */
private static $all_devices = [ 'd', 't', 'm' ];
/**
* TCB_Logo constructor.
*/
public function __construct() {
$this->hooks();
}
/**
* Add actions and filters.
*/
private function hooks() {
add_action( 'init', [ $this, 'init_shortcode' ] );
add_filter( 'tcb_main_frame_localize', [ $this, 'add_localize_params' ] );
add_filter( 'tcb_content_allowed_shortcodes', [ $this, 'tcb_content_allowed_shortcodes' ] );
}
/**
* Add data to the main frame localize parameters.
*
* @param $data
*
* @return mixed
*/
public function add_localize_params( $data ) {
$logos = static::get_logos();
$active_logos = array_filter( $logos, function ( $logo ) {
return (int) $logo['active'] === 1;
} );
/* get the src for each attachment ID */
foreach ( $active_logos as $key => $logo ) {
$logo_data = static::get_attachment_data( $logo['id'], $logo );
$active_logos[ $key ]['src'] = $logo_data['src'];
$active_logos[ $key ]['width'] = $logo_data['width'];
$active_logos[ $key ]['height'] = $logo_data['height'];
$active_logos[ $key ]['data-alt'] = empty( $logo_data['data-alt'] ) ? '' : $logo_data['data-alt'];
}
$data['logo'] = array(
'routes' => array(
'base' => get_rest_url( get_current_blog_id(), 'tcb/v1/logo' ),
'rename_logo' => get_rest_url( get_current_blog_id(), 'tcb/v1/logo/rename_logo' ),
),
/* only localize the active logos */
'sources' => array_values( $active_logos ),
'deleted_placeholder' => tve_editor_url( static::DELETED_PLACEHOLDER_SRC ),
'is_ttb_active' => tve_dash_is_ttb_active(),
'is_ta_active' => tve_dash_is_plugin_active( 'thrive-apprentice' ),
);
return $data;
}
/**
* Render the element. Inside the editor, render a simplified version without responsive stuff.
* On the frontend, render a <source> tag for each logo chosen for a responsive device screen.
*
* @param array $attr
* @param bool $render_fallback
*
* @return string
*/
public static function render_logo( $attr = [], $render_fallback = false ) {
/* if the desktop logo ID is not set, use id = 0 as default and set it in the attr */
if ( ! isset( $attr['data-id-d'] ) ) {
$attr['data-id-d'] = 0;
}
$desktop_id = (int) $attr['data-id-d'];
$logos = static::get_logos();
/* set the desktop source as a fallback; get only the src here, since this is an all-browser compatible version */
$fallback_data = static::get_attachment_data( $desktop_id, isset( $logos[ $desktop_id ] ) ? $logos[ $desktop_id ] : null );
/* If we do not have alt in attr, we read it from fallback data */
if ( empty( $attr['data-alt'] ) ) {
$attr['data-alt'] = empty( $fallback_data['data-alt'] ) ? '' : $fallback_data['data-alt'];
}
$img_attr = array(
'src' => $fallback_data['src'],
'height' => $fallback_data['height'],
'width' => $fallback_data['width'],
'alt' => $attr['data-alt'],
'style' => ! empty( $attr['data-img-style'] ) ? $attr['data-img-style'] : '',
);
/**
* Handle logo image loading
*/
if ( isset( $attr['loading'] ) ) {
$img_attr['loading'] = $attr['loading'];
unset( $attr['loading'] );
} else {
$img_attr['class'] = 'tve-not-lazy-loaded';
}
/* GIFs aren't compatible with srcset, so we use the fallback version */
if ( ! empty( $img_attr['src'] ) && substr( $img_attr['src'], - 4 ) === '.gif' ) {
$render_fallback = true;
}
/* in the editor or when doing ajax ( when the logo is in a symbol ) or when doing rest ( when you add new headers/footers and start from cloud templates ) or when we set a flag, return the desktop src only */
if ( TCB_Utils::in_editor_render() || wp_doing_ajax() || TCB_Utils::is_rest() || $render_fallback ) {
$content = TCB_Utils::wrap_content( '', 'img', '', '', $img_attr );
} else {
/* if the fallback data is empty and we're outside the editor, return an empty string ( this case happens when the logo was deleted ) */
if ( empty( $fallback_data['src'] ) ) {
$content = '';
} else {
$content = static::get_picture_element( $attr, $img_attr );
}
}
$logo_url = apply_filters( 'tcb_logo_site_url', '' );
/* We have to process the shortcode here because we cannot send it as a param inside another shortcode ( logo ) */
if ( ! empty( $attr['data-dynamic-link'] ) ) {
$shortcode = "{$attr['data-dynamic-link']} id={$attr['data-shortcode-id']}";
if ( ! empty( $attr['data-custom-redirect'] ) ) {
$shortcode .= " logout-redirect={$attr['data-custom-redirect']}";
}
$attr['href'] = do_shortcode( "[{$shortcode}]" );
}
/* embed the img in a link instead of wrapping it in a div (if an url exists) */
if ( empty( $attr['href'] ) ) {
if ( empty( $logo_url ) || ! empty( $attr['data-remove-href'] ) ) {
unset( $attr['href'] );
} else {
$attr['href'] = $logo_url;
}
}
$href = isset( $attr['href'] ) ? $attr['href'] : '';
/**
* Allows filtering the final value of the `href` logo attribute
*
* @param string $href current url
* @param array $attr array of shortcode attributes
*/
$href = apply_filters( 'tcb_logo_url', $href, $attr );
if ( ! empty( $href ) ) {
$attr['href'] = $href;
}
return TCB_Utils::wrap_content( $content, 'a', '', static::get_classes( $attr ), static::get_attr( $attr ) );
}
/**
* Get the picture element containing the sources. ( For info on how this works, see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture )
*
* @param array $attr
* @param array $img_attr
*
* @return string
*/
public static function get_picture_element( $attr, $img_attr ) {
$picture_content = '';
foreach ( static::$all_devices as $device ) {
if ( isset( $attr[ 'data-id-' . $device ] ) ) {
$id = (int) $attr[ 'data-id-' . $device ];
$media_attr = [
'srcset' => static::get_srcset( $id ),
];
/* add media rules to restrict where each source is displayed */
switch ( $device ) {
case 'd':
$media_attr['media'] = '(min-width:' . TCB_DESKTOP_THRESHOLD . 'px)';
break;
case 't':
$media_attr['media'] = '(min-width:' . TCB_TABLET_THRESHOLD . 'px) and (max-width:' . TCB_DESKTOP_THRESHOLD . 'px)';
break;
case 'm':
$media_attr['media'] = '(max-width:' . ( TCB_TABLET_THRESHOLD - 1 ) . 'px)';
break;
default:
break;
}
$picture_content .= TCB_Utils::wrap_content( '', 'source', '', '', $media_attr );
}
}
/* add the fallback img */
$picture_content .= TCB_Utils::wrap_content( '', 'img', '', '', $img_attr );
/* wrap it in the <picture> tag and return */
return TCB_Utils::wrap_content( $picture_content, 'picture' );
}
/**
* Get all the attachment data for this logo ID. If the logo ID is not found or we don't have an attachment ID, return placeholder data instead.
*
* @param int $id
* @param array $logo
*
* @return array
*/
public static function get_attachment_data( $id, $logo = null ) {
$attachment_id = static::get_attachment_id( $id );
if ( empty( $attachment_id ) ) {
/* get the placeholder for this id ( it can differ depending on the ID : 0 and 1 have their own placeholder ) */
$data = static::get_placeholder_data( $id, $logo );
} else {
$attachment_data = wp_get_attachment_image_src( $attachment_id, 'full' );
if ( empty( $attachment_data[0] ) ) {
$data = static::get_placeholder_data( $id );
} else {
$data = array(
'src' => $attachment_data[0],
'width' => $attachment_data[1],
'height' => $attachment_data[2],
'data-alt' => trim( strip_tags( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) ),
);
}
}
return $data;
}
/**
* For the given logo ID, look for the attachment ID and return it. If it's not found, return null.
*
* @param int $id
*
* @return mixed|null
*/
public static function get_attachment_id( $id ) {
$logos = static::get_logos();
$index = - 1;
/* look for the logo ID in the array of logo data */
foreach ( $logos as $key => $logo_data ) {
if ( $id === $logo_data['id'] ) {
$index = $key;
break;
}
}
$attachment_id = null;
/* if the logo ID was not found, render the placeholder */
if ( $index !== - 1 ) {
/* if we found the key for the logo ID, get the src */
$logo_data = $logos[ $index ];
/* if the logo is active or it's light or dark, start looking for the image ID */
if ( $logo_data['active'] || $id === 0 || $id === 1 ) {
if ( ! empty( $logo_data['attachment_id'] ) ) {
$attachment_id = $logo_data['attachment_id'];
}
}
}
return $attachment_id;
}
/**
* Get the image source for this logo ID. It can be a placeholder too
*
* @param $id
*
* @return mixed
*/
public static function get_src( $id ) {
$attachment_data = static::get_attachment_data( $id );
return $attachment_data['src'];
}
/**
* Get the srcset attribute for this logo ID. If empty, return the normal source instead.
*
* @param $id
*
* @return bool|mixed|string
*/
public static function get_srcset( $id ) {
$attachment_id = static::get_attachment_id( $id );
if ( ! empty( $attachment_id ) ) {
/* get the full srcset so the browser can pick the best image size for the current screen */
$srcset = wp_get_attachment_image_srcset( $attachment_id );
}
if ( empty( $srcset ) ) {
/* if the srcset is empty (this happens for SVGs and for small images) or we don't want the srcset, get the src instead */
$srcset = static::get_src( $id );
}
return $srcset;
}
/**
* Return the placeholder data according to the ID.
* For id = 0 or 1, return the light/dark placeholder, for any other ID, return a 'logo has been deleted' placeholder.
*
* @param int $id
* @param array $logo
*
* @return array
*/
public static function get_placeholder_data( $id, $logo = null ) {
$data = [
'height' => '',
'width' => '',
];
$is_default_logo = ! empty( $logo ) && isset( $logo['scope'] ) && $logo['scope'] === 'tva';
if ( $id === 0 || ( $is_default_logo && $logo['name'] === 'Dark' ) ) {
$data['src'] = tve_editor_url( 'editor/css/images/logo_placeholder_dark.svg' );
} elseif ( $id === 1 || ( $is_default_logo && $logo['name'] === 'Light' ) ) {
$data['src'] = tve_editor_url( 'editor/css/images/logo_placeholder_light.svg' );
} else {
/* If we're in the editor, render a <logo image deleted> image. On the frontend, leave it blank. */
$data['src'] = TCB_Utils::in_editor_render() ? tve_editor_url( static::DELETED_PLACEHOLDER_SRC ) : '';
}
$data['is_placeholder'] = 1;
return $data;
}
/**
* Get the src directly ( called from TTB )
*
* @param int $id
*
* @return mixed
*/
public static function get_placeholder_src( $id = 0 ) {
$data = static::get_placeholder_data( $id );
return $data['src'];
}
/**
* Add the two initial logos and their placeholders ( these exist without having to be added manually and cannot be deleted ).
*
* @return array
*/
public static function initialize_default_logos() {
$logos = [
0 => [
'id' => 0,
'attachment_id' => '',
'active' => 1,
'default' => 1,
'name' => 'Dark',
],
1 => [
'id' => 1,
'attachment_id' => '',
'active' => 1,
'default' => 1,
'name' => 'Light',
],
];
/* update inside the DB */
update_option( static::OPTION_NAME, $logos );
return $logos;
}
/**
* Get the logo data. ( get_option() is cached, so it's ok to call this lots of times ).
*
* @param bool $apply_filter
*
* @return mixed|void
*/
public static function get_logos( $apply_filter = true ) {
$logos = get_option( static::OPTION_NAME );
/* if the option is empty, then we have to initialize the logo array with the default values */
if ( empty( $logos ) ) {
/* initialize the default logos */
$logos = static::initialize_default_logos();
}
if ( $apply_filter ) {
/**
* Allow other plugins to alter the logo list.
* Used in Thrive Apprentice plugin to modify the default light and dark logo when the system edits an apprentice page
*/
$logos = apply_filters( 'tcb_get_logos', $logos );
}
return $logos;
}
/**
* @param $attr
*
* @return string
*/
private static function get_classes( $attr ) {
$class = [ static::IDENTIFIER, THRIVE_WRAPPER_CLASS ];
/* set responsive/animation classes, if they are present */
if ( ! empty( $attr['class'] ) ) {
$class[] = $attr['class'];
}
return implode( ' ', $class );
}
/**
* @param $attr
*
* @return array
*/
private static function get_attr( $attr ) {
/* if we're not in the editor or not doing ajax ( for symbols ), remove the logo ID dataset */
if ( ! TCB_Utils::in_editor_render() && ! wp_doing_ajax() ) {
foreach ( static::$all_devices as $device ) {
unset( $attr[ 'data-id-' . $device ] );
}
}
/* we don't need to save this since it's stored in the image */
unset( $attr['data-alt'] );
return $attr;
}
/**
* Add the logo shortcode.
*/
public function init_shortcode() {
add_shortcode( static::SHORTCODE_TAG, function ( $attr, $content, $tag ) {
/**
* Ability to modify logo attributes before render.
*
* Used in thrive apprentice to modify the image URL for apprentice pages
*
* @param array $attributes
*/
$attr = apply_filters( 'tcb_logo_attributes', TCB_Post_List_Shortcodes::parse_attr( $attr, $tag ) );
return TCB_Logo::render_logo( $attr );
} );
}
/**
* We need to add our shortcodes to this array in order for them to be processed in the editor.
* If we're on the frontend, we don't have to do this.
*
* @param $shortcodes
*
* @return array
*/
public function tcb_content_allowed_shortcodes( $shortcodes ) {
if ( is_editor_page_raw( true ) ) {
$shortcodes = array_merge( $shortcodes, [ static::SHORTCODE_TAG ] );
}
return $shortcodes;
}
/**
* Register REST Routes for the Logo.
*/
public static function rest_api_init() {
require_once TVE_TCB_ROOT_PATH . 'inc/classes/logo/class-tcb-logo-rest.php';
}
}
new TCB_Logo();