✨feature: Initial commit
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
<?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' ), '.' );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user