` die het thema * met de hand schrijft, of een CSS-background in plaats van een ``. * 2. Er staat geen focuspunt op die afbeelding. * 3. Het beeldformaat is hard gecropt, dus we blijven er expres af. * 4. We passen het wél toe, maar het thema cropt de afbeelding helemaal niet * (`object-fit` staat op `fill`), dus er valt niets te verschuiven. * * Zonder deze administratie is dat op een vreemde site niet uit elkaar te * houden. Met deze administratie staat het antwoord in de adminbalk. * * Het journaal wordt alleen bijgehouden als er een redacteur meekijkt. Voor een * bezoeker bestaat het niet en kost het niets. * * @package Yinga\Focus */ declare( strict_types = 1 ); namespace Yinga\Focus\Frontend; defined( 'ABSPATH' ) || exit; final class Journal { /** Toegepast: de afbeelding heeft het focuspunt gekregen. */ public const APPLIED = 'applied'; /** Deels: er stond al een object-position, die hebben we laten staan. */ public const PARTIAL = 'partial'; /** Geen focuspunt ingesteld op deze afbeelding. */ public const NO_DATA = 'no-data'; /** Hard formaat, nog vanuit het midden gesneden (focuspunt van vóór v0.8). */ public const HARD_CROP = 'hard-crop'; /** Hard formaat, en het bestand zelf is rond het focuspunt gesneden. */ public const FILE_CROP = 'file-crop'; /** De instelling staat uit. */ public const OFF = 'off'; /** Een filter van het thema of een andere plugin zei nee. */ public const FILTERED = 'filtered'; /** Toegepast op een CSS-achtergrond. */ public const BG_APPLIED = 'bg-applied'; /** Een CSS-achtergrond gevonden, maar de optie daarvoor staat uit. */ public const BG_FOUND = 'bg-found'; /** Toegepast op een Elementor-achtergrond. */ public const EL_APPLIED = 'el-applied'; /** Elementor-achtergrond gevonden, maar hij staat niet op Cover of Contain. */ public const EL_SIZE = 'el-size'; /** * @var array> Attachment-ID => verdict => aantal. */ private array $entries = array(); /** * @var array Attachment-ID => de waarde die we hebben gezet. * * Puur voor het rapport: "toegepast" is een bewering, "toegepast (62% 28%)" * is te controleren. */ private array $details = array(); private bool $active = false; /** * Zet het journaal aan. Zonder dit wordt er niets bijgehouden. */ public function activate(): void { $this->active = true; } /** * @return bool */ public function active(): bool { return $this->active; } /** * Legt één beslissing vast. * * @param int $attachment_id Attachment-ID. * @param string $verdict Een van de constanten hierboven. * @param string $detail De gezette waarde, bijvoorbeeld "62% 28%". */ public function record( int $attachment_id, string $verdict, string $detail = '' ): void { if ( ! $this->active || $attachment_id <= 0 ) { return; } if ( '' !== $detail ) { $this->details[ $attachment_id ] = $detail; } if ( ! isset( $this->entries[ $attachment_id ][ $verdict ] ) ) { $this->entries[ $attachment_id ][ $verdict ] = 0; } ++$this->entries[ $attachment_id ][ $verdict ]; } /** * Alles wat er langskwam. * * @return array> */ public function entries(): array { return $this->entries; } /** * De gezette waarde per afbeelding, voor zover er een was. * * @param int $attachment_id Attachment-ID. * @return string */ public function detail( int $attachment_id ): string { return $this->details[ $attachment_id ] ?? ''; } /** * De samenvatting. * * Een afbeelding telt als geslaagd zodra ze op deze pagina minstens één keer * is behandeld; dezelfde foto kan immers in een thumbnail worden * overgeslagen en in de hero wél gezet worden. * * @return array{seen: int, applied: int, skipped: int} */ public function totals(): array { $applied = 0; foreach ( $this->entries as $verdicts ) { if ( isset( $verdicts[ self::APPLIED ] ) || isset( $verdicts[ self::PARTIAL ] ) || isset( $verdicts[ self::BG_APPLIED ] ) || isset( $verdicts[ self::EL_APPLIED ] ) || isset( $verdicts[ self::FILE_CROP ] ) ) { ++$applied; } } $seen = count( $this->entries ); return array( 'seen' => $seen, 'applied' => $applied, 'skipped' => $seen - $applied, ); } /** * De uitleg bij één uitkomst, in gewone taal. * * @param string $verdict De uitkomst. * @return string */ public static function label( string $verdict ): string { $labels = array( self::APPLIED => __( 'applied', 'yinga-focus' ), self::PARTIAL => __( 'a position was already set', 'yinga-focus' ), self::NO_DATA => __( 'no focal point set', 'yinga-focus' ), self::HARD_CROP => class_exists( \Yinga\Focus\Media\FocalCrops::class ) ? __( 'hard-cropped size — save the focal point again to cut the file along with it', 'yinga-focus' ) : __( 'hard-cropped size — the file is already cut to these dimensions, so CSS cannot shift anything here', 'yinga-focus' ), self::FILE_CROP => __( 'file itself cut around the focal point', 'yinga-focus' ), self::OFF => __( 'the setting is off', 'yinga-focus' ), self::FILTERED => __( 'refused by a filter', 'yinga-focus' ), self::BG_APPLIED => __( 'applied to the CSS background', 'yinga-focus' ), self::BG_FOUND => __( 'found by the page scanner — switch the option on', 'yinga-focus' ), self::EL_APPLIED => __( 'applied to the Elementor background', 'yinga-focus' ), self::EL_SIZE => __( 'Elementor background is not set to Cover', 'yinga-focus' ), ); return $labels[ $verdict ] ?? $verdict; } /** * Hoeveel CSS-achtergronden zagen we die we hadden kunnen behandelen? * * @return int */ public function backgrounds_waiting(): int { $count = 0; foreach ( $this->entries as $verdicts ) { if ( isset( $verdicts[ self::BG_FOUND ] ) ) { ++$count; } } return $count; } }