'section', 'label' => 'LIT MCP Prüfung', 'rows' => [ [ 'columns' => '1_2,1_2', 'modules' => [ [ ['type' => 'heading', 'text' => 'litcheck-heading', 'level' => 'h2'], ['type' => 'text', 'content' => '

litcheck-text

'], ['type' => 'button', 'text' => 'litcheck-button', 'url' => '/'], ], [ ['type' => 'blurb', 'title' => 'litcheck-blurb', 'content' => '

litcheck-blurb-text

'], [ 'type' => 'cta', 'title' => 'litcheck-cta', 'button_text' => 'litcheck-cta-button', 'button_url' => '/', ], ['type' => 'divider'], ], ], ], [ 'columns' => '4_4', 'modules' => [ ['type' => 'toggle', 'title' => 'litcheck-toggle', 'content' => '

litcheck-toggle-text

'], ['type' => 'accordion', 'items' => [['title' => 'litcheck-accordion', 'content' => '

a

']]], ['type' => 'tabs', 'items' => [['title' => 'litcheck-tab', 'content' => '

t

']]], ['type' => 'icon-list', 'items' => [['text' => 'litcheck-icon-list']]], ], ], ], ]]; public const TEXTS = [ 'litcheck-heading', 'litcheck-text', 'litcheck-button', 'litcheck-blurb', 'litcheck-cta', 'litcheck-toggle', 'litcheck-accordion', 'litcheck-tab', 'litcheck-icon-list', ]; /** Only pages older than this are orphans – a running check's page is younger. */ private const ORPHAN_AGE = '10 minutes ago'; /** * @param string|null $diviDir PHP warnings from files below it fail the check; null = DiviEnvironment::themeDir(). */ public function __construct( private ContentComposer $composer, private ?PageRenderer $renderer = null, private ?string $diviDir = null ) { } /** @return list German problems; [] = green. */ public function run(): array { $id = wp_insert_post([ 'post_type' => 'page', 'post_status' => 'draft', 'post_title' => self::TITLE . ' ' . gmdate('Y-m-d H:i'), 'post_content' => '', 'meta_input' => [self::MARKER => '1'], ], true); if ($id instanceof WP_Error || (int) $id <= 0) { return ['Die Testseite konnte nicht angelegt werden: ' . ($id instanceof WP_Error ? $id->get_error_message() : 'keine ID')]; } $id = (int) $id; try { $problems = $this->exercise($id); } catch (Throwable $e) { $problems = ['Schreibtest abgebrochen: ' . $e->getMessage()]; } finally { if (! self::delete($id)) { $problems[] = sprintf( 'Die Testseite %d konnte nicht gelöscht werden; bitte unter Seiten endgültig löschen.', $id ); } } return $problems; } /** * @return list IDs of check pages a dead check left behind, deleted now. Only drafts whose title starts * with self::TITLE are considered – the marker meta alone is not enough (it is only a query hint here). */ public static function removeOrphans(): array { $posts = get_posts([ 'post_type' => 'page', 'post_status' => 'draft', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- a handful of marked pages at most. 'meta_key' => self::MARKER, 'date_query' => [['before' => self::ORPHAN_AGE, 'column' => 'post_date_gmt']], 'fields' => 'all', 'posts_per_page' => 20, 'no_found_rows' => true, 'suppress_filters' => true, ]); $removed = []; foreach (is_array($posts) ? $posts : [] as $post) { if (! $post instanceof WP_Post || ! str_starts_with((string) $post->post_title, self::TITLE)) { continue; } if (self::delete((int) $post->ID)) { $removed[] = (int) $post->ID; } } return $removed; } /** @return list */ private function exercise(int $id): array { $written = ReleaseGate::whileProbing( $id, fn (): array|WP_Error => $this->composer->write($id, 'page', self::SECTIONS) ); if ($written instanceof WP_Error) { return ['Die Kurzform der Testseite wurde abgelehnt: ' . Errors::clientMessage($written)]; } $post = get_post($id); if (! $post instanceof WP_Post) { return ['Die Testseite ist nach dem Schreiben nicht lesbar.']; } $problems = []; if (! str_contains((string) $post->post_content, '