GTL Business Directory

Description

GTL Business Directory turns any WordPress site into a structured business directory. It is deliberately image-free: featured image support is suppressed across nine independent layers so no theme, page builder, SEO plugin or legacy data can reintroduce a thumbnail. Listings render as clean, structured text cards with deterministic coloured monograms instead.

Core features

  • Business listing post type with 30+ structured fields
  • Hierarchical Categories (main category + unlimited subcategories) with summary, long intro, SEO title, meta description, focus keywords, custom H1, icon, accent colour, ordering, featured flag and FAQ
  • Hierarchical Locations (Country > State > City > Area) with all of the above plus location type, latitude/longitude, PIN codes and population
  • Front-end user registration with a dedicated Business Owner role, honeypot spam protection and email notifications
  • Owner dashboard with listing table, view counts and inline edit links
  • Front-end submit/edit form with dependent category dropdowns and opening-hours editor
  • “All lists” page with faceted sidebar (category, subcategory, location, price, rating, verified, featured), keyword search, eight sort modes and pagination
  • Single landing page with sticky contact panel, quick stats, services tags, opening hours with today highlighting, social links, related listings and a claim CTA
  • LocalBusiness, BreadcrumbList, CollectionPage and FAQPage JSON-LD — all without an image property
  • Admin settings screen for slugs, page assignments, accent colour, per-page count and auto-publish

Shortcodes

  • [gettoplists_directory] — full listings page
  • [gettoplists_categories] — main categories with subcategories and summaries
  • [gettoplists_locations] — primary locations with child cities
  • [gettoplists_search] — hero search bar
  • [gettoplists_register] — registration page
  • [gettoplists_login] — login form
  • [gettoplists_dashboard] — owner dashboard
  • [gettoplists_submit] — add/edit listing form

External services

This plugin connects to PayPal to process optional “boost” payments that give a
listing top placement. This connection is only made when the site administrator
explicitly enables PayPal in Directory -> Settings -> PayPal and a user chooses
to purchase a boost. The plugin makes no external requests otherwise.

What is sent and when

  1. When a user clicks a boost package, their browser is redirected to PayPal’s
    hosted checkout, at the host www.paypal.com (or www.sandbox.paypal.com in
    sandbox mode), path /cgi-bin/webscr. The form sends the item name, price,
    currency, the site’s configured PayPal business email, return URLs, and a
    reference containing the listing ID and package ID. No personal data is
    collected by the plugin at this step; the payer enters their details on
    PayPal’s own site.

  2. When PayPal notifies the site of a completed payment via Instant Payment
    Notification (IPN), the plugin posts the received payload back to PayPal for
    verification, at the host ipnpb.paypal.com (or ipnpb.sandbox.paypal.com in
    sandbox mode), path /cgi-bin/webscr. These are POST-only verification
    endpoints. This step is required by PayPal to confirm the notification is
    genuine. The payload posted back is exactly what PayPal sent, unmodified.

PayPal legal hub (user agreement and privacy statement): https://www.paypal.com/us/legalhub/home

Installation

  1. Upload the plugin ZIP via Plugins > Add New > Upload Plugin, then activate.
  2. Activation auto-creates seven pages, seeds starter categories and locations, and registers the Business Owner role.
  3. Visit Settings > Permalinks and click Save to flush rewrite rules.
  4. Review Directory > Settings to assign pages and set your accent colour.

FAQ

Does the plugin require PayPal?

No. PayPal is only used for the optional paid “boost” feature, which is
disabled by default. The directory, reviews, search and schema output all work
without it, and no external request is made unless an administrator enables
PayPal and a user purchases a boost.

Why are there no featured images?

This plugin is deliberately image-free. Listings are text and data only, which
keeps archive pages fast and consistent regardless of the active theme.

Who can leave a review?

Only logged-in users, to reduce spam. Reviews are stored as a custom post type
and can be moderated from the admin.

Does it work with any theme?

Yes. Output is rendered through templates that can be overridden by copying
them into a gtl-bd/ folder in your theme.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“GTL Business Directory” is open source software. The following people have contributed to this plugin.

Contributors

Changelog

