renderbit / faq-jsonld
WordPress plugin to manage FAQ items as CPT and inject FAQ JSON-LD with advanced caching and queueing.
Package info
github.com/renderbit-technologies/faq-jsonld-wordpress-plugin
Type:wordpress-plugin
pkg:composer/renderbit/faq-jsonld
Requires
- php: >=7.2
- composer/installers: ^1.9 || ^2.0
Requires (Dev)
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A WordPress plugin to manage FAQ items as a custom post type (CPT) and inject FAQ JSON-LD into posts/pages. Designed for performance and scalability with advanced cache management, background queueing, and admin/CLI tools.
Features
- Custom Post Type: Manage FAQ items via the
faq_itemCPT. - Mapping Table: Fast MySQL table (
fqj_mappings) links FAQ items to posts, post types, terms, URLs, or global context. - JSON-LD Output: Injects FAQ schema on the frontend, with per-post transient caching.
- Cache Invalidation: Background queue (WP-Cron or WP-CLI) for efficient cache purging.
- Admin UI: Meta boxes and settings for mapping, output, and diagnostics.
- Health & Diagnostics: Admin page for queue/logs and manual actions.
- WP-CLI Integration: Commands for cache and queue management.
Installation
- Copy the plugin folder to your WordPress
wp-content/plugins/directory. - Activate via the WordPress admin Plugins page.
- On activation, the mapping table is created automatically.
Usage
- Add FAQ Items: Use the
FAQ ItemsCPT in the admin menu. - Associate FAQs: Use meta boxes to link FAQs to posts, post types, terms, URLs, or globally.
- Singular content only: JSON-LD is printed on singular views (posts, pages, custom post types). Blog home, archives and search results never output FAQ markup, so URL mappings apply to singular content only (archive URLs are not matched).
- Output: Markup is schema.org
FAQPage. Question and answer text is plain text: tags stripped, entities decoded, whitespace collapsed. Answers run through blocks and shortcodes but not thethe_contentfilter. - Settings: Configure cache TTL and invalidation batch size (10-5000) under the FAQ Items > Settings menu.
- Translations: Strings use the
faq-jsonldtext domain (loaded just-in-time by WordPress 4.6+); admin JS strings are localized throughwp_localize_script. - Requirements: WordPress 6.5+, PHP 7.2+.
- Health: Monitor queue/logs and run manual actions under FAQ Items > Health.
- WP-CLI:
wp fqj purge-transients— Purge all FAQ JSON-LD transients.wp fqj process-queue [--limit=N]— Process the invalidation queue.wp fqj queue-info— Show the number of pending queue items.
Developer Notes
Filters
-
fqj_question_text( $text, $faq_post )— filter the plain-text question for a FAQ item. -
fqj_answer_text( $text, $faq_post )— filter the plain-text answer. Return plain text; the JSON encoder escapes<,>and&. Cached output is cleared on settings changes or withwp fqj purge-transients. -
Key Files:
faq-jsonld.php: Main loader and CPT registrationincludes/indexer.php: Mapping table logicincludes/queue.php: Invalidation queueincludes/frontend.php: JSON-LD output/cachingincludes/admin.php: Admin UI/meta boxesincludes/settings.php: Settings pageincludes/health.php: Health/diagnostics UIincludes/class-fqjcli.php: WP-CLI commandsassets/js/fqj-admin.js,assets/js/fqj-health.js: Admin JS (Select2 is bundled inassets/vendor/select2)
-
Mapping Types: All associations are stored in a single table for fast lookups.
-
Transient Keys:
fqj_faq_json_{generation}_{post_id}(build withfqj_cache_key( $post_id )). "Purge all" bumps thefqj_cache_genoption, which works with persistent object caches too. -
Uninstall: Deleting the plugin removes its options, transients, cron events, post meta and mapping table (on every site of a multisite network).
faq_itemposts are kept by default; to delete them as well, addadd_filter( 'fqj_uninstall_delete_faqs', '__return_true' );(e.g. in a mu-plugin) before deleting the plugin. -
Admin JS: Uses Select2 for post selectors, AJAX for search (
fqj_search_postsaction; all public post types except attachments and FAQs). Switching the association type keeps each type's in-progress selection until you save; only the selected type is stored. -
Background Processing: The invalidation queue lives in a database table and is processed every 5 minutes by WP-Cron (up to the batch size per run), or on demand from the Health page or WP-CLI.
-
Asset versions: The plugin's own JS is versioned with
FQJ_VERSION; keep it in sync with theVersionheader when releasing.
Testing
- PHP: PHPUnit integration tests against a real WordPress install (
tests/php). Run withcomposer test; needs a MySQL database. - JavaScript: Jest tests for the admin scripts (
tests/js). Run withnpm test. - Coding standards:
composer lint.
See CONTRIBUTING.md for setup.
Contributing
Pull requests and issues are welcome. Please follow project conventions and review inline comments in each file for guidance.
License
This project is licensed under the GNU General Public License v2.0 or later — see the LICENSE.md file for details.
SPDX-License-Identifier: GPL-2.0-or-later
For more details, see the inline comments in each file or the .github/copilot-instructions.md for AI agent guidance.