close
Skip to content

Add Activity Library — activity_kit post type, archive, single pages, stats dashboard#3496

Open
Piyopiyo-Kitsune wants to merge 14 commits into
trunkfrom
feature/activity-library
Open

Add Activity Library — activity_kit post type, archive, single pages, stats dashboard#3496
Piyopiyo-Kitsune wants to merge 14 commits into
trunkfrom
feature/activity-library

Conversation

@Piyopiyo-Kitsune

Copy link
Copy Markdown
Collaborator

Summary

Introduces the Activity Library (/activity-library/), a new section of Learn WordPress that surfaces downloadable facilitator kits for educators, meetup organizers, and community facilitators.

Plugin (wporg-learn)

  • activity_kit post type with archive slug activity-library, REST support, and custom capabilities
  • Post meta: _activity_duration, _activity_guide_pdf_id, _activity_slides_pdf_id, _activity_zip_id, _view_count, _download_count, _activity_feedback_url
  • REST endpoint POST /activity-kits/v1/track — records views (every page load) and downloads (rate-limited to one per IP per 24 h via transient)
  • Stats dashboard (Activity Kits → Stats) — Chart.js bar chart, sortable table, time-range filters, custom date-range picker with Apply/Clear, Export CSV; blueberry design-system colours throughout
  • Settings page (Activity Kits → Settings) — global feedback form URL stored as activity_kit_feedback_url site option
  • Block editor sidebar panel — PDF pickers (Facilitator Guide, Slide Deck), ZIP picker, duration field, per-kit feedback URL override, experience-level radio
  • WP-CLI import commandwp activity-kit import seeds 11 draft kits
  • Admin list columns — sortable Views and Downloads columns

