feat(M3): dossier edit+rerun UI, F2/F3, run-list badges — v0.20.0
- Dossier_Actions (4 AJAX endpoints, manage_options+nonce): save fork / queue replay / queue rebuild / stage-status poll. Run identity always derived server-side from post meta; the AJAX layer validates + queues ONLY — all mutations happen in the cron handlers (chained-cron, CPO hard constraint). Fork saves lock message structure (count/roles) so every version stays replayable. - Edit panel per editable stage: per-message textareas prefilled from the latest fork or the recorded request_json; explicit fork + downstream-stale + queued-execution copy; spend strip with ceiling warning (filterable fraction, default 0.8). Disabled stages always show WHY (policy reasons; missing-input retention copy). - Stale / human-edited / attempt chips per stage + header badges (M2 slot filled); dossier polls stage status while a re-run is active (board poll interval setting) and re-renders when the run settles. - F2: sidebar Models & Prompts card (per-stage model/pv/role) + Run Spend card. F3: log-only stages (image_a/b, llm_research, ...) render from generation_log + the _prautoblogger_image_role attachment grid. - M2 correctness: dossier is now item-scoped (idea-hash meta) and excludes gen_log rows linked to other posts of a multi-article run. - Run-list visibility (product AC): board cards get a Human-modified chip; Review Queue rows get a stale-stages chip linking to the dossier. Both via single batched queries (no N+1). - v0.20.0 + CHANGELOG + ARCHITECTURE #24 (+ file tree, schema tables, db-version note) in this commit per versioning discipline. Agent-Session: engineer-prab-m3-20260612
This commit is contained in:
82
includes/admin/class-dossier-image-data.php
Normal file
82
includes/admin/class-dossier-image-data.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* phpcs:ignore WordPress.Files.FileName.InvalidClassFileName -- class naming convention differs from WordPress standard
|
||||
*
|
||||
* Resolves a post's pipeline image attachments for the dossier (M3/F3).
|
||||
*
|
||||
* What: The image sections' REAL data source — the attachments the
|
||||
* image pipeline produced (featured + composed og/square variants,
|
||||
* discovered via the `_prautoblogger_image_role` attachment meta
|
||||
* and the post thumbnail), paired in the template with the
|
||||
* image_a/image_b generation_log rows. Replaces the M2 sections
|
||||
* that keyed off run_stages rows the image pipeline never writes
|
||||
* (QA M2 F3 — wiring the dossier to real data was the smaller,
|
||||
* safer change vs. teaching the live image pipeline to write
|
||||
* run_stages; the pipeline restructure is Phase 2b).
|
||||
* Who triggers it: PRAutoBlogger_Dossier_Data_Assembler::assemble().
|
||||
* Dependencies: get_children(), attachment meta, wp_get_attachment_image_url().
|
||||
*
|
||||
* @see admin/class-dossier-data-assembler.php — Caller.
|
||||
* @see templates/admin/dossier-log-stage-section.php — Renders the pairs.
|
||||
* @see ARCHITECTURE.md #24 — M3 design (F3 note).
|
||||
*/
|
||||
class PRAutoBlogger_Dossier_Image_Data {
|
||||
|
||||
/**
|
||||
* The post's pipeline attachments (featured/og/square) via the
|
||||
* `_prautoblogger_image_role` attachment meta — the image sections'
|
||||
* real data source (QA M2 F3).
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @return array<int, array{id: int, role: string, url: string, is_featured: bool}>
|
||||
*/
|
||||
public static function for_post( int $post_id ): array {
|
||||
$featured_id = (int) get_post_thumbnail_id( $post_id );
|
||||
$children = get_children(
|
||||
array(
|
||||
'post_parent' => $post_id,
|
||||
'post_type' => 'attachment',
|
||||
'numberposts' => 12,
|
||||
)
|
||||
);
|
||||
|
||||
$images = array();
|
||||
$seen = array();
|
||||
foreach ( (array) $children as $attachment ) {
|
||||
$att_id = (int) ( $attachment->ID ?? 0 );
|
||||
if ( $att_id <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
$role = (string) get_post_meta( $att_id, '_prautoblogger_image_role', true );
|
||||
if ( '' === $role && $att_id !== $featured_id ) {
|
||||
continue; // Not a pipeline attachment.
|
||||
}
|
||||
$url = (string) wp_get_attachment_image_url( $att_id, 'medium' );
|
||||
if ( '' === $url ) {
|
||||
continue;
|
||||
}
|
||||
$seen[ $att_id ] = true;
|
||||
$images[] = array(
|
||||
'id' => $att_id,
|
||||
'role' => '' !== $role ? $role : 'featured',
|
||||
'url' => $url,
|
||||
'is_featured' => $att_id === $featured_id,
|
||||
);
|
||||
}
|
||||
// Featured image attached elsewhere (not a child) still renders.
|
||||
if ( $featured_id > 0 && ! isset( $seen[ $featured_id ] ) ) {
|
||||
$url = (string) wp_get_attachment_image_url( $featured_id, 'medium' );
|
||||
if ( '' !== $url ) {
|
||||
$images[] = array(
|
||||
'id' => $featured_id,
|
||||
'role' => 'featured',
|
||||
'url' => $url,
|
||||
'is_featured' => true,
|
||||
);
|
||||
}
|
||||
}
|
||||
return $images;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user