{"id":303098,"date":"2026-05-21T18:45:06","date_gmt":"2026-05-21T18:45:06","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/nettertech-events\/"},"modified":"2026-05-21T18:44:28","modified_gmt":"2026-05-21T18:44:28","slug":"nettertech-events","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/nettertech-events\/","author":14764245,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.2","stable_tag":"1.0.2","tested":"6.9.4","requires":"6.5","requires_php":"8.2","requires_plugins":null,"header_name":"NetterTech Events","header_author":"NetterTech","header_description":"A clean, performant WordPress events plugin with ticketing, recurring events, and WooCommerce integration.","assets_banners_color":"36485d","last_updated":"2026-05-21 18:44:28","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/nettertech.com\/plugins\/events\/","header_author_uri":"https:\/\/nettertech.com\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":53,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.2":{"tag":"1.0.2","author":"shawnmcburnie","date":"2026-05-21 18:44:28"}},"upgrade_notice":{"1.0.0":"<p>Major release: category system migrated to internal tables, event reminders, GDPR privacy tools, 7 bug fixes, 8 UX improvements. Database migration runs automatically. Requires WordPress 6.5+.<\/p>","0.9.0":"<p>Schema improvements for multi-organizer support. Database migration runs automatically on activation.<\/p>","0.8.0":"<p>Security update with OWASP 2025 compliance fixes. Recommended for all users.<\/p>","0.7.0":"<p>Adds QR check-in and email confirmations. Database migration runs automatically.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3542593,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3542593,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3542593,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3542593,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":{"nettertech-events\/carousel":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"nettertech-events\/carousel","version":"0.8.0","title":"Event Carousel","category":"widgets","icon":"slides","description":"Display upcoming events in a responsive carousel.","keywords":["events","carousel","slider","featured"],"textdomain":"nettertech-events","supports":{"html":false,"align":["wide","full"],"className":true},"attributes":{"limit":{"type":"number","default":6},"columns":{"type":"number","default":3},"showImage":{"type":"boolean","default":true},"showDate":{"type":"boolean","default":true},"showTime":{"type":"boolean","default":true},"showVenue":{"type":"boolean","default":true},"showYear":{"type":"boolean","default":false},"autoplay":{"type":"boolean","default":false},"interval":{"type":"number","default":5000}},"editorScript":"file:.\/build\/index.js","editorStyle":"file:.\/build\/index.css","render":"file:.\/render.php"},"nettertech-events\/calendar":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"nettertech-events\/calendar","version":"0.8.0","title":"Event Calendar","category":"widgets","icon":"calendar-alt","description":"Display an interactive event calendar with month, week, or day views.","keywords":["events","calendar","schedule"],"textdomain":"nettertech-events","supports":{"html":false,"align":["wide","full"],"className":true},"attributes":{"view":{"type":"string","default":"month","enum":["month","week","day"]},"showViewSwitcher":{"type":"boolean","default":true},"showNavigation":{"type":"boolean","default":true}},"editorScript":"file:.\/build\/index.js","editorStyle":"file:.\/build\/index.css","render":"file:.\/render.php"},"nettertech-events\/grid":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"nettertech-events\/grid","version":"0.8.0","title":"Event Grid","category":"widgets","icon":"grid-view","description":"Display events in a filterable grid or list layout.","keywords":["events","grid","list","filter"],"textdomain":"nettertech-events","supports":{"html":false,"align":["wide","full"],"className":true},"attributes":{"limit":{"type":"number","default":12},"columns":{"type":"number","default":3},"layout":{"type":"string","default":"grid","enum":["grid","list","cards"]},"showFilters":{"type":"boolean","default":true},"showSearch":{"type":"boolean","default":true},"showCategory":{"type":"boolean","default":true},"showImage":{"type":"boolean","default":true},"showDate":{"type":"boolean","default":true},"showTime":{"type":"boolean","default":true},"showVenue":{"type":"boolean","default":true},"showExcerpt":{"type":"boolean","default":false},"pagination":{"type":"boolean","default":true},"ajax":{"type":"boolean","default":true},"category":{"type":"string","default":""},"past":{"type":"boolean","default":false}},"editorScript":"file:.\/build\/index.js","editorStyle":"file:.\/build\/index.css","render":"file:.\/render.php","variations":[{"name":"grid-view","title":"Grid View","description":"Display events in a multi-column grid with images and filters.","icon":"grid-view","attributes":{"layout":"grid","columns":3,"showFilters":true,"showSearch":true,"showImage":true},"isDefault":true,"scope":["inserter"]},{"name":"list-view","title":"List View","description":"Display events in a compact single-column list without images.","icon":"list-view","attributes":{"layout":"list","columns":1,"showFilters":false,"showSearch":false,"showImage":false},"scope":["inserter"]},{"name":"card-view","title":"Card View","description":"Display events as rich cards with excerpts and full details.","icon":"align-none","attributes":{"layout":"cards","columns":2,"showFilters":true,"showSearch":true,"showImage":true,"showExcerpt":true},"scope":["inserter"]}]}},"tagged_versions":["1.0.2"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3542593,"resolution":"1","location":"assets","locale":"","width":1770,"height":1800},"screenshot-10.png":{"filename":"screenshot-10.png","revision":3542593,"resolution":"10","location":"assets","locale":"","width":1000,"height":1792},"screenshot-2.jpg":{"filename":"screenshot-2.jpg","revision":3542593,"resolution":"2","location":"assets","locale":"","width":1770,"height":1800},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3542593,"resolution":"3","location":"assets","locale":"","width":2880,"height":1800},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3542593,"resolution":"4","location":"assets","locale":"","width":1770,"height":1800},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3542593,"resolution":"5","location":"assets","locale":"","width":2880,"height":1800},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3542593,"resolution":"6","location":"assets","locale":"","width":2880,"height":1800},"screenshot-7.png":{"filename":"screenshot-7.png","revision":3542593,"resolution":"7","location":"assets","locale":"","width":2880,"height":1800},"screenshot-8.png":{"filename":"screenshot-8.png","revision":3542593,"resolution":"8","location":"assets","locale":"","width":2880,"height":1800},"screenshot-9.png":{"filename":"screenshot-9.png","revision":3542593,"resolution":"9","location":"assets","locale":"","width":1000,"height":1792}},"screenshots":{"1":"Monthly calendar with month, week, and day views","2":"Upcoming events archive with search, category filters, and responsive card layout","3":"Single event page with featured image, date, price, and site navigation","4":"Weekly regulars table and calendar with event detail popup on hover","5":"Admin event editor with recurring event patterns and capacity settings","6":"Admin events list with status filters, event types, and bulk actions","7":"Display settings with drag-and-drop layout builder for single event pages","8":"Advanced settings showing rate limits, lookahead controls, and the opt-in attribution badge (disabled by default)","9":"Mobile-responsive archive page with event cards","10":"Mobile single event page with ticket type selector and add-to-cart"}},"plugin_section":[],"plugin_tags":[416,1486,5881,15480,4771],"plugin_category":[40,58],"plugin_contributors":[263861],"plugin_business_model":[],"class_list":["post-303098","plugin","type-plugin","status-publish","hentry","plugin_tags-calendar","plugin_tags-events","plugin_tags-recurring-events","plugin_tags-rsvp","plugin_tags-tickets","plugin_category-calendar-and-events","plugin_category-user-management","plugin_contributors-shawnmcburnie","plugin_committers-shawnmcburnie"],"banners":{"banner":"https:\/\/ps.w.org\/nettertech-events\/assets\/banner-772x250.png?rev=3542593","banner_2x":"https:\/\/ps.w.org\/nettertech-events\/assets\/banner-1544x500.png?rev=3542593","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/nettertech-events\/assets\/icon-128x128.png?rev=3542593","icon_2x":"https:\/\/ps.w.org\/nettertech-events\/assets\/icon-256x256.png?rev=3542593","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/nettertech-events\/assets\/screenshot-1.png?rev=3542593","caption":"Monthly calendar with month, week, and day views"},{"src":"https:\/\/ps.w.org\/nettertech-events\/assets\/screenshot-2.jpg?rev=3542593","caption":"Upcoming events archive with search, category filters, and responsive card layout"},{"src":"https:\/\/ps.w.org\/nettertech-events\/assets\/screenshot-3.png?rev=3542593","caption":"Single event page with featured image, date, price, and site navigation"},{"src":"https:\/\/ps.w.org\/nettertech-events\/assets\/screenshot-4.png?rev=3542593","caption":"Weekly regulars table and calendar with event detail popup on hover"},{"src":"https:\/\/ps.w.org\/nettertech-events\/assets\/screenshot-5.png?rev=3542593","caption":"Admin event editor with recurring event patterns and capacity settings"},{"src":"https:\/\/ps.w.org\/nettertech-events\/assets\/screenshot-6.png?rev=3542593","caption":"Admin events list with status filters, event types, and bulk actions"},{"src":"https:\/\/ps.w.org\/nettertech-events\/assets\/screenshot-7.png?rev=3542593","caption":"Display settings with drag-and-drop layout builder for single event pages"},{"src":"https:\/\/ps.w.org\/nettertech-events\/assets\/screenshot-8.png?rev=3542593","caption":"Advanced settings showing rate limits, lookahead controls, and the opt-in attribution badge (disabled by default)"},{"src":"https:\/\/ps.w.org\/nettertech-events\/assets\/screenshot-9.png?rev=3542593","caption":"Mobile-responsive archive page with event cards"},{"src":"https:\/\/ps.w.org\/nettertech-events\/assets\/screenshot-10.png?rev=3542593","caption":"Mobile single event page with ticket type selector and add-to-cart"}],"raw_content":"<!--section=description-->\n<p>NetterTech Events stores your events in dedicated database tables rather than WordPress post meta. That architectural choice means calendar queries stay fast whether you have 50 events or 5,000, and it means recurring event schedules are pre-computed rather than recalculated on every page load.<\/p>\n\n<p><strong>Recurring events that handle real schedules:<\/strong> Full RFC 5545 recurrence rule support covers patterns like \"every second Tuesday\" and \"last Friday of the month.\" Change a rule, and occurrences regenerate automatically.<\/p>\n\n<p><strong>Ticketing without per-ticket fees:<\/strong> Sell tickets through WooCommerce with automatic capacity tracking per occurrence. Series passes let attendees buy once for an entire recurring event run. No external ticketing service means no percentage taken on each sale.<\/p>\n\n<p><strong>Free event registration:<\/strong> RSVP forms work without WooCommerce for events that don't require payment. Attendees register, receive confirmations, and can be tracked through the same admin interface.<\/p>\n\n<p><strong>Check-in built in:<\/strong> Manual attendee check-in by name or email search works from any device. QR code and volunteer check-in workflows can be added with the separate NetterTech Events Pro plugin.<\/p>\n\n<p><strong>Spaces and locations management:<\/strong> Define bookable spaces and physical locations through a dedicated admin interface. Assign spaces to events via the event editor metabox to track which room or area each event occupies.<\/p>\n\n<p><strong>Display options for any layout:<\/strong> Month, week, and day calendar views. Carousel slider for featured events. Filterable grid with live search. Weekly regulars table for recurring events. All three calendar views are available as Gutenberg blocks and Beaver Builder modules.<\/p>\n\n<p><strong>Reminder emails that send themselves:<\/strong> Configure pre-event reminders at any interval you choose. Emails go out automatically via WordPress cron - no third-party service required.<\/p>\n\n<p><strong>SEO handled at the source:<\/strong> Schema.org Event structured data integrates with Yoast SEO and Rank Math's JSON-LD output rather than generating a second duplicate block. Custom sitemap entries cover recurring occurrence URLs individually. Custom SEO title variables (<code>%%nettertech_events_event_date%%<\/code>, <code>%%nettertech_events_event_venue%%<\/code>, <code>%%nettertech_events_event_organizer%%<\/code>) let you build dynamic titles per-occurrence. Breadcrumb trail follows the full event hierarchy. Works without either SEO plugin using built-in Schema.org and Open Graph output.<\/p>\n\n<p><strong>Accessibility throughout:<\/strong> Designed to WCAG 2.2 AA standards with ARIA labels, full keyboard navigation, focus management, and reduced motion support across every public-facing view.<\/p>\n\n<p><strong>Your data stays yours:<\/strong> All attendee, ticket, and event data is stored in your WordPress database. No data is sent to external services. GDPR tools let site administrators export or erase attendee records on request.<\/p>\n\n<p><strong>For Developers:<\/strong><\/p>\n\n<ul>\n<li>Repository and Service patterns with documented hooks and filters throughout<\/li>\n<li>Theme-overridable templates in <code>nettertech-events\/templates\/<\/code> - copy to your theme to customize<\/li>\n<li>REST API for headless or custom implementations<\/li>\n<li>Over 5,000 automated tests with over 17,000 assertions covering core functionality<\/li>\n<\/ul>\n\n<h3>Shortcodes<\/h3>\n\n<p><strong>[nettertech_events_calendar]<\/strong> - Monthly, weekly, and daily calendar views with navigation.<\/p>\n\n<p><strong>[nettertech_events_list]<\/strong> - Filterable event grid or list with live search and category filters. (Also available as <code>[nettertech_events_grid]<\/code> for grid-only layout.)<\/p>\n\n<p><strong>[nettertech_events_carousel]<\/strong> - Sliding carousel of upcoming events with configurable columns.<\/p>\n\n<p><strong>[nettertech_events_rsvp]<\/strong> - RSVP registration form for free events. Supports party size and custom confirmation messages.<\/p>\n\n<p><strong>[nettertech_events_regulars]<\/strong> - Display weekly recurring events in a compact table grouped by day of week. Replaces manually maintained static HTML with live data from published recurring events. Parameters:<\/p>\n\n<ul>\n<li><code>limit<\/code> - Maximum events to display (default: 50)<\/li>\n<li><code>show_venue<\/code> - Show venue name column, true\/false (default: true)<\/li>\n<li><code>show_time<\/code> - Show event time column, true\/false (default: true)<\/li>\n<li><code>show_day<\/code> - Show day-of-week grouping, true\/false (default: true)<\/li>\n<li><code>heading<\/code> - Optional table heading text (default: empty)<\/li>\n<li><code>class<\/code> - Additional CSS class for the wrapper (default: empty)<\/li>\n<\/ul>\n\n<p>Example: <code>[nettertech_events_regulars show_venue=\"false\" heading=\"Weekly Classes\"]<\/code><\/p>\n\n<h3>Third Party Services<\/h3>\n\n<p>This plugin does not connect to any external third-party services by default.<\/p>\n\n<h4>WooCommerce Integration (Optional)<\/h4>\n\n<p>When WooCommerce is installed and activated, this plugin integrates with it to provide paid ticketing functionality. WooCommerce is a separate plugin that handles payment processing through payment gateways you configure.<\/p>\n\n<ul>\n<li>WooCommerce is developed by Automattic<\/li>\n<li><a href=\"https:\/\/woocommerce.com\/terms-conditions\/\">WooCommerce Terms of Service<\/a><\/li>\n<li><a href=\"https:\/\/automattic.com\/privacy\/\">WooCommerce Privacy Policy<\/a><\/li>\n<\/ul>\n\n<p>No data is sent to WooCommerce servers by this plugin. All ticket and order data remains in your WordPress database.<\/p>\n\n<h4>QR Code Generation<\/h4>\n\n<p>QR codes are generated entirely on your server using the bundled PHP QR Code library. No external API calls are made.<\/p>\n\n<h4>Bundled Third-Party Libraries<\/h4>\n\n<p>NetterTech Events is licensed under GPL-2.0-or-later. The plugin bundles the following GPL-compatible third-party libraries via Composer. The authoritative dependency list and resolved versions live in <code>composer.json<\/code> and <code>composer.lock<\/code> (both shipped with the plugin so reviewers can verify vendor contents).<\/p>\n\n<ul>\n<li><code>chillerlan\/php-qrcode<\/code> 6.0.1 \u2014 MIT (selected from the upstream dual MIT \/ Apache-2.0 license). Used for QR code rendering on tickets and check-in flows. Source: https:\/\/github.com\/chillerlan\/php-qrcode<\/li>\n<li><code>chillerlan\/php-settings-container<\/code> 3.3.0 \u2014 MIT. Transitive dependency of <code>php-qrcode<\/code>. Source: https:\/\/github.com\/chillerlan\/php-settings-container<\/li>\n<li><code>symfony\/polyfill-mbstring<\/code> 1.33.0 \u2014 MIT. UTF-8 string-function polyfill (transitive). Source: https:\/\/github.com\/symfony\/polyfill-mbstring<\/li>\n<\/ul>\n\n<p>The MIT license is selected for the dual-licensed <code>chillerlan\/php-qrcode<\/code> because Apache-2.0's patent-retaliation clause is GPL-3.0+ compatible but not GPL-2.0 compatible. MIT keeps the bundled code consistent with the plugin's GPL-2.0+ choice.<\/p>\n\n<h3>Privacy Policy<\/h3>\n\n<p>NetterTech Events collects and stores the following data in your WordPress database:<\/p>\n\n<h4>Data Collected<\/h4>\n\n<ul>\n<li><strong>Attendee Records<\/strong>: Name, email address, and ticket details when users purchase tickets or submit RSVPs<\/li>\n<li><strong>Check-in Data<\/strong>: Timestamps when attendees are checked in at events<\/li>\n<li><strong>Event Data<\/strong>: Event details, occurrences, and ticket configurations created by administrators<\/li>\n<\/ul>\n\n<h4>Data Storage<\/h4>\n\n<ul>\n<li>All data is stored locally in your WordPress database in custom tables prefixed with <code>nettertech_events_<\/code> (e.g. <code>{$wpdb-&gt;prefix}nettertech_events_events<\/code>)<\/li>\n<li>No data is transmitted to external servers by this plugin<\/li>\n<li>Data retention is controlled by you; delete events and ticket records to remove associated data<\/li>\n<\/ul>\n\n<h4>Data Export and Erasure<\/h4>\n\n<ul>\n<li>Attendee data integrates with WordPress's built-in privacy tools<\/li>\n<li>Site administrators can export or erase attendee data on request<\/li>\n<li>Event organizers should document ticket\/RSVP data collection in their site privacy policy<\/li>\n<\/ul>\n\n<h4>Cookies<\/h4>\n\n<p>This plugin does not set any cookies.<\/p>\n\n<h3>Source Code &amp; Build<\/h3>\n\n<p>The plugin ships pre-built block assets under <code>blocks\/*\/build\/<\/code> (compiled from\n    @wordpress\/scripts) so it runs without requiring users to install Node.js or\nrun a build step. The human-readable source for every compiled file is\nincluded in the same distribution under <code>blocks\/*\/src\/<\/code>:<\/p>\n\n<ul>\n<li><code>blocks\/calendar\/src\/index.jsx<\/code> \u2014 source for <code>blocks\/calendar\/build\/index.js<\/code><\/li>\n<li><code>blocks\/carousel\/src\/index.jsx<\/code> \u2014 source for <code>blocks\/carousel\/build\/index.js<\/code><\/li>\n<li><code>blocks\/event-grid\/src\/index.jsx<\/code> \u2014 source for <code>blocks\/event-grid\/build\/index.js<\/code><\/li>\n<\/ul>\n\n<p>To rebuild from source after editing any <code>*.jsx<\/code> file:<\/p>\n\n<pre><code>npm install &amp;&amp; npm run build\n<\/code><\/pre>\n\n<p>The build configuration lives in <code>package.json<\/code> (<code>scripts.build<\/code>) and uses the\nofficial <code>@wordpress\/scripts<\/code> toolchain with no custom webpack config.<\/p>\n\n<h3>Additional Resources<\/h3>\n\n<ul>\n<li><a href=\"https:\/\/nettertech.com\/plugins\/events\/\">Plugin Homepage<\/a><\/li>\n<li><a href=\"https:\/\/wordpress.org\/support\/plugin\/nettertech-events\/\">Support Forum<\/a><\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>nettertech-events<\/code> folder to <code>\/wp-content\/plugins\/<\/code><\/li>\n<li>Activate the plugin through the 'Plugins' menu<\/li>\n<li>Go to Events &gt; Settings to configure options<\/li>\n<li>Create your first event under Events &gt; Add New<\/li>\n<\/ol>\n\n<p><strong>For Ticketing:<\/strong><\/p>\n\n<ol>\n<li>Install and activate WooCommerce 8.5+<\/li>\n<li>NetterTech Events will automatically create products for ticket types<\/li>\n<li>Configure ticket types in the Event Editor<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20require%20woocommerce%3F\"><h3>Does this plugin require WooCommerce?<\/h3><\/dt>\n<dd><p>No. WooCommerce is optional and only needed for paid ticketing. The plugin works without it for event display, calendars, and free RSVP registration.<\/p><\/dd>\n<dt id=\"what%27s%20included%20in%20the%20free%20version%3F\"><h3>What's included in the free version?<\/h3><\/dt>\n<dd><p>The free version includes unlimited events, recurring event support, RSVP forms, manual attendee check-in by name or email search, all three display views (calendar, grid, carousel), SEO integration, and full GDPR tools. QR code check-in, volunteer check-in mode, and QR code generation for promotion are available in NetterTech Events Pro.<\/p><\/dd>\n<dt id=\"can%20i%20import%20events%20from%20the%20events%20calendar%3F\"><h3>Can I import events from The Events Calendar?<\/h3><\/dt>\n<dd><p>Yes. The companion plugin <strong>NetterTech Events Migrator<\/strong> supports bidirectional migration with The Events Calendar. Import and export cover all 13 entity types including recurring events, venues, organizers, categories, tickets, and attendees with lossless round-trip fidelity.<\/p><\/dd>\n<dt id=\"how%20do%20recurring%20events%20work%3F\"><h3>How do recurring events work?<\/h3><\/dt>\n<dd><p>NetterTech Events pre-computes occurrences using RFC 5545 recurrence rules (the same standard used by Google Calendar and iCal). Rules support patterns like \"every second Tuesday\" and \"last Friday of the month.\" When you change a rule, occurrences regenerate automatically.<\/p><\/dd>\n<dt id=\"can%20attendees%20buy%20a%20ticket%20to%20an%20entire%20recurring%20event%20series%3F\"><h3>Can attendees buy a ticket to an entire recurring event series?<\/h3><\/dt>\n<dd><p>Yes. Series passes grant access to all occurrences of a recurring event with a single purchase. They're configured as a ticket type in the event editor.<\/p><\/dd>\n<dt id=\"will%20this%20slow%20down%20my%20site%20as%20the%20event%20count%20grows%3F\"><h3>Will this slow down my site as the event count grows?<\/h3><\/dt>\n<dd><p>Event data is stored in dedicated database tables with indexes built for calendar queries. Calendar views query by date range against pre-computed occurrences rather than scanning post meta. The query load does not scale with total event count the way post-meta-based plugins do.<\/p><\/dd>\n<dt id=\"how%20do%20i%20customize%20the%20event%20display%20templates%3F\"><h3>How do I customize the event display templates?<\/h3><\/dt>\n<dd><p>Copy templates from <code>nettertech-events\/templates\/<\/code> to <code>your-theme\/nettertech-events\/<\/code> and modify as needed. Templates exist for single event pages, occurrence lists, event cards, the calendar view, grid view, and carousel. Your customizations are preserved across plugin updates.<\/p><\/dd>\n<dt id=\"is%20the%20plugin%20accessible%3F\"><h3>Is the plugin accessible?<\/h3><\/dt>\n<dd><p>Yes. NetterTech Events is designed for WCAG 2.2 AA compliance with ARIA labels, keyboard navigation, focus management, and reduced motion support across all public-facing views.<\/p><\/dd>\n<dt id=\"how%20are%20event%20categories%20managed%3F\"><h3>How are event categories managed?<\/h3><\/dt>\n<dd><p>Categories are managed through a built-in editor at <strong>Events - Categories<\/strong> in the admin menu. They use dedicated database tables rather than WordPress taxonomies, support parent\/child hierarchy, and are available as frontend filters in event lists and calendars.<\/p><\/dd>\n<dt id=\"what%20php%20version%20is%20required%3F\"><h3>What PHP version is required?<\/h3><\/dt>\n<dd><p>PHP 8.2 or higher. The plugin uses strict types, enums, and constructor property promotion throughout.<\/p><\/dd>\n<dt id=\"will%20this%20plugin%20conflict%20with%20other%20event%20plugins%3F\"><h3>Will this plugin conflict with other event plugins?<\/h3><\/dt>\n<dd><p>NetterTech Events uses its own custom tables and a dedicated URL namespace (<code>\/events\/<\/code> by default). If you have The Events Calendar or another plugin registered to the same URL prefix, there will be a conflict. The plugin detects this on activation and displays a notice with instructions for resolving it.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>Compliance: Round-2 WP.org Plugin Review remediation. Suppression-as-documentation removed across the source tree; per-issue root-cause refactors landed in waves.<\/li>\n<li>Compliance (Wave A): Output escaping refactored across blocks, BeaverBuilder modules, frontend shortcodes, admin\/repo\/service classes, and templates. Custom <code>wp_kses<\/code> allowlist helper (<code>ShortcodeOutput::get_allowlist()<\/code>) preserves SVG, ARIA, and data-* attributes that <code>wp_kses_post<\/code> would strip.<\/li>\n<li>Compliance (Wave B): Service classes (<code>RecurrenceRuleBuilder<\/code>, <code>TicketTypeSaver<\/code>, <code>CheckInEmailSaver<\/code>, <code>AttendeeFieldsSaveHandler<\/code>) no longer fall back on <code>$_POST<\/code> \u2014 callers must pass verified data after nonce\/capability checks. Bulk-action handlers extract input only after nonce verification.<\/li>\n<li>Compliance (Wave B): <code>SecurityHeaders<\/code> re-anchored to <code>current_screen<\/code> + <code>WP_Screen<\/code> API (was reading <code>$_GET<\/code> on <code>admin_init<\/code> priority 1).<\/li>\n<li>Compliance (Wave B): Calendar shortcode URL parameters migrated from <code>?month=<\/code> \/ <code>?date=<\/code> to registered query vars <code>nettertech_events_calendar_month<\/code> \/ <code>..._date<\/code>; legacy URLs 301-redirect to the prefixed format.<\/li>\n<li>Compliance (Wave B): Settings page sanitizes <code>$_POST['nettertech_events_settings']<\/code> at the boundary via <code>map_deep( ..., 'sanitize_textarea_field' )<\/code>; type-specific tightening continues in <code>SettingsSanitizer<\/code>.<\/li>\n<li>Compliance (Wave B): <code>TicketCartAjax<\/code> sanitizes the JSON ticket payload at the boundary; the prior suppression is removed.<\/li>\n<li>Compliance (Wave B): <code>EventTemplateResolver::can_preview_event()<\/code> refactored to close a bypass gap where a malformed <code>?preview=<\/code> value could skip nonce verification.<\/li>\n<li>Compliance (Wave C): Dynamic-hook patterns (e.g. <code>Hooks::SETTINGS_TAB_PREFIX . $tab<\/code>, <code>{filter_prefix}_get_template_part_{slug}<\/code>) replaced with fixed <code>Hooks::*<\/code> constants; listeners receive what was previously encoded in the suffix as an action argument. Backward-compat bridges fire the deprecated names alongside the canonical ones (will be removed in 2.0).<\/li>\n<li>Compliance (Wave C): <code>AdminMenu<\/code> exposes explicit <code>SUBMENU_NEW<\/code>, <code>SUBMENU_EDIT<\/code>, <code>SUBMENU_ATTENDEES<\/code>, <code>SUBMENU_QR_GENERATOR<\/code>, <code>SUBMENU_CSV_IMPORT<\/code>, <code>SUBMENU_ACTIVITY_LOG<\/code>, <code>SUBMENU_SETTINGS<\/code> constants. Eight callsites refactored.<\/li>\n<li>Compliance (Wave C): <code>MigrationManager<\/code> (legacy <code>ve_*<\/code> \u2192 canonical) state-option keys renamed from <code>nte_rebrand_migration_*<\/code> to <code>nettertech_events_legacy_rebrand_*<\/code>. A v1.0.2 upgrade-path transition forwards legacy keys onto the new names for sites that ran the migration under v1.0.0\/1.0.1. Only the canonical <code>nettertech_events_legacy_rebrand_complete<\/code> action fires on completion; the legacy bridge hook was removed for the initial WP.org submission.<\/li>\n<li>Compliance (Wave C): <code>PrefixMigrationManager<\/code> loads its old\/new prefix maps from <code>config\/legacy-prefix-map.json<\/code> instead of carrying <code>nte_*<\/code> literals in PHP source. The remaining <code>nte_*<\/code> mentions in production source are confined to the <code>MigrationManager<\/code> legacy-rename code path: state-transition source-key strings (<code>nte_rebrand_migration_complete<\/code>, <code>nte_rebrand_migration_log<\/code>) read on upgrade from v1.0.0\/1.0.1, the intermediate post-type and taxonomy slugs targeted by the <code>ve_*<\/code> \u2192 canonical rename, and docblock examples documenting them. No <code>nte_*<\/code> literal is emitted at steady-state runtime.<\/li>\n<li>Compliance (Wave C): Template loader now passes a typed <code>TemplateContext<\/code> (or <code>EmailContext<\/code> for email templates) as a single <code>$context<\/code> parameter instead of injecting locals via <code>extract()<\/code>. Thirty-two templates refactored to property-style access (<code>$context-&gt;event<\/code>). The <code>NonPrefixedVariableFound<\/code> suppressions across <code>templates\/<\/code> are gone (was 38).<\/li>\n<li>Compliance (Wave D): Vendor documentation (per-library <code>LICENSE<\/code>, <code>NOTICE<\/code>, <code>CHANGELOG.md<\/code>, <code>README.md<\/code>, tests, examples) excluded from the distribution zip. The \"Bundled Third-Party Libraries\" section of this <code>readme.txt<\/code> is the authoritative attribution surface (a standalone <code>CREDITS.md<\/code> was previously used and has been inlined here). License selected for the dual-licensed <code>chillerlan\/php-qrcode<\/code> dependency: MIT (GPL-2.0 compatible).<\/li>\n<li>Compliance (Wave D): <code>.eslintignore<\/code> removed from the distribution (Plugin Check's \"hidden files are not permitted\" rule).<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Compliance: Renamed all <code>nte_*<\/code> prefix identifiers to <code>nettertech_events_*<\/code> to satisfy WP.org plugin review's 4-character minimum prefix requirement (hooks, options, post\/user\/order-item meta keys, transients, AJAX action strings, nonces, $POST keys, JS-localized variables, table prefixes, cron hook names)<\/li>\n<li>Compliance: Renamed custom post type slug from <code>nte_event<\/code> to <code>nettertech_event<\/code> (16 chars; the originally-planned 23-char name exceeded WP core's 20-char <code>register_post_type()<\/code> limit and would have silently failed registration)<\/li>\n<li>Compliance: Renamed taxonomies to <code>nettertech_event_category<\/code> and <code>nettertech_event_tag<\/code> for safer headroom under WP's 32-char taxonomy slug limit<\/li>\n<li>Compliance: Renamed style handle <code>nte-public-ticket<\/code> to <code>nettertech-events-public-ticket<\/code><\/li>\n<li>Compliance: Sanitization fixes \u2014 added <code>wp_unslash()<\/code> and <code>sanitize_text_field()<\/code> to 13 superglobal access points flagged by <code>WordPress.Security.ValidatedSanitizedInput<\/code> sniff (Rentals: 11 sites; Seating: 2 sites)<\/li>\n<li>Migration: New <code>PrefixMigrationManager<\/code> class (Step 2 migration, separate from the existing legacy <code>ve_* \u2192 nte_*<\/code> MigrationManager) automatically renames all DB-persisted artifacts on plugin upgrade \u2014 custom tables (RENAME TABLE), <code>wp_posts.post_type<\/code>, <code>wp_term_taxonomy.taxonomy<\/code>, options (exact-match per key, no broad REPLACE), <code>wp_postmeta<\/code>\/<code>wp_usermeta<\/code>\/<code>wp_woocommerce_order_itemmeta<\/code> keys, transients (cache vs stateful classification), cron hook reschedule with cadence preserved, and shortcode rewrites in <code>wp_posts.post_content<\/code><\/li>\n<li>Migration: Conflict-detection rule \u2014 if both old and new tables exist, migration logs the conflict and aborts rather than auto-merging (per data-safety policy); transient lock prevents parallel runs<\/li>\n<li>Migration: Per-addon migrators (Pro, Rentals, Seating) listen on the base completion action AND run a <code>plugins_loaded<\/code> priority 20 fallback check, so addons activated after base migrate independently. Each addon has its own completion flag and log option.<\/li>\n<li>Note for site owners: existing sites running the in-review v1.0.0 should run <code>update_option( 'nettertech_events_prefix_migration_complete', '' )<\/code> before upgrade only if they want the migration to re-run; otherwise the migration runs automatically on plugin update.<\/li>\n<li><strong>BREAKING \u2014 Yoast SEO templates:<\/strong> The three custom title-template variables registered via <code>wpseo_register_var_replacement()<\/code> were renamed from <code>%%nte_event_date%%<\/code>, <code>%%nte_event_venue%%<\/code>, <code>%%nte_event_organizer%%<\/code> to <code>%%nettertech_events_event_date%%<\/code>, <code>%%nettertech_events_event_venue%%<\/code>, <code>%%nettertech_events_event_organizer%%<\/code>. Sites with the legacy variable names in their Yoast title templates will need to update those templates after the upgrade \u2014 the old names no longer resolve and will render as the literal string. Rank Math equivalents were already migrated and are unaffected.<\/li>\n<li>Cleanup: Swept all stale <code>nte_*<\/code> references out of comments, PHPDocs, local PHP variable names, test fixtures, block render templates, Beaver Builder module render templates, and the uninstall handler. The only remaining <code>nte_*<\/code> strings in the codebase are inside <code>MigrationManager.php<\/code> (Step-1 <code>ve_*<\/code> \u2192 <code>nte_*<\/code> migrator, never executes on a fresh install) and <code>PrefixMigrationManager.php<\/code> (Step-2 input keys for the rename map). Both are documented carve-outs.<\/li>\n<li>Fix: <code>uninstall.php<\/code> was deleting transients matching <code>_transient_nte_%<\/code> (the pre-1.0.1 prefix) which would have left <code>nettertech_events_*<\/code> transients orphaned on uninstall after the migration ran. Pattern updated to match the post-migration prefix.<\/li>\n<li>Fix: <code>uninstall.php<\/code> was filtering shadow posts by the post-type slug <code>'nettertech_events_event'<\/code> (23 chars; exceeded WP's 20-char limit and was never the live slug). Replaced with the canonical <code>ShadowPostType::POST_TYPE<\/code> constant so it stays in sync with the registered slug.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Feature: Category system migrated from WordPress taxonomy to internal tables with dedicated editor<\/li>\n<li>Feature: Event reminder emails with configurable timing and cron scheduling<\/li>\n<li>Feature: GDPR privacy tools \u2014 WordPress privacy exporter\/eraser for attendee data<\/li>\n<li>Feature: Event card redesign with full-tile clickability and responsive images<\/li>\n<li>Feature: Category checkbox UI in event editor sidebar<\/li>\n<li>Feature: WooCommerce event_id meta on cart items for integration support<\/li>\n<li>Feature: Distribution packaging with .distignore and GPL v2 LICENSE<\/li>\n<li>Enhancement: God class decomposition \u2014 8 large classes refactored into focused modules<\/li>\n<li>Enhancement: PHPStan Level 7 static analysis with zero-error baseline<\/li>\n<li>Enhancement: CSS custom properties for themeable colors (date badge, ticket area, borders)<\/li>\n<li>Enhancement: 12px minimum font floor enforced; systemic rem-to-em CSS conversion<\/li>\n<li>Enhancement: Test suite of over 5,000 unit tests with over 17,000 assertions<\/li>\n<li>Fix: Event time not saving correctly (BUG-001)<\/li>\n<li>Fix: Past events AJAX pagination missing parameter (BUG-002)<\/li>\n<li>Fix: Category filter dropdown empty after iCal import (BUG-003)<\/li>\n<li>Fix: Ticket quantity buttons non-functional due to script timing (BUG-004)<\/li>\n<li>Fix: Event editor browser tab title stuck on \"All Events\" (BUG-005)<\/li>\n<li>Fix: Category UI missing from event editor (BUG-007)<\/li>\n<li>Fix: ActivityLogHooks signature updated to accept Attendee model<\/li>\n<li>Fix: Admin bar \"Edit Event\" hover color<\/li>\n<li>Security: Compatible with WooCommerce High-Performance Order Storage<\/li>\n<li>Security: OWASP 2025 compliance verified across all endpoints<\/li>\n<\/ul>\n\n<h4>0.9.0<\/h4>\n\n<ul>\n<li>Feature: Multi-organizer support with junction tables<\/li>\n<li>Feature: Categories and tags junction tables for scalability<\/li>\n<li>Enhancement: Test coverage improved to 29.30% (1,077 unit tests)<\/li>\n<li>Enhancement: E2E test suite expanded to 53 Playwright tests<\/li>\n<li>Enhancement: Schema version bump with automatic migration<\/li>\n<li>Security: Check-in codes generated via random_bytes (16-hex-char codes, cryptographically secure per OWASP 2025)<\/li>\n<\/ul>\n\n<h4>0.8.0<\/h4>\n\n<ul>\n<li>Feature: ServiceRegistry DI pattern with 7 contracts<\/li>\n<li>Feature: Denormalized counter caching for ticket sales<\/li>\n<li>Feature: N+1 query prevention with identity maps<\/li>\n<li>Security: OWASP 2025 compliance (authorization order fixes)<\/li>\n<li>Enhancement: 887 unit tests + 51 E2E Playwright tests<\/li>\n<li>Enhancement: Beaver Builder modules with direct class invocation<\/li>\n<li>Enhancement: Gutenberg blocks for Calendar, Carousel, and Grid<\/li>\n<\/ul>\n\n<h4>0.7.0<\/h4>\n\n<ul>\n<li>Feature: QR code generation with color customization<\/li>\n<li>Feature: Atomic check-in operations (race-condition safe)<\/li>\n<li>Feature: Email confirmations with ICS attachments<\/li>\n<li>Feature: Series passes for recurring events<\/li>\n<li>Feature: Template tickets with automatic propagation<\/li>\n<li>Enhancement: Centralized capacity service<\/li>\n<\/ul>\n\n<h4>0.6.0<\/h4>\n\n<ul>\n<li>Feature: WooCommerce ticketing integration<\/li>\n<li>Feature: RSVP form shortcode<\/li>\n<li>Feature: Theme-overridable template system<\/li>\n<li>Enhancement: Event categories taxonomy<\/li>\n<\/ul>\n\n<h4>0.5.0<\/h4>\n\n<ul>\n<li>Feature: Recurring event frontend pages<\/li>\n<li>Feature: Occurrence-specific pages with tickets<\/li>\n<li>Feature: Event carousel shortcode<\/li>\n<li>Feature: Event list shortcode with AJAX filters<\/li>\n<\/ul>\n\n<h4>0.4.0<\/h4>\n\n<ul>\n<li>Feature: REST API endpoints<\/li>\n<li>Feature: Calendar shortcode with multiple views<\/li>\n<li>Enhancement: Frontend router for clean URLs<\/li>\n<\/ul>\n\n<h4>0.3.0<\/h4>\n\n<ul>\n<li>Feature: Admin event editor with metaboxes<\/li>\n<li>Feature: Events list table with bulk actions<\/li>\n<li>Feature: Recurrence rule builder UI<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>Feature: RFC 5545 RRULE parser<\/li>\n<li>Feature: Occurrence generation service<\/li>\n<li>Feature: Pre-computed occurrence storage<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Initial pre-release<\/li>\n<li>Custom database tables for events, occurrences, tickets, attendees<\/li>\n<li>Basic event CRUD operations<\/li>\n<\/ul>","raw_excerpt":"A WordPress event management plugin with dedicated database tables, recurring events, RSVP forms, and WooCommerce ticketing for venues and nonprofits.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/303098","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=303098"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/shawnmcburnie"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=303098"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=303098"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=303098"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=303098"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=303098"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=303098"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}