Skip to content

Commit cbcf912

Browse files
committed
Initial commit
1 parent 06b782c commit cbcf912

File tree

5 files changed

+702
-0
lines changed

5 files changed

+702
-0
lines changed

README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Article Sequence Optimizer
2+
3+
**Contributors:** XWP
4+
**Tags:** performance, infinite-scroll, inp, dom-optimization
5+
**Requires at least:** 6.3
6+
**Tested up to:** 6.8
7+
**Requires PHP:** 8.1
8+
**Stable tag:** 1.0.0
9+
10+
Optimizes infinite scroll performance by managing DOM nodes and visibility for articles.
11+
12+
## Description
13+
14+
The Article Sequence Optimizer improves the performance of long article sequences (infinite scroll) by intelligently managing the DOM. It uses a hybrid approach to reduce Interaction to Next Paint (INP) and memory usage:
15+
16+
1. **CSS Content Visibility**: For articles containing iframes (like embeds), it uses `content-visibility: hidden` to prevent heavy reloads and flickering when scrolling back.
17+
2. **DOM Detachment**: For text/image-only articles, it detaches the content from the DOM and stores it in a memory fragment, significantly reducing the DOM size and style recalculation costs.
18+
19+
## Configuration
20+
21+
Go to **Settings → Article Sequence Optimizer** to configure the plugin:
22+
23+
* **Container Selector**: The CSS selector for the **direct parent container** of your articles (default: `#articles-area`).
24+
* **Article Selector**: The CSS selector for the article elements that are **direct children** of the container (default: `article`).
25+
* **Safelist Iframes Selector**: Selectors for iframes that should remain visible (default: `.ad`).
26+
* **Buffer Distance**: The distance in pixels for pre-loading articles. Use a single value like `2500px` or specify all 4 directions (default: `2500px`).
27+
* **Max Cache Size**: Maximum number of articles to keep in memory (default: `50`).
28+
29+
## Installation
30+
31+
1. Upload the plugin files to the `/wp-content/plugins/articles-sequence-optimizer` directory, or install the plugin through the WordPress plugins screen directly.
32+
2. Activate the plugin through the 'Plugins' screen in WordPress.
33+
3. Navigate to **Settings → Article Sequence Optimizer** to configure the selectors for your theme.
34+
35+
## Frequently Asked Questions
36+
37+
### Does this work with any theme?
38+
Yes, as long as you configure the correct **Container Selector** and **Article Selector** in the settings.
39+
40+
### Will this break my dynamic embeds?
41+
The plugin is designed to handle embeds safely. It uses CSS hiding for articles with iframes/embeds instead of detaching them, which prevents ads from reloading or losing their state. You can also use the **Safelist Iframes Selector** to exclude specific elements.
42+
43+
## Developer Hooks
44+
45+
### `article_sequence_optimizer_should_load`
46+
Filters whether the optimizer script should be loaded.
47+
48+
**Parameters:**
49+
* `$should_load` (bool): Whether to load the script. Default is `true` only on single posts of type 'post'.
50+
51+
**Example:**
52+
Enable on all post types (including pages and custom post types):
53+
```php
54+
add_filter( 'article_sequence_optimizer_should_load', function( $should_load ) {
55+
return is_singular();
56+
} );
57+
```

