Init Reading Position – Automatically resume where readers left off

Version: 1.6 Tiếng Việt

Init Reading Position – Automatically resume where readers left off
Init Reading Position is a WordPress plugin that helps readers return to exactly where they left off in a post. As users scroll through a post, the plugin remembers their position and automatically scrolls back to that point when they revisit — whether logged in or not. It’s ultra-lightweight, jQuery-free, and uses pure JavaScript and REST API for logged-in users.

Main Features

  • Remembers reading position using localStorage for guests.
  • Saves reading position to user_meta per device for logged-in users (PC, Mobile, Tablet…).
  • Automatically scrolls back to the last read position on reload or return.
  • Choose which post types are enabled via settings panel.
  • No tables, no tracking, no bloat – fully clean and safe.
  • No jQuery used, written in modern Vanilla JS.
  • Supports init_plugin_suite_reading_position_delay filter to customize debounce delay before saving.

For both guests and logged-in users

  • Guests’ reading positions are saved via browser localStorage.
  • Logged-in users’ positions are saved in user_meta per post and per device, ensuring each device remembers its own state.

Easy Customization

  • You can choose which post types enable the reading position feature.
  • Supports filters for developers to modify saving delay or logic based on post ID.

Quick Setup

  1. Download the plugin and extract it into /wp-content/plugins/
  2. Activate it via the Plugins menu in WP admin
  3. Configure supported post types in Settings → Reading Position
  4. Done – it runs automatically, no shortcode or block needed.

Performance & Compatibility

  • Compatible with WordPress 5.5 and above
  • Requires PHP 7.4+
  • Theme-independent – works with any modern theme
  • Highly optimized code, no slowdown even on long posts

For Developers

  • Filter init_plugin_suite_reading_position_delay to customize debounce time
  • Filter init_plugin_suite_reading_position_meta_key to change the meta key name
  • Filter init_plugin_suite_reading_position_data_to_store to modify saved content
  • Filter init_plugin_suite_reading_position_should_delete to decide whether to delete saved position
  • Filter init_plugin_suite_reading_position_localized_data to inject extra data into frontend JS

Examples using advanced filters:

// Change debounce time (default: 1000ms)
add_filter('init_plugin_suite_reading_position_delay', fn() => 2000); // 2 seconds

// Customize meta_key used for storing position
add_filter('init_plugin_suite_reading_position_meta_key', function ($key, $post_id, $device) {
    return "_custom_rp_{$post_id}_{$device}"; // Example: _custom_rp_123_PC
}, 10, 3);

// Modify data stored to user_meta (default includes scrollTop, percent, screenHeight, updated)
add_filter('init_plugin_suite_reading_position_data_to_store', function ($data, $post_id, $device, $user_id) {
    $data['ip'] = $_SERVER['REMOTE_ADDR'] ?? ''; // Optionally store user IP
    return $data;
}, 10, 4);

// Prevent deletion of saved position when user reaches end
add_filter('init_plugin_suite_reading_position_should_delete', fn($yes) => false); // Keep it for next session

// Inject debug mode into JS
add_filter('init_plugin_suite_reading_position_localized_data', function ($data, $post_id) {
    $data['debug'] = current_user_can('manage_options'); // Add debug flag for admins
    return $data;
});

Get Started

Whether you’re running a blog, novel site, magazine or long-form content hub, Init Reading Position delivers a smooth and smart reading experience – lightweight, intelligent, and fully automatic.

Review

5.0/5 (1)

