Skip to content

Commit 588d98f

Browse files
committed
Avoid duplicate e-content wrapper when theme supports microformats2
Add detection for microformats2 theme support that: - Checks explicit theme support via current_theme_supports('microformats2') - Falls back to detecting e-content class in rendered page output - Caches the result in an option for performance - Clears cache on theme switch - Ignores code/pre blocks to avoid false positives Only wraps content in e-content div when theme doesn't provide it. Fixes #294
1 parent a316c1b commit 588d98f

4 files changed

Lines changed: 225 additions & 2 deletions

File tree

includes/class-micropub.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ class Micropub {
3232
*/
3333
const TEXT_DOMAIN = 'micropub';
3434

35+
/**
36+
* Option name for storing microformats2 theme support detection.
37+
*
38+
* @var string
39+
*/
40+
const MICROFORMATS2_SUPPORT_OPTION = 'micropub_theme_supports_mf2';
41+
3542
/**
3643
* Get the instance of the class.
3744
*
@@ -59,6 +66,9 @@ public function init() {
5966
\add_action( 'rest_api_init', array( $this, 'rest_init' ) );
6067
\add_action( 'init', array( $this, 'plugin_init' ) );
6168
\add_action( 'admin_notices', array( $this, 'ssl_notice' ) );
69+
70+
// Clear microformats2 support cache when theme changes.
71+
\add_action( 'switch_theme', array( $this, 'clear_microformats2_support_cache' ) );
6272
}
6373

6474
/**
@@ -102,4 +112,66 @@ public function ssl_notice() {
102112
</div>
103113
<?php
104114
}
115+
116+
/**
117+
* Clear the cached microformats2 support detection.
118+
*/
119+
public function clear_microformats2_support_cache() {
120+
\delete_option( self::MICROFORMATS2_SUPPORT_OPTION );
121+
}
122+
123+
/**
124+
* Check if the current theme supports microformats2.
125+
*
126+
* This checks explicit theme support first, then falls back to
127+
* cached detection results. If no cached result exists and we're
128+
* on a singular page, it will detect and cache the result.
129+
*
130+
* @return bool True if theme supports microformats2.
131+
*/
132+
public static function theme_supports_microformats2() {
133+
// First check explicit theme support declaration.
134+
if ( \current_theme_supports( 'microformats2' ) ) {
135+
return true;
136+
}
137+
138+
// Check cached detection result.
139+
$cached = \get_option( self::MICROFORMATS2_SUPPORT_OPTION );
140+
141+
if ( false !== $cached ) {
142+
return 'yes' === $cached;
143+
}
144+
145+
// If we're on a singular frontend page, detect and cache the result.
146+
if ( ! \is_admin() && \is_singular() ) {
147+
// Hook into shutdown to check the rendered output.
148+
\add_action( 'shutdown', array( self::class, 'detect_microformats2_support' ), 0 );
149+
}
150+
151+
// Return false for now, will be cached after first detection.
152+
return false;
153+
}
154+
155+
/**
156+
* Detect microformats2 support by checking the rendered page output.
157+
*
158+
* This runs at shutdown to capture the full page HTML and check
159+
* if e-content class exists in the template markup.
160+
*/
161+
public static function detect_microformats2_support() {
162+
$output = \ob_get_contents();
163+
164+
if ( empty( $output ) ) {
165+
return;
166+
}
167+
168+
// Remove code and pre blocks to avoid false positives from user content.
169+
$output = preg_replace( '/<(code|pre)[^>]*>.*?<\/\1>/is', '', $output );
170+
171+
// Check if e-content exists as a class attribute value.
172+
// Matches class="...e-content..." or class='...e-content...'.
173+
$has_support = preg_match( '/class=["\'][^"\']*\be-content\b[^"\']*["\']/', $output );
174+
175+
\update_option( self::MICROFORMATS2_SUPPORT_OPTION, $has_support ? 'yes' : 'no', true );
176+
}
105177
}

includes/class-render.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,14 @@ public static function generate_post_content( $post_content, $input ) {
159159
}
160160

161161
if ( ! empty( $post_content ) ) {
162-
$lines[] = '<div class="e-content">';
162+
// Only wrap in e-content if theme doesn't already provide microformats2 support.
163+
if ( ! Micropub::theme_supports_microformats2() ) {
164+
$lines[] = '<div class="e-content">';
165+
}
163166
$lines[] = $post_content;
164-
$lines[] = '</div>';
167+
if ( ! Micropub::theme_supports_microformats2() ) {
168+
$lines[] = '</div>';
169+
}
165170
}
166171

167172
// Generate gallery markup for media fields.

