189 lines
6.9 KiB
PHP
189 lines
6.9 KiB
PHP
<?php
|
|
/**
|
|
* Block registration.
|
|
*
|
|
* @package LogoSoup
|
|
*/
|
|
|
|
namespace LogoSoup\Blocks;
|
|
|
|
use LogoSoup\Plugin;
|
|
use LogoSoup\Settings;
|
|
use LogoSoup\Support\Logo_Sanitizer;
|
|
|
|
/**
|
|
* Registers and renders the Logo Soup block.
|
|
*/
|
|
class Logo_Soup_Block {
|
|
/**
|
|
* Register the block.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function register() {
|
|
register_block_type(
|
|
Plugin::asset_path( 'blocks/logo-soup/block.json' ),
|
|
array(
|
|
'render_callback' => array( __CLASS__, 'render' ),
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Render callback.
|
|
*
|
|
* @param array<string, mixed> $attributes Block attributes.
|
|
* @return string
|
|
*/
|
|
public static function render( $attributes ) {
|
|
$settings = Settings::get();
|
|
$logos = Logo_Sanitizer::sanitize_collection( isset( $attributes['logos'] ) ? $attributes['logos'] : array() );
|
|
$layout = isset( $attributes['layout'] ) ? sanitize_key( $attributes['layout'] ) : $settings['default_layout'];
|
|
$layout = in_array( $layout, array( 'carousel', 'grid' ), true ) ? $layout : $settings['default_layout'];
|
|
$speed = isset( $attributes['speed'] ) ? absint( $attributes['speed'] ) : (int) $settings['default_speed'];
|
|
$speed = max( 8, min( 80, $speed ) );
|
|
$grayscale = isset( $attributes['grayscale'] ) ? (bool) $attributes['grayscale'] : ! empty( $settings['default_gray'] );
|
|
$pause_on_hover = isset( $attributes['pauseOnHover'] ) ? (bool) $attributes['pauseOnHover'] : true;
|
|
$base_size = isset( $attributes['baseSize'] ) ? absint( $attributes['baseSize'] ) : (int) $settings['base_size'];
|
|
$base_size = max( 16, min( 160, $base_size ) );
|
|
$scale_factor = self::sanitize_float(
|
|
isset( $attributes['scaleFactor'] ) ? $attributes['scaleFactor'] : $settings['scale_factor'],
|
|
0.5,
|
|
0.1,
|
|
2
|
|
);
|
|
$density_aware = isset( $attributes['densityAware'] ) ? (bool) $attributes['densityAware'] : ! empty( $settings['density_aware'] );
|
|
$density_factor = self::sanitize_float(
|
|
isset( $attributes['densityFactor'] ) ? $attributes['densityFactor'] : $settings['density_factor'],
|
|
0.5,
|
|
0,
|
|
1
|
|
);
|
|
$crop_to_content = isset( $attributes['cropToContent'] ) ? (bool) $attributes['cropToContent'] : ! empty( $settings['crop_to_content'] );
|
|
$align_by = isset( $attributes['alignBy'] ) ? sanitize_key( $attributes['alignBy'] ) : $settings['align_by'];
|
|
$align_by = in_array( $align_by, array( 'bounds', 'visual-center', 'visual-center-x', 'visual-center-y' ), true ) ? $align_by : $settings['align_by'];
|
|
$open_new_tab = ! empty( $settings['open_new_tab'] );
|
|
$size_multiplier = 0.75 + ( $scale_factor * 0.5 );
|
|
$gap_multiplier = 1;
|
|
$width_factor = 3 + $scale_factor;
|
|
$opacity_floor = 0.72;
|
|
|
|
if ( $density_aware ) {
|
|
$size_multiplier += ( $density_factor * 0.35 );
|
|
$gap_multiplier = max( 0.7, 1 - ( $density_factor * 0.22 ) );
|
|
$width_factor += ( $density_factor * 0.6 );
|
|
$opacity_floor = max( 0.45, 0.78 - ( $density_factor * 0.18 ) );
|
|
}
|
|
|
|
$effective_size = (int) round( $base_size * $size_multiplier );
|
|
|
|
if ( empty( $logos ) ) {
|
|
return '';
|
|
}
|
|
|
|
$wrapper_classes = array( 'logo-soup', 'layout-' . $layout );
|
|
|
|
if ( $grayscale ) {
|
|
$wrapper_classes[] = 'is-grayscale';
|
|
}
|
|
|
|
if ( $pause_on_hover ) {
|
|
$wrapper_classes[] = 'pause-on-hover';
|
|
}
|
|
|
|
if ( $density_aware ) {
|
|
$wrapper_classes[] = 'is-density-aware';
|
|
}
|
|
|
|
if ( $crop_to_content ) {
|
|
$wrapper_classes[] = 'crop-to-content';
|
|
}
|
|
|
|
$wrapper_classes[] = 'align-by-' . $align_by;
|
|
|
|
$style = sprintf(
|
|
'--logo-soup-speed:%1$ds;--logo-soup-base-size:%2$dpx;--logo-soup-scale-factor:%3$s;--logo-soup-density-factor:%4$s;--logo-soup-effective-size:%5$dpx;--logo-soup-gap-factor:%6$s;--logo-soup-width-factor:%7$s;--logo-soup-gray-opacity:%8$s;',
|
|
$speed,
|
|
$base_size,
|
|
self::format_float( $scale_factor ),
|
|
self::format_float( $density_factor ),
|
|
$effective_size,
|
|
self::format_float( $gap_multiplier ),
|
|
self::format_float( $width_factor ),
|
|
self::format_float( $opacity_floor )
|
|
);
|
|
|
|
ob_start();
|
|
?>
|
|
<div
|
|
class="<?php echo esc_attr( implode( ' ', $wrapper_classes ) ); ?>"
|
|
style="<?php echo esc_attr( $style ); ?>"
|
|
data-base-size="<?php echo esc_attr( (string) $base_size ); ?>"
|
|
data-scale-factor="<?php echo esc_attr( self::format_float( $scale_factor ) ); ?>"
|
|
data-density-aware="<?php echo esc_attr( $density_aware ? 'true' : 'false' ); ?>"
|
|
data-density-factor="<?php echo esc_attr( self::format_float( $density_factor ) ); ?>"
|
|
data-crop-to-content="<?php echo esc_attr( $crop_to_content ? 'true' : 'false' ); ?>"
|
|
data-align-by="<?php echo esc_attr( $align_by ); ?>"
|
|
>
|
|
<div class="logo-soup__track">
|
|
<?php self::render_logo_items( $logos, $open_new_tab ); ?>
|
|
<?php if ( 'carousel' === $layout ) : ?>
|
|
<?php self::render_logo_items( $logos, $open_new_tab, true ); ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
|
|
return (string) ob_get_clean();
|
|
}
|
|
|
|
/**
|
|
* Render individual logo items.
|
|
*
|
|
* @param array<int, array<string, mixed>> $logos Logos.
|
|
* @param bool $open_new_tab Open in new tab.
|
|
* @param bool $duplicate Duplicate set.
|
|
* @return void
|
|
*/
|
|
private static function render_logo_items( array $logos, $open_new_tab, $duplicate = false ) {
|
|
foreach ( $logos as $index => $logo ) {
|
|
$tag = ! empty( $logo['link'] ) ? 'a' : 'div';
|
|
$href_attr = ! empty( $logo['link'] ) ? ' href="' . esc_url( $logo['link'] ) . '"' : '';
|
|
$rel_attr = ( ! empty( $logo['link'] ) && $open_new_tab ) ? ' rel="noreferrer noopener"' : '';
|
|
$target = ( ! empty( $logo['link'] ) && $open_new_tab ) ? ' target="_blank"' : '';
|
|
$key = $duplicate ? 'dup-' . $index : (string) $index;
|
|
?>
|
|
<<?php echo esc_html( $tag ); ?> class="logo-soup__item" data-key="<?php echo esc_attr( $key ); ?>"<?php echo $href_attr; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?><?php echo $target; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?><?php echo $rel_attr; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
|
|
<img class="logo-soup__image" src="<?php echo esc_url( $logo['url'] ); ?>" alt="<?php echo esc_attr( (string) $logo['alt'] ); ?>" loading="lazy" decoding="async" />
|
|
</<?php echo esc_html( $tag ); ?>>
|
|
<?php
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sanitize a float-like block attribute.
|
|
*
|
|
* @param mixed $value Value.
|
|
* @param float $fallback Fallback.
|
|
* @param float $min Minimum.
|
|
* @param float $max Maximum.
|
|
* @return float
|
|
*/
|
|
private static function sanitize_float( $value, $fallback, $min, $max ) {
|
|
$value = is_numeric( $value ) ? (float) $value : $fallback;
|
|
$value = max( $min, min( $max, $value ) );
|
|
|
|
return round( $value, 2 );
|
|
}
|
|
|
|
/**
|
|
* Format a float for HTML attributes and CSS variables.
|
|
*
|
|
* @param float $value Value.
|
|
* @return string
|
|
*/
|
|
private static function format_float( $value ) {
|
|
return rtrim( rtrim( number_format( $value, 2, '.', '' ), '0' ), '.' );
|
|
}
|
|
}
|