diff --git a/src/class-ad-code-manager.php b/src/class-ad-code-manager.php index 557a7f2..324e956 100644 --- a/src/class-ad-code-manager.php +++ b/src/class-ad-code-manager.php @@ -797,6 +797,30 @@ function get_acm_tag( $tag_id ): string { */ $output_html = apply_filters( 'acm_output_html_after_tokens_processed', $output_html, $tag_id ); + /** + * Configuration filter: acm_wrapper_classes + * Filter the CSS classes applied to the ad wrapper div. + * + * @since 0.8.0 + * + * @param array $classes Array of CSS class names. Default: 'acm-wrapper', 'acm-tag-{tag_id}'. + * @param string $tag_id The ad tag ID being rendered. + */ + $wrapper_classes = apply_filters( + 'acm_wrapper_classes', + array( 'acm-wrapper', 'acm-tag-' . sanitize_html_class( $tag_id ) ), + $tag_id + ); + + // Allow disabling the wrapper by returning an empty array. + if ( ! empty( $wrapper_classes ) && is_array( $wrapper_classes ) ) { + $output_html = sprintf( + '
%s
', + esc_attr( implode( ' ', array_map( 'sanitize_html_class', $wrapper_classes ) ) ), + $output_html + ); + } + return $output_html; } diff --git a/tests/Integration/AdCodeManagerTest.php b/tests/Integration/AdCodeManagerTest.php index 6271986..42ec5f9 100644 --- a/tests/Integration/AdCodeManagerTest.php +++ b/tests/Integration/AdCodeManagerTest.php @@ -66,4 +66,115 @@ private function mock_ad_code() { private function create_ad_code_and_return() { return $this->acm->create_ad_code( $this->mock_ad_code() ); } + + /** + * Test that ad output includes wrapper div with default classes. + * + * @covers Ad_Code_Manager::get_acm_tag + */ + public function test_get_acm_tag_includes_wrapper_with_default_classes(): void { + // Create an ad code and register it. + $ad_code_id = $this->create_ad_code_and_return(); + $this->acm->flush_cache(); + $this->acm->register_ad_codes( $this->acm->get_ad_codes() ); + + // Get the first available tag. + $test_tag = null; + foreach ( $this->acm->ad_tag_ids as $tag ) { + $test_tag = $tag['tag']; + break; + } + + if ( ! $test_tag ) { + $this->markTestSkipped( 'No ad tags available for testing.' ); + } + + // Enable display of ad codes without conditionals. + add_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' ); + + $output = $this->acm->get_acm_tag( $test_tag ); + + remove_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' ); + $this->acm->delete_ad_code( $ad_code_id ); + + $this->assertStringContainsString( 'class="acm-wrapper', $output, 'Output should contain acm-wrapper class.' ); + $this->assertStringContainsString( 'acm-tag-' . sanitize_html_class( $test_tag ), $output, 'Output should contain tag-specific class.' ); + } + + /** + * Test that acm_wrapper_classes filter can modify wrapper classes. + * + * @covers Ad_Code_Manager::get_acm_tag + */ + public function test_acm_wrapper_classes_filter_modifies_classes(): void { + // Create an ad code and register it. + $ad_code_id = $this->create_ad_code_and_return(); + $this->acm->flush_cache(); + $this->acm->register_ad_codes( $this->acm->get_ad_codes() ); + + // Get the first available tag. + $test_tag = null; + foreach ( $this->acm->ad_tag_ids as $tag ) { + $test_tag = $tag['tag']; + break; + } + + if ( ! $test_tag ) { + $this->markTestSkipped( 'No ad tags available for testing.' ); + } + + // Filter to add custom classes. + $filter_callback = function ( $classes, $tag_id ) { + $classes[] = 'custom-ad-class'; + $classes[] = 'another-class'; + return $classes; + }; + + add_filter( 'acm_wrapper_classes', $filter_callback, 10, 2 ); + add_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' ); + + $output = $this->acm->get_acm_tag( $test_tag ); + + remove_filter( 'acm_wrapper_classes', $filter_callback, 10 ); + remove_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' ); + $this->acm->delete_ad_code( $ad_code_id ); + + $this->assertStringContainsString( 'custom-ad-class', $output, 'Output should contain custom class.' ); + $this->assertStringContainsString( 'another-class', $output, 'Output should contain another custom class.' ); + } + + /** + * Test that acm_wrapper_classes filter can disable wrapper. + * + * @covers Ad_Code_Manager::get_acm_tag + */ + public function test_acm_wrapper_classes_filter_can_disable_wrapper(): void { + // Create an ad code and register it. + $ad_code_id = $this->create_ad_code_and_return(); + $this->acm->flush_cache(); + $this->acm->register_ad_codes( $this->acm->get_ad_codes() ); + + // Get the first available tag. + $test_tag = null; + foreach ( $this->acm->ad_tag_ids as $tag ) { + $test_tag = $tag['tag']; + break; + } + + if ( ! $test_tag ) { + $this->markTestSkipped( 'No ad tags available for testing.' ); + } + + // Filter to return empty array (disables wrapper). + add_filter( 'acm_wrapper_classes', '__return_empty_array' ); + add_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' ); + + $output = $this->acm->get_acm_tag( $test_tag ); + + remove_filter( 'acm_wrapper_classes', '__return_empty_array' ); + remove_filter( 'acm_display_ad_codes_without_conditionals', '__return_true' ); + $this->acm->delete_ad_code( $ad_code_id ); + + $this->assertStringNotContainsString( 'acm-wrapper', $output, 'Output should not contain wrapper when filter returns empty array.' ); + } }