articles-sequence-optimizer.php

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
/**
3+
* Plugin Name: Article Sequence Optimizer
4+
* Plugin URI: https://github.com/xwp/article-sequence-optimizer
5+
* Description: Optimizes infinite scroll performance by managing DOM nodes and visibility for articles.
6+
* Version: 1.0.0
7+
* Requires PHP: 8.1
8+
* Requires at least: 6.3
9+
* Author: XWP
10+
* Author URI: https://xwp.co/
11+
*
12+
* @package ArticleSequenceOptimizer
13+
*/
14+
15+
namespace ArticleSequenceOptimizer;
16+
17+
const MAIN_DIR = __DIR__;
18+
const VERSION = '1.0.0';
19+
20+
// Include admin settings.
21+
require_once MAIN_DIR . '/includes/admin-settings.php';
22+
23+
// Register hooks.
24+
add_action( 'admin_menu', __NAMESPACE__ . '\register_settings_page' );
25+
add_action( 'admin_init', __NAMESPACE__ . '\register_settings' );
26+
add_action( 'wp_enqueue_scripts', __NAMESPACE__ . '\enqueue_script' );
27+
add_action( 'wp_footer', __NAMESPACE__ . '\output_inline_styles' );
28+
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), __NAMESPACE__ . '\add_settings_link' );
29+
30+
/**
31+
* Add "Settings" link to plugin action links.
32+
*
33+
* @param array $links Existing plugin action links.
34+
* @return array Modified plugin action links.
35+
*/
36+
function add_settings_link( $links ) {
37+
$settings_link = sprintf(
38+
'<a href="%s">%s</a>',
39+
esc_url( admin_url( 'options-general.php?page=article-sequence-optimizer' ) ),
40+
esc_html__( 'Settings', 'article-sequence-optimizer' )
41+
);
42+
array_unshift( $links, $settings_link );
43+
return $links;
44+
}
45+
46+
/**
47+
* Enqueue the optimizer script.
48+
*
49+
* @return void
50+
*/
51+
function enqueue_script() {
52+
// Check if we should load the script.
53+
// Default: Only on single 'post' types (standard articles).
54+
$should_load = is_singular( 'post' );
55+
56+
/**
57+
* Filter to allow developers to modify the condition for loading the script.
58+
*
59+
* @param bool $should_load Whether to load the script.
60+
*/
61+
if ( ! apply_filters( 'article_sequence_optimizer_should_load', $should_load ) ) {
62+
return;
63+
}
64+
65+
// Only enqueue if we have settings or defaults.
66+
$settings = get_settings();
67+
68+
wp_register_script(
69+
'article-sequence-optimizer',
70+
plugin_dir_url( __FILE__ ) . 'assets/js/article-sequence-optimizer.js',
71+
[],
72+
VERSION,
73+
true
74+
);
75+
wp_script_add_data( 'article-sequence-optimizer', 'strategy', 'defer' );
76+
77+
// Pass configuration to JS.
78+
$buffer_distance = $settings['buffer_distance'];
79+
80+
// Helper: If buffer_distance is a single value, expand it to 4 directions.
81+
// E.g., "2500px" becomes "2500px 0px 2500px 0px" (top right bottom left).
82+
$parts = explode( ' ', trim($buffer_distance) );
83+
if ( count( $parts ) === 1 ) {
84+
$buffer_distance = "{$buffer_distance} 0px {$buffer_distance} 0px";
85+
}
86+
87+
$config = [
88+
'containerSelector' => $settings['container_selector'],
89+
'articleSelector' => $settings['article_selector'],
90+
'safelistIframes' => $settings['safelist_iframes'],
91+
'bufferDistance' => $buffer_distance,
92+
'maxCacheSize' => (int) $settings['max_cache_size'],
93+
];
94+
95+
wp_add_inline_script(
96+
'article-sequence-optimizer',
97+
'window.articleSequenceOptimizerConfig = ' . wp_json_encode( $config ) . ';',
98+
'before'
99+
);
100+
101+
wp_enqueue_script( 'article-sequence-optimizer' );
102+
}
103+
104+
/**
105+
* Output inline styles for optimizer classes in footer.
106+
*
107+
* @return void
108+
*/
109+
function output_inline_styles() {
110+
// Check if we should load the styles (same condition as script).
111+
$should_load = is_singular( 'post' );
112+
113+
/**
114+
* Filter to allow developers to modify the condition for loading the styles.
115+
*
116+
* @param bool $should_load Whether to load the styles.
117+
*/
118+
if ( ! apply_filters( 'article_sequence_optimizer_should_load', $should_load ) ) {
119+
return;
120+
}
121+
122+
?>
123+
<style id="article-sequence-optimizer-styles">
124+
.inp-article-offloaded{min-height:var(--inp-article-height)}.inp-article-visibility-optimized{content-visibility:auto;contain-intrinsic-size:auto var(--inp-article-height)}
125+
</style>
126+
<?php
127+
}

0 commit comments

Comments
 (0)