tests/test_functions.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,92 @@ function test_mp_filter() {
2727
);
2828
}
2929
}
30+
31+
class MicropubMicroformats2DetectionTest extends WP_UnitTestCase {
32+
function tear_down() {
33+
// Clean up after each test.
34+
remove_theme_support( 'microformats2' );
35+
delete_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION );
36+
parent::tear_down();
37+
}
38+
39+
function test_theme_supports_microformats2_with_explicit_support() {
40+
add_theme_support( 'microformats2' );
41+
42+
$this->assertTrue( \Micropub\Micropub::theme_supports_microformats2() );
43+
}
44+
45+
function test_theme_supports_microformats2_with_cached_yes() {
46+
update_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION, 'yes' );
47+
48+
$this->assertTrue( \Micropub\Micropub::theme_supports_microformats2() );
49+
}
50+
51+
function test_theme_supports_microformats2_with_cached_no() {
52+
update_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION, 'no' );
53+
54+
$this->assertFalse( \Micropub\Micropub::theme_supports_microformats2() );
55+
}
56+
57+
function test_theme_supports_microformats2_returns_false_when_not_cached() {
58+
// No theme support and no cached value.
59+
$this->assertFalse( \Micropub\Micropub::theme_supports_microformats2() );
60+
}
61+
62+
function test_clear_microformats2_support_cache() {
63+
update_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION, 'yes' );
64+
65+
$micropub = \Micropub\Micropub::get_instance();
66+
$micropub->clear_microformats2_support_cache();
67+
68+
$this->assertFalse( get_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION ) );
69+
}
70+
71+
function test_detect_microformats2_support_finds_econtent_in_class() {
72+
// Start output buffering to simulate page output.
73+
ob_start();
74+
echo '<html><body><div class="entry-content e-content">Test</div></body></html>';
75+
76+
\Micropub\Micropub::detect_microformats2_support();
77+
78+
ob_end_clean();
79+
80+
$this->assertEquals( 'yes', get_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION ) );
81+
}
82+
83+
function test_detect_microformats2_support_ignores_econtent_in_code_blocks() {
84+
// Start output buffering to simulate page output.
85+
ob_start();
86+
echo '<html><body><code>class="e-content"</code></body></html>';
87+
88+
\Micropub\Micropub::detect_microformats2_support();
89+
90+
ob_end_clean();
91+
92+
$this->assertEquals( 'no', get_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION ) );
93+
}
94+
95+
function test_detect_microformats2_support_ignores_econtent_in_pre_blocks() {
96+
// Start output buffering to simulate page output.
97+
ob_start();
98+
echo '<html><body><pre>class="e-content"</pre></body></html>';
99+
100+
\Micropub\Micropub::detect_microformats2_support();
101+
102+
ob_end_clean();
103+
104+
$this->assertEquals( 'no', get_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION ) );
105+
}
106+
107+
function test_detect_microformats2_support_ignores_econtent_as_plain_text() {
108+
// Start output buffering to simulate page output.
109+
ob_start();
110+
echo '<html><body><p>The e-content class is used in microformats2.</p></body></html>';
111+
112+
\Micropub\Micropub::detect_microformats2_support();
113+
114+
ob_end_clean();
115+
116+
$this->assertEquals( 'no', get_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION ) );
117+
}
118+
}

tests/test_render.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,4 +218,61 @@ function test_merges_auto_generated_content() {
218218
$post_content
219219
);
220220
}
221+
222+
function test_no_econtent_wrapper_when_theme_supports_microformats2() {
223+
// Simulate theme support for microformats2.
224+
add_theme_support( 'microformats2' );
225+
226+
$content = '<p>Test content</p>';
227+
$input = array(
228+
'properties' => array(
229+
'content' => array( $content ),
230+
),
231+
);
232+
$post_content = \Micropub\Render::generate_post_content( $content, $input );
233+
234+
// Should not have e-content wrapper.
235+
$this->assertEquals( '<p>Test content</p>', $post_content );
236+
237+
// Clean up.
238+
remove_theme_support( 'microformats2' );
239+
}
240+
241+
function test_econtent_wrapper_when_theme_does_not_support_microformats2() {
242+
// Ensure no theme support.
243+
remove_theme_support( 'microformats2' );
244+
// Clear any cached detection.
245+
delete_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION );
246+
247+
$content = '<p>Test content</p>';
248+
$input = array(
249+
'properties' => array(
250+
'content' => array( $content ),
251+
),
252+
);
253+
$post_content = \Micropub\Render::generate_post_content( $content, $input );
254+
255+
// Should have e-content wrapper.
256+
$this->assertEquals( "<div class=\"e-content\">\n<p>Test content</p>\n</div>", $post_content );
257+
}
258+
259+
function test_econtent_wrapper_with_cached_mf2_support() {
260+
// Simulate cached detection of microformats2 support.
261+
remove_theme_support( 'microformats2' );
262+
update_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION, 'yes' );
263+
264+
$content = '<p>Test content</p>';
265+
$input = array(
266+
'properties' => array(
267+
'content' => array( $content ),
268+
),
269+
);
270+
$post_content = \Micropub\Render::generate_post_content( $content, $input );
271+
272+
// Should not have e-content wrapper due to cached support.
273+
$this->assertEquals( '<p>Test content</p>', $post_content );
274+
275+
// Clean up.
276+
delete_option( \Micropub\Micropub::MICROFORMATS2_SUPPORT_OPTION );
277+
}
221278
}

0 commit comments

Comments
 (0)