{"id":374344,"date":"2026-09-29T15:16:28","date_gmt":"2026-09-29T15:16:28","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/sharing-activity-detector-by-shibisty\/"},"modified":"2026-09-29T14:19:47","modified_gmt":"2026-09-29T14:19:47","slug":"shibisty-sharing-activity-detector","status":"publish","type":"plugin","link":"https:\/\/li.wordpress.org\/plugins\/shibisty-sharing-activity-detector\/","author":23570832,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"5.0.2","stable_tag":"5.0.2","tested":"7.1.2","requires":"5.0","requires_php":"7.4","requires_plugins":null,"header_name":"Shibisty Sharing Activity Detector","header_author":"Alexander Shibisty","header_description":"Detection of suspicious activity with an interactive timeline, request log, and heartbeat.","assets_banners_color":"","last_updated":"2026-09-29 14:19:47","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/shibisty.com\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":42,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"5.0.2":{"tag":"5.0.2","author":"shibisty","date":"2026-09-29 14:19:47","revision":3719244}},"upgrade_notice":[],"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["5.0.2"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[231823,8534,283435,600,257747],"plugin_category":[54],"plugin_contributors":[283436],"plugin_business_model":[],"class_list":["post-374344","plugin","type-plugin","status-publish","hentry","plugin_tags-activity-monitor","plugin_tags-audit-log","plugin_tags-multi-device","plugin_tags-security","plugin_tags-session-tracking","plugin_category-security-and-spam-protection","plugin_contributors-shibisty","plugin_committers-shibisty"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/shibisty-sharing-activity-detector.svg","icon_2x":false,"generated":true},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Shibisty Sharing Activity Detector logs requests (page views, REST\/AJAX calls, admin-area hits, and optional heartbeat pings) into a dedicated database table, then groups them into sessions per user\/device. From that it computes, for each user:<\/p>\n\n<ul>\n<li><strong>Range<\/strong> \u2014 the sum of all active time intervals (how long the user was actually on the site).<\/li>\n<li><strong>Total per device<\/strong> \u2014 the sum of each device's active time, computed separately.<\/li>\n<li><strong>Parallel time<\/strong> \u2014 <code>Total \u2212 Range<\/code>. A value greater than zero means two or more devices were active for the same user at the same time, which is the core signal this plugin is built to detect (e.g. a shared account being used from two locations at once).<\/li>\n<\/ul>\n\n<p>Session boundaries are computed with a simple gap rule: if two consecutive requests from the same user\/device are \u2264 5 minutes apart, they belong to the same session and the time between them is counted; a gap of more than 5 minutes is treated as the user having left, and that gap is <em>not<\/em> counted toward active time.<\/p>\n\n<h3>Admin screens<\/h3>\n\n<p>All screens live under <strong>Suspicious Activity<\/strong> in the admin menu (<code>manage_options<\/code> capability required):<\/p>\n\n<ul>\n<li><strong>Activity<\/strong> (<code>wp-suspicious-activity<\/code>) \u2014 list of users with a suspicious-activity timeline, sortable\/filterable.<\/li>\n<li><strong>Request Logs<\/strong> (<code>wp-sad-request-logs<\/code>) \u2014 full paginated log of every recorded request, with filters and sortable columns.<\/li>\n<li><strong>Settings<\/strong> (<code>wp-sad-settings<\/code>) \u2014 logging rules and heartbeat.<\/li>\n<li><strong>Log View<\/strong> (<code>wp-sad-log-view<\/code>, hidden) \u2014 detail view of a single log entry, linked from the Request Logs list.<\/li>\n<li><strong>Activity View<\/strong> (<code>wp-sad-activity-view<\/code>, hidden) \u2014 detail view of a single user's activity\/timeline, linked from the Activity list.<\/li>\n<\/ul>\n\n<p>Filter selections on the Activity and Request Logs screens are remembered in the browser (<code>localStorage<\/code>) and restored on your next visit; the Reset button always clears them and returns to the default view. Wherever a user is identified from a session, their name links directly to their WordPress profile\/edit-user page.<\/p>\n\n<h3>Settings<\/h3>\n\n<p>Found under <strong>Suspicious Activity \u2192 Settings<\/strong>:<\/p>\n\n<ul>\n<li><strong>Audience (who gets logged)<\/strong> \u2014 All users (including guests), Registered users only, or Admins only.<\/li>\n<li><strong>Logging scope (what gets logged)<\/strong> \u2014 all pages\/API\/admin area, only pages and heartbeat, only the site excluding admin area and heartbeat, only admin area and heartbeat, or stop logging entirely.<\/li>\n<li><strong>Logging window (when to log)<\/strong> \u2014 Always, or only during a specific time-of-day window (<code>from<\/code>\u2013<code>to<\/code>). Windows that cross midnight (e.g. <code>22:00<\/code>\u2013<code>06:00<\/code>) are supported.<\/li>\n<li><strong>Heartbeat<\/strong> \u2014 enable\/disable, plus a configurable ping interval (15\u2013600 seconds). When enabled, a small script pings the plugin's own REST endpoint (<code>\/wp-json\/wp-sad\/v1\/heartbeat<\/code>) at that interval for as long as the browser tab is open and visible, so active time is counted accurately even between page loads, without relying on <code>admin-ajax.php<\/code>.<\/li>\n<\/ul>\n\n<h3>Localization<\/h3>\n\n<p>The plugin's source strings are in English (<code>shibisty-sharing-activity-detector<\/code> text domain, <code>.pot<\/code> template included in <code>\/languages<\/code>) and hand-written translations already exist for 30 additional languages &mdash; Ukrainian, Russian, German, French, Spanish, Italian, Portuguese (Brazil), Portuguese (Portugal), Polish, Dutch, Romanian, Czech, Hungarian, Bulgarian, Greek, Turkish, Swedish, Finnish, Lithuanian, Croatian, Serbian, Georgian, Azerbaijani, Kazakh, Belarusian, Arabic, Hebrew, Hindi, Chinese (Simplified), and Japanese. Like every WordPress.org-hosted plugin, translations are delivered through translate.wordpress.org and applied automatically based on each admin's own profile language \u2014 there's no plugin-specific language setting.<\/p>\n\n<h3>Architecture<\/h3>\n\n<p>The plugin is split into logic and presentation layers rather than one monolithic file:<\/p>\n\n<pre><code>`\n<\/code><\/pre>\n\n<p>shibisty-sharing-activity-detector\/\n\u251c\u2500\u2500 shibisty-sharing-activity-detector.php     # Bootstrap: constants, requires, activation\n\u251c\u2500\u2500 includes\/\n\u2502   \u251c\u2500\u2500 class-plugin.php           # Orchestrator: hooks, wiring\n\u2502   \u251c\u2500\u2500 class-db.php                # Table name\/schema, install + upgrade (dbDelta), checked on every init\n\u2502   \u251c\u2500\u2500 class-settings.php          # Settings storage and sanitization\n\u2502   \u251c\u2500\u2500 class-request-logger.php    # Classifies + gates + records each request\n\u2502   \u251c\u2500\u2500 class-heartbeat.php         # REST heartbeat route + front-end pinger\n\u2502   \u251c\u2500\u2500 class-session-analyzer.php  # Pure session\/timeline\/risk calculation logic\n\u2502   \u251c\u2500\u2500 class-view-helpers.php \/ class-query-helpers.php\n\u2502   \u251c\u2500\u2500 class-admin-menu.php        # Menu registration, asset enqueueing\n\u2502   \u2514\u2500\u2500 admin\/                      # Page controllers (Activity, Request Logs, Log View, Activity View, Settings)\n\u251c\u2500\u2500 views\/                          # Plain PHP templates \u2014 no business logic or queries\n\u251c\u2500\u2500 assets\/                         # css\/, js\/ (timeline UI, filter persistence, heartbeat pinger)\n\u2514\u2500\u2500 languages\/                      # .pot template (translations delivered via translate.wordpress.org)\n    `<\/p>\n\n<p>Request records carry a <code>request_type<\/code> (<code>page<\/code>, <code>api<\/code>, <code>admin<\/code>, or <code>heartbeat<\/code>), set at write time, which the session analyzer uses to decide what counts as a genuine presence signal versus administrative\/system noise.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Copy the <code>shibisty-sharing-activity-detector<\/code> folder into <code>wp-content\/plugins\/<\/code>, or install it as a zip from the Plugins \u2192 Add New screen.<\/li>\n<li>Activate <strong>Shibisty Sharing Activity Detector<\/strong> from the WordPress admin Plugins screen.<\/li>\n<li>The plugin creates its own table (<code>{$wpdb-&gt;prefix}request_logs<\/code>) automatically on activation, and also re-checks the table\/schema on every <code>init<\/code> \u2014 so the table is repaired automatically if it's ever missing, without needing to reactivate the plugin.<\/li>\n<li>Visit <strong>Suspicious Activity \u2192 Settings<\/strong> to choose who gets logged, what gets logged, and whether heartbeat is enabled.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20delete%20any%20data%20when%20deactivated%20or%20uninstalled%3F\"><h3>Does this plugin delete any data when deactivated or uninstalled?<\/h3><\/dt>\n<dd><p>No. The plugin does not delete its data on deactivation, and uninstalling\/deleting the plugin does not currently remove the <code>request_logs<\/code> table or its data either. Back it up or drop it manually if you need a clean removal.<\/p><\/dd>\n<dt id=\"can%20i%20add%20a%20language%20that%20isn%27t%20available%20yet%3F\"><h3>Can I add a language that isn't available yet?<\/h3><\/dt>\n<dd><p>Yes, the standard WordPress.org way: contribute the translation on <a href=\"https:\/\/translate.wordpress.org\/\">translate.wordpress.org<\/a> using <code>shibisty-sharing-activity-detector.pot<\/code> (included in <code>\/languages<\/code>) as the reference for all translatable strings. Once a locale reaches 100% (or the site's configured threshold), WordPress downloads and applies it automatically \u2014 no plugin update needed.<\/p><\/dd>\n<dt id=\"can%20heartbeat%20data%20be%20added%20retroactively%20for%20past%20traffic%3F\"><h3>Can heartbeat data be added retroactively for past traffic?<\/h3><\/dt>\n<dd><p>No. Heartbeat and <code>request_type<\/code>-aware session data are only accurate for traffic recorded after the relevant setting was enabled; there's no way to reconstruct heartbeat signal for historical requests.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h3>5.0.2<\/h3>\n\n<ul>\n<li>Rewrote the plugin as an MVC-style architecture (includes\/admin\/views\/assets) instead of a single monolithic file.<\/li>\n<li>Fixed a session-time calculation bug where the signal-type filter was inverted, and where <code>admin-ajax.php<\/code> requests were being skipped entirely.<\/li>\n<li>Added settings for logging audience, scope, time window, and heartbeat.<\/li>\n<li>Added Request Logs, Log View, Activity View, and Settings admin pages.<\/li>\n<li>Added a user-type filter (All \/ Registered \/ Admins) and <code>localStorage<\/code>-based filter persistence.<\/li>\n<li>Made the plugin translation-ready with an English source and a <code>.pot<\/code> template; hand-written translations exist for 30 additional languages and roll out via translate.wordpress.org.<\/li>\n<\/ul>","raw_excerpt":"Tracks user sessions\/requests, flags suspicious multi-device activity, and gives admins an interactive timeline, a full request log, and settings.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/374344","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=374344"}],"author":[{"embeddable":true,"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/shibisty"}],"wp:attachment":[{"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=374344"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=374344"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=374344"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=374344"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=374344"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/li.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=374344"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}