4.3.0

  • The printable invoice now loads a real stylesheet through wp_enqueue_style() and wp_head(); the accent colour is attached with wp_add_inline_style(). No inline block remains in the plugin.
  • SECURITY: The content width setting is validated as a CSS length (number plus an allowed unit) instead of plain text. It is written into a stylesheet, where sanitize_text_field() would have permitted a value such as “1px;background:url(…)”.
  • Removed the unprefixed business_* shortcode aliases. Pages still containing the old tags are rewritten automatically on upgrade, so existing content keeps working.
  • Replaced the PayPal legal links with the legal hub landing page; the previous document URL is 2.3 MB and timed out during review.

4.2.2

  • Numeric request values are now passed through absint() or sanitize_text_field() before casting, rather than relying on the cast alone. Covers the pagination, rating filter and admin boost fields.

4.2.1

  • Applied the reported issue classes across the whole plugin rather than only the lines quoted in the review.
  • SECURITY: Colour values written into stylesheets and style attributes are re-validated with sanitize_hex_color() at the point of output. esc_attr() is not a CSS escaper, so these previously relied on the save-time filter alone.
  • FIXED: Three superglobal reads were cast but not unslashed; added wp_unslash() before casting.
  • Documented the remaining conditional class-name echoes, which switch between two hardcoded literals.

4.2.0

  • Renamed the plugin’s global prefix to gettoplists_ / GETTOPLISTS_ so it meets the four-character requirement and no longer relies on the generic “business” prefix. Classes, constants, hooks, cron events, AJAX actions, options and shortcodes are all covered.
  • Shortcodes are now [gettoplists_directory], [gettoplists_listings], [gettoplists_categories], [gettoplists_locations], [gettoplists_search], [gettoplists_register], [gettoplists_login], [gettoplists_dashboard], [gettoplists_submit] and [gettoplists_boost]. Update any pages that use the old names.
  • Settings are migrated automatically on upgrade. Listings, categories, locations, user accounts and invoices are unaffected.
  • SECURITY: JSON-LD output is now encoded with JSON_HEX_TAG, so listing content containing a closing script tag can no longer break out of the schema block.
  • FIXED: The review nonce is sanitized before verification.
  • FIXED: The PayPal IPN payload is validated as an array and each member type-checked before use; json_decode() alone does not sanitize.
  • FIXED: The admin featured-image CSS now goes through wp_add_inline_style() instead of being printed on admin_head.

4.1.2

  • Annotated the remaining 26 class and constant prefix notices inline, completing the move away from the removed ruleset file. The submission now reports no errors and no warnings.

4.1.1

  • Removed phpcs.xml.dist from the distributed package; developer configuration files are not permitted in a submitted plugin.
  • Moved the prefix declarations that file provided into documented inline annotations at each of the 14 affected lines.
  • Restored the two exclusion-parameter annotations on the shortcode_atts() defaults.

4.1.0

  • Resolved the remaining 272 Plugin Check warnings. The submission now reports no errors.
  • Added phpcs.xml.dist declaring the GTL_BD_/gtl_bd_ prefixes this plugin owns, plus its text domain and minimum WordPress version. Without it the prefix sniff derived an expected prefix from the plugin slug and flagged all 21 correctly namespaced classes, 5 constants and 10 hooks as unprefixed.
  • FIXED: uninstall.php now wraps its cleanup in a named function so its working variables no longer enter the global namespace.
  • Documented the six dynamic $_POST[$key] loops that sanitize through a field-type dispatcher, which the sniff cannot follow.
  • Documented the meta/tax query notices that are inherent to a searchable directory, and the core wp_login hook that must not be prefixed.
  • Removed two stale suppressions left on shortcode default arrays where no sniff applies.

4.0.2

  • FIXED: Template data is now passed as $gtl_args instead of $args. Several templates build their own local $args array for WP_Query or get_terms(), so the incoming data depended on statement order inside the template — a latent bug that would have surfaced on any future edit that reordered those lines.
  • Verified every template/caller data contract matches, and that no template reads a variable no caller supplies.

