WpLinkTargets answers the library, internal "_" types and every type without a Divi post_link_url option like a missing ID; replace-text strips library IDs only from global subtrees. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
66 lines
2.2 KiB
PHP
66 lines
2.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace LIT\MCP\Integrations\Divi\Pages;
|
|
|
|
use Closure;
|
|
use LIT\MCP\Integrations\Divi\Compose\LinkTargets;
|
|
use WP_Post;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
/**
|
|
* {{link:<ID>}} and post_link_url_* targets from WordPress (rulings P10, Q14): the entry exists,
|
|
* lives (no trash, auto-draft or revision), is no attachment (whatever its status), its type has a
|
|
* Divi link option post_link_url_<type> (never the library et_pb_layout or an internal "_" type) and
|
|
* the current user may read it (read_post, like select_post settings, S37). Missing, unreadable and
|
|
* unlinkable entries give the same null (no existence or type oracle).
|
|
*/
|
|
final class WpLinkTargets implements LinkTargets
|
|
{
|
|
private const DEAD = ['trash', 'auto-draft', 'inherit'];
|
|
|
|
/** Never link targets, whatever Divi lists: attachments and the Divi Library (ruling Q14). */
|
|
private const NEVER = ['attachment', 'et_pb_layout'];
|
|
|
|
/** @var Closure(string): bool */
|
|
private Closure $linkable;
|
|
|
|
/**
|
|
* @param (Closure(string): bool)|null $linkable Whether Divi offers post_link_url_<type> (tests);
|
|
* null = Divi's et_builder_get_public_post_types(), the list its link option uses.
|
|
*/
|
|
public function __construct(?Closure $linkable = null)
|
|
{
|
|
$this->linkable = $linkable ?? self::diviLinkable(...);
|
|
}
|
|
|
|
public function postTypeOf(int $id): ?string
|
|
{
|
|
$post = get_post($id);
|
|
if (! $post instanceof WP_Post || in_array((string) $post->post_status, self::DEAD, true)) {
|
|
return null;
|
|
}
|
|
|
|
$type = (string) $post->post_type;
|
|
if (in_array($type, self::NEVER, true) || str_starts_with($type, '_') || ! ($this->linkable)($type)) {
|
|
return null;
|
|
}
|
|
|
|
return current_user_can('read_post', $id) ? $type : null;
|
|
}
|
|
|
|
/** Fail closed: without Divi's list no type has a link option. */
|
|
private static function diviLinkable(string $type): bool
|
|
{
|
|
if (! function_exists('et_builder_get_public_post_types')) {
|
|
return false;
|
|
}
|
|
|
|
$types = et_builder_get_public_post_types();
|
|
|
|
return is_array($types) && array_key_exists($type, $types);
|
|
}
|
|
}
|