Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow content matching selectors to be excluded #1198

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions admin/apple-actions/index/class-export.php
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ private function get_content( $post ) {
$content = apply_filters( 'the_content', $content ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

// Clean up the HTML a little.
$content = $this->exclude_selectors( $content );
$content = $this->remove_tags( $content );
$content = $this->remove_entities( $content );

Expand Down Expand Up @@ -643,6 +644,52 @@ private function remove_entities( $content ) {
return str_replace( '&', '&', $content );
}

/**
* Remove excluded selectors from the content.
*
* @param string $content The content to be filtered.
* @return string
*/
private function exclude_selectors( $content ) {
$raw_selectors = $this->get_setting( 'excluded_selectors' );

$selectors = explode( ',', $raw_selectors );
$selectors = array_map( 'trim', $selectors );
$selectors = array_filter( $selectors );

if ( count( $selectors ) === 0 ) {
return $content;
}

libxml_use_internal_errors( true );
$dom = new \DOMDocument();
$dom->loadHTML( '<?xml encoding="utf-8" ?>' . $content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
$xpath = new \DOMXPath( $dom );
libxml_clear_errors();

foreach ( $selectors as $selector ) {
$nodes = [];

if ( str_starts_with( $selector, '#' ) ) {
$nodes = $xpath->query( '//*[@id="' . substr( $selector, 1 ) . '"]' );
}

if ( str_starts_with( $selector, '.' ) ) {
$nodes = $xpath->query( '//*[contains(concat(" ", normalize-space(@class), " "), " ' . substr( $selector, 1 ) . ' ")]' );
}

if ( is_iterable( $nodes ) ) {
foreach ( $nodes as $node ) {
$node->parentNode->removeChild( $node ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
}
}
}

$content = $dom->saveHTML();

return $content;
}

/**
* Loads settings for the Exporter_Content from the WordPress post metadata.
*
Expand Down
23 changes: 19 additions & 4 deletions admin/settings/class-admin-apple-settings-section-advanced.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,26 +71,41 @@ public function __construct( $page ) {
'description' => __( 'Enter a CSS class name that will be used to generate the Aside component. Do not prefix with a period.', 'apple-news' ),
'required' => false,
],
'excluded_selectors' => [
'label' => __( 'Selectors', 'apple-news' ),
'type' => 'text',
'size' => 150,
'description' => sprintf(
/* translators: %s: <code> tag */
__( 'Enter a comma-separated list of CSS class or ID selectors, like %s. Elements in post content matching these selectors will be removed from the content published to Apple News.', 'apple-news' ),
'<code>.my-class, #my-id</code>',
),
'required' => false,
],
];

// Add the groups.
$this->groups = [
'alerts' => [
'alerts' => [
'label' => __( 'Alerts', 'apple-news' ),
'settings' => [ 'component_alerts' ],
],
'images' => [
'images' => [
'label' => __( 'Image Settings', 'apple-news' ),
'settings' => [ 'use_remote_images', 'full_bleed_images' ],
],
'format' => [
'format' => [
'label' => __( 'Format Settings', 'apple-news' ),
'settings' => [ 'html_support', 'in_article_position' ],
],
'aside' => [
'aside' => [
'label' => __( 'Aside Component', 'apple-news' ),
'settings' => [ 'aside_component_class' ],
],
'selectors' => [
'label' => __( 'Excluded Elements', 'apple-news' ),
'settings' => [ 'excluded_selectors' ],
],
];

parent::__construct( $page );
Expand Down
1 change: 1 addition & 0 deletions admin/settings/class-admin-apple-settings-section.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ class Admin_Apple_Settings_Section extends Apple_News {
'b' => [],
'strong' => [],
'i' => [],
'code' => [],
'em' => [],
'a' => [
'href' => [],
Expand Down
1 change: 1 addition & 0 deletions includes/apple-exporter/class-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Settings {
'post_types' => [ 'post' ],
'show_metabox' => 'yes',
'use_remote_images' => 'yes',
'excluded_selectors' => '',
];

/**
Expand Down
28 changes: 28 additions & 0 deletions tests/admin/apple-actions/index/test-class-export.php
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,34 @@ public function test_remove_entities() {
);
}

/**
* Tests the ability to remove selectors from the content.
*/
public function test_remove_selectors() {
$post_id = $this->factory->post->create(
[
'post_content' => <<<HTML
<p class="foo">First paragraph</p>
<p class="bar">Second paragraph</p>
<p class="foo bar">Third paragraph</p>
<p class="foobar">Fourth paragraph</p>
<p id="foo">Fifth paragraph</p>
<p id="bar">Sixth paragraph</p>
HTML,
]
);

$this->settings->excluded_selectors = '.foo, #foo';

$export = new Export( $this->settings, $post_id );
$exporter = $export->fetch_exporter();
$content = $exporter->get_content()->content();

$this->assertStringNotContainsString( 'First paragraph', $content );
$this->assertStringNotContainsString( 'Third paragraph', $content );
$this->assertStringNotContainsString( 'Fifth paragraph', $content );
}

/**
* Tests the behavior of the apple_news_is_exporting() function.
*/
Expand Down