=== Estasoft Name Catalog ===
Contributors: estasoft
Tags: names, directory, search, baby names, import
Requires at least: 5.8
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 2.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

A fast, searchable names directory for WordPress: bulk import, search, browse A-Z, and a name of the day.

== Description ==

Estasoft Name Catalog turns WordPress into a searchable names database - useful for baby names, place names, or any structured name collection. Add entries one at a time through a simple admin screen, or bulk-import thousands (or hundreds of thousands) at once from a CSV, JSON, or Excel file, with a guided wizard: drag a file in, map its columns, preview the first rows, then watch live progress with an estimated time remaining.

**Search and browse**, with AJAX filtering by gender and origin, A-Z navigation, and search that matches a name's meaning as well as its spelling. Kurdish Latin and Sorani (right-to-left) alphabets are supported natively.

**SEO built in.** Meta titles and descriptions (with a live Google-result preview), FAQPage and DefinedTerm structured data, Open Graph and Twitter cards, breadcrumbs, and automatic 301 redirects when a name or category is merged or removed - all independently toggleable, and all stepping aside automatically if Yoast, Rank Math, All in One SEO, or SEOPress is active.

**Visitor tools**, each its own shortcode and editor block: a personal "Namelist" visitors can save to and share, a name combination checker, a side-by-side comparison tool, a sibling-name generator, swipe-to-save discovery mode, a "name of the day," and a Root Dictionary linking names that share a linguistic root.

**Data quality tools** for admins: find duplicates, spot names missing key fields, and merge categories that drifted apart (like "Boy" and "Male") without creating duplicate taxonomy terms.

**Built for scale.** Imports and exports process in the background in batches, so even very large files never time out. An optional FULLTEXT search index and WP-CLI import support suit directories in the tens or hundreds of thousands of names. Every database query is prepared or goes through WP_Query, every admin action is nonce-verified and capability-checked, and all output is escaped at the point of use.

See the FAQ below for the full shortcode list with every available attribute, and for more on the SEO, security, and performance details.

== Installation ==

1. Upload the plugin files to `/wp-content/plugins/estasoft-name-catalog`, or install directly through the WordPress Plugins screen.
2. Activate the plugin through the "Plugins" screen.
3. Go to the new "Estasoft Name Catalog" menu in wp-admin and add your first name, or go to Estasoft Name Catalog > Import to bulk-upload a file.
4. Place any of the shortcodes above on a page or post.

== Screenshots ==

1. The admin "Getting Started" checklist, with one-click creation of the pages this plugin needs.
2. A guided import: drag a file in, map its columns, and preview the first rows before anything is written.
3. The live progress view during import, with an estimated time remaining and a line-by-line log.
4. A single name page, showing meaning, origin, pronunciation, and similar names.
5. The SEO settings tab, with a live preview of the Google result and social card.
6. The Settings screen's Display tab, for choosing grid or list layout, name cards, and more.

== Frequently Asked Questions ==

