shell bypass 403
<?php
/**
* Review block
*
* @package ThemeIsle\GutenbergBlocks\Render
*/
namespace ThemeIsle\GutenbergBlocks\Render;
use ThemeIsle\GutenbergBlocks\Pro;
/**
* Class Review_Block
*/
class Review_Block {
/**
* Static variable to track if the schema has already been added.
*
* This is used to prevent adding the same schema multiple times on the same page.
*
* @var array
*/
private static $added_schemas = array();
/**
* Block render function for server-side.
*
* This method will pe passed to the render_callback parameter and it will output
* the server side output of the block.
*
* @param array $attributes Blocks attrs.
* @return mixed|string
*/
public function render( $attributes ) {
if ( isset( $attributes['product'] ) && intval( $attributes['product'] ) >= 0 && Pro::is_pro_installed() && class_exists( 'WooCommerce' ) ) {
$attributes = apply_filters( 'otter_blocks_review_block_woocommerce', $attributes );
}
// Add a static variable to track if the schema has already been added.
if ( isset( $attributes['title'] ) && ! empty( $attributes['title'] ) && isset( $attributes['features'] ) && count( $attributes['features'] ) > 0 && get_option( 'themeisle_blocks_settings_disable_review_schema', true ) ) {
$post_id = get_the_ID();
add_action(
'wp_footer',
function() use ( $attributes, $post_id ) {
$added_schemas = &Review_Block::$added_schemas; // Reference the static property explicitly.
if ( ! isset( $added_schemas[ $post_id ] ) ) {
echo '<script type="application/ld+json">' . wp_json_encode( $this->get_json_ld( $attributes, $post_id ) ) . '</script>';
$added_schemas[ $post_id ] = true; // Mark schema as added for this post ID.
}
}
);
}
$id = isset( $attributes['id'] ) ? esc_attr( $attributes['id'] ) : 'wp-block-themeisle-blocks-review-' . wp_rand( 10, 100 );
$class = '';
$details_class = ( isset( $attributes['image'] ) && isset( $attributes['description'] ) && ! empty( $attributes['description'] ) ) ? '' : 'is-single ';
$scale = get_option( 'themeisle_blocks_settings_review_scale', false ) ? 2 : 1;
if ( ! ( ( isset( $attributes['pros'] ) && count( $attributes['pros'] ) > 0 ) || ( isset( $attributes['cons'] ) && count( $attributes['cons'] ) > 0 ) ) ) {
$class = 'no-pros-cons';
}
if ( ! ( isset( $attributes['links'] ) && count( $attributes['links'] ) > 0 ) ) {
$class .= ' no-footer';
}
$details_width = array(
25 => 'is-quarter',
50 => 'is-half',
100 => 'is-full',
);
$details_class .= isset( $attributes['imageWidth'] ) && 33 !== $attributes['imageWidth'] ? $details_width[ $attributes['imageWidth'] ] : '';
$wrapper_attributes = get_block_wrapper_attributes(
array(
'id' => $id,
'class' => $class,
)
);
$is_one_colum_layout = strpos( $wrapper_attributes, 'is-style-single-column' ) !== false;
$is_inline_features = strpos( $wrapper_attributes, 'is-style-inline-features' ) !== false;
$main_heading = isset( $attributes['mainHeading'] ) ? esc_attr( $attributes['mainHeading'] ) : 'h2';
$sub_heading = isset( $attributes['subHeading'] ) ? esc_attr( $attributes['subHeading'] ) : 'h3';
$html = '<div ' . $wrapper_attributes . '>';
$html .= ' <div class="o-review__header">';
if ( isset( $attributes['title'] ) && ! empty( $attributes['title'] ) ) {
$html .= '<' . $main_heading . '>' . esc_html( $attributes['title'] ) . '</' . $main_heading . '>';
}
$html .= ' <div class="o-review__header_meta">';
$html .= ' <div class="o-review__header_ratings">';
$html .= ' <div class="o-review__header_ratings__stars">';
$html .= $this->get_overall_stars( $this->get_overall_ratings( $attributes['features'] ), $scale );
$html .= ' </div>';
$html .= ' <span>' . sprintf(
// translators: %1$g is the overall rating, %2$g is the maximum rating.
__( '%1$g out of %2$g', 'otter-blocks' ),
$this->get_overall_ratings( $attributes['features'], $scale ),
10 / $scale
) . '</span>';
$html .= ' </div>';
if ( ( isset( $attributes['price'] ) && ! empty( $attributes['price'] ) ) || isset( $attributes['discounted'] ) ) {
$html .= ' <span class="o-review__header_price">';
if ( ( isset( $attributes['price'] ) && ! empty( $attributes['price'] ) ) && isset( $attributes['discounted'] ) ) {
$html .= ' <del>' . self::get_currency( isset( $attributes['currency'] ) ? $attributes['currency'] : 'USD' ) . esc_html( $attributes['price'] ) . '</del>';
}
$html .= self::get_currency( isset( $attributes['currency'] ) ? $attributes['currency'] : 'USD' ) . ( isset( $attributes['discounted'] ) ? $attributes['discounted'] : $attributes['price'] );
$html .= ' </span>';
}
$html .= ' </div>';
if ( ( isset( $attributes['image'] ) || ( isset( $attributes['description'] ) && ! empty( $attributes['description'] ) ) ) ) {
$html .= ' <div class="o-review__header_details ' . trim( esc_attr( $details_class ) ) . '">';
if ( isset( $attributes['image'] ) ) {
if ( isset( $attributes['image']['id'] ) && wp_attachment_is_image( $attributes['image']['id'] ) ) {
$html .= wp_get_attachment_image( $attributes['image']['id'], isset( $attributes['imageSize'] ) ? esc_attr( $attributes['imageSize'] ) : 'medium' );
} else {
$html .= ' <img src="' . esc_url( $attributes['image']['url'] ) . '" alt="' . esc_attr( $attributes['image']['alt'] ) . '"/>';
}
}
if ( isset( $attributes['description'] ) && ! empty( $attributes['description'] ) ) {
$html .= ' <p>' . wp_kses( $attributes['description'], array( 'br' => array() ) ) . '</p>';
}
$html .= ' </div>';
}
$html .= ' </div>';
$html .= ' <div class="o-review__left">';
if ( isset( $attributes['features'] ) && count( $attributes['features'] ) > 0 ) {
$html .= ' <div class="o-review__left_features">';
foreach ( $attributes['features'] as $feature ) {
$html .= ' <div class="o-review__left_feature">';
if ( isset( $feature['title'] ) ) {
$html .= ' <span class="o-review__left_feature_title">' . esc_html( $feature['title'] ) . '</span>';
}
$html .= ' <div class="o-review__left_feature_ratings">';
$html .= ' <div class="o-review__left_feature_ratings__stars">';
$html .= $this->get_overall_stars( $feature['rating'], $scale );
$html .= ' </div>';
$html .= ' <span class="o-review__left_feature_num">' . sprintf(
// translators: %1$g is the overall rating, %2$g is the maximum rating.
__( '%1$g out of %2$g', 'otter-blocks' ),
1 <= round( $feature['rating'] / $scale, 1 ) ? round( $feature['rating'] / $scale, 1 ) : 1,
10 / $scale
) . '</span>';
$html .= ' </div>';
if ( isset( $feature['description'] ) ) {
$html .= ' <span class="o-review__left_feature_description">' . esc_html( $feature['description'] ) . '</span>';
}
$html .= ' </div>';
}
$html .= ' </div>';
}
$html .= ' </div>';
if ( ( isset( $attributes['pros'] ) && count( $attributes['pros'] ) > 0 ) || ( isset( $attributes['cons'] ) && count( $attributes['cons'] ) > 0 ) ) {
$html .= ' <div class="o-review__right">';
if ( isset( $attributes['pros'] ) && count( $attributes['pros'] ) > 0 ) {
$html .= ' <div class="o-review__right_pros">';
if ( isset( $attributes['prosLabel'] ) && ! empty( $attributes['prosLabel'] ) ) {
$html .= ' <' . $sub_heading . '>' . esc_html( $attributes['prosLabel'] ) . '</' . $sub_heading . '>';
}
foreach ( $attributes['pros'] as $pro ) {
$html .= ' <div class="o-review__right_pros_item">';
$html .= ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.3 5.6L9.9 16.9l-4.6-3.4-.9 2.4 5.8 4.3 9.3-12.6z" /></svg>';
$html .= ' <p>' . esc_html( $pro ) . '</p>';
$html .= ' </div>';
}
$html .= ' </div>';
}
if ( isset( $attributes['cons'] ) && count( $attributes['cons'] ) > 0 ) {
$html .= ' <div class="o-review__right_cons">';
if ( isset( $attributes['consLabel'] ) && ! empty( $attributes['consLabel'] ) ) {
$html .= ' <' . $sub_heading . '>' . esc_html( $attributes['consLabel'] ) . '</' . $sub_heading . '>';
}
foreach ( $attributes['cons'] as $con ) {
$html .= ' <div class="o-review__right_cons_item">';
$html .= ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" /></svg>';
$html .= ' <p>' . esc_html( $con ) . '</p>';
$html .= ' </div>';
}
$html .= ' </div>';
}
$html .= ' </div>';
}
if ( isset( $attributes['links'] ) && count( $attributes['links'] ) > 0 ) {
$html .= ' <div class="o-review__footer">';
if ( isset( $attributes['buttonsLabel'] ) && ! empty( $attributes['buttonsLabel'] ) ) {
$html .= ' <' . $sub_heading . ' class="o-review__footer_label">' . esc_html( $attributes['buttonsLabel'] ) . '</' . $sub_heading . '>';
}
$html .= ' <div class="o-review__footer_buttons">';
foreach ( $attributes['links'] as $link ) {
$rel = ( isset( $link['isSponsored'] ) && true === $link['isSponsored'] ) ? 'sponsored' : 'nofollow';
$html .= ' <a href="' . esc_url( $link['href'] ) . '" rel="' . $rel . '" target="' . ( empty( $link['target'] ) ? '_blank' : esc_attr( $link['target'] ) ) . '">' . esc_html( $link['label'] ) . '</a>';
}
$html .= ' </div>';
$html .= ' </div>';
}
$html .= '</div>';
return wp_kses_post( $html );
}
/**
* Get overall ratings
*
* @param array $features An array of features.
* @param int $divide The scale of ratings.
*
* @return int
*/
public function get_overall_ratings( $features, $divide = 1 ) {
if ( count( $features ) <= 0 ) {
return 0;
}
$rating = array_reduce(
$features,
function( $carry, $feature ) {
$carry += $feature['rating'];
return $carry;
},
0
);
$rating = round( ( $rating / count( $features ) ) / $divide, 1 );
return 1 <= $rating ? $rating : 1;
}
/**
* Get overall ratings stars
*
* @param int $ratings Overall ratings of features.
* @param int $divide The scale of ratings.
*
* @return string
*/
public function get_overall_stars( $ratings = 0, $divide = 1 ) {
$stars = '';
for ( $i = 0; $i < 10 / $divide; $i++ ) {
$class = '';
if ( $i < round( $ratings / $divide ) ) {
$class = 'filled';
}
$stars .= '<svg xmlns="http://www.w3.org/2000/svg" class="' . esc_attr( $class ) . '" viewbox="0 0 24 24"><path d="M11.776 4.454a.25.25 0 01.448 0l2.069 4.192a.25.25 0 00.188.137l4.626.672a.25.25 0 01.139.426l-3.348 3.263a.25.25 0 00-.072.222l.79 4.607a.25.25 0 01-.362.263l-4.138-2.175a.25.25 0 00-.232 0l-4.138 2.175a.25.25 0 01-.363-.263l.79-4.607a.25.25 0 00-.071-.222L4.754 9.881a.25.25 0 01.139-.426l4.626-.672a.25.25 0 00.188-.137l2.069-4.192z" /></svg>';
}
return $stars;
}
/**
* Generate JSON-LD schema
*
* @param array $attributes Block attributes.
* @param int $post_id Post ID.
*
* @return array
*/
public function get_json_ld( $attributes, $post_id ) {
$json = array(
'@context' => 'https://schema.org/',
'@type' => 'Product',
'name' => esc_attr( $attributes['title'] ),
);
if ( isset( $attributes['image'] ) && isset( $attributes['image']['url'] ) ) {
$json['image'] = esc_url( $attributes['image']['url'] );
}
if ( isset( $attributes['description'] ) && ! empty( $attributes['description'] ) ) {
$json['description'] = esc_attr( $attributes['description'] );
}
$json['review'] = array(
'@type' => 'Review',
'reviewRating' => array(
'@type' => 'Rating',
'ratingValue' => $this->get_overall_ratings( $attributes['features'], 2 ),
'bestRating' => 5,
),
'author' => array(
'@type' => 'Person',
'name' => get_the_author_meta( 'display_name', intval( get_post_field( 'post_author', $post_id ) ) ),
),
);
if ( isset( $attributes['pros'] ) && count( $attributes['pros'] ) > 0 ) {
$count = 1;
$items = array();
foreach ( $attributes['pros'] as $pro ) {
$item = array(
'@type' => 'ListItem',
'position' => $count,
'name' => esc_html( $pro ),
);
$count++;
array_push( $items, $item );
}
$json['review']['positiveNotes'] = array(
'@type' => 'ItemList',
'itemListElement' => $items,
);
}
if ( isset( $attributes['cons'] ) && count( $attributes['cons'] ) > 0 ) {
$count = 1;
$items = array();
foreach ( $attributes['cons'] as $con ) {
$item = array(
'@type' => 'ListItem',
'position' => $count,
'name' => esc_html( $con ),
);
$count++;
array_push( $items, $item );
}
$json['review']['negativeNotes'] = array(
'@type' => 'ItemList',
'itemListElement' => $items,
);
}
if ( isset( $attributes['links'] ) && count( $attributes['links'] ) > 0 ) {
$offers = array();
foreach ( $attributes['links'] as $link ) {
if ( ! isset( $link['href'] ) || empty( $link['href'] ) ) {
continue;
}
if ( ! isset( $attributes['price'] ) && ! isset( $attributes['discounted'] ) ) {
continue;
}
$offer = array(
'@type' => 'Offer',
'url' => esc_url( $link['href'] ),
'priceCurrency' => isset( $attributes['currency'] ) ? esc_attr( $attributes['currency'] ) : 'USD',
'price' => isset( $attributes['discounted'] ) ? esc_attr( $attributes['discounted'] ) : esc_attr( $attributes['price'] ),
);
array_push( $offers, $offer );
}
if ( count( $offers ) > 1 ) {
$json['offers'] = $offers;
} elseif ( count( $offers ) === 1 ) {
$json['offers'] = $offers[0];
}
}
return apply_filters( 'otter_blocks_review_block_schema', $json, $attributes );
}
/**
* Get currency symbol
*
* @param string $currency Currency.
*
* @return string
*/
public static function get_currency( $currency = 'USD' ) {
$symbols = apply_filters(
'themeisle_gutenberg_currency_symbols',
array(
'AED' => 'د.إ',
'AFN' => '؋',
'ALL' => 'L',
'AMD' => 'AMD',
'ANG' => 'ƒ',
'AOA' => 'Kz',
'ARS' => '$',
'AUD' => '$',
'AWG' => 'Afl.',
'AZN' => 'AZN',
'BAM' => 'KM',
'BBD' => '$',
'BDT' => '৳ ',
'BGN' => 'лв.',
'BHD' => '.د.ب',
'BIF' => 'Fr',
'BMD' => '$',
'BND' => '$',
'BOB' => 'Bs.',
'BRL' => 'R$',
'BSD' => '$',
'BTC' => '฿',
'BTN' => 'Nu.',
'BWP' => 'P',
'BYR' => 'Br',
'BYN' => 'Br',
'BZD' => '$',
'CAD' => '$',
'CDF' => 'Fr',
'CHF' => 'CHF',
'CLP' => '$',
'CNY' => '¥',
'COP' => '$',
'CRC' => '₡',
'CUC' => '$',
'CUP' => '$',
'CVE' => '$',
'CZK' => 'Kč',
'DJF' => 'Fr',
'DKK' => 'DKK',
'DOP' => 'RD$',
'DZD' => 'د.ج',
'EGP' => 'EGP',
'ERN' => 'Nfk',
'ETB' => 'Br',
'EUR' => '€',
'FJD' => '$',
'FKP' => '£',
'GBP' => '£',
'GEL' => '₾',
'GGP' => '£',
'GHS' => '₵',
'GIP' => '£',
'GMD' => 'D',
'GNF' => 'Fr',
'GTQ' => 'Q',
'GYD' => '$',
'HKD' => '$',
'HNL' => 'L',
'HRK' => 'kn',
'HTG' => 'G',
'HUF' => 'Ft',
'IDR' => 'Rp',
'ILS' => '₪',
'IMP' => '£',
'INR' => '₹',
'IQD' => 'ع.د',
'IRR' => '﷼',
'IRT' => 'تومان',
'ISK' => 'kr.',
'JEP' => '£',
'JMD' => '$',
'JOD' => 'د.ا',
'JPY' => '¥',
'KES' => 'KSh',
'KGS' => 'сом',
'KHR' => '៛',
'KMF' => 'Fr',
'KPW' => '₩',
'KRW' => '₩',
'KWD' => 'د.ك',
'KYD' => '$',
'KZT' => '₸',
'LAK' => '₭',
'LBP' => 'ل.ل',
'LKR' => 'රු',
'LRD' => '$',
'LSL' => 'L',
'LYD' => 'ل.د',
'MAD' => 'د.م.',
'MDL' => 'MDL',
'MGA' => 'Ar',
'MKD' => 'ден',
'MMK' => 'Ks',
'MNT' => '₮',
'MOP' => 'P',
'MRU' => 'UM',
'MUR' => '₨',
'MVR' => '.ރ',
'MWK' => 'MK',
'MXN' => '$',
'MYR' => 'RM',
'MZN' => 'MT',
'NAD' => 'N$',
'NGN' => '₦',
'NIO' => 'C$',
'NOK' => 'kr',
'NPR' => '₨',
'NZD' => '$',
'OMR' => 'ر.ع.',
'PAB' => 'B/.',
'PEN' => 'S/',
'PGK' => 'K',
'PHP' => '₱',
'PKR' => '₨',
'PLN' => 'zł',
'PRB' => 'р.',
'PYG' => '₲',
'QAR' => 'ر.ق',
'RMB' => '¥',
'RON' => 'lei',
'RSD' => 'рсд',
'RUB' => '₽',
'RWF' => 'Fr',
'SAR' => 'ر.س',
'SBD' => '$',
'SCR' => '₨',
'SDG' => 'ج.س.',
'SEK' => 'kr',
'SGD' => '$',
'SHP' => '£',
'SLL' => 'Le',
'SOS' => 'Sh',
'SRD' => '$',
'SSP' => '£',
'STN' => 'Db',
'SYP' => 'ل.س',
'SZL' => 'L',
'THB' => '฿',
'TJS' => 'ЅМ',
'TMT' => 'm',
'TND' => 'د.ت',
'TOP' => 'T$',
'TRY' => '₺',
'TTD' => '$',
'TWD' => 'NT$',
'TZS' => 'Sh',
'UAH' => '₴',
'UGX' => 'UGX',
'USD' => '$',
'UYU' => '$',
'UZS' => 'UZS',
'VEF' => 'Bs F',
'VES' => 'Bs.S',
'VND' => '₫',
'VUV' => 'Vt',
'WST' => 'T',
'XAF' => 'CFA',
'XCD' => '$',
'XOF' => 'CFA',
'XPF' => 'Fr',
'YER' => '﷼',
'ZAR' => 'R',
'ZMW' => 'ZK',
)
);
$symbol = isset( $symbols[ $currency ] ) ? $symbols[ $currency ] : '$';
return $symbol;
}
}