{"id":400155,"date":"2026-11-10T17:08:22","date_gmt":"2026-11-10T17:08:22","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/rooster-lrs\/"},"modified":"2026-11-10T17:36:51","modified_gmt":"2026-11-10T17:36:51","slug":"rooster-lrs","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/rooster-lrs\/","author":21057082,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.1.4","requires":"6.7","requires_php":"8.1","requires_plugins":null,"header_name":"Rooster LRS","header_author":"Oxford Metadata","header_description":"An xAPI Learning Record Store (xAPI 1.0.3 and 2.0): statements, documents, attachments and per-client credentials, inside WordPress.","last_updated":"2026-11-10 17:36:51","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/rooster.systems\/","header_author_uri":"https:\/\/oxfordmetadata.co.uk\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":118,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.1.0":{"tag":"0.1.0","author":"oxfordmetadata","date":"2026-11-10 17:07:50","revision":3794906},"1.0.0":{"tag":"1.0.0","author":"oxfordmetadata","date":"2026-11-10 17:36:51","revision":3794962}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3794902,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3794902,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3794902,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3794902,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3794902,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.1.0","1.0.0"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[291894,18342,68799,176445,34125],"plugin_category":[],"plugin_contributors":[250108],"plugin_business_model":[],"class_list":["post-400155","plugin","type-plugin","status-publish","hentry","plugin_tags-cmi5","plugin_tags-elearning","plugin_tags-lrs","plugin_tags-tin-can","plugin_tags-xapi","plugin_contributors-oxfordmetadata","plugin_committers-oxfordmetadata"],"banners":{"banner":"https:\/\/ps.w.org\/rooster-lrs\/assets\/banner-772x250.png?rev=3794902","banner_2x":"https:\/\/ps.w.org\/rooster-lrs\/assets\/banner-1544x500.png?rev=3794902","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/rooster-lrs\/assets\/icon.svg?rev=3794902","icon":"https:\/\/ps.w.org\/rooster-lrs\/assets\/icon.svg?rev=3794902","icon_2x":false,"generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p><strong>Rooster LRS makes your WordPress site an xAPI Learning Record Store (LRS).<\/strong> Learning applications, e-learning packages (xAPI and cmi5), simulators and learning management systems send their xAPI statements to it, and reporting tools read them back. The records stay in your own database, in the plugin's own tables, and nothing is sent anywhere else.<\/p>\n\n<p><strong><a href=\"https:\/\/rooster.systems\/get-rooster-lrs\/\">Website<\/a> \u00b7 <a href=\"https:\/\/rooster.systems\/category\/en\/documentation\/rooster-lrs\/\">Documentation<\/a> \u00b7 <a href=\"https:\/\/wordpress.org\/plugins\/rooster-lms\/\">Rooster LMS<\/a><\/strong><\/p>\n\n<h4>What it does<\/h4>\n\n<ul>\n<li>The xAPI resources under <code>\/wp-json\/rooster-lrs\/xapi\/<\/code>: statements (store, query, void), State, Activity Profile, Agent Profile, Activities, Agents and About.<\/li>\n<li>xAPI 1.0.3 and xAPI 2.0 (IEEE 9274.1.1) at the same endpoint, chosen by the <code>X-Experience-API-Version<\/code> header.<\/li>\n<li>Strict statement validation with clear error messages that name the property and the rule.<\/li>\n<li>xAPI Profiles: statements that follow the Rooster assessment or adaptive profile (quiz attempts and answers, from Rooster LMS Pro or any platform that emits them) have the profile's extensions checked against their schemas. The profiles are bundled with the plugin, so nothing is fetched.<\/li>\n<li>Every statement query parameter: agent, verb, activity, registration, related activities and agents, since and until, limit, ascending, formats exact, ids and canonical, paging with <code>more<\/code>, and statements that refer to other statements.<\/li>\n<li>Attachments (multipart\/mixed) and signed statements (JWS structure, payload, and the signature when the certificate is included).<\/li>\n<li>Documents with ETags and concurrency control (If-Match \/ If-None-Match).<\/li>\n<li>The 1.0.3 alternate request syntax and CORS for browser-based content.<\/li>\n<li>Credentials per application (HTTP Basic): a key and a secret shown once, xAPI scopes, an authority, an expiry, revocation.<\/li>\n<li>LRS \u2192 Statements: a statement browser with filters and a \"Void\" action. LRS \u2192 Credentials and LRS \u2192 Settings.<\/li>\n<li>Privacy: personal-data export and erasure, erasure of one person's records by e-mail address or xAPI agent, a retention period.<\/li>\n<li>Built for large stores: its own tables, an index for every query parameter, keyset paging (tested with 100,000 statements).<\/li>\n<li>WordPress Abilities: read-only reports (activity per course, lesson, verb or learner, time spent, unfinished activities, quiz answers per question) that AI assistants on your own site, such as Rooster One's Insights Chat, can ask for; learners are pseudonymised.<\/li>\n<\/ul>\n\n<p>Rooster LRS implements xAPI 1.0.3 and 2.0 and is tested against its own conformance suite; it has not yet been certified with the ADL LRS Conformance Test Suite.<\/p>\n\n<p>When Rooster LMS is active, the screens use its design system. Rooster LRS works without it.<\/p>\n\n<h4>Endpoint and credentials<\/h4>\n\n<ol>\n<li>Go to LRS \u2192 Credentials and create a credential with the scopes the application needs.<\/li>\n<li>Copy the key and the secret (the secret is shown once).<\/li>\n<li>Give the application the endpoint shown on that screen (for example <code>https:\/\/example.com\/wp-json\/rooster-lrs\/xapi\/<\/code>), the key as the user name and the secret as the password.<\/li>\n<\/ol>\n\n<p>To forward statements from Rooster LMS Pro, create a credential with the scopes <code>statements\/write<\/code> and <code>define<\/code>, and choose a custom authority with Rooster LMS Pro's LMS agent.<\/p>\n\n<h4>Caching and security plugins<\/h4>\n\n<p>xAPI requests must never be cached. If your site uses a page cache, a CDN or a caching plugin, exclude <code>\/wp-json\/rooster-lrs\/<\/code> (and <code>?rest_route=\/rooster-lrs\/<\/code> on sites without pretty permalinks).<\/p>\n\n<p>Some security plugins block REST API requests from visitors who are not logged in; allow <code>\/wp-json\/rooster-lrs\/<\/code> for xAPI clients. Some servers remove the <code>Authorization<\/code> header before PHP sees it; Rooster LRS also reads <code>REDIRECT_HTTP_AUTHORIZATION<\/code> and <code>PHP_AUTH_USER<\/code>.<\/p>\n\n<h4>Multi-tenant mode<\/h4>\n\n<p>For the Rooster Adaptive LMS service only, which keeps the statements of many sites in one store. It is off on every other site, where it costs nothing and nothing changes. <code>wp rooster-lrs multi-tenant on<\/code> turns it on (<code>status<\/code> and <code>off<\/code> too; off is refused while tenants exist). In this mode:<\/p>\n\n<ul>\n<li>Every stored row belongs to a tenant. A credential reads and writes its own tenant only; another tenant's statement, document or activity answers 404, and the same statement id sent by two tenants is two statements.<\/li>\n<li>Tenants and their signed credentials are created by the service's own plugin on the same site, through Rooster LRS's PHP API (<code>RoosterLRS\\Tenancy\\TenantRegistry<\/code>, <code>TenantCredentials<\/code>): there is no provisioning endpoint. A tenant credential may send statements and activity definitions only, at most 300 requests a minute.<\/li>\n<li>Quiz answers and engagement statements that follow the Rooster profiles are also written, in the same transaction, to two tables the service's models read (<code>rooster_lrs_responses<\/code>, <code>rooster_lrs_exposures<\/code>). <code>wp rooster-lrs projection rebuild --tenant=&lt;id&gt;<\/code> derives them again from the statements.<\/li>\n<li>Each tenant has its own retention period; a person's records and a whole tenant are erased through <code>RoosterLRS\\Privacy\\TenantEraser<\/code>.<\/li>\n<li>LRS \u2192 Statements and LRS \u2192 Credentials show every tenant, with a tenant filter and column.<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p>Rooster LRS does not connect to any external service. Your site never sends anything anywhere because of it: it only answers the xAPI requests that the applications you give a credential send to it. The links below open in the browser only when someone clicks them, and the addresses after them are identifiers that are never contacted.<\/p>\n\n<h4>rooster.systems: links (on click only)<\/h4>\n\n<p>The Rooster LRS header and Home page link to the website of Oxford Metadata Ltd, the makers of Rooster LRS: the manual (<code>https:\/\/rooster.systems\/category\/en\/documentation\/rooster-lrs\/<\/code>), <a href=\"https:\/\/rooster.systems\/help-and-support\/\">help<\/a>, <a href=\"https:\/\/rooster.systems\/help-and-support\/feedback\/\">feedback<\/a> and <a href=\"https:\/\/rooster.systems\/\">rooster.systems<\/a>. Nothing is sent before the click. <a href=\"https:\/\/rooster.systems\/terms-and-conditions\/\">Terms and conditions<\/a> \u00b7 <a href=\"https:\/\/rooster.systems\/privacy-policy\/\">Privacy policy<\/a><\/p>\n\n<h4>wordpress.org and Viber links (on click only)<\/h4>\n\n<p>The Rooster LRS header links to this plugin's <a href=\"https:\/\/wordpress.org\/plugins\/rooster-lrs\/\">page<\/a> and <a href=\"https:\/\/wordpress.org\/support\/plugin\/rooster-lrs\/reviews\/\">review form<\/a> on wordpress.org, and to the Rooster community's chat on Viber (<code>https:\/\/invite.viber.com\/<\/code>). <a href=\"https:\/\/wordpress.org\/about\/privacy\/\">WordPress.org privacy<\/a> \u00b7 <a href=\"https:\/\/www.viber.com\/en\/terms\/viber-terms-use\/\">Viber terms<\/a> \u00b7 <a href=\"https:\/\/www.viber.com\/en\/terms\/viber-privacy-policy\/\">Viber privacy<\/a><\/p>\n\n<h4>xAPI identifiers (never contacted)<\/h4>\n\n<p>xAPI names verbs, activity types, extensions and profiles with IRIs that look like web addresses. Rooster LRS compares them as text and never opens them: the ADL verbs (<code>http:\/\/adlnet.gov\/expapi\/verbs\/...<\/code> and <code>https:\/\/w3id.org\/xapi\/adl\/verbs\/...<\/code>), and the Rooster profiles' own identifiers (<code>https:\/\/rooster.systems\/xapi\/...<\/code>), whose definitions are bundled in <code>data\/xapi-profiles\/<\/code>.<\/p>\n\n<h3>Privacy<\/h3>\n\n<p>Rooster LRS stores the learning records that authorised applications send: xAPI statements and documents. A statement names a learner by the identifier the sending application chose (an e-mail address, a hashed e-mail address, an OpenID or an account) and describes an activity and its result. Records stay until the site owner deletes them, a person's records are erased, or the retention period set under LRS \u2192 Settings ends. Nothing is sent to other services. The plugin adds suggested text to the privacy policy guide and registers a personal-data exporter and eraser.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate Rooster LRS from Plugins \u2192 Add New, or upload the <code>rooster-lrs<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Go to LRS \u2192 Credentials and create a credential for each application that sends or reads statements.<\/li>\n<li>Give each application the endpoint shown on that screen, its key and its secret.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20rooster%20lrs%20send%20data%20anywhere%3F\"><h3>Does Rooster LRS send data anywhere?<\/h3><\/dt>\n<dd><p>No. It makes no outbound requests. Its screens show links (to the manual, help and wordpress.org) that open only when you click them.<\/p><\/dd>\n<dt id=\"which%20authentication%20methods%20are%20supported%3F\"><h3>Which authentication methods are supported?<\/h3><\/dt>\n<dd><p>HTTP Basic with a credential per application. OAuth is planned.<\/p><\/dd>\n<dt id=\"how%20do%20i%20delete%20a%20person%27s%20records%3F\"><h3>How do I delete a person's records?<\/h3><\/dt>\n<dd><p>Use Tools \u2192 Erase Personal Data with their e-mail address, or LRS \u2192 Settings \u2192 \"Erase a person's learning records\" with an e-mail address or an xAPI agent. Other systems can call <code>POST \/wp-json\/rooster-lrs\/v1\/erasure<\/code> with a credential that has the <code>rooster:erase<\/code> scope.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20the%20records%20when%20i%20delete%20the%20plugin%3F\"><h3>What happens to the records when I delete the plugin?<\/h3><\/dt>\n<dd><p>They stay, unless \"Delete all Rooster LRS data when the plugin is deleted\" is ticked under LRS \u2192 Settings: then deleting the plugin removes its tables, settings and capabilities.<\/p><\/dd>\n<dt id=\"is%20it%20fast%20with%20many%20statements%3F\"><h3>Is it fast with many statements?<\/h3><\/dt>\n<dd><p>Every query parameter has its own index and the lists page by key, so a query reads only the rows it returns. The suite stores 100,000 statements and checks the number of database queries each request makes.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First version: the core LRS, xAPI 1.0.3 and 2.0 (statements, documents, attachments, signed statements, every query parameter), credentials per application, the statement browser, privacy tools and retention.<\/li>\n<li>The Rooster assessment and adaptive xAPI Profiles (JSON-LD, bundled): statements that name them have their extension values checked.<\/li>\n<li>Read-only reports as WordPress Abilities for AI assistants on the site (Rooster One's Insights Chat): activity per course, lesson, verb or learner, time spent, activities launched but never completed, and quiz answers per question, quiz, item or skill; learners pseudonymised.<\/li>\n<li>Multi-tenant mode for the Rooster Adaptive LMS service (off by default): tenant scoping, tenant credentials issued in-process, the answer and exposure tables with their rebuild, erasure and retention per tenant.<\/li>\n<\/ul>","raw_excerpt":"An xAPI Learning Record Store (xAPI 1.0.3 and 2.0) inside WordPress: statements, documents, attachments and per-client credentials.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/400155","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=400155"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/oxfordmetadata"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=400155"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=400155"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=400155"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=400155"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=400155"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=400155"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}