fix: Divi-Reiter ohne Divi, Zustandstexte, Schreibsperren und Aufräum-Filter aus der Abschlussprüfung
Behebt die fünf Befunde der Abschlussprüfung von divi-absicherung: Divi-Reiter ohne aktives Divi zeigt nur noch einen Hinweis (kein Status, keine Prüfung, kein Aufräumen), Zustandstexte werden erst beim Rendern übersetzt, DiviPages::setFlags() und DiviThemeBuilder::liveId(true) prüfen jetzt selbst die Freigabesperre, WriteProbe::removeOrphans() löscht nur noch Entwürfe mit passendem Titel, und wp lit-mcp divi-check --update-reference verweigert sich ohne Entwicklungskopie, bevor irgendetwas geschrieben wird. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+20
-7
@@ -31,12 +31,6 @@ final class DiviTab implements AdminTab
|
||||
public const RELEASE_ACTION = 'lit_mcp_divi_release';
|
||||
public const WITHDRAW_ACTION = 'lit_mcp_divi_withdraw';
|
||||
|
||||
private const STATES = [
|
||||
'released' => 'freigegeben',
|
||||
'untested' => 'ungetestet',
|
||||
'incompatible' => 'inkompatibel',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param (Closure(): string)|null $version Installed Divi version ('' = none); null = DiviEnvironment.
|
||||
* @param (Closure(string): string)|null $stateKey null = ReleaseResolver::stateKey().
|
||||
@@ -123,6 +117,16 @@ final class DiviTab implements AdminTab
|
||||
|
||||
public function render(): void
|
||||
{
|
||||
if ($this->version() === '') {
|
||||
echo '<p>' . esc_html__(
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong -- WordPress.WP.I18n forbids splitting the text.
|
||||
'Divi ist auf dieser Website nicht aktiv; die Divi-Freigabe ist ohne Bedeutung.',
|
||||
'wp-lit-mcp'
|
||||
) . '</p>';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$removed = WriteProbe::removeOrphans();
|
||||
$status = ReleaseGate::status();
|
||||
$report = $this->reports()->latest();
|
||||
@@ -162,7 +166,7 @@ final class DiviTab implements AdminTab
|
||||
printf(
|
||||
'<tr><th scope="row">%s</th><td><strong>%s</strong> – %s</td></tr>',
|
||||
esc_html__('Zustand', 'wp-lit-mcp'),
|
||||
esc_html(self::STATES[$status->state->value]),
|
||||
esc_html($this->stateLabel($status->state)),
|
||||
esc_html($this->explanation($status))
|
||||
);
|
||||
if ($status->problems !== []) {
|
||||
@@ -175,6 +179,15 @@ final class DiviTab implements AdminTab
|
||||
echo '</tbody></table>';
|
||||
}
|
||||
|
||||
private function stateLabel(ReleaseState $state): string
|
||||
{
|
||||
return match ($state) {
|
||||
ReleaseState::Released => __('freigegeben', 'wp-lit-mcp'),
|
||||
ReleaseState::Untested => __('ungetestet', 'wp-lit-mcp'),
|
||||
ReleaseState::Incompatible => __('inkompatibel', 'wp-lit-mcp'),
|
||||
};
|
||||
}
|
||||
|
||||
private function explanation(ReleaseStatus $status): string
|
||||
{
|
||||
if ($status->state === ReleaseState::Incompatible) {
|
||||
|
||||
@@ -161,6 +161,13 @@ final class DiviCheckCommand
|
||||
}
|
||||
}
|
||||
|
||||
$sourceDir = ($this->sourceDir ?? DiviReference::sourceDir(...))();
|
||||
if ($sourceDir === null) {
|
||||
($this->out)('Referenz nicht aktualisiert: nur in einer Entwicklungskopie mit tests/ möglich.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$themeDir = ($this->themeDir ?? DiviEnvironment::themeDir(...))();
|
||||
try {
|
||||
$prints = DiviReference::current((string) $themeDir);
|
||||
@@ -172,11 +179,10 @@ final class DiviCheckCommand
|
||||
return 1;
|
||||
}
|
||||
|
||||
$sourceDir = ($this->sourceDir ?? DiviReference::sourceDir(...))();
|
||||
try {
|
||||
// Sources first, fingerprints.json last: the fingerprints decide the release gate, so a write that
|
||||
// fails before this last one leaves the gate exactly as it was.
|
||||
foreach ($sourceDir === null ? [] : $prints as $id => $print) {
|
||||
foreach ($prints as $id => $print) {
|
||||
DiviReference::writeSource($id, $print->source, $sourceDir);
|
||||
}
|
||||
DiviReference::writeExpected(
|
||||
|
||||
@@ -6,8 +6,10 @@ namespace LIT\MCP\Integrations\Divi\Pages;
|
||||
|
||||
use LIT\MCP\Integrations\Divi\Release\Call;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviAdapter;
|
||||
use LIT\MCP\Integrations\Divi\Release\DiviLocked;
|
||||
use LIT\MCP\Integrations\Divi\Release\Manifest;
|
||||
use LIT\MCP\Integrations\Divi\Release\Mirror;
|
||||
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
|
||||
use RuntimeException;
|
||||
use WP_Post;
|
||||
|
||||
@@ -50,9 +52,13 @@ final class DiviPages implements DiviAdapter
|
||||
);
|
||||
}
|
||||
|
||||
/** @throws RuntimeException When a flag does not read back as set. */
|
||||
/**
|
||||
* @throws RuntimeException When a flag does not read back as set.
|
||||
* @throws DiviLocked When Divi is not released (spec §5.5) – before anything is written.
|
||||
*/
|
||||
public static function setFlags(int $postId): void
|
||||
{
|
||||
ReleaseGate::assertWritable($postId);
|
||||
foreach (self::FLAGS as $key => $value) {
|
||||
update_post_meta($postId, $key, $value);
|
||||
}
|
||||
|
||||
@@ -114,25 +114,31 @@ class WriteProbe
|
||||
return $problems;
|
||||
}
|
||||
|
||||
/** @return list<int> IDs of check pages a dead check left behind, deleted now. */
|
||||
/**
|
||||
* @return list<int> 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
|
||||
{
|
||||
$ids = get_posts([
|
||||
$posts = get_posts([
|
||||
'post_type' => 'page',
|
||||
'post_status' => 'any',
|
||||
'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' => 'ids',
|
||||
'fields' => 'all',
|
||||
'posts_per_page' => 20,
|
||||
'no_found_rows' => true,
|
||||
'suppress_filters' => true,
|
||||
]);
|
||||
|
||||
$removed = [];
|
||||
foreach (is_array($ids) ? $ids : [] as $id) {
|
||||
if (self::delete((int) $id)) {
|
||||
$removed[] = (int) $id;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,9 +126,17 @@ class DiviThemeBuilder implements DiviAdapter
|
||||
);
|
||||
}
|
||||
|
||||
/** The live Theme Builder post (publish, no library TB); $create makes it like Divi's first save. 0 = none. */
|
||||
/**
|
||||
* The live Theme Builder post (publish, no library TB); $create makes it like Divi's first save. 0 = none.
|
||||
*
|
||||
* @throws DiviLocked When $create and Divi is not released (spec §5.5) – before anything is written.
|
||||
*/
|
||||
public function liveId(bool $create = false): int
|
||||
{
|
||||
if ($create) {
|
||||
ReleaseGate::assertWritable();
|
||||
}
|
||||
|
||||
return function_exists('et_theme_builder_get_theme_builder_post_id')
|
||||
? (int) et_theme_builder_get_theme_builder_post_id(true, $create)
|
||||
: 0;
|
||||
|
||||
Reference in New Issue
Block a user