Theme (wporg-learn-2024)

  • Archive template — 3-column card grid with Topic/Level/Language filter dropdowns, search bar, 12-per-page pagination
  • wporg/activity-kit-card block — server-rendered card with featured image, excerpt, clock-icon duration, level, outlined View + filled Download buttons
  • Single kit pattern — breadcrumb, meta row, PDF tab toggle (Facilitator Guide / Slide Deck), per-browser PDF UX (#toolbar=0 for Chromium; #view=FitH + tracked "Download PDF" link for Firefox/Safari), feedback strip below preview, "What's included" grid, "Download this kit" box
  • Search resultsrender_block_core/template-part filter replaces the generic card template with the full activity kit card when post_type = activity_kit, keeping View/Download buttons consistent with the archive
  • SCSS_activity-kit.scss with BEM components using design-system CSS variables; feedback strip with blueberry outlined button and visible focus ring

Test plan

  • Visit /activity-library/ — 12 cards render with image, excerpt, duration, level, View + Download buttons
  • Filter by Topic, Level, or Language — grid filters correctly; pagination carries filters
  • Search "accessibility" from archive search bar — results show activity kit cards (not generic cards)
  • Visit a single kit page — breadcrumb, PDF tabs switch between Facilitator Guide and Slide Deck, feedback strip links to configured form with ?kit={slug}
  • Click Download kit — stats increment download count (check Stats page)
  • Stats page (Activity Kits → Stats) — chart renders, time range buttons work, Custom range Apply/Clear work, table rows link to single kit
  • Settings page (Activity Kits → Settings) — save a feedback URL, confirm it appears on kit pages; clear it, confirm strip disappears
  • Block editor — open an activity_kit post; sidebar shows Activity Kit Details panel with PDF pickers and feedback URL field
  • Run composer run lint — 0 new errors
  • Run yarn workspace wporg-learn-plugin lint:js — 0 errors

🤖 Generated with Claude Code

Piyopiyo-Kitsune and others added 3 commits May 22, 2026 13:19
Introduces a new Activity Library section with downloadable WordPress
activity kits (facilitator guides, slide decks, ZIP downloads) for
educators and meetup organizers.

**Plugin changes (wporg-learn)**
- Register `activity_kit` CPT with archive slug `activity-library`
- Register `activity_language` taxonomy; add `activity_kit` to `topic` and `level`
- Register 6 post meta fields: duration, guide/slides PDF IDs, zip URL, view/download counts
- Add admin list table columns (Views, Downloads, sortable) and Stats submenu page
- REST API: `POST activity-kits/v1/track` (rate-limited), `GET activity-kits/v1/stats`
- Events table for time-range tracking via `dbDelta()`
- WP-CLI `wp activity-kit import` creates 11 initial activity kit posts
- `wporg/activity-kit-card` dynamic block (server-side render with featured image, title, level/duration meta, View + Download buttons)
- `wporg/activity-kits` query block variation
- Editor sidebar panel for PDF pickers, duration, ZIP URL, read-only stats
- Fix: add `function_exists('Sensei')` guard in `restrict_my_courses_page_access()`
- Fix: skip nonce check in `tax_save_term_fields()` when running via WP-CLI
- Fix: wrap `0-sandbox.php` mu-plugin requires in `file_exists()` guards

**Theme changes (wporg-learn-2024)**
- `archive-activity_kit.html` FSE template with pattern reference
- `single-activity_kit.html` FSE template with pattern reference
- `archive-activity-kits-content.php` pattern: heading, search bar, `wporg/query-filter` blocks, card grid with no-results message and pagination
- `single-activity-kit-content.php` pattern: breadcrumb, title, metadata, PDF tab toggle with `<iframe>` previews, content, download button with tracking POST
- Filter options hooks (`activity_kit_topic`, `activity_kit_level`, `activity_kit_language`) in `block-config.php`
- `pre_get_posts` handler in `query.php` for activity kit archive filtering
- Fix: add `function_exists` guard in `sensei-lesson-actions.php` pattern

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-fixed by eslint --fix to bring existing files in line with the
project's prettier config (trailing commas, line breaks in argument lists).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…search alignment

Iterative improvements on top of the initial activity-library commit:

Plugin (wporg-learn):
- Add per-kit `_activity_feedback_url` meta and global `activity_kit_feedback_url`
  site option with a Settings API page under Activity Kits → Settings
- Feedback strip on single kit pages links to a configurable form URL with
  automatic `?kit={slug}` attribution parameter
- PDF tab improvements: hide Chromium native toolbar via `#toolbar=0`,
  use `#view=FitH` for Safari/Firefox with a tracked "Download PDF" link
  shown only for non-Chromium browsers (via `window.chrome` detection)
- View tracking fires unconditionally on page load (not inside ZIP guard);
  download rate-limiting applies to ZIP downloads only (not views)
- Stats dashboard: blueberry design-system colours (#3858e9 / #9fb1ff),
  custom date-range picker with Apply + Clear buttons, script version via
  filemtime for proper cache-busting
- Activity kit card block: correct image sizing, excerpt display, clock-icon
  duration row, View + Download buttons

Theme (wporg-learn-2024):
- Archive page: Topic / Level / Language filter dropdowns; 12 posts per page;
  language fallback when WordPressdotorg\Locales is unavailable locally
- Single kit pattern: breadcrumb, meta row, PDF tab toggle, feedback strip,
  "What's included" grid, "Download this kit" box with file-size note
- Search results: `render_block_core/template-part` filter swaps the generic
  card template with the full activity kit card for `activity_kit` posts,
  keeping View + Download buttons and duration/level meta consistent with
  the archive grid
- SCSS: `.wporg-activity-kit-*` component styles, `.wporg-activity-kit-
  feedback-strip` with blueberry outlined button and visible focus ring
- All PHP auto-fixed via phpcbf (WordPress-Extra ruleset); JS curly-brace
  lint errors resolved

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an “Activity Library” feature to Learn WordPress by adding an activity_kit custom post type in the wporg-learn plugin (including REST tracking, admin stats/settings, editor tooling, and WP‑CLI seeding) and adding theme templates/patterns/styles in wporg-learn-2024 to render an archive + single-kit experience with filtering and consistent cards.

Changes:

  • Plugin: Adds activity_kit CPT, related meta/capabilities, REST endpoints for view/download tracking + stats, admin stats/settings pages, and editor sidebar tooling.
  • Theme: Adds archive/single templates and patterns for Activity Kits, plus filtering/search alignment and new SCSS for the Activity Kit UI.
  • Build/JS: Adds new block variation and multiple JS formatting changes across existing plugin scripts.

Reviewed changes

Copilot reviewed 48 out of 49 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
wp-content/themes/pub/wporg-learn-2024/templates/single-activity_kit.html Adds the single Activity Kit template referencing a dedicated pattern.
wp-content/themes/pub/wporg-learn-2024/templates/archive-activity_kit.html Adds the Activity Kit archive template referencing a dedicated pattern.
wp-content/themes/pub/wporg-learn-2024/src/style/style.scss Imports the new Activity Kit SCSS partial.
wp-content/themes/pub/wporg-learn-2024/src/style/_activity-kit.scss Adds front-end styles for Activity Kit archive cards and single-kit UI.
wp-content/themes/pub/wporg-learn-2024/patterns/single-activity-kit-content.php Implements the single-kit page layout (PDF tabs, feedback strip, download box) and client-side tracking calls.
wp-content/themes/pub/wporg-learn-2024/patterns/archive-activity-kits-content.php Implements the archive layout with search, filters, grid, and pagination.
wp-content/themes/pub/wporg-learn-2024/patterns/sensei-lesson-actions.php Adds a guard to avoid calling Sensei functions when unavailable.
wp-content/themes/pub/wporg-learn-2024/inc/query.php Adds pre_get_posts filtering for Activity Kit archive/search filtering.
wp-content/themes/pub/wporg-learn-2024/inc/block-hooks.php Replaces generic cards with Activity Kit cards on search results for activity_kit.
wp-content/themes/pub/wporg-learn-2024/inc/block-config.php Adds Activity Kit Topic/Level filter options and passes through new query vars.
wp-content/plugins/wporg-learn/wporg-learn.php Loads new Activity Kit include files (REST/settings/stats/import).
wp-content/plugins/wporg-learn/webpack.config.js Adds webpack entries for new Activity Kit-related JS bundles.
wp-content/plugins/wporg-learn/views/block-activity-kit-card.php Adds server-rendered Activity Kit card block markup.
wp-content/plugins/wporg-learn/js/workshop-details/src/index.js Prettier reformatting of block registration strings.
wp-content/plugins/wporg-learn/js/workshop-application-form/src/index.js Prettier reformatting of block registration strings.
wp-content/plugins/wporg-learn/js/workshop-application-form/src/edit.js Prettier reformatting of JSX props.
wp-content/plugins/wporg-learn/js/utils.js Prettier reformatting of function signature.
wp-content/plugins/wporg-learn/js/query-activity-kits/src/index.js Adds a core/query block variation for Activity Kits.
wp-content/plugins/wporg-learn/js/locale-notice.js Refactors object method syntax + formatting changes.
wp-content/plugins/wporg-learn/js/lesson-plan-details/src/index.js Prettier reformatting of block registration strings.
wp-content/plugins/wporg-learn/js/lesson-plan-actions/src/index.js Prettier reformatting of block registration strings.
wp-content/plugins/wporg-learn/js/lesson-plan-actions/src/edit.js Prettier reformatting of JSX props.
wp-content/plugins/wporg-learn/js/lesson-featured-meta/index.js Prettier reformatting of hooks/JSX.
wp-content/plugins/wporg-learn/js/language-meta/index.js Prettier reformatting of hooks.
wp-content/plugins/wporg-learn/js/hooks/use-is-block-in-sidebar.js Prettier reformatting of destructuring.
wp-content/plugins/wporg-learn/js/form.js Prettier reformatting of event listener.
wp-content/plugins/wporg-learn/js/expiration-date/index.js Prettier reformatting of imports and long expressions.
wp-content/plugins/wporg-learn/js/duration-meta/index.js Prettier reformatting of hooks/JSX.
wp-content/plugins/wporg-learn/js/course-data/src/index.js Prettier reformatting of block registration strings.
wp-content/plugins/wporg-learn/js/course-data/src/edit.js Prettier reformatting of JSX props.
wp-content/plugins/wporg-learn/js/course-completion-meta/index.js Prettier reformatting of hooks/JSX.
wp-content/plugins/wporg-learn/js/constants.js Prettier reformatting of i18n strings.
wp-content/plugins/wporg-learn/js/activity-kit-stats/index.js Adds the stats dashboard client-side logic (fetching, chart/table UI, export).
wp-content/plugins/wporg-learn/js/activity-kit-sidebar/src/index.js Adds Gutenberg sidebar panels for Activity Kit meta (PDF/ZIP, duration, feedback URL, level).
wp-content/plugins/wporg-learn/js/activity-kit-card/src/index.js Registers the Activity Kit card dynamic block in the editor.
wp-content/plugins/wporg-learn/js/activity-kit-card/block.json Defines the wporg/activity-kit-card block metadata.
wp-content/plugins/wporg-learn/inc/taxonomy.php Adds activity_kit to shared taxonomies and skips term nonce checks under WP-CLI.
wp-content/plugins/wporg-learn/inc/sensei.php Adds guard for Sensei availability before restricting My Courses.
wp-content/plugins/wporg-learn/inc/post-type.php Registers the activity_kit post type and adds it to Jetpack integrations.
wp-content/plugins/wporg-learn/inc/post-meta.php Registers Activity Kit meta and broadens language meta support; adds locales fallback logic.
wp-content/plugins/wporg-learn/inc/capabilities.php Adds Activity Kit capability mapping to “edit any learn content”.
wp-content/plugins/wporg-learn/inc/blocks.php Registers the Activity Kit card block and editor assets; maps query variation namespace.
wp-content/plugins/wporg-learn/inc/admin.php Adds Activity Kit admin columns, sorting, and a Stats submenu page.
wp-content/plugins/wporg-learn/inc/activity-kit-stats-page.php Adds wp-admin stats page renderer and enqueues Chart.js + stats JS.
wp-content/plugins/wporg-learn/inc/activity-kit-settings.php Adds wp-admin settings page for global Activity Kit feedback URL.
wp-content/plugins/wporg-learn/inc/activity-kit-rest.php Adds REST routes for tracking views/downloads and retrieving stats; creates an events table.
wp-content/plugins/wporg-learn/inc/activity-kit-import.php Adds WP-CLI command to seed initial Activity Kit posts.
.wp-env/0-sandbox.php Adds file_exists() guards for local mu-plugin loading in dev env.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wp-content/plugins/wporg-learn/js/activity-kit-sidebar/src/index.js Outdated
Comment thread wp-content/plugins/wporg-learn/js/activity-kit-sidebar/src/index.js Outdated
Comment thread wp-content/themes/pub/wporg-learn-2024/inc/query.php Outdated
Comment thread wp-content/themes/pub/wporg-learn-2024/inc/query.php Outdated
Comment thread wp-content/plugins/wporg-learn/inc/admin.php
Comment thread wp-content/plugins/wporg-learn/inc/activity-kit-stats-page.php
Comment thread wp-content/plugins/wporg-learn/inc/activity-kit-stats-page.php
Comment thread wp-content/plugins/wporg-learn/inc/activity-kit-stats-page.php Outdated
Comment thread wp-content/themes/pub/wporg-learn-2024/src/style/_activity-kit.scss Outdated
Piyopiyo-Kitsune and others added 5 commits May 26, 2026 15:25
- Add `root: true` to plugin .eslintrc.js so CI's generated root config
  does not override the workspace's own prettier settings
- Fix `sort-imports`: reorder `useSelect, useDispatch` → `useDispatch, useSelect`
- Fix `id-length`: rename single/two-char parameters `n`, `ds`, `d` to
  `num`, `dateStr`, `date` in activity-kit-stats helpers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Display the post's last-modified date in the meta row below the kit
title, alongside duration, level, and topic. Uses a calendar icon
and <time> element with machine-readable datetime attribute.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Point directly to the activity kits section of the Training team
handbook rather than the handbook root.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add .prettierrc to plugin dir (printWidth: 80) so CI and local use
  the same prettier settings, ending the formatting conflict
- Fix useSelect() dep arrays in sidebar ([] caused stale editor state)
- Fix filter_activity_kit_archive() to merge meta_query instead of
  overwriting the one set by add_language_to_archive_queries()
- Sanitize $_GET['level'] before comparing to 'all'
- Add post_status=publish to activity kit filter term lookups
- Add is_main_query() guard to sortable columns pre_get_posts handler
- Remove wp_add_inline_style('wp-admin','') no-op
- Remove data-track-download from PDF tab link (PDF views should not
  count as kit downloads); add it to archive card download button
- Replace hard-coded /wp-json/ REST URL with rest_url() in tracking JS
- Add activity_kit post-type validation to card block render callback
- Remove dead .activity-kit-stats-page styles from theme SCSS
  (admin page uses its own inline <style>; theme CSS is frontend-only)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The installed @wordpress/editor (v9.26.3) does not export
PluginDocumentSettingPanel. It lives in @wordpress/edit-post
(v3.25.3), which is the correct package for this project's
version of Gutenberg. Fixes the import/named error in CI lint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Piyopiyo-Kitsune Piyopiyo-Kitsune added the [Type] Enhancement New feature request for the Learn website. label May 26, 2026
@Piyopiyo-Kitsune Piyopiyo-Kitsune moved this to Draft (PRs only) in LearnWP Website Development May 26, 2026
Piyopiyo-Kitsune and others added 2 commits May 28, 2026 18:09
Aligns with the PR description which states the WP-CLI import
command creates 11 draft activity_kit posts. Publishing on import
bypassed editorial review; drafts let editors review and publish
intentionally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Expected 5 spaces after 'array' to align with '\WP_Block' parameter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rjekic

rjekic commented Jun 6, 2026

Copy link
Copy Markdown

@jonathanbossenger

I've checked this PR and found no errors. Could you recheck this and merge if everything is working fine?

Thank you.
cc @Piyopiyo-Kitsune @devmuhib009 @sumitsinghwp

@dd32

dd32 commented Jun 8, 2026

Copy link
Copy Markdown
Member

REST endpoint POST /activity-kits/v1/track — records views (every page load) and downloads (rate-limited to one per IP per 24 h via transient)

This isn't viable for WordPress.org, if this kind of stats is needed, a dedicated page-view stats system should be used, not the WordPress Rest API. Pageviews can probably be extracted via Jetpack Stats (Looks like it tracks both page views and downloads, or will, once I connect Jetpack correctly)

I think I'm going to strip this out of this PR, and push it into a followup PR, where we can look at alternative options for this.

@dd32

dd32 commented Jun 9, 2026

Copy link
Copy Markdown
Member

Note

AI-assisted investigation, reviewed before posting. I had an AI agent (Claude) dig into this by querying learn.wordpress.org's live Jetpack Stats connection and reading the Jetpack/WP.com tracker source. I've reviewed the findings below; the empirical claims are against the running site (WP.com blog 47261184), but sanity-check before relying on them.

Can Jetpack Stats replace the removed /activity-kits/v1/track collection?

Short version: views — yes; downloads — partially, via the Clicks report, with caveats. The dedicated File Downloads report is structurally unavailable for this site.

Page views ✅

Jetpack Stats already records per-post views, queryable by date range via the site's own connection (WPCOM_Stats::get_top_posts() / get_post_views( $post_id )). The activity-kit single pages will accrue views automatically like any other post, so the REST "view" tracking is redundant and safe to drop.

Downloads — the File Downloads report does not work here

WPCOM_Stats::get_file_downloads() returns Failed to fetch Stats from WPCOM for every period on this blog. Root cause: that report is fed by WP.com's f.gif beacon, which is logged server-side by WP.com when WP.com itself serves the file (its params are host=*.files.wordpress.com&uri=…&ip=…&country=…, i.e. edge-derived). learn.wordpress.org serves uploads from its own learn.wordpress.org/files/… path, not *.files.wordpress.com, so f.gif is never emitted and the report has no data. It is not a client-side hook — you can't fire it from the page.

The client tracker (stats.wp.com/e-*.js) only emits two beacons: g.gif (view) and c.gif (click). No f.gif.

Downloads via the Clicks report — viable

The automatic click tracker skips same-host links unless the URL contains /wp-content/uploads:

if ( a(e) && !e.href.includes("/wp-content/uploads") ) return; // a(e) = same-host

WP.org uploads live under /files/…, so kit ZIPs (wp_get_attachment_url()) are same-host, not /wp-content/uploads, and get skipped — which is exactly why the existing PDFs on the site appear in no stats report.

A manual push bypasses that guard (it lives only in the auto DOM handler, not the click command processor):

window._stq = window._stq || [];
_stq.push([ "click", { s:"2", u: btn.href, r:"0", b:"47261184", p:String(postId) } ]);

This lands in the Clicks report, which is queryable: WPCOM_Stats::get_clicks({ period, date, summarize:1, max }) returns a flat summary.clicks array of { url, views } over any date range. Confirmed that same-host learn.wordpress.org URLs already surface there (it is not outbound-only), so a /files/…/kit.zip click would round-trip and be readable back by matching the ZIP URL.

Caveats for the downloads-via-clicks approach

  • Keyed by URL, not post_id — the p param isn't exposed in the clicks output; attribution is via the unique ZIP URL, so keep that mapping stable (re-uploading/renaming the ZIP breaks history).
  • Client-side only — undercounts no-JS, bots, ad-blocked, and direct/hotlinked file hits (the archive links straight to the file). No per-IP/day dedup (the removed REST code deduped).
  • Top-N / samplingget_clicks returns top URLs bounded by max; fine for a finite kit set.
  • Latency — stats are not real-time.
  • Undocumented push_stq.push(["click",…]) uses the supported c.gif channel but isn't a documented API; it's tied to the weekly e-*.js build.

Recommendation

Lean on Jetpack for views. For downloads, the Clicks-beacon trick is a zero-infrastructure option that gets numbers into Jetpack and is queryable — good enough for a rough trend. If an accurate, deduped, per-kit count is required (as the removed admin dashboard implied), a small server-side counting redirect to the ZIP is more reliable, since the client beacon will always undercount direct/file-URL hits.

@rjekic

rjekic commented Jun 14, 2026

Copy link
Copy Markdown

@Piyopiyo-Kitsune @jonathanbossenger

Can you take a look at the above-mentioned report and limitation/solution, so we can continue with the merge process if everything looks good?

Thank you.
cc @dd32 @sumitsinghwp @devmuhib009

@Piyopiyo-Kitsune

Copy link
Copy Markdown
Collaborator Author

@dd32 I'm reading that if we ensure that updated files have the same name, our download counts will be interrupted-- is that right? If that's the case, I'm ok to try to move forward with this unless a better solution arises.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Enhancement New feature request for the Learn website.

Projects

Status: Draft (PRs only)

Development

Successfully merging this pull request may close these issues.

5 participants