= What shortcodes are available, and what attributes does each take? =
* `[wpned_search]` - live search box with gender and origin filters (AJAX, no page reload). Matches a name's meaning as well as its title (searching "sun" finds a name meaning "sun, day" even if it isn't spelled that way). Attributes: `target` (CSS selector of a results container to update instead of its own - used to combine with an existing listing so there is only ever one results area on the page), `fixed_gender` / `fixed_origin` (lock the query to one taxonomy term and hide that dropdown - handy on a page that's already about one gender/origin), `columns` (1-6, default 3).
* `[wpned_az]` - A-Z browsing navigation. Attribute: `target` (same CSS selector as a `[wpned_search]` on the same page, so letter clicks and search/filter changes drive the exact same results instead of conflicting).
* `[wpned_of_day]` - a featured random name, refreshed once per day.
* `[wpned_popular gender="girl" count="5" title="Popular Girl Names"]` - a simple popularity list.
* `[wpned_ranked_list gender="boy" count="20" columns="3"]` - a "Top 20" style multi-column list with a save/favorite heart on each row.
* `[wpned_favorites columns="3"]` - shows the current visitor's saved names (stored in their browser, or synced to their account if logged in), with a "Print this list" and "Share my list" button. Put this on its own page (e.g. "My Namelist") and add that page to Appearance > Menus - no extra plugin setup needed.
* `[wpned_compare slots="3"]` - lets a visitor type/pick 2-3 existing names and see them compared side by side (meaning, gender, origin, pronunciation).
* `[wpned_sibling_generator columns="3"]` - pick one name, get suggestions that share its origin and/or gender - a "goes well with" tool that needs no extra data entry.
* `[wpned_random label="Show me a random name"]` - a button linking to one randomly chosen name, picked fresh each time the page renders, equally likely regardless of gaps in your database's ID numbering.
* `[wpned_roots orderby="name" limit="500" min_count="1"]` - the Root Dictionary: every linguistic root that names are built from, grouped alphabetically (or `orderby="count"` for most-used first), each linking to a page listing every name that shares it.
* `[wpned_swipe]` - shows one random name at a time; swipe right (or Save / right arrow) to add it to the visitor's Namelist, swipe left (Skip / left arrow) to move on. Options: `gender="boy"`, `origin="kurdish"`, `favorites_url="/my-list/"`.
* `[wpned_name_combo]` - lets a visitor type a first, optional middle, and last name and see the initials, a rough syllable count, the rhythm, and how the names hand off to each other. Worked out entirely in the browser; nothing is stored.

Every feature above is also available as an editor block (search the block inserter for the feature's name, such as "Name search" or "A-Z bar") and through the shortcode builder on the Getting Started page. Every name page also has social share buttons built in automatically (X, Facebook, WhatsApp, Pinterest, Telegram, Copy Link - choose which ones appear in Settings) - no shortcode needed.

= What does this plugin do for security and performance? =
* Every database query goes through `WP_Query` or a fully prepared statement - no raw, unescaped SQL.
* All admin form submissions and AJAX requests are nonce-verified and capability-checked.
* All output is escaped at the point of output; JSON-LD output is additionally hardened against a literal `</script>` in any field breaking out of the schema block.
* The Compare Names and Sibling Generator tools build their UI from raw JSON field values entirely through safe DOM methods (never innerHTML of untrusted text), so a name or meaning containing markup can never execute as code.
* Uploaded import files are stored under a randomized filename in a directory with directory-listing and direct-access blocked, and are deleted once the import completes.
* No content is deleted on uninstall unless you remove it yourself.
* Imports and exports process in small background batches, so files with hundreds of thousands of rows will not hit a server timeout.
* An optional FULLTEXT search index (Settings > Advanced) suits large directories (roughly 50,000+ names) by giving search a real MySQL index instead of pattern matching, which can't use one at all. Off by default; reversed automatically if the plugin is ever deleted.
* `wp wpned import <file>` (WP-CLI) reuses the same import logic as the browser importer, but processes a whole file in one pass - faster for a one-time bulk load than the browser importer, which is built for smaller day-to-day additions.

= Does this support multiple genders? =
The Gender taxonomy ships with "Boy" and "Girl" by default. You can rename or add terms under Estasoft Name Catalog > Gender at any time, since it's a standard WordPress taxonomy - and any new gender value in an imported file is created automatically.

= Can I change how a single name page, archive, or gender/origin page looks? =
Yes. Add a `single-wpned_name.php`, `archive-wpned_name.php`, or `taxonomy-wpned_gender.php` / `taxonomy-wpned_origin.php` file to your active theme and it will automatically override the plugin's default template.

= How do I add a "My Namelist" (favorites) link to my site's header menu? =
Create a new Page (e.g. titled "My Namelist"), add the `[wpned_favorites]` shortcode to it, publish it, then go to Appearance > Menus in wp-admin and add that Page to your navigation menu like any other page. No extra plugin configuration is needed - favorites are stored in each visitor's own browser, so the page just displays whatever they've saved.

= Does this conflict with Yoast/Rank Math/AIOSEO/SEOPress? =
No. This plugin detects whether one of those is active and lets it fully own the meta title and meta description (so you keep using that plugin's own editor UI for those). The structured data (JSON-LD) this plugin adds is separate and additive - it will not remove or duplicate anything those plugins generate on their own.

= I merged two categories / trashed a name - will old links to it break? =
Not if redirects are on (Settings > SEO, on by default). Merging two categories in Merge Terms 301-redirects the old category's page to the surviving one. For an individual name, open it, fill in "Redirect this name to" with the address of the page you want visitors sent to instead, then move the name to the Trash - the redirect activates as soon as it's trashed. Neither happens unless you set it up; nothing is redirected automatically just because a name is deleted.

= Should I turn on "hide thin pages from search engines"? =
It's off by default because it can remove a page search engines had already indexed. If your site has many categories or letters with only one or two names each, turning it on (Settings > SEO) can help by keeping those near-empty pages out of results until they have more content - search engines generally rank a site better when it isn't full of thin pages. If most of your categories are well populated, you likely don't need it.

= The content isn't lined up with my header/footer. =
The pages follow your theme's "wide" width by default. If your header uses a different width, set Estasoft Name Catalog > Settings > Maximum content width to match it. If the header or footer itself looks wrong on these pages, untick "Theme header & footer" in the same screen. Note that pages you build yourself with shortcodes take their width from your theme's normal page layout, not from this plugin.

= How do I translate the plugin into Kurdish (or anything else)? =
Install Loco Translate or Poedit and start from `languages/wpned.pot`. Sorani is locale `ckb` and Kurmanji is `kmr`; the files must be named `wpned-ckb.mo` / `wpned-kmr.mo` (Loco does this for you). Then set your site language under Settings > General, or use a multilingual plugin such as Polylang, WPML or TranslatePress.

First drafts of a few dozen short labels for both dialects are included as `wpned-ckb.po` and `wpned-kmr.po`. They are deliberately marked "fuzzy" - a draft by a non-native speaker - so WordPress ignores them until a native speaker reviews each one and clears the flag. Entries marked "LOW CONFIDENCE" need the closest look. Sentences were left blank rather than guessed. The plugin's on-page messages (search status, sharing, name checker) are translated too, since they come from the same files.

= How does sharing my list work, and is it private? =
The link contains only the IDs of the public names on your list, compressed into the address, so there is nothing to look up and nothing stored on the server. Anyone who has the link can see those names, and nothing else about you. Up to your 500 most recent names go into a link.

= The A-Z bar doesn't have Ç, Ş, Î... or my Sorani letters. =
Settings > Display > A-Z bar alphabet. Choose Kurdish Latin or Sorani. Names already stored as a plain letter followed by a separate accent mark may need re-importing (with "update existing names" ticked) so they sort under the right letter.

= My file says "Male" but my site uses "Boy". How do I avoid two categories? =
Add `Male = Boy` under Settings > Import. It applies to imports from then on. If both categories already exist, use Estasoft Name Catalog > Tools > Merge Terms to combine them.

= How do I show names as a table instead of cards? =
Estasoft Name Catalog > Settings > Display > Name list layout > List. It applies to every place names are listed. Switch back to Grid at any time; nothing about your names changes.

= Where do I create the Compare / My Namelist pages? =
Estasoft Name Catalog > Getting Started creates them for you in one click. It only creates pages that don't exist yet.

= How do I show the meaning on each name card? =
Estasoft Name Catalog > Settings > Display > Name cards > Detailed. It shows gender, origin and a short meaning under each name. Detailed cards suit 2-4 columns better than 5-6.

= Do saved names really sync between my devices? =
For visitors who are logged in, yes: their list is stored on their account and merged whenever they load a page. Each device remembers what it last synced, so additions and removals both carry over. Visitors who are not logged in keep a browser-only list, and when they later log in, what they saved is added to their account rather than lost.

= Will choosing "Update existing" or "Skip existing" make an import slower? =
Somewhat: each row needs one lookup to see whether that name already exists. "Create new" (the default) skips that lookup entirely. Matching is by exact name, and whether "Welat" and "welat" count as the same follows your database's collation (the WordPress default treats them as the same).

= My file's columns aren't named exactly "name", "gender", etc. - do I need to rename them? =
No. After choosing a file, a mapping step lets you match each of your file's columns to the right field (so a column called "Full Name" can be mapped to "name", for instance). Your file itself is never changed. Only "name" needs to be mapped before you can continue; anything left unmapped is simply not imported.

= Where do I find out which rows failed during an import? =
Once the import finishes, if anything was skipped, a "Download error log" link appears with the result. It lists the specific row number and reason for every skipped row (a missing name, or "already exists" when Skip existing is chosen, for example) - not just a count.

= Will this work with 500,000+ names? =
Yes. Bulk import is processed in small batches with a file-offset cursor, so memory use stays flat regardless of file size - or use `wp wpned import <file>` via WP-CLI for a one-time full-dataset load, which is faster than the browser importer. The "similar names" feature queries a bounded candidate pool per lookup and caches results. Once your directory is large, turning on the optional FULLTEXT search index (Estasoft Name Catalog > Settings) keeps the search box fast; for extremely high-traffic sites at that scale, also consider adding an object cache (e.g. Redis).

= Is the FULLTEXT search index safe to turn on? =
Yes - it only adds a standard MySQL search index to the post title column, the same kind of index countless WordPress plugins add for their own purposes. It's off by default (you choose when to enable it, typically once your directory is large enough to benefit), and one click reverses it completely with no other effect on your site. It's also automatically reversed if you delete the plugin entirely.

== External services ==

This plugin does not contact any external service by itself. It makes no outbound requests from your server, and nothing is sent anywhere when a page loads.

The only links to outside services are the optional social share buttons on each name page. You choose which ones appear (or turn them all off) under Settings > Sharing. Each is an ordinary link that does nothing until a visitor clicks it. When clicked, it opens that service in the visitor's own browser and hands it two things so the service can pre-fill a post: the name page's web address, and the short text "Check out the name" followed by the name. No other data from your site or from the visitor is sent by this plugin. What the service then does with that information is governed by its own terms and privacy policy:

* X (formerly Twitter), `twitter.com/intent/tweet` - receives the page address and share text. [Terms of Service](https://x.com/en/tos) - [Privacy Policy](https://x.com/en/privacy)
* Facebook, `facebook.com/sharer/sharer.php` - receives the page address. [Terms](https://www.facebook.com/terms.php) - [Privacy Policy](https://www.facebook.com/privacy/policy/)
* WhatsApp, `api.whatsapp.com/send` - receives the share text and page address. [Terms of Service](https://www.whatsapp.com/legal/terms-of-service) - [Privacy Policy](https://www.whatsapp.com/legal/privacy-policy)
* Pinterest, `pinterest.com/pin/create/button/` - receives the page address and share text. [Terms of Service](https://policy.pinterest.com/en/terms-of-service) - [Privacy Policy](https://policy.pinterest.com/en/privacy-policy)
* Telegram, `t.me/share/url` - receives the page address and share text. [Terms of Service](https://telegram.org/tos) - [Privacy Policy](https://telegram.org/privacy)

The "Copy Link" button does not use any external service; it copies the page address to the visitor's own clipboard.

== Changelog ==

= 2.1.0 =
* Changed: the plugin is now "Estasoft Name Catalog" (slug `estasoft-name-catalog`), following WordPress.org plugin-review feedback that the previous name was too close to an existing trademark and plugin. The admin menu and every in-app label use the new name.
* Changed: import file uploads now go through WordPress's own upload handler, `wp_handle_upload()`, instead of PHP's `move_uploaded_file()` directly.
* Security: the JSON-LD structured data printed in page HTML is now encoded with the full set of HTML-safe JSON flags. The previous safeguard neutralized only a literal closing script tag, not other markup that could appear in a name or meaning. JSON exports use standard JSON escaping and are sent with a `nosniff` header.
* Added: an "External services" section documenting the optional share buttons, with each service's terms and privacy links. The plugin itself makes no outbound requests.
* Removed: bundled translation drafts - WordPress.org supplies translations through translate.wordpress.org. The `.pot` template stays.
* Fixed: the readme's Contributors entry now matches the WordPress.org account that owns the plugin.
* Fixed: CSV and JSON import files that begin with a UTF-8 byte-order mark - which Excel's "CSV UTF-8" option adds, and which the plugin's own downloadable sample file carries - are now read correctly. Previously the first column name did not match "name", so such a file could not be imported without manual remapping.
* Security: the CSV export now guards against spreadsheet formula injection. A name or meaning beginning with =, +, - or @ is exported with a leading apostrophe so Excel and Sheets treat it as text instead of running it, and the importer removes the apostrophe again so an export re-imports exactly as exported.
* Security: output is now escaped at the moment it is printed, everywhere. The name grids, cards, table and breadcrumbs pass through a strict `wp_kses()` allow-list of exactly the tags the plugin emits; the structured data uses WordPress's own `wp_print_inline_script_tag()`; the accent and heading colors must be real hex colors before they reach the stylesheet; and file downloads (CSV, JSON, Excel) are streamed instead of echoed. No visible change to any page.
* Changed: file removal now uses WordPress's `wp_delete_file()`, and the sample JSON download uses standard JSON escaping (non-Latin text appears as \uXXXX codes that every JSON reader, including this plugin's importer, decodes to the same letters).
* Fixed: a debug-mode notice on the hidden Duplicates, Data Quality and Merge Terms admin pages (a missing page title).

= 2.0.0 =
* Changed: the plugin's formal name is now "Name Engine Directory" and its slug/text domain is now `name-engine-directory` - WordPress.org does not permit a plugin name or slug to begin with "WP". The WPNED brand, logo, and every in-app label (the admin menu, page titles, etc.) are unchanged; only the formal listing identity and the folder/file name moved.
* Fixed: the plugin's own bootstrap class and boot function had kept their very first internal name since well before the WPNED rename and were never actually updated - fixed, with no effect on how the plugin runs.
* Fixed: a handful of internal helper names that should have been plugin-prefixed (or made non-global) were not; corrected, each verified to have no effect on behavior.
* Changed: `mt_rand()` replaced with `wp_rand()` in the swipe-mode name picker, per WordPress's own guidance.
* Removed: the manual `load_plugin_textdomain()` call - redundant since WordPress.org has loaded this plugin's translations automatically since WP 4.6.
* Changed: the readme's Description section is now a concise overview (WordPress.org truncates anything past 2,500 characters); the full shortcode reference and the security/performance details that used to live there are now their own FAQ entries, so no information was lost.
* Passed a full review against the WordPress Plugin Check tool's Plugin Repo category: every flagged line was individually checked against the actual code, confirmed safe, and annotated with the reasoning (not silently suppressed).

= 1.16.1 =
* Fixed: removed the Plugin URI header, which was identical to the Author URI - the WordPress.org plugin directory requires these two to be different (or only one provided).

= 1.16.0 =
* Changed: the default accent color is now this plugin's own teal (#00bcd4) instead of the previous purple.
* New: a separate heading color (Settings > Branding), defaulting to #292929, for name and category page titles - independent of the accent color used for buttons and links. In dark mode, a very dark heading color automatically falls back to a readable light tone rather than disappearing against a dark background; a lighter custom choice is always respected as-is.

= 1.15.0 =
* Changed: the admin menu is more focused - Duplicates, Data Quality, and Merge Terms are now reached through a single "Tools" area (which also shows what was "Diagnostics") instead of four separate sidebar entries. Each one still works exactly as before, including for anyone with a bookmarked link; a shared strip of tabs ties them together, and only shows tabs the current user actually has permission to open.
* Security: completed a full review against every major category (SQL injection, output escaping, CSRF/nonce coverage, capability checks, path traversal, and more) - no issues found; see the plugin's documentation for the specifics checked.
* Housekeeping: readme brought in line with the WordPress.org plugin directory format - added the missing Screenshots section, shortened the description to fit the required length, and updated the tested-up-to version.

= 1.14.0 =
* Plugin renamed to WPNED - Name Engine Directory (folder, text domain, every internal identifier, and the admin UI all updated together).
* New: a proper brand icon - the WordPress admin menu now shows the plugin's own icon instead of a generic dashicon, and the Getting Started page shows the full logo.

= 1.13.0 =
* New: drag-and-drop file upload on the Import Names page, with client-side checks against the file types and size the server will actually accept.
* New: "Download a sample file" (CSV, Excel, JSON) showing the exact expected format with example rows.
* New: a column-mapping step - a file whose headers don't exactly match (e.g. "Full Name" instead of "name") can now be mapped instead of rejected.
* New: a dry-run preview of the first 5 rows before anything is written, flagging a missing name, a duplicate within the file, or a name that already exists.
* New: live progress now includes an estimated time remaining and an expandable log of each batch.
* New: a downloadable error log with a specific reason for every skipped row.
* Changed: "Update existing names" is now three choices - Create new, Update existing, or Skip existing - instead of one on/off checkbox. Existing integrations passing `true`/`false` continue to work unchanged.
* New: import batch size is configurable in Settings > Import (10-1000, default 200).
* Changed: the "Undo last import" confirmation now states the exact date, time, and count of the import it is about to undo.

= 1.12.0 =
* New: Google Search Console and Bing Webmaster Tools verification fields (Settings > SEO) - paste the code, or the whole tag, either works.
* New: optional title and description templates for category pages (gender/origin/root, shared across all three, with `{term}`/`{count}`) and for the main browse page (`{count}`). Empty by default, so nothing changes until you fill them in.
* New: a live Google-result and social-card preview on the SEO tab, updating as you type.
* Changed: "Structured data (schema)" is now two independent switches - name-page schema and breadcrumb schema - so one can be turned off without the other. A site that had the old combined switch off keeps both new switches off automatically; nothing is silently re-enabled.
* New: redirects. Merging two categories in Merge Terms can 301 the old category's page to the surviving one. A "Redirect this name to" field on the name edit screen activates a 301 when that name is trashed. Both are on by default and can be turned off in Settings > SEO.
* New: an optional "hide thin pages from search engines" setting - noindexes a category, browse, or letter-filtered page once it has fewer than a configurable number of names. Off by default.

= 1.11.2 =
* Plugin renamed to WP Name Directory Engine.

= 1.11.1 =
* Removed: the pronunciation audio field and Listen button added in 1.11.0, including the `audio_url` import/export column. The ordinary text Pronunciation field is unchanged. Any recording links already saved on names are left in the database, unused.

= 1.11.0 =
* New: Data Quality page and filtered Names list (missing meaning, gender, origin, pronunciation, root).
* New: Swipe mode shortcode `[wpned_swipe]`.
* New: "New in this version - and where to find it" box on the Getting Started page.
* New: Shortcode builder (Getting Started page) and one editor block per shortcode, generated from a single registry.
* New: Undo last import (moves the names it created to the Trash; batched; one file, no per-name database rows).
* Changed: version bumped so browsers and cache plugins fetch the new scripts and styles (this is why earlier 1.10.0 features could look missing).

= 1.10.0 =
* New: A-Z bar alphabet setting with Kurdish Latin (Hawar) and Sorani presets; exact letter matching for the Kurdish options; Arabic-keyboard variants (ك ي ه) grouped under the matching Sorani letter. The default alphabet behaves exactly as before.
* New: imported names are normalized to one Unicode form (works without PHP's intl extension); optional Romanian S-comma to Kurdish S-cedilla correction with the Kurdish Latin preset.
* New: import value aliases (Settings > Import) and a Merge Terms tool.
* New: Open Graph and Twitter tags for name, browse and category pages, with a Settings switch and default-image field.
* New: translation template (`languages/wpned.pot`, all 409 strings) plus first drafts for Sorani (`ckb`) and Kurmanji (`kmr`). The drafts are short visitor-facing labels only, are marked fuzzy so WordPress does not use them, and need a native speaker's review before use.
* Fixed: four messages in the front-end script were hard-coded in English and could not be translated ("Namelist full", the generic error, the empty-list message, and the compare hint).
* New: name combination checker shortcode `[wpned_name_combo]`, also on the Getting Started page.
* New: Share my list - a link that shows a partner which names you both like. Nothing is stored server-side; shared links are noindex.
* Fixed: the favorites Print button is now really hidden until there is a list (the stylesheet's !important display rule used to override the inline hiding).
* Fixed: the favorites list no longer loads twice if the page's scripts initialise twice.
* New: breadcrumbs on browse and category pages, and BreadcrumbList structured data on every page that shows a trail.
* Changed: text alignment uses direction-aware values; the search and suggestion fields set their own direction from what is typed.
* Changed: the letter filter is validated and applied in one place instead of three (and two copies of the same query).

= 1.9.0 =
* New: Name list layout setting (Grid or List). The List layout is a branded table with Save, Name, Gender, Origin and Meaning columns, hover highlighting, muted dashes for missing values, stacked rows on phones, and real table headers for screen readers. Existing sites keep the Grid.

= 1.8.0 =
* New: Getting Started screen with one-click, duplicate-safe page creation.
* New: search result count, removable filter chips, "Clear all", and an empty-state message.
* New: optional detailed name cards (gender, origin, short meaning), with the extra data fetched in two batched queries per list rather than per card.
* New: keyboard-accessible suggestion lists (arrow keys, Enter, Escape, Tab) with screen-reader announcements.
* New: Settings organised in tabs over a single form.
* Changed: buttons and text fields share one consistent shape, size, and visible focus outline. Load more and Print are now pill-shaped like the other buttons, and the search fields use the plugin's font.
* Removed: the column "View" switcher added in 1.7.0. Columns can still be set to 1-6 in Settings and on the shortcodes.
* Fixed: a slow suggestion response could re-open a list the visitor had just dismissed.

= 1.7.0 =
* New: pages use the theme's wide width (or 1280px, or a width you set) instead of a fixed narrow column, so they can line up with the site header and footer. Body text stays at a readable line length.
* New: on block themes, these pages show the theme's real header and footer instead of WordPress's plain fallback (with a Settings switch and a filter to turn it off).
* New: grids support up to 6 columns, and a "View" switcher (2-6, remembered per visitor) on the browse pages, also available as `[wpned_view_switcher]`.
* Fixed: on tablets, a single search result no longer sits in half a row.
* Fixed: the single name page no longer applies its own separate narrow width on top of the page container.

= 1.6.0 =
* New: Namelist follows a logged-in visitor's account across devices, with additions and removals both syncing (guests unchanged, and make no extra requests).
* New: Roots - a new taxonomy, a `root` import/export column, links and a "names built from the same root" section on each name's page, a page per root, a `[wpned_roots]` dictionary shortcode, and a root question in the FAQ structured data.
* New: `[wpned_random]` shortcode.
* New: Duplicates tool, importer/WP-CLI update mode, and a Diagnostics page.
* New: right-to-left text (e.g. Arabic-script spellings) now displays with the correct direction per item, even in a list that mixes scripts.
* Fixed: on a root/gender/origin page, the live search is now scoped to that page's own taxonomy; the list of browsable taxonomies is defined in one place instead of six.
* Fixed: a plugin update that adds new page types (like roots) now refreshes WordPress's URL rules automatically - no need to re-save Permalinks.

= 1.5.0 =
* New: SEO meta title/description and structured data (schema) can now be turned on or off independently, instead of being bundled together.
* New: customizable title template with `{name}`, `{meaning}`, `{gender}`, `{origin}`, and `{site_name}` placeholders.
* New: choose which social share buttons appear (added Pinterest and Telegram options alongside the existing X/Facebook/WhatsApp/Copy Link).
* New: primary accent color picker, replacing the default purple throughout the front end (a matching hover shade is derived automatically).
* New: customizable "Add to my Namelist" / "Added to my Namelist" button wording.
* New: view-tracking on/off switch, and a configurable cap on how many names a visitor can save at once.
* New: Advanced section in Settings - one-click cache clearing (featured name + similar-names caches) and a reset-to-defaults safety net.
* Fixed: the favorites-cap-reached message is now visible on every favorite button, including the grid/archive heart buttons (their label is screen-reader-only, so a text-only message there would have been invisible to sighted visitors) - it now uses a visual flash that works everywhere.

= 1.4.0 =
* New: Settings screen (Estasoft Name Catalog > Settings) - results per page, default sort order, and default grid columns are now configurable instead of hardcoded. Fixed a related inconsistency: the archive/gender/origin pages' first paint used to follow WordPress's unrelated "Blog pages show at most" Reading Setting instead of this plugin's own page-size setting.
* New: Export tool (Estasoft Name Catalog > Export) - download every name as CSV or JSON, streamed in batches so it stays safe at very large directory sizes.
* New: quick "Set Gender" bulk actions in the admin Names list.
* New: automatic view tracking per name (debounced, excludes the site owner's own views), a sortable Views admin column, and `?wpned_orderby=views` alongside the existing manual popularity rank.
* New: `wp wpned import <file>` WP-CLI command for fast, one-pass imports of a full dataset - reuses the exact same row-import logic as the browser importer.
* New: optional MySQL FULLTEXT search index (Settings screen) for large directories, with an automatic, safe fallback to the existing search behavior for search terms too short to be indexed. Off by default; fully reversible; automatically reversed on uninstall.

= 1.3.2 =
* Fixed the admin Names list: the "Meaning" column was inserted before Gender/Origin instead of after, so on narrower admin windows the two most scannable columns could get pushed off-screen. Meaning now appears after Gender/Origin, right before Date.
* Improved wording: a name with no popularity rank set no longer shows two separate "not ranked" sentences back to back - now shows one clean sentence.
* Added a real animated loading indicator to search, browse, and Sibling Generator results (previously just dimmed the content, with no other feedback).
* Compare Names now shows "Pick at least one more name" instead of a blank area when only one name has been picked so far.

= 1.3.1 =
* Fixed a real bug in Compare Names: clearing a picked name's input field didn't actually remove it from the comparison table - it now does.
* Accessibility: share links now announce "(opens in a new window)" to screen readers; the Compare table's row labels are now properly marked as row headers.
* Added short instructional text to Compare Names and the Sibling Generator so first-time visitors know what to do before they start typing.
* Audited the full plugin for dark-mode consistency, shortcode/documentation accuracy, and AJAX action-name collisions - none found beyond the one real bug above.

= 1.3.0 =
* New: `[wpned_compare]` - compare 2-3 names side by side (meaning, gender, origin, pronunciation).
* New: `[wpned_sibling_generator]` - suggests names that share a picked name's origin and/or gender.
* New: search now matches a name's meaning as well as its title, not just literal spelling.
* New: social share buttons (X, Facebook, WhatsApp, copy-link) on every name page.
* New: "Print this list" button on the favorites page, with clean print-only styling (no header/footer/buttons in the printed output).

= 1.2.0 =
* New: automatic SEO meta title and meta description on every name, gender, origin, and archive page (steps aside automatically if Yoast/Rank Math/AIOSEO/SEOPress is active).
* New: FAQPage + DefinedTerm JSON-LD structured data on every name page, built from the same meaning/spellings/popularity content already shown, eligible for Google rich results.
* New: canonical URLs strip the plugin's own filter query args (`wpned_letter`, `wpned_orderby`) so filtered views never read as duplicate content.
* New: defensive (additive-only) safeguard keeping the Name post type and Gender/Origin taxonomies in WordPress's core XML sitemap.

= 1.1.3 =
* Fixed a real duplicate-results bug: the archive/gender/origin pages used to show a separate live-search results panel above a separate static "browse all" listing, so the same name could appear twice and letter/search filters could contradict each other. There is now exactly one results area per page; search text, gender/origin, A-Z letter, and sort order all combine into that same view.
* Added a "Load more" control to that unified results area so large result sets stay reachable (real paginated URLs still exist too, for no-JS visitors and search engines).
* New `[wpned_favorites]` shortcode - a page showing the visitor's saved names, so you can add a "My Namelist" link to your header menu (see FAQ).
* New `target`, `fixed_gender`, `fixed_origin`, and `columns` attributes on `[wpned_search]` and `[wpned_az]` for building custom unified browse pages.
* Hardened the front-end JS against double-initialization (defensive fix - protects against duplicate event bindings if a script is ever enqueued twice).
* Removed unused CSS left over from the retired dual-results design.

= 1.1.2 =
* Fixed the ranked-list grid always reserving the requested number of columns even when there weren't enough results to fill them, leaving lone results floating next to empty space. The grid now never shows more columns than there are actual names to display.

= 1.1.1 =
* Fixed ranked-list styling not overriding some themes' default link/text styles (added defensive !important rules consistent with the rest of the plugin's front-end CSS).
* Removed the rank number from the ranked-list rows; it now shows just the name and the favorite heart.
* Fixed popularity sorting (?wpned_orderby=popularity) silently excluding any name with no popularity rank set.
* Fixed the A-Z letter filter leaking into unrelated queries on the same page load.
* Fixed pagination losing the active letter/popularity filter when moving between pages.
* Hardened text-truncation helpers against hosts without the mbstring PHP extension.

= 1.1.0 =
* Bulk import from CSV, JSON, and Excel (.xlsx) files, processed in the background in batches.
* Professional redesign of the single name page, archive, and gender/origin pages.
* Dynamic "similar names" and "how popular is this name" sections.
* Plugin renamed to Name Directory Platform; developed by ESTASOFT TECHNOLOGIES.

= 1.0.0 =
* Initial release.
