Skip to content

Commit cce5180

Browse files
committed
feat: add wrapper div with CSS classes for improved ad styling
This addresses a long-standing request from 2013 for better styling control of ad output. Previously, themes needed to target ads by numeric IDs that could change, making consistent styling difficult. The implementation wraps all ad output in a div with descriptive CSS classes: a generic 'acm-wrapper' class for broad styling rules, and a tag-specific 'acm-tag-{tag_id}' class for targeted control. This enables straightforward centering and other layout adjustments without depending on fragile numeric IDs. A new 'acm_wrapper_classes' filter allows developers to customise the classes or disable the wrapper entirely by returning an empty array, ensuring backwards compatibility for sites that need to opt out. Fixes #71
1 parent c2f1ab7 commit cce5180

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

src/class-ad-code-manager.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,30 @@ function get_acm_tag( $tag_id ): string {
797797
*/
798798
$output_html = apply_filters( 'acm_output_html_after_tokens_processed', $output_html, $tag_id );
799799

800+
/**
801+
* Configuration filter: acm_wrapper_classes
802+
* Filter the CSS classes applied to the ad wrapper div.
803+
*
804+
* @since 0.8.0
805+
*
806+
* @param array $classes Array of CSS class names. Default: 'acm-wrapper', 'acm-tag-{tag_id}'.
807+
* @param string $tag_id The ad tag ID being rendered.
808+
*/
809+
$wrapper_classes = apply_filters(
810+
'acm_wrapper_classes',
811+
array( 'acm-wrapper', 'acm-tag-' . sanitize_html_class( $tag_id ) ),
812+
$tag_id
813+
);
814+
815+
// Allow disabling the wrapper by returning an empty array.
816+
if ( ! empty( $wrapper_classes ) && is_array( $wrapper_classes ) ) {
817+
$output_html = sprintf(
818+
'<div class="%s">%s</div>',
819+
esc_attr( implode( ' ', array_map( 'sanitize_html_class', $wrapper_classes ) ) ),
820+
$output_html
821+
);
822+
}
823+
800824
return $output_html;
801825
}
802826

tests/Integration/AdCodeManagerTest.php

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,115 @@ private function mock_ad_code() {
6666
private function create_ad_code_and_return() {
6767
return $this->acm->create_ad_code( $this->mock_ad_code() );
6868
}
69+
70+
/**
71+
* Test that ad output includes wrapper div with default classes.
72+
*
73+
* @covers Ad_Code_Manager::get_acm_tag
74+
*/
75+
public function test_get_acm_tag_includes_wrapper_with_default_classes(): void {
76+
// Create an ad code and register it.
77+
$ad_code_id = $this->create_ad_code_and_return();
78+
$this->acm->flush_cache();
79+
$this->acm->register_ad_codes( $this->acm->get_ad_codes() );
80+
81+
// Get the first available tag.
82+
$test_tag = null;
83+
foreach ( $this->acm->ad_tag_ids as $tag ) {
84+
$test_tag = $tag['tag'];
85+
break;
86+
}
87+
88+
if ( ! $test_tag ) {
89+
$this->markTestSkipped( 'No ad tags available for testing.' );
90+
}
91+
92+
// Enable display of ad codes without conditionals.
93+
add_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' );
94+
95+
$output = $this->acm->get_acm_tag( $test_tag );
96+
97+
remove_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' );
98+
$this->acm->delete_ad_code( $ad_code_id );
99+
100+
$this->assertStringContainsString( 'class="acm-wrapper', $output, 'Output should contain acm-wrapper class.' );
101+
$this->assertStringContainsString( 'acm-tag-' . sanitize_html_class( $test_tag ), $output, 'Output should contain tag-specific class.' );
102+
}
103+
104+
/**
105+
* Test that acm_wrapper_classes filter can modify wrapper classes.
106+
*
107+
* @covers Ad_Code_Manager::get_acm_tag
108+
*/
109+
public function test_acm_wrapper_classes_filter_modifies_classes(): void {
110+
// Create an ad code and register it.
111+
$ad_code_id = $this->create_ad_code_and_return();
112+
$this->acm->flush_cache();
113+
$this->acm->register_ad_codes( $this->acm->get_ad_codes() );
114+
115+
// Get the first available tag.
116+
$test_tag = null;
117+
foreach ( $this->acm->ad_tag_ids as $tag ) {
118+
$test_tag = $tag['tag'];
119+
break;
120+
}
121+
122+
if ( ! $test_tag ) {
123+
$this->markTestSkipped( 'No ad tags available for testing.' );
124+
}
125+
126+
// Filter to add custom classes.
127+
$filter_callback = function ( $classes, $tag_id ) {
128+
$classes[] = 'custom-ad-class';
129+
$classes[] = 'another-class';
130+
return $classes;
131+
};
132+
133+
add_filter( 'acm_wrapper_classes', $filter_callback, 10, 2 );
134+
add_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' );
135+
136+
$output = $this->acm->get_acm_tag( $test_tag );
137+
138+
remove_filter( 'acm_wrapper_classes', $filter_callback, 10 );
139+
remove_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' );
140+
$this->acm->delete_ad_code( $ad_code_id );
141+
142+
$this->assertStringContainsString( 'custom-ad-class', $output, 'Output should contain custom class.' );
143+
$this->assertStringContainsString( 'another-class', $output, 'Output should contain another custom class.' );
144+
}
145+
146+
/**
147+
* Test that acm_wrapper_classes filter can disable wrapper.
148+
*
149+
* @covers Ad_Code_Manager::get_acm_tag
150+
*/
151+
public function test_acm_wrapper_classes_filter_can_disable_wrapper(): void {
152+
// Create an ad code and register it.
153+
$ad_code_id = $this->create_ad_code_and_return();
154+
$this->acm->flush_cache();
155+
$this->acm->register_ad_codes( $this->acm->get_ad_codes() );
156+
157+
// Get the first available tag.
158+
$test_tag = null;
159+
foreach ( $this->acm->ad_tag_ids as $tag ) {
160+
$test_tag = $tag['tag'];
161+
break;
162+
}
163+
164+
if ( ! $test_tag ) {
165+
$this->markTestSkipped( 'No ad tags available for testing.' );
166+
}
167+
168+
// Filter to return empty array (disables wrapper).
169+
add_filter( 'acm_wrapper_classes', '__return_empty_array' );
170+
add_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' );
171+
172+
$output = $this->acm->get_acm_tag( $test_tag );
173+
174+
remove_filter( 'acm_wrapper_classes', '__return_empty_array' );
175+
remove_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' );
176+
$this->acm->delete_ad_code( $ad_code_id );
177+
178+
$this->assertStringNotContainsString( 'acm-wrapper', $output, 'Output should not contain wrapper when filter returns empty array.' );
179+
}
69180
}

0 commit comments

Comments
 (0)