feat: lit/tb-assign – conditions with dry run on live templates, reattach
- ThemeBuilderAccess::changeableTemplate(): rights (Q18 not_found), group gate, no TB draft, never the default template, current template_rev - omitted exclude_from stays, [] clears (Q3); live dry run shows use_on and exclude_from before/after, overlaps and possible overlaps (B9) - reattach only with published layouts (B10) and a live TB post; always disabled, unmarks template and layouts; failure restores everything Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -145,6 +145,75 @@ final class Template
|
||||
return $overlaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Live templates other than $exceptId whose conditions are not identical to one of $useOn but may cover
|
||||
* the same pages (ruling Q8/B9 – "kann sich überschneiden"): same family, e.g. all pages vs. one page,
|
||||
* all archives vs. one category archive, posts in a category vs. any single post, the front page vs. pages.
|
||||
* Deliberately generous – the dry run is the user's only preview. Identical conditions are overlaps().
|
||||
*
|
||||
* @param list<Template> $live
|
||||
* @param list<string> $useOn
|
||||
* @return list<array{id: int, title: string, conditions: list<string>}>
|
||||
*/
|
||||
public static function possibleOverlaps(array $live, int $exceptId, array $useOn): array
|
||||
{
|
||||
$overlaps = [];
|
||||
foreach ($live as $other) {
|
||||
if ($other->id === $exceptId || ! $other->isLive()) {
|
||||
continue;
|
||||
}
|
||||
$conditions = [];
|
||||
foreach ($other->useOn as $theirs) {
|
||||
foreach ($useOn as $ours) {
|
||||
if ($theirs !== $ours && self::mayOverlap($theirs, $ours)) {
|
||||
$conditions[] = $theirs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($conditions !== []) {
|
||||
$overlaps[] = ['id' => $other->id, 'title' => $other->title, 'conditions' => $conditions];
|
||||
}
|
||||
}
|
||||
|
||||
return $overlaps;
|
||||
}
|
||||
|
||||
private static function mayOverlap(string $a, string $b): bool
|
||||
{
|
||||
foreach (self::scopesOf($a) as $x) {
|
||||
foreach (self::scopesOf($b) as $y) {
|
||||
if ($x === $y || str_starts_with($x, $y . ':') || str_starts_with($y, $x . ':')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The page families a condition covers (Divi's IDs, theme-builder.php:689-1060): singular:post_type:<type>,
|
||||
* archive:taxonomy:<taxonomy>, archive:post_type:<type>, archive:user, archive:date; "<kind>:all" and posts
|
||||
* in a term (singular:taxonomy:…) the whole kind; the front page may be a page or the posts archive.
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
private static function scopesOf(string $condition): array
|
||||
{
|
||||
if ($condition === 'homepage') {
|
||||
return ['homepage', 'singular:post_type:page', 'archive:post_type:post'];
|
||||
}
|
||||
|
||||
$parts = explode(':', $condition);
|
||||
$second = $parts[1] ?? '';
|
||||
if (($parts[0] === 'singular' && $second === 'taxonomy') || $second === 'all') {
|
||||
return [$parts[0]];
|
||||
}
|
||||
|
||||
return [implode(':', array_slice($parts, 0, in_array($second, ['post_type', 'taxonomy'], true) ? 3 : 2))];
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
private static function strings(mixed $list): array
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user