Changelog

  • 1.6 – Bulk query & multi-device cache optimization
    • Improved: reading position retrieval now uses a single bulk query instead of per-device queries — reduces database load and improves performance.
    • Added: deterministic bulk cache key (pc_mobile_tablet) — ensures consistent caching and easier invalidation.
    • Improved: cache invalidation is now synchronized — clears both single-device and bulk cache entries to prevent stale data.
    • Improved: frontend receives all device positions — JavaScript dynamically selects the correct device at runtime.
    • Fixed: previous md5-based cache keys could lead to inconsistent or stale cache — replaced with deterministic keys.
    • Fixed: undefined savedPositions for guest users — now always initialized with default values.
    • No breaking changes — REST API, database, localStorage, and all settings remain fully compatible.
  • 1.5 – Scroll tracking & rate limit optimizations
    • Fixed: autoClearOnEnd with no selector configured would never trigger — now correctly falls back to page-bottom detection.
    • Improved: scope element bounds cached after DOMContentLoaded and refreshed on resize — getBoundingClientRect() is no longer called on every scroll event.
    • Improved: device detection fully moved to JavaScript — PHP no longer performs UA sniffing server-side, eliminating device mismatches between page load and save.
    • Improved: rate limiting switched from transient to wp_cache — eliminates transient writes to wp_options on high-traffic sites; works best with an object cache (Redis/Memcached), degrades gracefully without one.
    • No breaking changes — REST API, localStorage keys, and all existing settings remain fully compatible.
  • 1.4 – Background migration via self-scheduling cron
    • Refactored: Migration now runs via self-scheduling WP-Cron instead of admin requests.
    • Automatically re-runs every 30 seconds until all data is processed.
    • Removed dependency on admin traffic for background execution.
    • Added locking mechanism to prevent overlapping cron runs.
    • Simplified lifecycle: auto start → batch processing → auto stop when done.
    • Reduced admin_init overhead for better backend performance.
    • No breaking changes — fully backward compatible.
  • 1.3 – Custom database migration & performance improvements
    • Switched from user_meta to a dedicated custom database table for storing reading positions.
    • Automatically migrates existing data from user_meta to the new table (safe background process).
    • Optimized schema with unique key (user_id, post_id, device) for efficient upsert operations.
    • Improved read/write performance and scalability for larger websites.
    • Reduced API requests by adding a throttle layer on top of existing debounce.
    • Standardized device values (pc, mobile, tablet) for backend consistency.
    • Added fail-safe handling for REST API to prevent JavaScript errors on failed requests.
    • Significantly reduced server load for logged-in users and improved overall responsiveness.
    • Fully backward-compatible: legacy data is migrated gradually with fallback support during transition.
    • No changes to frontend behavior — localStorage, REST API, and tracking remain intact.
  • 1.2 – Multi-selector & auto-clear at content end
    • Added support for multiple CSS selectors at once — e.g. .entry-content, .post-content, #main.
    • Scroll progress is tracked when the reader is inside any of the configured selectors.
    • Automatically clears the saved reading position when reaching the end of the content area (selector).
    • If auto-clear is disabled, the plugin falls back to the previous behavior: deleting progress only when reaching the bottom of the page.
    • Progress percentage prioritizes the selector currently in scope, with fallback to full page tracking when outside all selectors.
    • New setting added in the options page: “Auto-clear saved position at content end” (enabled by default).
    • No breaking changes: existing localStorage keys and user_meta structure remain fully compatible.
    • All new setting strings are fully i18n-ready (English + Vietnamese).
  • 1.1 – Selector support & scoped reading progress tracking
    • Added CSS Selector option to track reading progress only inside a specific content area (e.g., .entry-content).
    • Progress is saved only while the user is scrolling inside the selected content area — scrolling in the comments section no longer updates progress.
    • Progress is always removed only when the reader reaches the end of the page, regardless of the selector.
    • No logic changes to persistence: localStorage for guests and user_meta for logged-in users.
    • No breaking changes — keeps existing localStorage keys and user_meta structure.
    • Settings page updated with new selector input (placeholder only, default empty).
    • Added full i18n support (English + Vietnamese translation strings included).
    • Code remains lightweight — no dependency, no extra scripts injected.
  • 1.0 – First release of Init Reading Position
    • Remembers reading position and resumes when user revisits a post.
    • Stores using localStorage for guests, user_meta for logged-in users — per device.
    • Preloads position from user_meta to avoid redundant REST calls.
    • Deletes saved position when user reaches end of the post.
    • Settings panel to control which post types are enabled.
    • Written in clean Vanilla JavaScript – no jQuery used.
    • No custom DB tables or interference with other plugins.
    • Includes filters: init_plugin_suite_reading_position_delay, init_plugin_suite_reading_position_meta_key, init_plugin_suite_reading_position_data_to_store, init_plugin_suite_reading_position_should_delete, init_plugin_suite_reading_position_localized_data.
    • Lightweight, extendable, and ideal for long-form UX.
Made with in HCMC.

Comments


  • No comments yet.

Init Toolbox

Press Ctrl + \ on desktop, or swipe left anywhere on mobile.

Login