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 = '
Old label
'; $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 = '
old
'; 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 = '
x
'; $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 = '
x
'; foreach (['javascript:alert(1)', 'jAvAsCrIpt:alert(1)', 'data:text/html,', '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 = '
old
'; $result = (new Button())->apply($this->buttonBlock($html), 'text', 'hi'); $this->assertStringContainsString('hi', $result['innerHTML']); $this->assertStringNotContainsString('buttonBlock($html); $result = (new Button())->apply($block, 'url', ''); $this->assertStringNotContainsString('href=', $result['innerHTML']); } public function test_apply_url_does_not_mutate_attrs() { $html = '
y
'; $block = $this->buttonBlock($html); $result = (new Button())->apply($block, 'url', 'https://example.test'); // The button's canonical link target is the inner , not a block attribute. $this->assertSame($block['attrs'], $result['attrs']); } public function test_apply_with_unknown_field_returns_block_unchanged() { $block = $this->buttonBlock('
y
'); $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], ]; } }