HEX
Server: LiteSpeed
System: Linux server342.web-hosting.com 4.18.0-553.124.4.lve.el8.x86_64 #1 SMP Fri May 15 13:02:13 UTC 2026 x86_64
User: ksonpoau (1099)
PHP: 8.2.31
Disabled: NONE
Upload Files
File: //home/ksonpoau/www/wp-content/plugins/extendify/tests/Integration/QuickEdit/Schemas/ButtonTest.php
<?php

namespace Extendify\Tests\Integration\QuickEdit\Schemas;

use Extendify\QuickEdit\Schemas\Button;
use WP_UnitTestCase;

class ButtonTest extends WP_UnitTestCase
{
    public function test_fields_returns_text_then_url()
    {
        $fields = (new Button())->fields();

        $this->assertCount(2, $fields);
        $this->assertSame('text', $fields[0]['key']);
        $this->assertSame('text', $fields[0]['control']);
        $this->assertSame('url',  $fields[1]['key']);
        $this->assertSame('link', $fields[1]['control']);
    }

    public function test_apply_text_replaces_anchor_text_preserving_anchor_attrs()
    {
        $html = '<div class="wp-block-button"><a class="wp-block-button__link" href="/about" target="_blank">Old label</a></div>';
        $block = $this->buttonBlock($html);

        $result = (new Button())->apply($block, 'text', 'New label');

        $this->assertStringContainsString('>New label<', $result['innerHTML']);
        $this->assertStringContainsString('href="/about"', $result['innerHTML']);
        $this->assertStringContainsString('target="_blank"', $result['innerHTML']);
    }

    public function test_apply_text_treats_regex_backreferences_in_user_text_as_literal()
    {
        $inputs = ['Try $1 for size', 'Use \\1 here', '$0 free', 'Mixed $1 and \\2'];
        $html   = '<div class="wp-block-button"><a class="wp-block-button__link" href="/about">old</a></div>';

        foreach ($inputs as $input) {
            $result = (new Button())->apply($this->buttonBlock($html), 'text', $input);

            $this->assertStringContainsString('>' . $input . '<', $result['innerHTML'], "input: {$input}");
            $this->assertStringContainsString('href="/about"', $result['innerHTML']);
        }
    }

    public function test_apply_url_sets_anchor_href()
    {
        $html = '<div class="wp-block-button"><a class="wp-block-button__link" href="/old">x</a></div>';
        $block = $this->buttonBlock($html);

        $result = (new Button())->apply($block, 'url', 'https://example.test/new');

        $this->assertStringContainsString('href="https://example.test/new"', $result['innerHTML']);
        $this->assertStringNotContainsString('href="/old"', $result['innerHTML']);
    }

    public function test_apply_url_strips_dangerous_schemes()
    {
        $html = '<div class="wp-block-button"><a class="wp-block-button__link" href="/old">x</a></div>';

        foreach (['javascript:alert(1)', 'jAvAsCrIpt:alert(1)', 'data:text/html,<script>x</script>', 'vbscript:msgbox(1)'] as $url) {
            $result = (new Button())->apply($this->buttonBlock($html), 'url', $url);

            // esc_url_raw rejects the scheme entirely, so the href is dropped.
            $this->assertStringNotContainsString('href=', $result['innerHTML'], "url: {$url}");
            $this->assertStringNotContainsString('javascript', strtolower($result['innerHTML']), "url: {$url}");
        }
    }

    public function test_apply_text_runs_through_wp_kses_post()
    {
        $html  = '<div class="wp-block-button"><a class="wp-block-button__link" href="/x">old</a></div>';
        $result = (new Button())->apply($this->buttonBlock($html), 'text', 'hi<script>alert(1)</script>');

        $this->assertStringContainsString('hi', $result['innerHTML']);
        $this->assertStringNotContainsString('<script', $result['innerHTML']);
    }

    public function test_apply_url_empty_string_removes_href()
    {
        $html = '<div class="wp-block-button"><a class="wp-block-button__link" href="/old">x</a></div>';
        $block = $this->buttonBlock($html);

        $result = (new Button())->apply($block, 'url', '');

        $this->assertStringNotContainsString('href=', $result['innerHTML']);
    }

    public function test_apply_url_does_not_mutate_attrs()
    {
        $html = '<div class="wp-block-button"><a href="/x">y</a></div>';
        $block = $this->buttonBlock($html);

        $result = (new Button())->apply($block, 'url', 'https://example.test');

        // The button's canonical link target is the inner <a href>, not a block attribute.
        $this->assertSame($block['attrs'], $result['attrs']);
    }

    public function test_apply_with_unknown_field_returns_block_unchanged()
    {
        $block = $this->buttonBlock('<div><a href="/x">y</a></div>');

        $this->assertSame($block, (new Button())->apply($block, 'bogus', 'z'));
    }

    private function buttonBlock(string $innerHTML): array
    {
        return [
            'blockName'    => 'core/button',
            'attrs'        => [],
            'innerBlocks'  => [],
            'innerHTML'    => $innerHTML,
            'innerContent' => [$innerHTML],
        ];
    }
}