Plugin Directory

Changeset 3492765


Ignore:
Timestamp:
03/27/2026 03:33:48 PM (5 days ago)
Author:
palasthotel
Message:

Release version 3.0.1

Location:
headless
Files:
89 added
59 edited

Legend:

Unmodified
Added
Removed
  • headless/trunk/README.txt

    r3254930 r3492765  
    66Tested up to: 6.7.2
    77Requires PHP: 8.0
    8 Stable tag: 2.3.1
     8Stable tag: 3.0.1
    99License: GPLv3
    1010License URI: http://www.gnu.org/licenses/gpl
     
    2727
    2828== Changelog ==
     29
     30= 3.0.1 =
     31* **core-image:** use alt text from block if set (b799413)
     32* **core-image:** use block alt if set (e2d0e6c)
     33* **core-image:** use image alt text from block props if set in block (0ed3974)
     34
    2935
    3036= 2.3.1 =
  • headless/trunk/classes/Ajax.php

    r3196946 r3492765  
    55use Palasthotel\WordPress\Headless\Components\Component;
    66
     7/**
     8 * Handles AJAX endpoints for triggering cache revalidation from the WordPress admin.
     9 *
     10 * Registers two wp_ajax actions: one to revalidate a specific path or post,
     11 * and one to process all pending revalidations from the queue.
     12 */
    713class Ajax extends Component {
    814
     
    1925    }
    2026
     27    /**
     28     * Handles the AJAX revalidate action.
     29     *
     30     * Accepts either a path or a post ID via GET parameters and triggers
     31     * revalidation on the specified frontend. Requires edit_posts capability.
     32     *
     33     * @return void
     34     */
    2135    public function revalidate(){
    2236
     
    7387
    7488
     89    /**
     90     * Handles the AJAX revalidate_pending action.
     91     *
     92     * Triggers the scheduled revalidation run to process all pending items.
     93     * Requires edit_posts capability.
     94     *
     95     * @return void
     96     */
    7597    function revalidate_pending() {
    7698        if(!current_user_can('edit_posts')){
  • headless/trunk/classes/BlockPreparations/CoreEmbedBlockPreparation.php

    r2766747 r3492765  
    66use Palasthotel\WordPress\Headless\Model\BlockName;
    77
    8 class CoreEmbedBlockPreparation implements IBlockPreparation {
    9 
    10     function blockName(): ?BlockName {
     8/**
     9 * Normalizes the legacy "core-embed/wordpress" block name to "core/embed"
     10 *
     11 * Handles blocks saved with the old "core-embed" namespace so they are
     12 * treated as standard embed blocks by subsequent preparations
     13 */
     14class CoreEmbedBlockPreparation implements IBlockPreparation
     15{
     16    /**
     17     * Returns the legacy block name this preparation targets.
     18     *
     19     * @return BlockName The "core-embed/wordpress" block name.
     20     */
     21    function blockName(): ?BlockName
     22    {
    1123        return new BlockName("core-embed", "wordpress");
    1224    }
    1325
    14     function prepare( array $block ): array {
    15 
     26    /**
     27     * Rewrites the block name from "core-embed/wordpress" to "core/embed".
     28     *
     29     * @param array $block The parsed block data.
     30     * @return array The block with the corrected name.
     31     */
     32    function prepare(array $block): array
     33    {
    1634        $block["blockName"] = "core/embed";
    1735
  • headless/trunk/classes/BlockPreparations/EmbedBlockPreparation.php

    r2766747 r3492765  
    66use Palasthotel\WordPress\Headless\Model\BlockName;
    77
     8/**
     9 * Resolves oEmbed data for core/embed blocks.
     10 *
     11 * Fetches the oEmbed HTML for the block's URL and adds "isResolved" and
     12 * "resolvedHTML" attributes. Removes innerContent from the block data.
     13 */
    814class EmbedBlockPreparation implements IBlockPreparation {
    915
     16    /**
     17     * Returns the block name this preparation targets.
     18     *
     19     * @return BlockName The "core/embed" block name.
     20     */
    1021    function blockName(): ?BlockName {
    1122        return new BlockName("core", "embed");
    1223    }
    1324
     25    /**
     26     * Resolves the oEmbed HTML for the block URL and strips innerContent.
     27     *
     28     * @param array $block The parsed block data.
     29     * @return array The block with "isResolved" and "resolvedHTML" attrs added.
     30     */
    1431    function prepare( array $block ): array {
    1532
  • headless/trunk/classes/BlockPreparations/FreeFormBlockPreparation.php

    r2752593 r3492765  
    66use Palasthotel\WordPress\Headless\Model\BlockName;
    77
     8/**
     9 * Processes free-form (classic) blocks by running shortcodes and stripping innerContent.
     10 *
     11 * Returns null from blockName() to apply to all blocks without a specific name.
     12 */
    813class FreeFormBlockPreparation implements IBlockPreparation {
    914
     15    /**
     16     * Returns null to indicate this preparation applies to all blocks.
     17     *
     18     * @return null
     19     */
    1020    function blockName(): ?BlockName {
    1121        return null;
    1222    }
    1323
     24    /**
     25     * Runs shortcodes on innerHTML and removes innerContent from the block.
     26     *
     27     * @param array $block The parsed block data.
     28     * @return array The block with shortcodes processed and innerContent removed.
     29     */
    1430    function prepare( array $block ): array {
    1531
  • headless/trunk/classes/BlockPreparations/GalleryBlockPreparation.php

    r2752593 r3492765  
    77use Palasthotel\WordPress\Headless\Model\PostContentAttachmentCollector;
    88
     9/**
     10 * Prepares core/gallery blocks by extracting image IDs and attachment attributes.
     11 *
     12 * Handles both modern gallery blocks (innerBlocks) and legacy gallery markup (innerHTML).
     13 * Registers attachment IDs with the PostContentAttachmentCollector and removes
     14 * raw HTML from the block data.
     15 */
    916class GalleryBlockPreparation implements IBlockPreparation {
    1017
     18    /**
     19     * Returns the block name this preparation targets.
     20     *
     21     * @return BlockName The "core/gallery" block name.
     22     */
    1123    function blockName(): BlockName {
    1224        return new BlockName("core", "gallery");
    1325    }
    1426
     27    /**
     28     * Extracts image IDs, builds inner image blocks for legacy markup, and cleans up raw HTML.
     29     *
     30     * @param array $block The parsed block data.
     31     * @return array The prepared block with ids attribute and innerBlocks populated.
     32     */
    1533    function prepare( array $block ): array {
    1634
  • headless/trunk/classes/BlockPreparations/ImageBlockPreparation.php

    r2901812 r3492765  
    77use Palasthotel\WordPress\Headless\Model\BlockName;
    88use Palasthotel\WordPress\Headless\Model\PostContentAttachmentCollector;
     9use WP_HTML_Tag_Processor;
    910
     11/**
     12 * Prepares core/image blocks with attachment data including src, sizes, alt, and caption.
     13 *
     14 * Registers the attachment with the PostContentAttachmentCollector and strips
     15 * innerHTML and innerContent from the block.
     16 */
    1017class ImageBlockPreparation implements IBlockPreparation {
    1118
     19    /**
     20     * Returns the block name this preparation targets.
     21     *
     22     * @return BlockName The "core/image" block name.
     23     */
    1224    function blockName(): BlockName {
    1325        return new BlockName("core", "image");
    1426    }
    1527
     28    /**
     29     * Enriches the image block with attachment metadata and removes raw HTML fields.
     30     *
     31     * @param array $block The parsed block data.
     32     * @return array The block with src, sizes, alt, and caption attrs added.
     33     */
    1634    function prepare( array $block ): array {
    1735
     
    2947    }
    3048
     49    /**
     50     * Adds attachment-related attributes (src, sizes, alt, caption) to a block attrs array.
     51     *
     52     * @param int    $id        The attachment ID.
     53     * @param array  $attrs     The existing block attributes.
     54     * @param string $innerHTML The block innerHTML, used to extract alt and caption.
     55     * @return array The enriched attributes array.
     56     */
    3157    public static function addAttachmentAttributes($id, $attrs, $innerHTML){
     58
     59        $tags = new WP_HTML_Tag_Processor( $innerHTML );
     60        $tags->next_tag(['tag_name' => 'img']);
     61        // alt set in the core/image block settings
     62        $block_alt = $tags->get_attribute('alt');
     63        $alt = empty($block_alt) ? get_post_meta($id, '_wp_attachment_image_alt', true) : $block_alt;
     64
    3265        $attrs["src"] = wp_get_attachment_image_src($id, 'full');
    3366
    3467        $attrs["sizes"] = FeaturedMedia::imageSizes($id);
    3568
    36         $attrs["alt"] = get_post_meta($id, '_wp_attachment_image_alt', true);
     69        $attrs["alt"] = $alt;
    3770        $attrs["caption"] = str_replace(
    3871            ["\n","\r"],
  • headless/trunk/classes/BlockPreparations/MoreBlockPreparation.php

    r2730402 r3492765  
    66use Palasthotel\WordPress\Headless\Model\BlockName;
    77
     8/**
     9 * Strips all data from core/more blocks, keeping only the block name.
     10 *
     11 * The "read more" block has no meaningful content for the headless frontend,
     12 * so its presence alone is surfaced as a marker.
     13 */
    814class MoreBlockPreparation implements IBlockPreparation {
    915
     16    /**
     17     * Returns the block name this preparation targets.
     18     *
     19     * @return BlockName The "core/more" block name.
     20     */
    1021    function blockName(): BlockName {
    1122        return new BlockName("core", "more");
    1223    }
    1324
     25    /**
     26     * Returns a minimal block array containing only the block name.
     27     *
     28     * @param array $block The parsed block data.
     29     * @return array A block array with only the "blockName" key.
     30     */
    1431    function prepare( array $block ): array {
    1532        return [
  • headless/trunk/classes/BlockPreparations/ParagraphBlockPreparation.php

    r2752593 r3492765  
    66use Palasthotel\WordPress\Headless\Model\BlockName;
    77
     8/**
     9 * Prepares core/paragraph blocks by removing the redundant innerContent field.
     10 */
    811class ParagraphBlockPreparation implements IBlockPreparation {
    912
     13    /**
     14     * Returns the block name this preparation targets.
     15     *
     16     * @return BlockName The "core/paragraph" block name.
     17     */
    1018    function blockName(): ?BlockName {
    1119        return new BlockName("core", "paragraph");
    1220    }
    1321
     22    /**
     23     * Removes innerContent from the paragraph block.
     24     *
     25     * @param array $block The parsed block data.
     26     * @return array The block with innerContent removed.
     27     */
    1428    function prepare( array $block ): array {
    1529
  • headless/trunk/classes/BlockPreparations/ReferenceBlockPreparation.php

    r2802385 r3492765  
    66use Palasthotel\WordPress\Headless\Model\BlockName;
    77
     8/**
     9 * Resolves core/block (reusable block) references by inlining the referenced block content.
     10 *
     11 * When a block has a "ref" attribute pointing to a wp_block post, this preparation
     12 * fetches and parses its content and replaces the reference block's innerBlocks.
     13 * Must run before all other preparations so the inlined blocks can be further processed.
     14 */
    815class ReferenceBlockPreparation implements IBlockPreparation {
    916
     17    /**
     18     * Returns the block name this preparation targets.
     19     *
     20     * @return BlockName The "core/block" block name.
     21     */
    1022    function blockName(): ?BlockName {
    1123        return new BlockName("core", "block");
    1224    }
    1325
     26    /**
     27     * Inlines the referenced reusable block content into innerBlocks.
     28     *
     29     * @param array $block The parsed block data.
     30     * @return array The block with innerBlocks replaced by the referenced block's content.
     31     */
    1432    function prepare( array $block ): array {
    1533
  • headless/trunk/classes/BlockPreparations/TagCloudPreparation.php

    r2791162 r3492765  
    88use Palasthotel\WordPress\Headless\Model\PostContentAttachmentCollector;
    99
     10/**
     11 * Prepares core/tag-cloud blocks by resolving and embedding term data.
     12 *
     13 * Fetches terms using block attributes (taxonomy, numberOfTags) and adds
     14 * them as a "tags" array within the block's attributes. Removes innerBlocks,
     15 * innerHTML, and innerContent from the output.
     16 */
    1017class TagCloudPreparation implements IBlockPreparation {
    1118
     19    /**
     20     * Returns the block name this preparation targets.
     21     *
     22     * @return BlockName The "core/tag-cloud" block name.
     23     */
    1224    function blockName(): BlockName {
    1325        return new BlockName("core", "tag-cloud");
    1426    }
    1527
     28    /**
     29     * Resolves taxonomy terms and embeds them in the block attributes.
     30     *
     31     * @param array $block The parsed block data.
     32     * @return array The block with a "tags" attribute and raw HTML fields removed.
     33     */
    1634    function prepare( array $block ): array {
    1735
     
    4967    }
    5068
     69    /**
     70     * Adds attachment-related attributes (src, sizes, alt, caption) to a block attrs array.
     71     *
     72     * @param int    $id        The attachment ID.
     73     * @param array  $attrs     The existing block attributes.
     74     * @param string $innerHTML The block innerHTML, used for caption extraction.
     75     * @return array The enriched attributes array.
     76     */
    5177    public static function addAttachmentAttributes($id, $attrs, $innerHTML){
    5278        $attrs["src"] = wp_get_attachment_image_src($id, 'full');
  • headless/trunk/classes/Components/Assets.php

    r3196946 r3492765  
    44namespace Palasthotel\WordPress\Headless\Components;
    55
     6/**
     7 * Helper for registering plugin scripts and styles with automatic versioning.
     8 *
     9 * Resolves file paths relative to the plugin root, uses file modification time
     10 * for cache busting, and reads webpack-generated asset manifests for scripts.
     11 */
    612class Assets {
    713
     14    /**
     15     * @var Plugin The plugin instance used to resolve paths and URLs.
     16     */
    817    private Plugin $plugin;
    918
     19    /**
     20     * @param Plugin $plugin The plugin instance.
     21     */
    1022    public function __construct(Plugin $plugin) {
    1123        $this->plugin = $plugin;
    1224    }
    1325
     26    /**
     27     * Registers a stylesheet with WordPress using a plugin-relative path.
     28     *
     29     * Logs an error and returns false if the file does not exist.
     30     *
     31     * @param string   $handle            The stylesheet handle.
     32     * @param string   $pluginPathToFile  Path to the file relative to the plugin root.
     33     * @param string[] $dependencies      Array of registered stylesheet handles this depends on.
     34     * @param string   $media             The media type for the stylesheet.
     35     * @return bool True if the stylesheet was registered successfully, false otherwise.
     36     */
    1437    public function registerStyle(string $handle, string $pluginPathToFile, array $dependencies = [], string $media = 'all'): bool {
    1538        $filePath = $this->plugin->path . $pluginPathToFile;
     
    2548    }
    2649
     50    /**
     51     * Registers a script with WordPress using a plugin-relative path.
     52     *
     53     * If a corresponding .asset.php manifest exists, its dependencies and version
     54     * are used; otherwise filemtime is used as the version. Logs an error and
     55     * returns false if the file does not exist.
     56     *
     57     * @param string   $handle            The script handle.
     58     * @param string   $pluginPathToFile  Path to the file relative to the plugin root.
     59     * @param string[] $dependencies      Additional script dependencies to merge with the manifest.
     60     * @param bool     $footer            Whether to enqueue the script in the footer.
     61     * @return bool True if the script was registered successfully, false otherwise.
     62     */
    2763    public function registerScript(string $handle, string $pluginPathToFile, array $dependencies = [], bool $footer = true): bool {
    2864        $filePath = $this->plugin->path . $pluginPathToFile;
     
    5389    }
    5490
     91    /**
     92     * Checks whether the given string ends with ".js".
     93     *
     94     * @param string $haystack The string to check.
     95     * @return bool True if the string ends with ".js".
     96     */
    5597    private function endsWithJS($haystack): bool {
    5698        $length = strlen(".js");
  • headless/trunk/classes/Components/Component.php

    r3196946 r3492765  
    44namespace Palasthotel\WordPress\Headless\Components;
    55
     6/**
     7 * Base class for all plugin components.
     8 *
     9 * Receives the Plugin instance via constructor injection and calls onCreate()
     10 * to allow subclasses to register hooks and initialize state.
     11 */
    612abstract class Component {
    713
     
    1319
    1420    /**
    15      * overwrite this method in component implementations
     21     * Called after construction. Override in subclasses to register hooks and initialize state.
     22     *
     23     * @return void
    1624     */
    1725    public function onCreate(): void {
  • headless/trunk/classes/Components/Database.php

    r3196946 r3492765  
    66use wpdb;
    77
     8/**
     9 * Base class for plugin database handlers.
     10 *
     11 * Injects the global wpdb instance and calls init() on construction to allow
     12 * subclasses to set up table names and other properties.
     13 */
    814abstract class Database {
    915
     16    /**
     17     * @var wpdb The WordPress database instance.
     18     */
    1019    protected wpdb $wpdb;
    1120
     21    /**
     22     * Initializes the database handler by injecting wpdb and calling init().
     23     */
    1224    public function __construct() {
    1325        global $wpdb;
     
    1729
    1830    /**
    19      * initialize table names and other properties
     31     * Initializes table names and other properties. Must be implemented by subclasses.
     32     *
     33     * @return void
    2034     */
    2135    abstract function init(): void;
    2236
     37    /**
     38     * Loads the WordPress database upgrade functions required for dbDelta().
     39     *
     40     * Subclasses should call parent::createTables() before running dbDelta().
     41     *
     42     * @return void
     43     */
    2344    public function createTables(): void {
    2445        require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
  • headless/trunk/classes/Components/Plugin.php

    r3196946 r3492765  
    66use ReflectionException;
    77
     8/**
     9 * Abstract base class for WordPress plugins using a singleton pattern.
     10 *
     11 * Resolves the plugin's file path, URL, and basename via reflection, registers
     12 * activation and deactivation hooks, and provides multisite support.
     13 * Subclasses must implement onCreate() for component initialization.
     14 */
    815abstract class Plugin {
    916
    1017    /**
    11      * @var ReflectionClass
     18     * @var ReflectionClass Reflection of the concrete plugin class, used to resolve paths.
    1219     */
    1320    private $ref;
     21
     22    /**
     23     * @var bool Whether the textdomain registration window has passed.
     24     */
    1425    private $tooLateForTextdomain;
     26
     27    /**
     28     * @var string Absolute path to the plugin directory, with trailing slash.
     29     */
    1530    public $path;
     31
     32    /**
     33     * @var string URL to the plugin directory, with trailing slash.
     34     */
    1635    public $url;
     36
     37    /**
     38     * @var string Plugin basename (e.g. plugin-folder/plugin-file.php).
     39     */
    1740    public $basename;
    1841
     
    3861    // lifecycle methods
    3962    // -----------------------------------------------------------------------------
     63    /**
     64     * Called during construction. Implement to initialize plugin components and hooks.
     65     *
     66     * @return void
     67     */
    4068    abstract function onCreate();
    4169
     70    /**
     71     * Handles plugin activation, dispatching to each site on multisite networks.
     72     *
     73     * @param bool $networkWide Whether the plugin is being activated network-wide.
     74     * @return void
     75     */
    4276    public function onActivation( $networkWide ) {
    4377        if ( $networkWide ) {
     
    4882    }
    4983
     84    /**
     85     * Called during activation for the current site. Override to run site-specific setup.
     86     *
     87     * @return void
     88     */
    5089    public function onSiteActivation() {
    5190
    5291    }
    5392
     93    /**
     94     * Handles plugin deactivation, dispatching to each site on multisite networks.
     95     *
     96     * @param bool $networkWide Whether the plugin is being deactivated network-wide.
     97     * @return void
     98     */
    5499    public function onDeactivation( $networkWide ) {
    55100        if ( $networkWide ) {
     
    60105    }
    61106
     107    /**
     108     * Called during deactivation for the current site. Override to run site-specific teardown.
     109     *
     110     * @return void
     111     */
    62112    public function onSiteDeactivation() {
    63113
     
    67117    // utility methods
    68118    // -----------------------------------------------------------------------------
     119
     120    /**
     121     * Registers the plugin textdomain for translations.
     122     *
     123     * Must be called within onCreate(). Calling it after construction will log an error.
     124     *
     125     * @param string $domain                 The textdomain identifier.
     126     * @param string $relativeLanguagesPath  Path to the languages directory relative to the plugin file.
     127     * @return void
     128     */
    69129    public function loadTextdomain( string $domain, string $relativeLanguagesPath ) {
    70130        if ( $this->tooLateForTextdomain ) {
     
    81141    }
    82142
     143    /**
     144     * Iterates over all sites in a multisite network and calls the given callback for each.
     145     *
     146     * Does nothing if not running on a multisite installation.
     147     *
     148     * @param callable $onSite Callback to invoke for each site (called after switch_to_blog).
     149     * @return void
     150     */
    83151    public function foreachMultisite(callable $onSite){
    84152        if ( function_exists( 'is_multisite' ) && is_multisite() ) {
     
    101169    // singleton pattern
    102170    // -----------------------------------------------------------------------------
     171    /**
     172     * @var static[] Map of class name to singleton instance.
     173     */
    103174    private static $instances = [];
    104175
     176    /**
     177     * Returns the singleton instance for the called class.
     178     *
     179     * @return static The plugin instance.
     180     */
    105181    public static function instance() {
    106182        $class = get_called_class();
  • headless/trunk/classes/Dashboard.php

    r3196946 r3492765  
    33namespace Palasthotel\WordPress\Headless;
    44
     5/**
     6 * Registers and renders the Headless dashboard widget in the WordPress admin.
     7 *
     8 * Displays revalidation schedule status, pending item counts, and provides
     9 * buttons for manual and automatic cache revalidation.
     10 */
    511class Dashboard extends Components\Component {
    612    public function onCreate(): void {
     
    915    }
    1016
     17    /**
     18     * Registers the dashboard widget if revalidation is active and the user can edit posts.
     19     *
     20     * @return void
     21     */
    1122    public function setup(){
    1223        if(!current_user_can('edit_posts')) return;
     
    2132    }
    2233
     34    /**
     35     * Renders the dashboard widget HTML including revalidation status and controls.
     36     *
     37     * @return void
     38     */
    2339    public function render(){
    2440        $timeFormat = get_option('time_format');
  • headless/trunk/classes/Extensions.php

    r3196946 r3492765  
    2525use Palasthotel\WordPress\Headless\Model\UserRouteExtensions;
    2626
     27/**
     28 * Registers all built-in block preparations and REST API route extensions.
     29 *
     30 * Hooks into the plugin's registration actions during REST API init to add
     31 * default extensions for posts, comments, blocks, users, and terms.
     32 * Only active on headless requests with valid API key access.
     33 */
    2734class Extensions extends Component {
    2835
     36    /**
     37     * @var BlockPreparations
     38     */
    2939    private BlockPreparations $blockPreparations;
     40
     41    /**
     42     * @var PostRouteExtensions
     43     */
    3044    private PostRouteExtensions $postRouteExtensions;
     45
     46    /**
     47     * @var CommentRouteExtensions
     48     */
    3149    private CommentRouteExtensions $commentRouteExtensions;
     50
     51    /**
     52     * @var UserRouteExtensions
     53     */
    3254    private UserRouteExtensions $userRouteExtensions;
     55
     56    /**
     57     * @var TermRouteExtensions
     58     */
    3359    private TermRouteExtensions $termRouteExtensions;
    3460
     
    5985    }
    6086
     87    /**
     88     * Registers block preparations that must run before all others.
     89     *
     90     * @param BlockPreparations $extensions The block preparations collection.
     91     * @return void
     92     */
    6193    public function block_preparation_extensions_with_prio( BlockPreparations $extensions ) {
    6294        // needs to be the very first preparation step so others can apply to the result
     
    6496    }
    6597
     98    /**
     99     * Registers the default set of block preparations.
     100     *
     101     * @param BlockPreparations $extensions The block preparations collection.
     102     * @return void
     103     */
    66104    public function block_preparation_extensions( BlockPreparations $extensions ) {
    67105        $extensions->add( new ParagraphBlockPreparation() );
     
    77115    }
    78116
     117    /**
     118     * Registers the default post route extensions.
     119     *
     120     * @param PostRouteExtensions $extensions The post route extensions collection.
     121     * @return void
     122     */
    79123    public function post_route_extensions( PostRouteExtensions $extensions ) {
    80124        $extensions->add( new Title() );
     
    85129    }
    86130
     131    /**
     132     * Registers the default comment route extensions.
     133     *
     134     * @param CommentRouteExtensions $extensions The comment route extensions collection.
     135     * @return void
     136     */
    87137    public function comment_route_extensions( CommentRouteExtensions $extensions ) {
    88138        $extensions->add( new CommentAuthorUser() );
    89139    }
    90140
     141    /**
     142     * Fires all extension registration actions and attaches REST response filters.
     143     *
     144     * Called on rest_api_init. Only proceeds if the request has valid API key access.
     145     *
     146     * @return void
     147     */
    91148    public function rest_api_init() {
    92149
  • headless/trunk/classes/Extensions/AbsPostExtensionPost.php

    r2730402 r3492765  
    66use Palasthotel\WordPress\Headless\Plugin;
    77
     8/**
     9 * Abstract base class for post route extensions that self-register via a filter.
     10 *
     11 * Subclasses automatically hook into Plugin::ACTION_REGISTER_POST_ROUTE_EXTENSIONS
     12 * on construction and add themselves to the extension array.
     13 */
    814abstract class AbsPostExtensionPost implements IPostRouteExtension {
    915
     
    1723     * @return IPostRouteExtension[]
    1824     */
     25    /**
     26     * Appends this extension to the provided extensions array.
     27     *
     28     * @param IPostRouteExtension[] $extensions The existing list of post route extensions.
     29     * @return IPostRouteExtension[] The extensions array with this instance appended.
     30     */
    1931    public function register(array $extensions){
    2032        $extensions[] = $this;
  • headless/trunk/classes/Extensions/CommentAuthorUser.php

    r2766747 r3492765  
    77use WP_REST_Response;
    88
     9/**
     10 * Extends the comment REST response with the author's user data.
     11 *
     12 * Adds an "author_user" field containing display_name and nickname
     13 * if the comment has an associated WordPress user account.
     14 */
    915class CommentAuthorUser implements ICommentRouteExtension {
    1016
     17    /**
     18     * Appends author user data to the comment REST response.
     19     *
     20     * @param WP_REST_Response $response The current REST response.
     21     * @param \WP_Comment      $comment  The comment object.
     22     * @param WP_REST_Request  $request  The current REST request.
     23     * @return WP_REST_Response The modified response with "author_user" field added.
     24     */
    1125    function response( WP_REST_Response $response, \WP_Comment $comment, WP_REST_Request $request ): WP_REST_Response {
    1226        $data = $response->get_data();
  • headless/trunk/classes/Extensions/ContentAttachments.php

    r2730402 r3492765  
    88use WP_REST_Response;
    99
     10/**
     11 * Extends the post REST response with attachment IDs collected from post content.
     12 *
     13 * Adds a "headless_attachment_ids" field to the content object containing
     14 * all attachment IDs found in the post's blocks during preparation.
     15 */
    1016class ContentAttachments extends AbsPostExtensionPost {
    1117
     18    /**
     19     * Adds collected attachment IDs to the content field of the post REST response.
     20     *
     21     * @param WP_REST_Response $response The current REST response.
     22     * @param WP_Post          $post     The post object.
     23     * @param WP_REST_Request  $request  The current REST request.
     24     * @return WP_REST_Response The modified response with "headless_attachment_ids" added.
     25     */
    1226    function response( WP_REST_Response $response, WP_Post $post, WP_REST_Request $request ): WP_REST_Response {
    1327        $data = $response->get_data();
  • headless/trunk/classes/Extensions/ContentBlocks.php

    r3072776 r3492765  
    99use WP_REST_Response;
    1010
     11/**
     12 * Extends the post REST response with parsed and prepared Gutenberg block data.
     13 *
     14 * Adds a "headless_blocks" field to the content object when the post has blocks.
     15 * Skips blocks and other heavy fields when the request uses the teasers variant.
     16 * Applies all registered block preparations during parsing.
     17 */
    1118class ContentBlocks extends AbsPostExtensionPost {
    1219
     20    /**
     21     * @var BlockPreparations The registered block preparation handlers.
     22     */
    1323    private BlockPreparations $preparations;
    1424
     25    /**
     26     * @param BlockPreparations $preparations The block preparations collection to use.
     27     */
    1528    public function __construct(BlockPreparations $preparations) {
    1629        parent::__construct();
     
    2134    }
    2235
     36    /**
     37     * Adds parsed block data to the post REST response.
     38     *
     39     * @param WP_REST_Response $response The current REST response.
     40     * @param WP_Post          $post     The post object.
     41     * @param WP_REST_Request  $request  The current REST request.
     42     * @return WP_REST_Response The modified response with "headless_blocks" added to content.
     43     */
    2344    function response( WP_REST_Response $response, WP_Post $post, WP_REST_Request $request ): WP_REST_Response {
    2445        $data = $response->get_data();
     
    4162    }
    4263
     64    /**
     65     * Filters out blocks that should not be included in the response.
     66     *
     67     * Uses the Plugin::FILTER_BLOCKS_PREPARE_FILTER filter to determine inclusion.
     68     *
     69     * @param array $blocks The raw array of parsed blocks.
     70     * @return array The filtered blocks with sequential keys.
     71     */
    4372    private function filterBlocks( $blocks ) {
    4473        return array_values( array_filter( $blocks, function ( $block ) {
     
    4776    }
    4877
     78    /**
     79     * Parses raw post content into a prepared array of blocks.
     80     *
     81     * @param string $post_content The raw block content string.
     82     * @param int    $level        The current nesting depth (1 for top-level).
     83     * @return array The prepared block array.
     84     */
    4985    private function parse($post_content, $level = 1): array {
    5086        $blocks = parse_blocks($post_content);
     
    5288    }
    5389
     90    /**
     91     * Filters and prepares a set of blocks by applying registered preparations recursively.
     92     *
     93     * @param array $blocks The blocks to prepare.
     94     * @param int   $level  The current nesting depth.
     95     * @return array The prepared blocks.
     96     */
    5497    private function prepare( $blocks, $level ) {
    5598        $blocks = $this->filterBlocks( $blocks );
  • headless/trunk/classes/Extensions/FeaturedMedia.php

    r2766747 r3492765  
    88use WP_REST_Response;
    99
     10/**
     11 * Extends the post REST response with detailed featured media information.
     12 *
     13 * Adds featured_media_url, featured_media_src, featured_media_sizes,
     14 * featured_media_caption, featured_media_description, and featured_media_alt fields.
     15 */
    1016class FeaturedMedia extends AbsPostExtensionPost {
    1117
     18    /**
     19     * Appends featured media data to the post REST response.
     20     *
     21     * @param WP_REST_Response $response The current REST response.
     22     * @param WP_Post          $post     The post object.
     23     * @param WP_REST_Request  $request  The current REST request.
     24     * @return WP_REST_Response The modified response with featured media fields added.
     25     */
    1226    function response( WP_REST_Response $response, WP_Post $post, WP_REST_Request $request ): WP_REST_Response {
    1327        $data = $response->get_data();
     
    3650    }
    3751
     52    /**
     53     * Returns all available intermediate image size sources for the given attachment.
     54     *
     55     * @param int $imageId The attachment ID.
     56     * @return array[] Array of wp_get_attachment_image_src result arrays for each size.
     57     */
    3858    static function imageSizes( $imageId ) {
    3959        return array_values(
  • headless/trunk/classes/Extensions/Taxonomies.php

    r2748985 r3492765  
    77use WP_REST_Response;
    88
     9/**
     10 * Extends the post REST response with taxonomy term IDs for all REST-visible taxonomies.
     11 *
     12 * Adds any missing taxonomy fields that may not appear by default, which is
     13 * particularly useful for custom post types requested via hl_post_type.
     14 */
    915class Taxonomies extends AbsPostExtensionPost {
    1016
  • headless/trunk/classes/Extensions/Title.php

    r2730402 r3492765  
    77use WP_REST_Response;
    88
     9/**
     10 * Extends the post REST response by HTML-decoding the rendered title.
     11 *
     12 * Converts HTML entities in the title's "rendered" field to their plain text equivalents.
     13 */
    914class Title extends AbsPostExtensionPost {
    1015
     16    /**
     17     * Decodes HTML entities in the post title before returning the response.
     18     *
     19     * @param WP_REST_Response $response The current REST response.
     20     * @param WP_Post          $post     The post object.
     21     * @param WP_REST_Request  $request  The current REST request.
     22     * @return WP_REST_Response The modified response with decoded title.
     23     */
    1124    function response( WP_REST_Response $response, WP_Post $post, WP_REST_Request $request ): WP_REST_Response {
    1225        $data = $response->get_data();
  • headless/trunk/classes/Headers.php

    r3196946 r3492765  
    33namespace Palasthotel\WordPress\Headless;
    44
     5/**
     6 * Sets cache-control headers on REST API responses for headless requests.
     7 *
     8 * Applies a stale-while-revalidate caching strategy to REST responses
     9 * when the request is identified as a headless request.
     10 */
    511class Headers extends Components\Component {
    612    public function onCreate(): void {
     
    915    }
    1016
     17    /**
     18     * Adds Cache-Control headers to the REST response for headless requests.
     19     *
     20     * @param \WP_REST_Response $response The REST response object.
     21     * @return \WP_REST_Response The modified response with cache headers applied.
     22     */
    1123    public function rest_post_dispatch(\WP_REST_Response $response){
    1224        if($this->plugin->security->isHeadlessRequest()){
  • headless/trunk/classes/Headquarter.php

    r2868064 r3492765  
    66use Palasthotel\WordPress\Headless\Model\Frontend;
    77
     8/**
     9 * Provides the list of configured headless frontend instances.
     10 *
     11 * Returns Frontend objects based on the HEADLESS_HEAD_BASE_URL constant,
     12 * with support for filtering via the Plugin::FILTER_FRONTENDS hook.
     13 */
    814class Headquarter extends Component {
    915
  • headless/trunk/classes/Interfaces/IBlockPreparation.php

    r2748985 r3492765  
    55use Palasthotel\WordPress\Headless\Model\BlockName;
    66
    7 interface IBlockPreparation {
    8 
     7/**
     8 * Contract for block preparation handlers.
     9 *
     10 * Implementations transform a parsed Gutenberg block array before it’s
     11 * included in the headless REST API response.
     12 */
     13interface IBlockPreparation
     14{
     15    /**
     16     * Returns the block name this preparation applies to, or null to apply to all blocks.
     17     *
     18     * @return BlockName|null The target block name, or null for a catch-all preparation.
     19     */
    920    function blockName(): ?BlockName;
    1021
    11     function prepare( array $block ): array;
     22    /**
     23     * Transforms the block data array.
     24     *
     25     * @param array $block The parsed block data.
     26     * @return array The modified block data.
     27     */
     28    function prepare(array $block): array;
    1229}
  • headless/trunk/classes/Interfaces/ICommentRouteExtension.php

    r2766747 r3492765  
    66use WP_REST_Response;
    77
     8/**
     9 * Contract for extensions that modify the REST API response for comments.
     10 */
    811interface ICommentRouteExtension {
     12
     13    /**
     14     * Modifies the REST response for a comment.
     15     *
     16     * @param WP_REST_Response $response The current REST response.
     17     * @param \WP_Comment      $comment  The comment object.
     18     * @param WP_REST_Request  $request  The current REST request.
     19     * @return WP_REST_Response The modified response.
     20     */
    921    function response( WP_REST_Response $response, \WP_Comment $comment, WP_REST_Request $request): WP_REST_Response;
    1022}
  • headless/trunk/classes/Interfaces/IPostRouteExtension.php

    r2730402 r3492765  
    77use WP_REST_Response;
    88
     9/**
     10 * Contract for extensions that modify the REST API response for posts.
     11 */
    912interface IPostRouteExtension {
     13
     14    /**
     15     * Modifies the REST response for a post.
     16     *
     17     * @param WP_REST_Response $response The current REST response.
     18     * @param WP_Post          $post     The post object.
     19     * @param WP_REST_Request  $request  The current REST request.
     20     * @return WP_REST_Response The modified response.
     21     */
    1022    function response( WP_REST_Response $response, WP_Post $post, WP_REST_Request $request): WP_REST_Response;
    1123}
  • headless/trunk/classes/Interfaces/ITermRouteExtension.php

    r2791162 r3492765  
    66use WP_REST_Response;
    77
    8 interface ITermRouteExtension {
    9 
     8/**
     9 * Contract for extensions that modify the REST API response for taxonomy terms
     10 */
     11interface ITermRouteExtension
     12{
    1013    /**
    1114     * @return string[]
     
    1316    function taxonomies(): array;
    1417
    15     function response( WP_REST_Response $response, \WP_Term $comment, WP_REST_Request $request): WP_REST_Response;
     18    /**
     19     * Modifies the REST response for a term.
     20     *
     21     * @param WP_REST_Response $response The current REST response.
     22     * @param \WP_Term         $comment  The term object.
     23     * @param WP_REST_Request  $request  The current REST request.
     24     * @return WP_REST_Response The modified response.
     25     */
     26    function response(
     27        WP_REST_Response $response,
     28        \WP_Term $comment,
     29        WP_REST_Request $request,
     30    ): WP_REST_Response;
    1631}
  • headless/trunk/classes/Interfaces/IUserRouteExtension.php

    r2791162 r3492765  
    66use WP_REST_Response;
    77
     8/**
     9 * Contract for extensions that modify the REST API response for users.
     10 */
    811interface IUserRouteExtension {
     12
     13    /**
     14     * Modifies the REST response for a user.
     15     *
     16     * @param WP_REST_Response $response The current REST response.
     17     * @param \WP_User         $comment  The user object.
     18     * @param WP_REST_Request  $request  The current REST request.
     19     * @return WP_REST_Response The modified response.
     20     */
    921    function response( WP_REST_Response $response, \WP_User $comment, WP_REST_Request $request): WP_REST_Response;
    1022}
  • headless/trunk/classes/Log.php

    r3196946 r3492765  
    33namespace Palasthotel\WordPress\Headless;
    44
     5/**
     6 * Provides logging for the headless plugin.
     7 *
     8 * Writes info and warning messages to CronLogger if available,
     9 * falling back to error_log. Also forwards messages to WP-CLI when running in CLI context.
     10 */
    511class Log extends Components\Component {
    612    /**
     
    1622    }
    1723
     24    /**
     25     * Logs an info-level message.
     26     *
     27     * @param string $message The message to log.
     28     * @return void
     29     */
    1830    public function add($message){
    1931        if(class_exists('\CronLogger\Log') && $this->log instanceof \CronLogger\Log){
     
    2739    }
    2840
     41    /**
     42     * Logs a warning-level message, prefixed with "WARNING:".
     43     *
     44     * @param string $message The warning message to log.
     45     * @return void
     46     */
    2947    public function warning($message){
    3048        if(class_exists('\CronLogger\Log') && $this->log instanceof \CronLogger\Log){
  • headless/trunk/classes/Migration.php

    r3196946 r3492765  
    33namespace Palasthotel\WordPress\Headless;
    44
     5/**
     6 * Handles database schema migrations for the headless plugin.
     7 *
     8 * Checks the current schema version on component creation and runs
     9 * any necessary upgrade steps, including dropping and recreating tables.
     10 */
    511class Migration extends Components\Component {
    612
    713    const LATEST_VERSION = 3;
    814
     15    /**
     16     * Persists the current schema version to the database.
     17     *
     18     * @param int $version The schema version number to store.
     19     * @return bool True if the option was updated, false otherwise.
     20     */
    921    private function setSchemaVersion(int $version): bool {
    1022        return update_option(Plugin::OPTION_SCHEMA_VERSION, $version);
    1123    }
     24    /**
     25     * Retrieves the current schema version from the database.
     26     *
     27     * @return int The stored schema version, or 0 if not set.
     28     */
    1229    private function getSchemaVersion(): int {
    1330        return intval(get_option(Plugin::OPTION_SCHEMA_VERSION, 0));
  • headless/trunk/classes/Model/BlockName.php

    r2730402 r3492765  
    33namespace Palasthotel\WordPress\Headless\Model;
    44
     5/**
     6 * Represents a Gutenberg block name composed of a namespace and a block ID.
     7 *
     8 * Stringifies to the standard "namespace/id" format used by WordPress block names.
     9 */
    510class BlockName {
    611
     12    /**
     13     * @var string The block namespace (e.g. "core").
     14     */
    715    private string $namespace;
     16
     17    /**
     18     * @var string The block identifier within the namespace (e.g. "paragraph").
     19     */
    820    private string $id;
    921
     22    /**
     23     * @param string $namespace The block namespace.
     24     * @param string $id        The block identifier.
     25     */
    1026    public function __construct(string $namespace, string $id) {
    1127        $this->namespace = $namespace;
     
    1329    }
    1430
     31    /**
     32     * Named constructor for creating a BlockName instance.
     33     *
     34     * @param string $namespace The block namespace.
     35     * @param string $id        The block identifier.
     36     * @return static A new BlockName instance.
     37     */
    1538    public static function build(string $namespace, string $id){
    1639        return new static($namespace, $id);
    1740    }
    1841
     42    /**
     43     * Returns the full block name in "namespace/id" format.
     44     *
     45     * @return string The block name string.
     46     */
    1947    public function __toString(): string {
    2048        return $this->namespace."/".$this->id;
  • headless/trunk/classes/Model/BlockPreparations.php

    r2730402 r3492765  
    55use Palasthotel\WordPress\Headless\Interfaces\IBlockPreparation;
    66
     7/**
     8 * Collection of IBlockPreparation instances.
     9 *
     10 * Used to register and retrieve all active block preparation handlers.
     11 */
    712class BlockPreparations {
    813
     
    1217    private array $items = [];
    1318
     19    /**
     20     * Adds a block preparation handler to the collection.
     21     *
     22     * @param IBlockPreparation $extension The block preparation to add.
     23     * @return void
     24     */
    1425    public function add( IBlockPreparation $extension ) {
    1526        $this->items[] = $extension;
    1627    }
    1728
     29    /**
     30     * Returns all registered block preparation handlers.
     31     *
     32     * @return IBlockPreparation[] The registered handlers.
     33     */
    1834    public function get(){
    1935        return $this->items;
  • headless/trunk/classes/Model/CommentRouteExtensions.php

    r2791162 r3492765  
    55use Palasthotel\WordPress\Headless\Interfaces\ICommentRouteExtension;
    66
     7/**
     8 * Collection of ICommentRouteExtension instances.
     9 *
     10 * Used to register and retrieve all active comment route extension handlers.
     11 */
    712class CommentRouteExtensions {
    813
     
    1217    private array $items = [];
    1318
     19    /**
     20     * Adds a comment route extension to the collection.
     21     *
     22     * @param ICommentRouteExtension $extension The extension to add.
     23     * @return void
     24     */
    1425    public function add( ICommentRouteExtension $extension ) {
    1526        $this->items[] = $extension;
    1627    }
    1728
     29    /**
     30     * Returns all registered comment route extensions.
     31     *
     32     * @return ICommentRouteExtension[] The registered extensions.
     33     */
    1834    public function get(){
    1935        return $this->items;
  • headless/trunk/classes/Model/Frontend.php

    r2868064 r3492765  
    33namespace Palasthotel\WordPress\Headless\Model;
    44
     5/**
     6 * Represents a headless frontend instance identified by its base URL.
     7 */
    58class Frontend {
     9
     10    /**
     11     * @var string The base URL of the headless frontend, with trailing slash.
     12     */
    613    private string $baseUrl;
     14
     15    /**
     16     * @param string $baseUrl The base URL of the frontend.
     17     */
    718    public function __construct( string $baseUrl ) {
    819        $this->baseUrl = $baseUrl;
    920    }
    1021
     22    /**
     23     * Returns the base URL of the frontend.
     24     *
     25     * @return string The base URL.
     26     */
    1127    public function getBaseUrl(): string {
    1228        return $this->baseUrl;
  • headless/trunk/classes/Model/PostContentAttachmentCollector.php

    r2730402 r3492765  
    33namespace Palasthotel\WordPress\Headless\Model;
    44
     5/**
     6 * Tracks attachment IDs referenced within post content during block preparation.
     7 *
     8 * Acts as a static registry mapping post IDs to arrays of attachment IDs
     9 * found in the post's content blocks.
     10 */
    511class PostContentAttachmentCollector {
    612
     13    /**
     14     * @var array<int, int[]> Map of post ID to array of attachment IDs.
     15     */
    716    public static array $map = [];
    817
     18    /**
     19     * Returns all attachment IDs collected for the given post.
     20     *
     21     * @param int $postId The post ID.
     22     * @return int[] Array of attachment IDs, or empty array if none collected.
     23     */
    924    public static function get($postId){
    1025        return static::$map[ $postId ] ?? [];
    1126    }
    1227
     28    /**
     29     * Registers an attachment ID for the given post, avoiding duplicates.
     30     *
     31     * @param int $postId       The post ID to associate the attachment with.
     32     * @param int $attachmentId The attachment ID to register.
     33     * @return void
     34     */
    1335    public static function add($postId, $attachmentId){
    1436        $attachmentId = intval($attachmentId);
  • headless/trunk/classes/Model/PostRouteExtensions.php

    r2730402 r3492765  
    55use Palasthotel\WordPress\Headless\Interfaces\IPostRouteExtension;
    66
     7/**
     8 * Collection of IPostRouteExtension instances.
     9 *
     10 * Used to register and retrieve all active post route extension handlers.
     11 */
    712class PostRouteExtensions {
    813
     
    1217    private array $items = [];
    1318
     19    /**
     20     * Adds a post route extension to the collection.
     21     *
     22     * @param IPostRouteExtension $extension The extension to add.
     23     * @return void
     24     */
    1425    public function add( IPostRouteExtension $extension ) {
    1526        $this->items[] = $extension;
    1627    }
    1728
     29    /**
     30     * Returns all registered post route extensions.
     31     *
     32     * @return IPostRouteExtension[] The registered extensions.
     33     */
    1834    public function get(){
    1935        return $this->items;
  • headless/trunk/classes/Model/TermRouteExtensions.php

    r2791162 r3492765  
    55use Palasthotel\WordPress\Headless\Interfaces\ITermRouteExtension;
    66
     7/**
     8 * Collection of ITermRouteExtension instances.
     9 *
     10 * Used to register and retrieve all active term route extension handlers.
     11 */
    712class TermRouteExtensions {
    813
     
    1217    private array $items = [];
    1318
     19    /**
     20     * Adds a term route extension to the collection.
     21     *
     22     * @param ITermRouteExtension $extension The extension to add.
     23     * @return void
     24     */
    1425    public function add( ITermRouteExtension $extension ) {
    1526        $this->items[] = $extension;
    1627    }
    1728
     29    /**
     30     * Returns all registered term route extensions.
     31     *
     32     * @return ITermRouteExtension[] The registered extensions.
     33     */
    1834    public function get(){
    1935        return $this->items;
  • headless/trunk/classes/Model/UserRouteExtensions.php

    r2791162 r3492765  
    55use Palasthotel\WordPress\Headless\Interfaces\IUserRouteExtension;
    66
     7/**
     8 * Collection of IUserRouteExtension instances.
     9 *
     10 * Used to register and retrieve all active user route extension handlers.
     11 */
    712class UserRouteExtensions {
    813
     
    1217    private array $items = [];
    1318
     19    /**
     20     * Adds a user route extension to the collection.
     21     *
     22     * @param IUserRouteExtension $extension The extension to add.
     23     * @return void
     24     */
    1425    public function add( IUserRouteExtension $extension ) {
    1526        $this->items[] = $extension;
    1627    }
    1728
     29    /**
     30     * Returns all registered user route extensions.
     31     *
     32     * @return IUserRouteExtension[] The registered extensions.
     33     */
    1834    public function get(){
    1935        return $this->items;
  • headless/trunk/classes/PluginAssets.php

    r3196946 r3492765  
    66use Palasthotel\WordPress\Headless\Components\Component;
    77
     8/**
     9 * Registers and enqueues plugin scripts and styles for the admin and block editor.
     10 *
     11 * Handles the Gutenberg editor script/style and the general admin script,
     12 * including localized data for frontend URLs, AJAX actions, and preview settings.
     13 */
    814class PluginAssets extends Component {
    915
     
    1218    const HANDLE_GUTENBERG_STYLE = "headless_gutenberg_styles";
    1319
     20    /**
     21     * @var Assets Asset registration helper.
     22     */
    1423    public Assets $assets;
    1524
     
    2332    }
    2433
     34    /**
     35     * Registers all plugin scripts and styles and enqueues the admin script for editors.
     36     *
     37     * @return void
     38     */
    2539    public function admin_init() {
    2640        $this->assets->registerScript(
     
    7185    }
    7286
     87    /**
     88     * Enqueues the Gutenberg script and style for headless post types in the block editor.
     89     *
     90     * @return void
     91     */
    7392    public function enqueue() {
    7493        if ( ! $this->plugin->post->isHeadlessPostType( get_post_type() ) ) {
  • headless/trunk/classes/Post.php

    r3196946 r3492765  
    77use WP_Term;
    88
     9/**
     10 * Handles post data preparation for the headless REST API response.
     11 *
     12 * Extends the default post response with featured media details, taxonomy terms,
     13 * and other post fields needed by the headless frontend.
     14 */
    915class Post extends Component {
    1016    public function onCreate(): void {
     
    1319    }
    1420
     21    /**
     22     * Determines whether the given post type is a headless post type.
     23     *
     24     * @param string $postType The post type slug to check.
     25     * @return bool True if the post type is considered headless, filterable via Plugin::FILTER_IS_HEADLESS_POST_TYPE.
     26     */
    1527    public function isHeadlessPostType(string $postType){
    1628        return apply_filters(Plugin::FILTER_IS_HEADLESS_POST_TYPE, true, $postType);
    1729    }
    1830
     31    /**
     32     * Filters the post response array to include headless-specific fields.
     33     *
     34     * Adds id, type, title, slug, featured media data, excerpt, and REST-visible taxonomy terms.
     35     *
     36     * @param array            $response   The existing response data array.
     37     * @param int|\WP_Post     $id_or_post A post ID or WP_Post object.
     38     * @return array The merged response array with headless fields appended.
     39     */
    1940    public function prepare_post( array $response, $id_or_post ): array {
    2041        $post            = get_post( $id_or_post );
  • headless/trunk/classes/Preview.php

    r3254930 r3492765  
    66use WP_Post;
    77
     8/**
     9 * Manages the headless preview functionality for WordPress posts.
     10 *
     11 * Overrides the standard WordPress preview link to redirect editors to the
     12 * headless frontend preview URL via an AJAX action. Supports enabling and
     13 * disabling preview functionality through a filter.
     14 */
    815class Preview extends Component {
    916
     
    1926    }
    2027
     28    /**
     29     * Builds the WordPress admin-ajax.php redirect URL for headless preview.
     30     *
     31     * @param int|null $id The post ID, or null to use the placeholder string.
     32     * @return string The admin AJAX URL for the headless preview action.
     33     */
    2134    public function getRedirectLink( $id ) {
    2235        if($id == null){
     
    2740    }
    2841
     42    /**
     43     * Returns the path segment for the headless frontend preview endpoint.
     44     *
     45     * @return string The preview path including the secret token query parameter.
     46     */
    2947    public function getHeadlessPreviewPath(){
    3048        return "/api/preview?secret_token=".HEADLESS_SECRET_TOKEN;
     
    4866    }
    4967
     68    /**
     69     * Filters the preview post link to redirect to the headless frontend preview.
     70     *
     71     * Only applies to headless post types; returns the original link for others.
     72     *
     73     * @param string  $link The default WordPress preview link.
     74     * @param WP_Post $post The post being previewed.
     75     * @return string The headless redirect URL or the original link.
     76     */
    5077    public function preview_post_link( string $link, WP_Post $post ) {
    5178
     
    6087    }
    6188
     89    /**
     90     * Handles the headless_preview AJAX action for logged-in users.
     91     *
     92     * Validates the post exists and the user has edit permission, then
     93     * redirects to the headless frontend preview URL.
     94     *
     95     * @return void
     96     */
    6297    public function admin_preview() {
    6398        $postId = intval( $_GET["post"] );
     
    77112    }
    78113
     114    /**
     115     * Handles the headless_preview AJAX action for unauthenticated users.
     116     *
     117     * Returns a 403 Forbidden response.
     118     *
     119     * @return void
     120     */
    79121    public function no_permission() {
    80122        header('HTTP/1.0 403 Forbidden');
     
    82124    }
    83125
     126    /**
     127     * Removes preview hooks when preview functionality is inactive.
     128     *
     129     * @return void
     130     */
    84131    public function plugins_loaded() {
    85132        if($this->isPreviewInactive()){
     
    90137    }
    91138
     139    /**
     140     * Checks whether preview functionality is inactive.
     141     *
     142     * @return bool True if preview is inactive.
     143     */
    92144    function isPreviewInactive() {
    93145        return !$this->isPreviewActive();
    94146    }
     147    /**
     148     * Checks whether preview functionality is active.
     149     *
     150     * @return bool True if preview is active, filterable via Plugin::FILTER_PREVIEW_IS_ACTIVE.
     151     */
    95152    function isPreviewActive() {
    96153        return apply_filters(Plugin::FILTER_PREVIEW_IS_ACTIVE, true);
  • headless/trunk/classes/Query.php

    r3196946 r3492765  
    55use Palasthotel\WordPress\Headless\Components\Component;
    66
     7/**
     8 * Extends REST API queries with custom meta and post type filtering parameters.
     9 *
     10 * Adds support for filtering REST posts queries by meta key/value pairs,
     11 * meta existence checks, and multiple post types via custom request parameters.
     12 * Only active on requests with valid API key access.
     13 */
    714class Query extends Component {
    815
     
    2734    }
    2835
     36    /**
     37     * Extracts and validates the post types requested via the hl_post_type parameter.
     38     *
     39     * @param \WP_REST_Request $request The current REST request.
     40     * @return string[] An array of validated post type slugs, or ["any"] if requested.
     41     */
    2942    public static function getRequestPostTypes( \WP_REST_Request $request ) {
    3043        $post_types = $request->get_param( static::POST_TYPE );
     
    4457    }
    4558
     59    /**
     60     * Filters the REST query arguments to apply meta and post type parameters.
     61     *
     62     * Processes hl_meta_keys, hl_meta_values, hl_meta_compares, hl_meta_exists,
     63     * hl_meta_not_exists, hl_meta_relation, and hl_post_type request parameters.
     64     *
     65     * @param array             $args    The current WP_Query arguments.
     66     * @param \WP_REST_Request  $request The current REST request.
     67     * @return array The modified query arguments.
     68     */
    4669    public function rest_query( array $args, \WP_REST_Request $request ) {
    4770
  • headless/trunk/classes/Revalidate.php

    r3196946 r3492765  
    66use Palasthotel\WordPress\Headless\Model\Frontend;
    77
     8/**
     9 * Triggers cache revalidation on headless frontends for posts and comments.
     10 *
     11 * Listens for post saves and comment changes to queue revalidation requests.
     12 * Supports revalidation by path, tag, or post ID across all configured frontends.
     13 * Revalidation can be toggled via the Plugin::FILTER_REVALIDATE_IS_ACTIVE filter.
     14 */
    815class Revalidate extends Component {
    916
     
    1522    }
    1623
     24    /**
     25     * Queues a post for revalidation when it is saved.
     26     *
     27     * @param int $post_id The ID of the saved post.
     28     * @return void
     29     */
    1730    public function on_post_change($post_id){
    1831        if($this->isRevalidationInactive()) return;
     
    2134    }
    2235
     36    /**
     37     * Queues the associated post and comment for revalidation when a comment changes.
     38     *
     39     * @param int $comment_id The ID of the inserted or edited comment.
     40     * @return void
     41     */
    2342    public function on_comment_change($comment_id){
    2443        if($this->isRevalidationInactive()) return;
     
    2847    }
    2948
     49    /**
     50     * Revalidates comments for the given post across all frontends by tag.
     51     *
     52     * @param int $post_id The post ID whose comment cache should be revalidated.
     53     * @return (\WP_Error|true)[] Results from each frontend revalidation attempt.
     54     */
    3055    function revalidateComments($post_id){
    3156
     
    6186    }
    6287
     88    /**
     89     * Revalidates the permalink path of a post on the given frontend.
     90     *
     91     * @param Frontend   $frontend The frontend to revalidate on.
     92     * @param int|string $post_id  The post ID to look up and revalidate.
     93     * @return \WP_Error|true|array The revalidation result, or empty array if inactive.
     94     */
    6395    function revalidateByPathByPostId(Frontend $frontend, $post_id) {
    6496
     
    73105    }
    74106
     107    /**
     108     * Revalidates a specific path on the given frontend.
     109     *
     110     * @param Frontend   $frontend The frontend to revalidate on.
     111     * @param string     $path     The URL path to revalidate.
     112     * @return \WP_Error|true|array The revalidation result, or empty array if inactive.
     113     */
    75114    function revalidateByPath(Frontend $frontend, $path){
    76115
     
    84123    }
    85124
     125    /**
     126     * Revalidates all pages tagged with the given cache tag on the frontend.
     127     *
     128     * @param Frontend $frontend The frontend to revalidate on.
     129     * @param string   $tag      The cache tag to revalidate.
     130     * @return \WP_Error|true|array The revalidation result, or empty array if inactive.
     131     */
    86132    function revalidateByTag(Frontend $frontend, string $tag) {
    87133
     
    95141    }
    96142
     143    /**
     144     * Executes a revalidation HTTP request to the given URL.
     145     *
     146     * Appends a cache-busting query parameter and issues a GET request.
     147     *
     148     * @param string $finalUrl The fully constructed revalidation URL.
     149     * @return \WP_Error|true WP_Error on HTTP error or non-200 response, true on success.
     150     */
    97151    private function executeRavalidation($finalUrl){
    98152
     
    112166    }
    113167
     168    /**
     169     * Checks whether revalidation is currently inactive.
     170     *
     171     * @return bool True if revalidation is inactive.
     172     */
    114173    function isRevalidationInactive() {
    115174        return !$this->isRevalidationActive();
    116175    }
     176    /**
     177     * Checks whether revalidation is currently active.
     178     *
     179     * @return bool True if revalidation is active, filterable via Plugin::FILTER_REVALIDATE_IS_ACTIVE.
     180     */
    117181    function isRevalidationActive() {
    118182        return apply_filters(Plugin::FILTER_REVALIDATE_IS_ACTIVE, true);
  • headless/trunk/classes/Routes.php

    r3196946 r3492765  
    77use Palasthotel\WordPress\Headless\Routes\Settings;
    88
     9/**
     10 * Initializes and exposes the plugin's custom REST API routes.
     11 *
     12 * Registers the Menus and Settings REST route handlers on rest_api_init.
     13 */
    914class Routes extends Components\Component {
    1015
     16    /**
     17     * @var Menus REST route handler for navigation menus.
     18     */
    1119    public Menus $menus;
     20
     21    /**
     22     * @var Settings REST route handler for site settings.
     23     */
    1224    public Settings $settings;
    1325
     
    1729    }
    1830
     31    /**
     32     * Instantiates and initializes the Menus and Settings route handlers.
     33     *
     34     * @return void
     35     */
    1936    public function rest_api_init() {
    2037
  • headless/trunk/classes/Routes/Menus.php

    r3254930 r3492765  
    66use Palasthotel\WordPress\Headless\Plugin;
    77
     8/**
     9 * Registers REST API endpoints for retrieving WordPress navigation menus.
     10 *
     11 * Exposes GET /headless/v1/menus for all menus and
     12 * GET /headless/v1/menus/{slug} for a specific menu.
     13 * Requires both a headless request and valid API key access.
     14 */
    815class Menus extends Component {
    916
     17    /**
     18     * @var array Cached menu items for the current request.
     19     */
    1020    private array $menu;
    1121
     22    /**
     23     * Registers the menus REST routes.
     24     *
     25     * @return void
     26     */
    1227    public function init(){
    1328        register_rest_route( Plugin::REST_NAMESPACE, '/menus', array(
     
    2944    }
    3045
     46    /**
     47     * Returns all registered navigation menus keyed by slug.
     48     *
     49     * @return array<string, array> Map of menu slug to menu items array.
     50     */
    3151    public function get_all_menus() {
    3252        $menus = wp_get_nav_menus();
     
    3858    }
    3959
     60    /**
     61     * Returns the cached menu items for the current menu request.
     62     *
     63     * @return array The menu items array.
     64     */
    4065    public function get_menu() {
    4166        return $this->menu;
    4267    }
    4368
     69    /**
     70     * Retrieves and prepares menu items for a given menu, decoding HTML entities in titles.
     71     *
     72     * @param \WP_Term|object $menu The menu object or term to fetch items for.
     73     * @return array The array of prepared menu item objects, or empty array if not found.
     74     */
    4475    private function getMenuResponse($menu) {
    4576        $menu  = wp_get_nav_menu_items( $menu );
  • headless/trunk/classes/Routes/Settings.php

    r3196946 r3492765  
    66use Palasthotel\WordPress\Headless\Plugin;
    77
     8/**
     9 * Registers the REST API endpoint for retrieving site settings.
     10 *
     11 * Exposes GET /headless/v1/settings with front page configuration and home URL.
     12 * Requires both a headless request and valid API key access.
     13 */
    814class Settings extends Component {
    915
     16    /**
     17     * Registers the settings REST route.
     18     *
     19     * @return void
     20     */
    1021    public function init(): void {
    1122        register_rest_route( Plugin::REST_NAMESPACE, '/settings', array(
     
    1930    }
    2031
     32    /**
     33     * Returns key site settings for the headless frontend.
     34     *
     35     * @return array{front_page: string, page_on_front: int, home_url: string}
     36     */
    2137    public function get_settings(): array {
    2238        return [
  • headless/trunk/classes/Schedule.php

    r3196946 r3492765  
    55use Palasthotel\WordPress\Headless\Components\Component;
    66
     7/**
     8 * Manages the WordPress cron schedule for periodic cache revalidation.
     9 *
     10 * Registers an hourly cron event that processes pending post and comment
     11 * revalidations from the database queue. Unschedules the event when
     12 * revalidation is inactive.
     13 */
    714class Schedule extends Component {
    815
     
    1421    }
    1522
     23    /**
     24     * Sets up or removes the revalidation cron schedule based on active state.
     25     *
     26     * Schedules an hourly event if revalidation is active and not yet scheduled.
     27     * Removes the event if revalidation is inactive.
     28     *
     29     * @return void
     30     */
    1631    public function init(){
    1732        if($this->plugin->revalidate->isRevalidationInactive()){
     
    2742    }
    2843
     44    /**
     45     * Returns the timestamp for the next scheduled revalidation run.
     46     *
     47     * @return int|false The Unix timestamp, or false if not scheduled.
     48     */
    2949    public function getNextSchedule(){
    3050        return wp_next_scheduled(Plugin::SCHEDULE_REVALIDATE);
    3151    }
    3252
     53    /**
     54     * Returns the Unix timestamp of the last completed revalidation run.
     55     *
     56     * @return int The timestamp, or 0 if it has never run.
     57     */
    3358    public function getLastRevalidationRun(): int{
    3459        return intval(get_option(Plugin::OPTION_LAST_REVALIDATION_RUN, 0));
    3560    }
    3661
     62    /**
     63     * Persists the timestamp of the last revalidation run.
     64     *
     65     * @param int $time Unix timestamp of the run.
     66     * @return void
     67     */
    3768    public function setLastRevalidationRun(int $time) {
    3869        update_option(Plugin::OPTION_LAST_REVALIDATION_RUN, $time);
    3970    }
    4071
     72    /**
     73     * Processes all pending post and comment revalidations from the database queue.
     74     *
     75     * Called by the cron event. Iterates pending items, triggers revalidation,
     76     * updates each item's state to "revalidated" or "error", then fires a side-effect action.
     77     *
     78     * @return void
     79     */
    4180    public function revalidate(){
    4281
  • headless/trunk/classes/Security.php

    r3196946 r3492765  
    55use Palasthotel\WordPress\Headless\Components\Component;
    66
     7/**
     8 * Handles security checks for headless REST API access.
     9 *
     10 * Detects headless requests via a dedicated query parameter, validates
     11 * request variants, and enforces optional API key header authentication.
     12 * Also enables WordPress application passwords globally.
     13 */
    714class Security extends Component {
    815
     
    1219    }
    1320
     21    /**
     22     * Checks whether the current request is a headless REST request.
     23     *
     24     * @return bool True if the HEADLESS_REST_PARAM query parameter matches HEADLESS_REST_VALUE.
     25     */
    1426    public function isHeadlessRequest(): bool {
    1527        return isset( $_GET[ HEADLESS_REST_PARAM ] ) && HEADLESS_REST_VALUE == $_GET[ HEADLESS_REST_PARAM ];
    1628    }
    1729
     30    /**
     31     * Checks whether the current headless request matches a specific variant.
     32     *
     33     * @param string $variant The variant value to check against HEADLESS_REST_VARIANT_PARAM.
     34     * @return bool True if the variant parameter matches the given value.
     35     */
    1836    public function isHeadlessRequestVariant(string $variant): bool {
    1937        return isset( $_GET[ HEADLESS_REST_VARIANT_PARAM ] ) && $variant == $_GET[ HEADLESS_REST_VARIANT_PARAM ];
    2038    }
    2139
     40    /**
     41     * Checks whether the current request has valid API key access.
     42     *
     43     * If no API key constants are configured, all requests are granted access.
     44     * Otherwise, the request must include the correct API key header value.
     45     *
     46     * @return bool True if access is granted.
     47     */
    2248    public function hasApiKeyAccess(): bool {
    2349
  • headless/trunk/classes/Store/RevalidationDatabase.php

    r3196946 r3492765  
    77use Palasthotel\WordPress\Headless\Components\Database;
    88
     9/**
     10 * Manages the revalidation queue database table.
     11 *
     12 * Stores posts and comments pending cache revalidation, tracks their state
     13 * (pending, revalidated, error), and provides methods to add, query, and update entries.
     14 */
    915class RevalidationDatabase extends Database {
    1016
     
    1218    const TYPE_COMMENT = "comment";
    1319
     20    /**
     21     * @var string The full database table name for revalidation queue entries.
     22     */
    1423    public string $table;
    1524
     
    1827    }
    1928
     29    /**
     30     * Inserts or replaces a content entry in the revalidation queue with state "pending".
     31     *
     32     * @param string $id   The content ID.
     33     * @param string $type The content type (post or comment).
     34     * @return int|false The number of rows affected, or false on error.
     35     */
    2036    private function addContent(string $id, string $type) {
    2137        return $this->wpdb->replace(
     
    3046    }
    3147
     48    /**
     49     * Adds a post to the revalidation queue.
     50     *
     51     * @param int $post_id The post ID to queue.
     52     * @return int|false The number of rows affected, or false on error.
     53     */
    3254    public function addPost(int $post_id) {
    3355        return $this->addContent($post_id, self::TYPE_POST);
    3456    }
    3557
     58    /**
     59     * Adds a comment to the revalidation queue.
     60     *
     61     * @param string $comment_id The comment ID to queue.
     62     * @return int|false The number of rows affected, or false on error.
     63     */
    3664    public function addComment(string $comment_id) {
    3765        return $this->addContent($comment_id, self::TYPE_COMMENT);
     
    4169    /**
    4270     * @return Int[]
     71     */
     72    /**
     73     * Returns all content IDs with state "pending" for the given content type.
     74     *
     75     * @param string $type The content type (post or comment).
     76     * @return int[] Array of content IDs.
    4377     */
    4478    private function getPendingContents(string $type): array {
     
    5892    }
    5993
     94    /**
     95     * Returns all comment IDs currently pending revalidation.
     96     *
     97     * @return int[] Array of comment IDs.
     98     */
    6099    public function getPendingComments(): array {
    61100        return $this->getPendingContents(self::TYPE_COMMENT);
     
    63102
    64103
     104    /**
     105     * Counts content entries with state "pending" for the given content type.
     106     *
     107     * @param string $type The content type (post or comment).
     108     * @return int The count of pending entries.
     109     */
    65110    private function countPendingContents(string $type): int {
    66111        $sql = $this->wpdb->prepare(
     
    71116    }
    72117
     118    /**
     119     * Returns the count of posts currently pending revalidation.
     120     *
     121     * @return int The number of pending posts.
     122     */
    73123    public function countPendingPosts(): int {
    74124        return $this->countPendingContents(self::TYPE_POST);
    75125    }
    76126
     127    /**
     128     * Returns the count of comments currently pending revalidation.
     129     *
     130     * @return int The number of pending comments.
     131     */
    77132    public function countPendingComments(): int {
    78133        return $this->countPendingContents(self::TYPE_COMMENT);
    79134    }
    80135
     136    /**
     137     * Updates the revalidation state and timestamp for a content entry.
     138     *
     139     * @param int    $id    The content ID.
     140     * @param string $type  The content type (post or comment).
     141     * @param string $state The new state (e.g. "revalidated" or "error").
     142     * @return int|false The number of rows updated, or false on error.
     143     */
    81144    public function setContentState(int $id, string $type, $state = "revalidated") {
    82145        return $this->wpdb->update(
     
    95158    }
    96159
     160    /**
     161     * Updates the revalidation state for a post entry.
     162     *
     163     * @param int    $post_id The post ID.
     164     * @param string $state   The new state (default "revalidated").
     165     * @return int|false The number of rows updated, or false on error.
     166     */
    97167    public function setPostState(int $post_id, $state = "revalidated") {
    98168        return $this->setContentState($post_id, self::TYPE_POST, $state);
    99169    }
    100170
     171    /**
     172     * Updates the revalidation state for a comment entry.
     173     *
     174     * @param int    $comment_id The comment ID.
     175     * @param string $state      The new state (default "revalidated").
     176     * @return int|false The number of rows updated, or false on error.
     177     */
    101178    public function setCommentState(int $comment_id, $state = "revalidated") {
    102179        return $this->setContentState($comment_id, self::TYPE_COMMENT, $state);
    103180    }
    104181
     182    /**
     183     * Creates the revalidation queue table if it does not already exist.
     184     *
     185     * @return void
     186     */
    105187    public function createTables(): void {
    106188        parent::createTables();
  • headless/trunk/classes/Utils.php

    r2730402 r3492765  
    33namespace Palasthotel\WordPress\Headless;
    44
     5/**
     6 * Utility helpers for the headless plugin.
     7 */
    58class Utils {
     9
     10    /**
     11     * Sanitizes HTML content, allowing only a safe subset of tags, and strips newlines.
     12     *
     13     * Permitted tags: a (href, target, rel), b, i, strong.
     14     *
     15     * @param string $html The raw HTML string to sanitize.
     16     * @return string The sanitized HTML with newlines removed.
     17     */
    618    public static function prepareHTML($html){
    719        return  str_replace( "\n", "", wp_kses(
  • headless/trunk/dist/admin.asset.php

    r3196946 r3492765  
    1 <?php return array('dependencies' => array(), 'version' => '8241f02c6df14b01c628');
     1<?php return array('dependencies' => array(), 'version' => '81924321d7c2c4b3be9a');
  • headless/trunk/dist/admin.js

    r3196946 r3492765  
    1 (()=>{"use strict";window.addEventListener("DOMContentLoaded",(async()=>{window.HeadlessAdmin.preview_is_active&&await Promise.all(window.HeadlessAdmin.frontends.map((e=>e+window.HeadlessAdmin.preview_path)).map((e=>fetch(e,{credentials:"include"}).then((e=>e.json())))))}))})();
     1(()=>{"use strict";window.addEventListener("DOMContentLoaded",async()=>{window.HeadlessAdmin.preview_is_active&&await Promise.all(window.HeadlessAdmin.frontends.map(e=>e+window.HeadlessAdmin.preview_path).map(e=>fetch(e,{credentials:"include"}).then(e=>e.json())))})})();
  • headless/trunk/dist/gutenberg.asset.php

    r3196946 r3492765  
    1 <?php return array('dependencies' => array('react-jsx-runtime', 'wp-components', 'wp-data', 'wp-edit-post', 'wp-element', 'wp-plugins'), 'version' => 'f64387f5a68638e1237e');
     1<?php return array('dependencies' => array('react-jsx-runtime', 'wp-components', 'wp-data', 'wp-editor', 'wp-element', 'wp-plugins'), 'version' => '05ef464d3548625e183a');
  • headless/trunk/dist/gutenberg.js

    r3196946 r3492765  
    1 (()=>{"use strict";const t=window.wp.plugins,e=window.wp.editPost,n=window.wp.components,s=window.wp.data,i=window.wp.element,a=()=>(0,s.useSelect)((t=>t("core/editor").getCurrentPost()),[]),r=window.ReactJSXRuntime,o=({index:t,baseUrl:e,controller:n,onStateChanged:s})=>{const{state:o,reload:l}=(t=>{const[e,n]=(0,i.useState)("idle"),s=a(),r=(0,i.useMemo)((()=>s?.link?new URL(s?.link).pathname:""),[s.link]);return{state:e,reload:()=>{n("loading"),(async()=>{try{const e=await fetch(((t,e)=>window.Headless.ajax+`?action=${window.Headless.actions.revalidate}&frontend=${t}&path=${e}`)(t,r)),s=await e.json();s.success?n("success"):(console.error(s),n("error"))}catch(t){n("error")}})()}}})(t),c=a(),d=(0,i.useMemo)((()=>{const t=c.link,n=new URL(t);return e.replace(/^\/|\/$/g,"")+n.pathname}),[c.link]);return(0,i.useEffect)((()=>{n.add(t,l)}),[t]),(0,i.useEffect)((()=>{s(t,o)}),[o]),(0,r.jsxs)("div",{title:d,children:[(0,r.jsxs)("a",{href:d,target:"_blank",children:["Frontend ",t]}),"loading"==o&&(0,r.jsx)(r.Fragment,{children:" 🧹"}),"success"==o&&(0,r.jsx)(r.Fragment,{children:" ✅"}),"error"==o&&(0,r.jsx)(r.Fragment,{children:" 🚨"})]})};window.HeadlessAdmin.revalidate_is_active&&(0,t.registerPlugin)("headless-plugin",{icon:()=>null,render:function(){const t=window.Headless.frontends,s=(0,i.useMemo)((()=>(()=>{const t=new Map;return{add:(e,n)=>{t.set(e,n)},run:()=>{t.forEach((t=>{t()}))}}})()),[]),[l,c]=(0,i.useState)({}),d="publish"==a().status,p=Object.values(l).find((t=>1==t));return(0,r.jsx)(e.PluginDocumentSettingPanel,{title:"Headless",children:d?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("ol",{children:t.map(((t,e)=>(0,r.jsx)("li",{children:(0,r.jsx)(o,{baseUrl:t,index:e,controller:s,onStateChanged:(t,e)=>{c((n=>{const s={...n};return s[t]="loading"==e,s}))}})},e)))}),(0,r.jsx)(n.Button,{variant:"secondary",disabled:p||!d,onClick:()=>{s.run()},children:"Revalidate cache"})]}):(0,r.jsx)("p",{className:"description",children:"Only published contents can be revalidated."})})}}),document.addEventListener("DOMContentLoaded",(function(){if(!window.HeadlessAdmin.preview_is_active)return;const t=(0,s.select)("core/editor"),e=t.getCurrentPostId,n=t.isSavingPost,i=(0,s.dispatch)("core/editor"),a=i.autosave,r=i.savePost,o=document.createElement("a");o.className="components-button",o.addEventListener("click",(e=>{if(e.preventDefault(),n())return;const s=window.open("about:blank",o.target);!function(t){let e="";e+='\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tmargin: 0;\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-direction: column;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\twidth: 100vw;\n\t\t\t}\n\t\t\t@-webkit-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@-moz-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@-o-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message svg {\n\t\t\t\twidth: 192px;\n\t\t\t\theight: 192px;\n\t\t\t\tstroke: #555d66;\n\t\t\t\tstroke-width: 0.75;\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message svg .outer,\n\t\t\t.editor-post-preview-button__interstitial-message svg .inner {\n\t\t\t\tstroke-dasharray: 280;\n\t\t\t\tstroke-dashoffset: 280;\n\t\t\t\t-webkit-animation: paint 1.5s ease infinite alternate;\n\t\t\t\t-moz-animation: paint 1.5s ease infinite alternate;\n\t\t\t\t-o-animation: paint 1.5s ease infinite alternate;\n\t\t\t\tanimation: paint 1.5s ease infinite alternate;\n\t\t\t}\n\t\t\tp {\n\t\t\t\ttext-align: center;\n\t\t\t\tfont-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;\n\t\t\t}\n\t\t</style>\n\t',e+='\n        <div class="editor-post-preview-button__interstitial-message">\n            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">\n                <path class="outer" d="M48 12c19.9 0 36 16.1 36 36S67.9 84 48 84 12 67.9 12 48s16.1-36 36-36" fill="none" />\n                <path class="inner" d="M69.5 46.4c0-3.9-1.4-6.7-2.6-8.8-1.6-2.6-3.1-4.9-3.1-7.5 0-2.9 2.2-5.7 5.4-5.7h.4C63.9 19.2 56.4 16 48 16c-11.2 0-21 5.7-26.7 14.4h2.1c3.3 0 8.5-.4 8.5-.4 1.7-.1 1.9 2.4.2 2.6 0 0-1.7.2-3.7.3L40 67.5l7-20.9L42 33c-1.7-.1-3.3-.3-3.3-.3-1.7-.1-1.5-2.7.2-2.6 0 0 5.3.4 8.4.4 3.3 0 8.5-.4 8.5-.4 1.7-.1 1.9 2.4.2 2.6 0 0-1.7.2-3.7.3l11.5 34.3 3.3-10.4c1.6-4.5 2.4-7.8 2.4-10.5zM16.1 48c0 12.6 7.3 23.5 18 28.7L18.8 35c-1.7 4-2.7 8.4-2.7 13zm32.5 2.8L39 78.6c2.9.8 5.9 1.3 9 1.3 3.7 0 7.3-.6 10.6-1.8-.1-.1-.2-.3-.2-.4l-9.8-26.9zM76.2 36c0 3.2-.6 6.9-2.4 11.4L64 75.6c9.5-5.5 15.9-15.8 15.9-27.6 0-5.5-1.4-10.8-3.9-15.3.1 1 .2 2.1.2 3.3z" fill="none" />\n            </svg>\n            <p>Generating preview…</p>\n        </div>\n    ',t.write('\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tmargin: 0;\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-direction: column;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\twidth: 100vw;\n\t\t\t}\n\t\t\t@-webkit-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@-moz-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@-o-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message svg {\n\t\t\t\twidth: 192px;\n\t\t\t\theight: 192px;\n\t\t\t\tstroke: #555d66;\n\t\t\t\tstroke-width: 0.75;\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message svg .outer,\n\t\t\t.editor-post-preview-button__interstitial-message svg .inner {\n\t\t\t\tstroke-dasharray: 280;\n\t\t\t\tstroke-dashoffset: 280;\n\t\t\t\t-webkit-animation: paint 1.5s ease infinite alternate;\n\t\t\t\t-moz-animation: paint 1.5s ease infinite alternate;\n\t\t\t\t-o-animation: paint 1.5s ease infinite alternate;\n\t\t\t\tanimation: paint 1.5s ease infinite alternate;\n\t\t\t}\n\t\t\tp {\n\t\t\t\ttext-align: center;\n\t\t\t\tfont-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;\n\t\t\t}\n\t\t</style>\n\t\n        <div class="editor-post-preview-button__interstitial-message">\n            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">\n                <path class="outer" d="M48 12c19.9 0 36 16.1 36 36S67.9 84 48 84 12 67.9 12 48s16.1-36 36-36" fill="none" />\n                <path class="inner" d="M69.5 46.4c0-3.9-1.4-6.7-2.6-8.8-1.6-2.6-3.1-4.9-3.1-7.5 0-2.9 2.2-5.7 5.4-5.7h.4C63.9 19.2 56.4 16 48 16c-11.2 0-21 5.7-26.7 14.4h2.1c3.3 0 8.5-.4 8.5-.4 1.7-.1 1.9 2.4.2 2.6 0 0-1.7.2-3.7.3L40 67.5l7-20.9L42 33c-1.7-.1-3.3-.3-3.3-.3-1.7-.1-1.5-2.7.2-2.6 0 0 5.3.4 8.4.4 3.3 0 8.5-.4 8.5-.4 1.7-.1 1.9 2.4.2 2.6 0 0-1.7.2-3.7.3l11.5 34.3 3.3-10.4c1.6-4.5 2.4-7.8 2.4-10.5zM16.1 48c0 12.6 7.3 23.5 18 28.7L18.8 35c-1.7 4-2.7 8.4-2.7 13zm32.5 2.8L39 78.6c2.9.8 5.9 1.3 9 1.3 3.7 0 7.3-.6 10.6-1.8-.1-.1-.2-.3-.2-.4l-9.8-26.9zM76.2 36c0 3.2-.6 6.9-2.4 11.4L64 75.6c9.5-5.5 15.9-15.8 15.9-27.6 0-5.5-1.4-10.8-3.9-15.3.1 1 .2 2.1.2 3.3z" fill="none" />\n            </svg>\n            <p>Generating preview…</p>\n        </div>\n    '),t.close()}(s.document),((()=>{const e=t.getCurrentPost().status;return"draft"==e||"auto-draft"==e})()?r:a)().then((()=>{s.location=o.href}))})),(0,s.subscribe)((()=>{n()?o.classList.add("is-disabled"):o.classList.remove("is-disabled")})),setInterval((function(){const t=e(),n=(t=>window.Headless.preview_url.replace(window.Headless.post_id_placeholder,`${t}`))(t),s=document.querySelectorAll("[target^=wp-preview-]");s&&s.length&&s.forEach((t=>{t.setAttribute("href",n)})),document.querySelectorAll(".components-snackbar-list .components-snackbar__content a.components-button").forEach((e=>{(e.href.includes("?post="+t)||e.href.includes("?page_id="+t)||e.href.includes("?p="+t))&&(e.href=n,e.target="wp-preview-"+t)}));const i=document.querySelectorAll(".components-menu-group");let a=null;if(i.forEach((t=>{t.querySelector(".editor-preview-dropdown__button-external")&&(a=t)})),!a)return;const r="headless-preview-link";if(a.querySelector("#"+r))return;const l=a.querySelector(".editor-preview-dropdown__button-external"),c=l.querySelector("svg"),d=l.getAttribute("target");o.text=l.textContent,o.append(c),o.target=d,o.href=n,o.id=r,l.style.display="none",a.querySelector('[role="group"]').append(o)}),300)}))})();
     1(()=>{"use strict";const t=window.wp.plugins,e=window.wp.editor,n=window.wp.components,s=window.wp.data,i=window.wp.element,a=()=>(0,s.useSelect)(t=>t(e.store).getCurrentPost(),[]),r=window.ReactJSXRuntime,o=({index:t,baseUrl:e,controller:n,onStateChanged:s})=>{const{state:o,reload:l}=(t=>{const[e,n]=(0,i.useState)("idle"),s=a(),r=(0,i.useMemo)(()=>s?.link?new URL(s?.link).pathname:"",[s?.link]);return{state:e,reload:()=>{n("loading"),(async()=>{try{const e=await fetch(((t,e)=>window.Headless.ajax+`?action=${window.Headless.actions.revalidate}&frontend=${t}&path=${e}`)(t,r)),s=await e.json();s.success?n("success"):(console.error(s),n("error"))}catch(t){n("error")}})()}}})(t),d=a(),c=(0,i.useMemo)(()=>{const t=d?.link;if(!t)return"#";const n=new URL(t);return e.replace(/^\/|\/$/g,"")+n.pathname},[d?.link]);return(0,i.useEffect)(()=>{n.add(t,l)},[t]),(0,i.useEffect)(()=>{s(t,o)},[o]),(0,r.jsxs)("div",{title:c,children:[(0,r.jsxs)("a",{href:c,target:"_blank",children:["Frontend ",t]}),"loading"==o&&(0,r.jsx)(r.Fragment,{children:" 🧹"}),"success"==o&&(0,r.jsx)(r.Fragment,{children:" ✅"}),"error"==o&&(0,r.jsx)(r.Fragment,{children:" 🚨"})]})};window.HeadlessAdmin.revalidate_is_active&&(0,t.registerPlugin)("headless-plugin",{icon:()=>null,render:function(){const t=window.Headless.frontends,s=(0,i.useMemo)(()=>(()=>{const t=new Map;return{add:(e,n)=>{t.set(e,n)},run:()=>{t.forEach(t=>{t()})}}})(),[]),[l,d]=(0,i.useState)({}),c="publish"==a()?.status,p=Object.values(l).find(t=>1==t);return(0,r.jsx)(e.PluginDocumentSettingPanel,{name:"palasthotel-headless",title:"Headless",children:c?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("ol",{children:t.map((t,e)=>(0,r.jsx)("li",{children:(0,r.jsx)(o,{baseUrl:t,index:e,controller:s,onStateChanged:(t,e)=>{d(n=>{const s={...n};return s[t]="loading"==e,s})}})},e))}),(0,r.jsx)(n.Button,{variant:"secondary",disabled:p||!c,onClick:()=>{s.run()},children:"Revalidate cache"})]}):(0,r.jsx)("p",{className:"description",children:"Only published contents can be revalidated."})})}}),document.addEventListener("DOMContentLoaded",function(){if(!window.HeadlessAdmin.preview_is_active)return;const t=(0,s.select)("core/editor"),e=t.getCurrentPostId,n=t.isSavingPost,i=(0,s.dispatch)("core/editor"),a=i.autosave,r=i.savePost,o=document.createElement("a");o.className="components-button",o.addEventListener("click",e=>{if(e.preventDefault(),n())return;const s=window.open("about:blank",o.target);s&&(!function(t){let e="";e+='\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tmargin: 0;\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-direction: column;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\twidth: 100vw;\n\t\t\t}\n\t\t\t@-webkit-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@-moz-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@-o-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message svg {\n\t\t\t\twidth: 192px;\n\t\t\t\theight: 192px;\n\t\t\t\tstroke: #555d66;\n\t\t\t\tstroke-width: 0.75;\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message svg .outer,\n\t\t\t.editor-post-preview-button__interstitial-message svg .inner {\n\t\t\t\tstroke-dasharray: 280;\n\t\t\t\tstroke-dashoffset: 280;\n\t\t\t\t-webkit-animation: paint 1.5s ease infinite alternate;\n\t\t\t\t-moz-animation: paint 1.5s ease infinite alternate;\n\t\t\t\t-o-animation: paint 1.5s ease infinite alternate;\n\t\t\t\tanimation: paint 1.5s ease infinite alternate;\n\t\t\t}\n\t\t\tp {\n\t\t\t\ttext-align: center;\n\t\t\t\tfont-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;\n\t\t\t}\n\t\t</style>\n\t',e+='\n        <div class="editor-post-preview-button__interstitial-message">\n            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">\n                <path class="outer" d="M48 12c19.9 0 36 16.1 36 36S67.9 84 48 84 12 67.9 12 48s16.1-36 36-36" fill="none" />\n                <path class="inner" d="M69.5 46.4c0-3.9-1.4-6.7-2.6-8.8-1.6-2.6-3.1-4.9-3.1-7.5 0-2.9 2.2-5.7 5.4-5.7h.4C63.9 19.2 56.4 16 48 16c-11.2 0-21 5.7-26.7 14.4h2.1c3.3 0 8.5-.4 8.5-.4 1.7-.1 1.9 2.4.2 2.6 0 0-1.7.2-3.7.3L40 67.5l7-20.9L42 33c-1.7-.1-3.3-.3-3.3-.3-1.7-.1-1.5-2.7.2-2.6 0 0 5.3.4 8.4.4 3.3 0 8.5-.4 8.5-.4 1.7-.1 1.9 2.4.2 2.6 0 0-1.7.2-3.7.3l11.5 34.3 3.3-10.4c1.6-4.5 2.4-7.8 2.4-10.5zM16.1 48c0 12.6 7.3 23.5 18 28.7L18.8 35c-1.7 4-2.7 8.4-2.7 13zm32.5 2.8L39 78.6c2.9.8 5.9 1.3 9 1.3 3.7 0 7.3-.6 10.6-1.8-.1-.1-.2-.3-.2-.4l-9.8-26.9zM76.2 36c0 3.2-.6 6.9-2.4 11.4L64 75.6c9.5-5.5 15.9-15.8 15.9-27.6 0-5.5-1.4-10.8-3.9-15.3.1 1 .2 2.1.2 3.3z" fill="none" />\n            </svg>\n            <p>Generating preview…</p>\n        </div>\n    ',t.write('\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tmargin: 0;\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-direction: column;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\twidth: 100vw;\n\t\t\t}\n\t\t\t@-webkit-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@-moz-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@-o-keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t@keyframes paint {\n\t\t\t\t0% {\n\t\t\t\t\tstroke-dashoffset: 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message svg {\n\t\t\t\twidth: 192px;\n\t\t\t\theight: 192px;\n\t\t\t\tstroke: #555d66;\n\t\t\t\tstroke-width: 0.75;\n\t\t\t}\n\t\t\t.editor-post-preview-button__interstitial-message svg .outer,\n\t\t\t.editor-post-preview-button__interstitial-message svg .inner {\n\t\t\t\tstroke-dasharray: 280;\n\t\t\t\tstroke-dashoffset: 280;\n\t\t\t\t-webkit-animation: paint 1.5s ease infinite alternate;\n\t\t\t\t-moz-animation: paint 1.5s ease infinite alternate;\n\t\t\t\t-o-animation: paint 1.5s ease infinite alternate;\n\t\t\t\tanimation: paint 1.5s ease infinite alternate;\n\t\t\t}\n\t\t\tp {\n\t\t\t\ttext-align: center;\n\t\t\t\tfont-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;\n\t\t\t}\n\t\t</style>\n\t\n        <div class="editor-post-preview-button__interstitial-message">\n            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">\n                <path class="outer" d="M48 12c19.9 0 36 16.1 36 36S67.9 84 48 84 12 67.9 12 48s16.1-36 36-36" fill="none" />\n                <path class="inner" d="M69.5 46.4c0-3.9-1.4-6.7-2.6-8.8-1.6-2.6-3.1-4.9-3.1-7.5 0-2.9 2.2-5.7 5.4-5.7h.4C63.9 19.2 56.4 16 48 16c-11.2 0-21 5.7-26.7 14.4h2.1c3.3 0 8.5-.4 8.5-.4 1.7-.1 1.9 2.4.2 2.6 0 0-1.7.2-3.7.3L40 67.5l7-20.9L42 33c-1.7-.1-3.3-.3-3.3-.3-1.7-.1-1.5-2.7.2-2.6 0 0 5.3.4 8.4.4 3.3 0 8.5-.4 8.5-.4 1.7-.1 1.9 2.4.2 2.6 0 0-1.7.2-3.7.3l11.5 34.3 3.3-10.4c1.6-4.5 2.4-7.8 2.4-10.5zM16.1 48c0 12.6 7.3 23.5 18 28.7L18.8 35c-1.7 4-2.7 8.4-2.7 13zm32.5 2.8L39 78.6c2.9.8 5.9 1.3 9 1.3 3.7 0 7.3-.6 10.6-1.8-.1-.1-.2-.3-.2-.4l-9.8-26.9zM76.2 36c0 3.2-.6 6.9-2.4 11.4L64 75.6c9.5-5.5 15.9-15.8 15.9-27.6 0-5.5-1.4-10.8-3.9-15.3.1 1 .2 2.1.2 3.3z" fill="none" />\n            </svg>\n            <p>Generating preview…</p>\n        </div>\n    '),t.close()}(s.document),((()=>{const e=t.getCurrentPost().status;return"draft"==e||"auto-draft"==e})()?r:a)().then(()=>{s.location=o.href}))}),(0,s.subscribe)(()=>{n()?o.classList.add("is-disabled"):o.classList.remove("is-disabled")}),setInterval(function(){const t=e(),n=(t=>window.Headless.preview_url.replace(window.Headless.post_id_placeholder,`${t}`))(t),s=document.querySelectorAll("[target^=wp-preview-]");s&&s.length&&s.forEach(t=>{t.setAttribute("href",n)}),document.querySelectorAll(".components-snackbar-list .components-snackbar__content a.components-button").forEach(e=>{(e.href.includes("?post="+t)||e.href.includes("?page_id="+t)||e.href.includes("?p="+t))&&(e.href=n,e.target="wp-preview-"+t)});const i=Array.from(document.querySelectorAll(".components-menu-group")).find(t=>t.querySelector(".editor-preview-dropdown__button-external"));if(!i)return;const a="headless-preview-link";if(i.querySelector("#"+a))return;const r=i.querySelector(".editor-preview-dropdown__button-external");if(!r)return;const l=r.querySelector("svg"),d=r.getAttribute("target")??"";o.text=r.textContent??"",l&&o.append(l),o.target=d,o.href=n,o.id=a,r.style.display="none",i.querySelector('[role="group"]')?.append(o)},300)})})();
  • headless/trunk/headless.php

    r3254930 r3492765  
    55 * Plugin URI: https://github.com/palasthotel/headless
    66 * Description: Adds features to use WordPress as headless CMS
    7  * Version: 2.3.1
     7 * Version: 3.0.1
    88 * Author: Palasthotel (Edward Bock) <edward.bock@palasthotel.de>
    99 * Author URI: http://www.palasthotel.de
     
    2222use Palasthotel\WordPress\Headless\Store\RevalidationDatabase;
    2323
    24 if ( ! defined( 'HEADLESS_HEAD_BASE_URL' ) ) {
    25     define( 'HEADLESS_HEAD_BASE_URL', '' );
     24if (!defined("HEADLESS_HEAD_BASE_URL")) {
     25    define("HEADLESS_HEAD_BASE_URL", "");
    2626}
    2727
    28 if ( ! defined( 'HEADLESS_SECRET_TOKEN' ) ) {
    29     define( 'HEADLESS_SECRET_TOKEN', "" );
     28if (!defined("HEADLESS_SECRET_TOKEN")) {
     29    define("HEADLESS_SECRET_TOKEN", "");
    3030}
    3131
    32 if ( ! defined( 'HEADLESS_REST_PARAM' ) ) {
    33     define( 'HEADLESS_REST_PARAM', "headless" );
     32if (!defined("HEADLESS_REST_PARAM")) {
     33    define("HEADLESS_REST_PARAM", "headless");
    3434}
    35 if ( ! defined( 'HEADLESS_REST_VALUE' ) ) {
    36     define( 'HEADLESS_REST_VALUE', 'true' );
     35if (!defined("HEADLESS_REST_VALUE")) {
     36    define("HEADLESS_REST_VALUE", "true");
    3737}
    3838
    39 if ( ! defined( 'HEADLESS_REST_VARIANT_PARAM' ) ) {
    40     define( 'HEADLESS_REST_VARIANT_PARAM', "headless_variant" );
     39if (!defined("HEADLESS_REST_VARIANT_PARAM")) {
     40    define("HEADLESS_REST_VARIANT_PARAM", "headless_variant");
    4141}
    42 if ( ! defined( 'HEADLESS_REST_VARIANT_TEASERS_VALUE' ) ) {
    43     define( 'HEADLESS_REST_VARIANT_TEASERS_VALUE', 'teaser' );
     42if (!defined("HEADLESS_REST_VARIANT_TEASERS_VALUE")) {
     43    define("HEADLESS_REST_VARIANT_TEASERS_VALUE", "teaser");
    4444}
    4545
    46 if ( ! defined( 'HEADLESS_API_KEY_HEADER_KEY' ) ) {
    47     define( 'HEADLESS_API_KEY_HEADER_KEY', "" );
     46if (!defined("HEADLESS_API_KEY_HEADER_KEY")) {
     47    define("HEADLESS_API_KEY_HEADER_KEY", "");
    4848}
    49 if ( ! defined( 'HEADLESS_API_KEY_HEADER_VALUE' ) ) {
    50     define( 'HEADLESS_API_KEY_HEADER_VALUE', "" );
     49if (!defined("HEADLESS_API_KEY_HEADER_VALUE")) {
     50    define("HEADLESS_API_KEY_HEADER_VALUE", "");
    5151}
    5252
    5353require_once __DIR__ . "/vendor/autoload.php";
    5454
    55 class Plugin extends Components\Plugin {
    56 
     55class Plugin extends Components\Plugin
     56{
    5757    const DOMAIN = "headless";
    5858
     
    7777
    7878    const FILTER_REST_RESPONSE_HEADERS = "headless_rest_response_headers";
    79     const FILTER_REST_RESPONSE_DATA = "headless_rest_response_data";
     79    const FILTER_REST_RESPONSE_DATA = "headless_rest_response_data";
    8080
    81     const FILTER_FRONTENDS = "headless_frontends";
     81    const FILTER_FRONTENDS = "headless_frontends";
    8282    const FILTER_REVALIDATE_BY_PATH_URL = "headless_revalidate_by_path_url";
    8383    const FILTER_REVALIDATE_BY_TAG_URL = "headless_revalidate_by_tag_url";
     
    106106    public Log $log;
    107107
    108     function onCreate(): void {
     108    function onCreate(): void
     109    {
     110        $this->dbRevalidation = new RevalidationDatabase();
     111        $this->log = new Log($this);
    109112
    110         $this->dbRevalidation = new RevalidationDatabase();
    111         $this->log            = new Log( $this );
     113        $this->security = new Security($this);
     114        $this->headers = new Headers($this);
     115        $this->routes = new Routes($this);
     116        $this->extensions = new Extensions($this);
     117        $this->query = new Query($this);
     118        $this->preview = new Preview($this);
     119        $this->headquarter = new Headquarter($this);
     120        $this->revalidate = new Revalidate($this);
     121        $this->gutenberg = new PluginAssets($this);
     122        $this->post = new Post($this);
     123        $this->dashboard = new Dashboard($this);
     124        $this->ajax = new Ajax($this);
     125        $this->schedule = new Schedule($this);
    112126
    113         $this->security    = new Security( $this );
    114         $this->headers     = new Headers( $this );
    115         $this->routes      = new Routes( $this );
    116         $this->extensions  = new Extensions( $this );
    117         $this->query       = new Query( $this );
    118         $this->preview     = new Preview( $this );
    119         $this->headquarter = new Headquarter( $this );
    120         $this->revalidate  = new Revalidate( $this );
    121         $this->gutenberg   = new PluginAssets( $this );
    122         $this->post        = new Post( $this );
    123         $this->dashboard   = new Dashboard( $this );
    124         $this->ajax        = new Ajax( $this );
    125         $this->schedule    = new Schedule( $this );
    126 
    127         new Migration( $this );
    128 
     127        new Migration($this);
    129128    }
    130129
    131     public function onSiteActivation() {
     130    public function onSiteActivation()
     131    {
    132132        parent::onSiteActivation();
    133133        $this->dbRevalidation->createTables();
    134 
    135134    }
    136135}
  • headless/trunk/vendor/composer/installed.php

    r3254930 r3492765  
    44        'pretty_version' => 'dev-main',
    55        'version' => 'dev-main',
    6         'reference' => 'a5281d48ac9eb004988aac6b05a2479363adae4c',
     6        'reference' => '0ed39749f95e81e607472c5bf5ac6bc5948f16d5',
    77        'type' => 'library',
    88        'install_path' => __DIR__ . '/../../',
     
    1414            'pretty_version' => 'dev-main',
    1515            'version' => 'dev-main',
    16             'reference' => 'a5281d48ac9eb004988aac6b05a2479363adae4c',
     16            'reference' => '0ed39749f95e81e607472c5bf5ac6bc5948f16d5',
    1717            'type' => 'library',
    1818            'install_path' => __DIR__ . '/../../',
Note: See TracChangeset for help on using the changeset viewer.