$structured Machine facts (price, stock, contact…) for exact classic answers. * @param array $links Outgoing links harvested for the link graph. * @param int|null $thumbnail_id Attachment id for chat thumbnails. * @param int $weight 0-100 retrieval priority. * @param string|null $source_modified_gmt Source last-modified (MySQL datetime), for staleness checks. */ public function __construct( public readonly string $source, public readonly string $external_id, public readonly string $subtype, public readonly string $title, public readonly string $permalink, public readonly string $lang, public readonly array $blocks, public readonly array $structured = array(), public readonly array $links = array(), public readonly ?int $thumbnail_id = null, public readonly int $weight = 50, public readonly ?string $source_modified_gmt = null, ) { } /** * Freshness hash over content + structured facts. Unchanged hash means * re-chunking can be skipped (cheap idempotency). */ public function content_hash(): string { $parts = array( $this->title, $this->permalink, $this->lang, (string) $this->thumbnail_id, (string) $this->weight ); foreach ( $this->blocks as $block ) { $parts[] = $block->kind . '|' . $block->level . '|' . $block->text; } $parts[] = (string) wp_json_encode( $this->structured ); return sha1( implode( "\n", $parts ) ); } }