4.0.1

  • Compliance release for the WordPress.org Plugin Check ruleset — 1,191 findings resolved.
  • FIXED: Text domain now matches the plugin slug across all 801 strings.
  • FIXED: All output escaped at the point of output. The form-repopulation helpers now return raw values and every call site escapes with esc_attr()/esc_textarea(), so escaping is visible to static analysis.
  • SECURITY: Added nonce verification to the user profile save routine, which previously relied on a capability check alone and was open to CSRF.
  • SECURITY: The no-JavaScript review submission path now verifies its nonce before any request data is read.
  • FIXED: Added 51 translators comments so every placeholder string can be translated accurately.
  • FIXED: Removed load_plugin_textdomain(); WordPress has loaded these automatically since 4.6 and calling it early triggers a notice on 6.7+.
  • FIXED: Replaced extract() in the template loader with an explicit $args array.
  • FIXED: Converted meta_key/meta_value pairs to meta_query and added no_found_rows to invoice lookups.
  • PERFORMANCE: The meta search query is now cached for five minutes, covering the pagination requests that follow a search.
  • Documented every remaining phpcs suppression with its specific sniff and rationale.

4.0.0

  • NEW: Complete JSON-LD schema on every page — LocalBusiness (auto-typed to Restaurant, Dentist, LegalService etc. from the category), Review, AggregateRating, BreadcrumbList, ItemList, CollectionPage, Place, FAQPage, Product/Offer, Organization, WebSite and SearchAction, all wired into one connected @graph.
  • NEW: Full Open Graph and Twitter Card output on every directory page, including business:contact_data and place:location tags. Yoast/Rank Math OG tags are suppressed on directory pages only, so nothing duplicates.
  • NEW: Review and rating system. Star ratings, headline, review body, helpful votes, owner responses, moderation queue, one review per account per listing, owner cannot review own listing. Feeds AggregateRating for review rich snippets.
  • NEW: Automatic invoicing. Every completed PayPal payment issues a sequentially numbered invoice (GTL-2026-0001), emails it to the customer, and lists it in the dashboard and admin. Print-ready HTML invoice with tax split, business details and Save-as-PDF.
  • NEW: Refund handling — a PayPal refund or reversal cancels the boost and flags the invoice.
  • EXPANDED: 199 location terms across 4 countries, 38 states/regions and 157 cities, covering the top 20 US states, all UK nations and regions, all Australian mainland states plus the ACT, and India.
  • IMPROVED: Every seeded location carries a unique SEO title, meta description, H1 and keyword set — verified 199/199 unique on all three fields.
  • IMPROVED: Terms added by hand get unique meta too. Fallback titles and descriptions rotate through several sentence templates keyed on term ID, and vary by depth, so no two pages read alike.
  • IMPROVED: Upgrade-safe location top-up. Activating over 3.x adds only the missing terms and never overwrites edits.
  • FIXED: Removed a duplicate meta description emitter that could fire alongside the SEO class.

3.0.0

  • Global locations: USA, UK, Australia and India — 81 pre-seeded terms (4 countries, 18 states/regions, 59 cities), every one with a unique summary, SEO title and meta description
  • Sponsored listings: paid top placement on the listings page, category pages and location pages
  • PayPal gateway with IPN verification — recurring monthly subscription plus optional 3-month and 12-month one-off packages
  • Boost checkout page with live card preview, package comparison and FAQ
  • Theme adaptation engine: auto-detects the theme accent colour from theme.json or theme mods, inherits typography and content width, four card styles, adjustable corner radius
  • Unique meta title and description generated for every directory page, integrating with Yoast and Rank Math rather than fighting them
  • Container-query layouts throughout so the plugin fits any theme column width
  • Hourly cron to expire boosts, admin boost metabox with manual grant and payment history

2.0.1

  • Fixed layouts overflowing narrow theme columns that have their own sidebar

2.0.0

  • Complete rewrite into a modular, class-based architecture
  • Added hierarchical locations and categories with full term meta
  • Added front-end registration, login, dashboard and submission
  • Added faceted listings page and single landing page templates
  • Added JSON-LD schema graph, admin settings and theme template overrides

1.0.0

  • Initial release