Files
roi-theme/wp-content/plugins/thrive-visual-editor/inc/classes/class-tcb-utils.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

943 lines
26 KiB
PHP
Executable File

<?php
/**
* Thrive Themes - https://thrivethemes.com
*
* @package thrive-visual-editor
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Silence is golden!
}
/**
* Class TCB_Utils
*/
class TCB_Utils {
/**
* Wrap content in tag with id and/or class
*
* @param $content
* @param string $tag
* @param string $id
* @param string|array $class
* @param array $attr
*
* @return string
*/
public static function wrap_content( $content, $tag = '', $id = '', $class = '', $attr = [] ) {
$class = is_array( $class ) ? trim( implode( ' ', $class ) ) : $class;
if ( empty( $tag ) && ! ( empty( $id ) && empty( $class ) ) ) {
$tag = 'div';
}
$attributes = '';
foreach ( $attr as $key => $value ) {
/* if the value is null, only add the key ( this is used for attributes that have no value, such as 'disabled', 'checked', etc ) */
if ( is_null( $value ) ) {
$attributes .= ' ' . $key;
} else {
$attributes .= ' ' . $key . '="' . esc_attr( $value ) . '"';
}
}
if ( ! empty( $tag ) ) {
$content = '<' . $tag . ( empty( $id ) ? '' : ' id="' . $id . '"' ) . ( empty( $class ) ? '' : ' class="' . $class . '"' ) . $attributes . '>' . $content . '</' . $tag . '>';
}
return $content;
}
/**
* Get all the banned post types for the post list/grid.
*
* @return mixed|void
*/
public static function get_banned_post_types() {
$banned_types = [
'attachment',
'revision',
'nav_menu_item',
'custom_css',
'customize_changeset',
'oembed_cache',
'project',
'et_pb_layout',
'tcb_lightbox',
'focus_area',
'thrive_optin',
'thrive_ad_group',
'thrive_ad',
'thrive_slideshow',
'thrive_slide_item',
'tve_lead_shortcode',
'tve_lead_2s_lightbox',
'tve_form_type',
'tve_lead_group',
'tve_lead_1c_signup',
TCB_CT_POST_TYPE,
'tcb_symbol',
'td_nm_notification',
];
/**
* Filter that other plugins can hook to add / remove ban types from post grid
*/
return apply_filters( 'tcb_post_grid_banned_types', $banned_types );
}
/**
* Get the image source for the id.
* This is used in TTB, don't delete it
*
* @param $image_id
* @param string $size
*
* @return mixed
*/
public static function get_image_src( $image_id, $size = 'full' ) {
$image_info = wp_get_attachment_image_src( $image_id, $size );
return empty( $image_info ) || empty( $image_info[0] ) ? '' : $image_info[0];
}
/**
* Get the pagination data that we want to localize.
*
* @return array
*/
public static function get_pagination_localized_data() {
$localized_data = [];
/* Apply a filter in case we want to add more pagination types from elsewhere. */
$all_pagination_types = apply_filters( 'tcb_post_list_pagination_types', TCB_Pagination::$all_types );
foreach ( $all_pagination_types as $type ) {
$instance = tcb_pagination( $type );
$localized_data[ $instance->get_type() ] = $instance->get_content();
}
/* we need this when we add new post lists to the page and they need a pagination element wrapper */
$localized_data['pagination_wrapper'] = tcb_pagination( TCB_Pagination::NONE )->render();
$localized_data['label_formats'] = array(
'pages' => tcb_template( 'pagination/label-pages.php', null, true ),
'posts' => tcb_template( 'pagination/label-posts.php', null, true ),
);
return $localized_data;
}
/**
* Adapt the pagination button component that inherits the button component by disabling some controls and adding new controls.
*
* @param $components
*
* @return mixed
*/
public static function get_pagination_button_config( $components ) {
$components['pagination_button'] = $components['button'];
unset( $components['button'] );
$all_controls = array_keys( $components['pagination_button']['config'] );
/* disable all the controls except the ones that we want to be enabled */
$disabled_controls = array_diff( $all_controls, [ 'MasterColor', 'icon_side' ] );
/* we have to add this manually */
$disabled_controls = array_merge( $disabled_controls, [ '.tcb-button-link-container' ] );
$components['pagination_button']['disabled_controls'] = array_values( $disabled_controls );
$components['pagination_button']['config']['icon_layout'] = array(
'config' => array(
'name' => __( 'Button Layout', 'thrive-cb' ),
'full-width' => true,
'buttons' => array(
array(
'value' => 'text',
'text' => __( 'Text Only', 'thrive-cb' ),
),
array(
'value' => 'icon',
'text' => __( 'Icon Only', 'thrive-cb' ),
),
array(
'value' => 'text_plus_icon',
'text' => __( 'Icon&Text', 'thrive-cb' ),
),
),
/* default is defined here so it can be overwritten by elements that inherit */
'default' => 'text',
),
'extends' => 'ButtonGroup',
);
$components['animation']['disabled_controls'] = [ '.btn-inline.anim-link', '.btn-inline.anim-popup' ];
/* add the root prefix in order to make this more specific than paragraph spacing settings from containers */
$components['layout']['config']['MarginAndPadding']['css_prefix'] = tcb_selection_root() . ' ';
$components['layout']['disabled_controls'] = [ 'Display', 'Alignment' ];
$components['scroll'] = [ 'hidden' => true ];
$components['responsive'] = [ 'hidden' => true ];
$components['shared-styles'] = [ 'hidden' => true ];
return $components;
}
/**
* Get the date/time format options for the wordpress date settings, and append a custom setting.
* Can return an associative array of key-value pairs, or multiple arrays of name/value.
*
* @param string $type
* @param bool $key_value_pairs
*
* @return array
*/
public static function get_post_date_format_options( $type = 'date', $key_value_pairs = false ) {
if ( $type === 'time' ) {
/**
* Filters the default time formats.
*
* @param string[] Array of default time formats.
*/
$formats = array_unique( apply_filters( 'time_formats', array( __( 'g:i a', 'thrive-cb' ), 'g:i A', 'H:i' ) ) );
} else {
/**
* Filters the default date formats.
*
* @param string[] Array of default date formats.
*/
$formats = array_unique( apply_filters( 'date_formats', array( __( 'F j, Y', 'thrive-cb' ), 'Y-m-d', 'm/d/Y', 'd/m/Y' ) ) );
}
$custom_option_name = __( 'Custom', 'thrive-cb' );
if ( $key_value_pairs ) {
foreach ( $formats as $format ) {
$options[ $format ] = get_the_time( $format );
}
$options['custom'] = $custom_option_name;
} else {
$options = array_map( function ( $format ) {
return array(
'name' => get_the_time( $format ),
'value' => $format,
);
}, $formats );
$options[] = [
'name' => $custom_option_name,
'value' => '',
];
}
return $options;
}
/**
* Get some inline shortcodes for the Pagination Label element.
*
* @return array
*/
public static function get_pagination_inline_shortcodes() {
return array(
'Post list pagination' => array(
array(
'option' => __( 'Current page number', 'thrive-cb' ),
'value' => 'tcb_pagination_current_page',
),
array(
'option' => __( 'Total number of pages', 'thrive-cb' ),
'value' => 'tcb_pagination_total_pages',
),
array(
'option' => __( 'Number of posts on this page', 'thrive-cb' ),
'value' => 'tcb_pagination_current_posts',
),
array(
'option' => __( 'Total number of posts', 'thrive-cb' ),
'value' => 'tcb_pagination_total_posts',
),
),
);
}
/**
* Get inline shortcodes for the Post List element.
*
* @return array
*/
public static function get_post_list_inline_shortcodes() {
$date_format_options = static::get_post_date_format_options( 'date', true );
$date_formats = array_keys( $date_format_options );
$time_format_options = static::get_post_date_format_options( 'time', true );
return array(
'Post' => array(
array(
'name' => __( 'Post title', 'thrive-cb' ),
'option' => __( 'Post title', 'thrive-cb' ),
'value' => 'tcb_post_title',
'input' => array(
'link' => array(
'type' => 'checkbox',
'label' => __( 'Link to post title', 'thrive-cb' ),
'value' => true,
),
'target' => array(
'type' => 'checkbox',
'label' => __( 'Open in new tab', 'thrive-cb' ),
'value' => false,
'disable_br' => true,
),
'rel' => array(
'type' => 'checkbox',
'label' => __( 'No follow', 'thrive-cb' ),
'value' => false,
),
),
),
array(
'name' => date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ),
'option' => __( 'Post date', 'thrive-cb' ),
'value' => 'tcb_post_published_date',
'input' => array(
'type' => array(
'type' => 'select',
'label' => __( 'Display', 'thrive-cb' ),
'value' => array(
'published' => __( 'Published date', 'thrive-cb' ),
'modified' => __( 'Modified date', 'thrive-cb' ),
),
),
'date-format-select' => array(
'type' => 'select',
'label' => __( 'Date format', 'thrive-cb' ),
'value' => $date_format_options,
),
'date-format' => array(
'type' => 'input',
'label' => __( 'Format string', 'thrive-cb' ),
'value' => $date_formats[0],
),
'show-time' => array(
'type' => 'checkbox',
'label' => __( 'Show time?', 'thrive-cb' ),
'value' => false,
),
'time-format-select' => array(
'type' => 'select',
'label' => __( 'Time format', 'thrive-cb' ),
'value' => $time_format_options,
),
'time-format' => array(
'type' => 'input',
'label' => __( 'Format string', 'thrive-cb' ),
'value' => '',
),
'link' => array(
'type' => 'checkbox',
'label' => __( 'Link to archive', 'thrive-cb' ),
'value' => false,
),
'target' => array(
'type' => 'checkbox',
'label' => __( 'Open in new tab', 'thrive-cb' ),
'value' => true,
'disable_br' => true,
),
'rel' => array(
'type' => 'checkbox',
'label' => __( 'No follow', 'thrive-cb' ),
'value' => false,
),
),
),
array(
'name' => __( 'Author name', 'thrive-cb' ),
'option' => __( 'Author name', 'thrive-cb' ),
'value' => 'tcb_post_author_name',
'input' => array(
'link' => array(
'type' => 'checkbox',
'label' => __( 'Link to author profile', 'thrive-cb' ),
'value' => false,
),
'target' => array(
'type' => 'checkbox',
'label' => __( 'Open in new tab', 'thrive-cb' ),
'value' => true,
'disable_br' => true,
),
'rel' => array(
'type' => 'checkbox',
'label' => __( 'No follow', 'thrive-cb' ),
'value' => false,
),
),
),
array(
'name' => __( 'Author role', 'thrive-cb' ),
'option' => __( 'Author role', 'thrive-cb' ),
'value' => 'tcb_post_author_role',
),
array(
'name' => __( 'Author bio', 'thrive-cb' ),
'option' => __( 'Author bio', 'thrive-cb' ),
'value' => 'tcb_post_author_bio',
),
array(
'name' => 24,
'option' => __( 'Number of comments', 'thrive-cb' ),
'value' => 'tcb_post_comments_number',
),
),
'Taxonomies' => array(
array(
'name' => __( 'Category-1, Category-2, Category-3', 'thrive-cb' ),
'option' => __( 'List of categories', 'thrive-cb' ),
'value' => 'tcb_post_categories',
'input' => array(
'link' => array(
'type' => 'checkbox',
'label' => __( 'Link to archive', 'thrive-cb' ),
'value' => true,
),
'target' => array(
'type' => 'checkbox',
'label' => __( 'Open in new tab', 'thrive-cb' ),
'value' => false,
'disable_br' => true,
),
'rel' => array(
'type' => 'checkbox',
'label' => __( 'No follow', 'thrive-cb' ),
'value' => false,
),
),
),
array(
'name' => __( 'Tag-1, Tag-2, Tag-3', 'thrive-cb' ),
'option' => __( 'List of tags', 'thrive-cb' ),
'value' => 'tcb_post_tags',
'input' => array(
'default' => array(
'type' => 'input',
'label' => __( 'Default value', 'thrive-cb' ),
'value' => '',
),
'link' => array(
'type' => 'checkbox',
'label' => __( 'Link to archive', 'thrive-cb' ),
'value' => true,
),
'target' => array(
'type' => 'checkbox',
'label' => __( 'Open in new tab', 'thrive-cb' ),
'value' => false,
'disable_br' => true,
),
'rel' => array(
'type' => 'checkbox',
'label' => __( 'No follow', 'thrive-cb' ),
'value' => false,
),
),
),
),
);
}
/**
* Return the post formats supported by the current theme.
*
* @return array|mixed
*/
public static function get_supported_post_formats() {
$post_formats = [];
if ( current_theme_supports( 'post-formats' ) ) {
$post_formats = get_theme_support( 'post-formats' );
if ( is_array( $post_formats[0] ) ) {
$post_formats = $post_formats[0];
}
}
return $post_formats;
}
/**
* Return the preview URL for this post( symbol or anything that has post meta ) ID along with height/width.
* If no URL is found, this can return a placeholder, if one was provided through the parameter.
*
* @param int $post_id
* @param string $sub_path
* @param array $placeholder_data
*
* @return array|mixed
*/
public static function get_thumb_data( $post_id, $sub_path, $placeholder_data = [] ) {
$upload_dir = wp_upload_dir();
$path = $sub_path . '/' . $post_id . '.png';
$thumb_path = static::get_uploads_path( $path, $upload_dir );
$thumb_url = trailingslashit( $upload_dir['baseurl'] ) . $path;
/* check if we have preview data in the post meta */
$thumb_data = static::get_thumbnail_data_from_id( $post_id );
/* if the post meta is empty, look inside the file and get the data directly from the it */
if ( empty( $thumb_data['url'] ) ) {
if ( file_exists( $thumb_path ) && ini_get( 'allow_url_fopen' ) ) {
list( $width, $height ) = getimagesize( $thumb_path );
$thumb_data = [
'url' => $thumb_url,
'h' => $height,
'w' => $width,
];
} else {
/* if no file is found and no placeholder is provided, return all the values set to blank */
if ( empty( $placeholder_data ) ) {
$thumb_data = [
'url' => '',
'h' => '',
'w' => '',
];
} else {
/* if a placeholder is provided, use it */
$thumb_data = $placeholder_data;
}
}
}
return $thumb_data;
}
/**
* Return the uploads physical path.
* Things can be appended to it by providing something in $path.
*
* @param string $path
* @param array $upload_dir
*
* @return string
*/
public static function get_uploads_path( $path = '', $upload_dir = [] ) {
if ( empty( $upload_dir ) ) {
$upload_dir = wp_upload_dir();
}
return trailingslashit( $upload_dir['basedir'] ) . $path;
}
/**
* Retrieve the image metadata for the provided post ID.
*
* @param $post_id
*
* @return array
*/
public static function get_thumbnail_data_from_id( $post_id ) {
return get_post_meta( $post_id, TCB_THUMBNAIL_META_KEY, true );
}
/**
* Set the image metadata for the provided post ID.
*
* @param $post_id
* @param $thumb_data
*/
public static function save_thumbnail_data( $post_id, $thumb_data ) {
update_post_meta( $post_id, TCB_THUMBNAIL_META_KEY, $thumb_data );
}
/**
* Check if we're inside the editor and filter the result.
*
* @param boolean $ajax_check
*
* @return mixed|void
*/
public static function in_editor_render( $ajax_check = false ) {
return apply_filters( 'tcb_in_editor_render', is_editor_page_raw( $ajax_check ) );
}
/**
* Check if we're in a REST request.
*
* @return bool
*/
public static function is_rest() {
return defined( 'REST_REQUEST' ) && REST_REQUEST;
}
/**
* Returns the content at the given path
* A more simpler and general version of tcb_template()
*
* @param string $full_path
*
* @return string
*/
public static function return_part( $full_path ) {
$content = '';
if ( file_exists( $full_path ) ) {
ob_start();
include $full_path;
$content = trim( ob_get_contents() );
ob_end_clean();
}
return $content;
}
/**
* parse and combine all font links => ensure a single request is sent out for a font
* Combines
*
* @import url("//fonts.googleapis.com/css?family=Muli:400,800,900,600&subset=latin");
* +
* @import url("//fonts.googleapis.com/css?family=Muli:400,900,600&subset=latin");
* into:
* @import url("//fonts.googleapis.com/css?family=Muli:400,600,800,900&subset=latin");
*
* @param array $imports
* @param string $return return type. Can be 'link' or 'import'
*
* @return array array of unique @import statements
*/
public static function merge_google_fonts( $imports, $return = 'import' ) {
return array_map( function ( $font_data ) use ( $return ) {
return TCB_Utils::build_font_string( $font_data, $return );
}, array_values( static::parse_css_imports( $imports ) ) );
}
/**
* Parses an array of CSS import statements and structures the data based on family and weights
* Merges all weights for a family
*
* @param array $imports
*
* @return array
*/
public static function parse_css_imports( $imports ) {
$data = [];
foreach ( array_unique( $imports ) as $import ) {
$font = static::parse_css_import( $import );
if ( ! isset( $data[ $font['family'] ] ) ) {
$data[ $font['family'] ] = $font;
} else {
$data[ $font['family'] ]['weights'] += $font['weights'];
}
}
return $data;
}
/**
* Parses an `@import` statement and generates an array containing useful data about the font (family, weights, subset etc)
* !!IMPORTANT: this only treats google fonts!!
*
* @param string $import import string
*
* @return array
*/
public static function parse_css_import( $import ) {
$data = [
'base_url' => '',
'family' => '',
'weights' => [],
'query' => [],
];
$import = str_replace( array( '"', "'", '@import url(', ')', ';' ), '', $import );
$result = parse_url( $import );
if ( $result ) {
$data['base_url'] = ( isset( $result['host'] ) ? 'https://' . $result['host'] : '' ) . $result['path'];
if ( ! empty( $result['query'] ) ) {
parse_str( $result['query'], $query );
list( $family, $weights ) = explode( ':', $query['family'] );
unset( $query['family'] );
$data['family'] = $family;
/* hold weights as keys, so it's less expensive to get unique weights */
$data['weights'] = array_flip( array_filter( explode( ',', $weights ), function ( $weight ) {
/**
* Preserve italic weights
*/
if ( substr( $weight, - 1 ) === 'i' ) {
$weight = substr( $weight, 0, - 1 );
}
return filter_var( $weight, FILTER_VALIDATE_INT );
} ) );
$data['query'] = $query;
}
}
return $data;
}
/**
* Builds an @import CSS rule based on $font_data
*
* @param array $font_data array in the form returned by self::parse_css_import
* @param string $return_type Controls the output. Can be 'link'/'url' or 'import'
*
* @return string
*/
public static function build_font_string( $font_data, $return_type = 'import' ) {
if ( empty( $font_data ) ) {
return '';
}
$font_data['query'] = array( 'family' => $font_data['family'] . ':' . implode( ',', array_keys( $font_data['weights'] ) ) ) + $font_data['query'];
/**
* https://web.dev/font-display/
* this ensures font is readable while external gfonts are loaded
*
*/
$font_data['query']['display'] = 'swap';
$result = $font_data['base_url'] . '?' . rawurldecode( http_build_query( $font_data['query'], '', '&' ) );
if ( $return_type === 'import' ) {
$result = '@import url("' . $result . '");';
}
return $result;
}
/**
* Create a rest nonce for our ajax requests
*
* @return mixed|void
*/
public static function create_nonce() {
return wp_create_nonce( 'wp_rest' );
}
/**
* Mark that we started processing custom CSS
*/
public static function before_custom_css_processing() {
$GLOBALS[ TVE_IS_PROCESSING_CUSTOM_CSS ] = true;
}
/**
* Mark that we finished processing custom CSS
*/
public static function after_custom_css_processing() {
$GLOBALS[ TVE_IS_PROCESSING_CUSTOM_CSS ] = false;
}
/**
* Check if we're currently processing CSS.
* Useful in shortcode handlers in case you want to see if the shortcode is called from CSS or HTML.
*
* @return bool
*/
public static function is_processing_custom_css() {
return ! empty( $GLOBALS[ TVE_IS_PROCESSING_CUSTOM_CSS ] );
}
/**
* If we're in a debug environment, we're not minifying JS files.
* The constant should be defined in the wp-config.php file
*
* @return string
*/
public static function get_js_suffix() {
return tve_dash_is_debug_on() ? '.js' : '.min.js';
}
/**
* Shortcut function that will output json encoded data or return it as it is based on the second parameter.
*
* @param mixed $data
* @param bool $output if true, it will use WordPress's wp_send_json to output data
*
* @return mixed
*/
public static function maybe_send_json( $data, $output = true ) {
if ( $output ) {
wp_send_json( $data );
} else {
return $data;
}
}
/**
* Write file using wordpress functionality
*
* @param $file
* @param string $content
* @param int $mode
*
* @return boolean
*/
public static function write_file( $file, $content = '', $mode = 0644 ) {
require_once( ABSPATH . 'wp-admin/includes/file.php' );
/* make sure that the FS_METHOD defaults to 'direct' so we use WP_Filesystem_direct in order to avoid the FTP implementations of put_contents */
defined( 'FS_METHOD' ) || define( 'FS_METHOD', 'direct' );
global $wp_filesystem;
return WP_Filesystem() && $wp_filesystem->put_contents( $file, $content, $mode );
}
/**
* Restore some fields of the $_POST data that have been previously replaced from javascript
* Wordfence blocks certain strings in POST - these are replaced from javascript before sending the ajax request to some equivalents
* Currently, this method handles:
* - <svg and </svg> ( these are replaced from javascript into <_wafsvg_ and </_wafsvg )
*/
public static function restore_post_waf_content() {
/**
* Filter the list of fields that should be processed
*
* @param array $field_list
*/
$field_list = apply_filters( 'tcb_waf_fields_restore', [
'template',
'template_content',
'tve_content',
'tve_stripped_content',
'symbol_content',
] );
/* map of search_string => replace_string */
$replace_map = [
'_wafsvg_' => 'svg',
];
$search = array_keys( $replace_map );
$replace = array_values( $replace_map );
foreach ( $field_list as $field ) {
if ( ! empty( $_POST[ $field ] ) && is_string( $_POST[ $field ] ) ) {
$_POST[ $field ] = str_replace( $search, $replace, $_POST[ $field ] );
}
}
}
/**
* @return string[]
*/
public static function get_api_list_with_tag_support() {
$apis_that_support_tags = [ 'activecampaign', 'aweber', 'convertkit', 'drip', 'klicktipp', 'mailchimp', 'sendlane', 'zapier' ];
return apply_filters( 'tcb_lead_generation_apis_with_tag_support', $apis_that_support_tags );
}
/**
* Get some values from the queried object.
*
* @return array
*/
public static function get_filtered_queried_object() {
$queried_object = get_queried_object();
$qo = [];
if ( $queried_object ) {
/* when we're using demo content the $queried_object can get weird, so check stuff before using it */
if (
property_exists( $queried_object, 'data' )
&& property_exists( $queried_object->data, 'ID' )
&&
! empty( $queried_object->data->ID )
) {
$qo ['ID'] = $queried_object->data->ID;
} elseif ( property_exists( $queried_object, 'ID' ) && ! empty( $queried_object->ID ) ) {
$qo ['ID'] = $queried_object->ID;
}
/* only keep the values for the specified keys */
$qo = array_filter( (array) $queried_object, function ( $key ) {
return in_array( $key, [ 'post_author', 'taxonomy', 'term_id', 'ID' ] );
}, ARRAY_FILTER_USE_KEY );
}
/**
* Filters the queried object needed in the frontend localization (used in generating "Edit with TTB" links that will show the same content)
*
* @param array $qo associative array the should have at least an `ID` key
*/
return apply_filters( 'tcb_frontend_queried_object', $qo );
}
/**
* @return string
*/
public static function get_placeholder_url() {
return tve_editor_url( 'admin/assets/images/no-template-preview.jpg' );
}
/**
* Get placeholder information for the template preview
*
* @return array
*/
public static function get_placeholder_data() {
return [
'url' => static::get_placeholder_url(),
/* hardcoded sizes taken from 'no-template-preview.jpg' */
'h' => '120',
'w' => '250',
];
}
/**
* Used to hide elements on certain post types, called in hide() method from element classes
*
* @return bool
*/
public static function should_hide_element_on_blacklisted_post_types() {
$blacklisted_post_types = static::get_banned_post_types();
$blacklisted_post_types = array_diff( $blacklisted_post_types, [ 'tcb_symbol' ] );
return in_array( get_post_type( get_the_ID() ), $blacklisted_post_types );
}
/**
* Get TVA_Order using product ID and user ID.
*
* @param int $product_id
* @param int $user_id
*
* @return TVA_Order|null
*/
public static function get_tva_order_by_product_and_user( $product_id, $user_id ) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT id FROM {$wpdb->prefix}tva_orders
WHERE user_id = %d
AND ID IN (SELECT order_id FROM {$wpdb->prefix}tva_order_items WHERE product_id = %d)
AND status = 1",
$user_id, $product_id
);
$order_id = $wpdb->get_results( $query );
// Check if an order ID was found then return the TVA_Order object.
if ( ! empty( $order_id ) && ! empty( $order_id[0] ) ) {
return new TVA_Order( (int) $order_id[0]->id );
}
return null;
}
}