{"id":313747,"date":"2026-05-29T13:42:49","date_gmt":"2026-05-29T13:42:49","guid":{"rendered":"https:\/\/ja.wordpress.org\/plugins\/cf7-lead-desk\/"},"modified":"2026-08-26T08:32:47","modified_gmt":"2026-08-26T08:32:47","slug":"neutrope-lead-desk-for-contact-form-7","status":"publish","type":"plugin","link":"https:\/\/ro.wordpress.org\/plugins\/neutrope-lead-desk-for-contact-form-7\/","author":23488465,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.3.0","stable_tag":"0.3.0","tested":"7.1","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"Neutrope Lead Desk for Contact Form 7","header_author":"Neutrope Inc.","header_description":"Save Contact Form 7 submissions to the database and manage them as leads in the WordPress admin (list, detail, status, notes, CSV export).","assets_banners_color":"37261b","last_updated":"2026-08-26 08:32:47","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/neutrope.biz\/neutrope-lead-desk-for-contact-form-7\/","header_author_uri":"https:\/\/neutrope.biz","rating":0,"author_block_rating":0,"active_installs":0,"downloads":320,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.1.0":{"tag":"0.1.0","author":"neutropeinc","date":"2026-05-29 13:42:12"},"0.1.1":{"tag":"0.1.1","author":"neutropeinc","date":"2026-05-30 14:08:38"},"0.1.2":{"tag":"0.1.2","author":"neutropeinc","date":"2026-05-30 15:28:40"},"0.1.3":{"tag":"0.1.3","author":"neutropeinc","date":"2026-06-01 06:46:20"},"0.1.5":{"tag":"0.1.5","author":"neutropeinc","date":"2026-08-25 08:05:43"},"0.2.0":{"tag":"0.2.0","author":"neutropeinc","date":"2026-08-26 01:26:18"},"0.3.0":{"tag":"0.3.0","author":"neutropeinc","date":"2026-08-26 08:32:47"}},"upgrade_notice":{"0.3.0":"<p>Adds a documented extension foundation for add-ons, plus two small Activity-history wording fixes. Your leads, notes, activity and database schema are unchanged, and no migration runs. With no add-on installed the plugin behaves exactly as before.<\/p>","0.2.0":"<p>Adds a per-entry activity history. Existing entries have their received time and existing notes reconstructed in the background; status, trash, and spam changes made before this update were never recorded and are not invented. Existing lead data is preserved.<\/p>","0.1.5":"<p>Adds a Trash view with per-row and bulk Restore, so an accidental Trash click is undoable from the admin. No database, settings, or URL changes.<\/p>","0.1.4":"<p>Fixes the row-level &quot;Trash&quot; link on the entries list, which could silently do nothing. No data, settings, or URL changes.<\/p>","0.1.3":"<p>Detail screen now shows the &quot;Status updated.&quot; \/ &quot;Note added.&quot; flash notice (regression from v0.1.1 menu move; v0.1.2 fixed the equivalent for Settings). No data, option, or URL changes.<\/p>","0.1.2":"<p>Fixes the missing &quot;Settings saved.&quot; confirmation on the Settings page. No data or URL changes.<\/p>","0.1.1":"<p>Menu moved under Contact Form 7 (&quot;\u304a\u554f\u3044\u5408\u308f\u305b&quot;). No data, settings, or URLs change.<\/p>","0.1.0":"<p>First public release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3553617,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3553617,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3664838,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3664838,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.1.0","0.1.1","0.1.2","0.1.3","0.1.5","0.2.0","0.3.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3553617,"resolution":"1","location":"assets","locale":"","width":1440,"height":1100},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3553617,"resolution":"2","location":"assets","locale":"","width":1440,"height":1100},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3553617,"resolution":"3","location":"assets","locale":"","width":1440,"height":1100},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3553617,"resolution":"4","location":"assets","locale":"","width":1440,"height":1100},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3553617,"resolution":"5","location":"assets","locale":"","width":1440,"height":1100}},"screenshots":{"1":"Entry list with summary cards, filters, and bulk actions.","2":"Detail view: submission fields, status management, internal notes.","3":"Settings page: field mapping, capture toggles, uninstall behaviour.","4":"CSV export form.","5":"Help screen."}},"plugin_section":[],"plugin_tags":[5445,1152,36677,14097,335],"plugin_category":[42],"plugin_contributors":[264944],"plugin_business_model":[],"class_list":["post-313747","plugin","type-plugin","status-publish","hentry","plugin_tags-cf7","plugin_tags-contact-form-7","plugin_tags-inquiries","plugin_tags-lead-management","plugin_tags-leads","plugin_category-contact-forms","plugin_contributors-neutropeinc","plugin_committers-neutropeinc"],"banners":{"banner":"https:\/\/ps.w.org\/neutrope-lead-desk-for-contact-form-7\/assets\/banner-772x250.png?rev=3664838","banner_2x":"https:\/\/ps.w.org\/neutrope-lead-desk-for-contact-form-7\/assets\/banner-1544x500.png?rev=3664838","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/neutrope-lead-desk-for-contact-form-7\/assets\/icon-128x128.png?rev=3553617","icon_2x":"https:\/\/ps.w.org\/neutrope-lead-desk-for-contact-form-7\/assets\/icon-256x256.png?rev=3553617","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/neutrope-lead-desk-for-contact-form-7\/assets\/screenshot-1.png?rev=3553617","caption":"Entry list with summary cards, filters, and bulk actions."},{"src":"https:\/\/ps.w.org\/neutrope-lead-desk-for-contact-form-7\/assets\/screenshot-2.png?rev=3553617","caption":"Detail view: submission fields, status management, internal notes."},{"src":"https:\/\/ps.w.org\/neutrope-lead-desk-for-contact-form-7\/assets\/screenshot-3.png?rev=3553617","caption":"Settings page: field mapping, capture toggles, uninstall behaviour."},{"src":"https:\/\/ps.w.org\/neutrope-lead-desk-for-contact-form-7\/assets\/screenshot-4.png?rev=3553617","caption":"CSV export form."},{"src":"https:\/\/ps.w.org\/neutrope-lead-desk-for-contact-form-7\/assets\/screenshot-5.png?rev=3553617","caption":"Help screen."}],"raw_content":"<!--section=description-->\n<p>Neutrope Lead Desk for Contact Form 7 captures every Contact Form 7 submission into a dedicated database table and provides a simple WordPress admin interface for managing those submissions as leads.<\/p>\n\n<p>The free version is intentionally focused: it saves submissions reliably, gives you an admin list\/detail UI, lets you change status, add internal notes, and export to CSV. It does this without pulling in external services, trackers, or upsell banners on unrelated screens.<\/p>\n\n<p>Version 0.3.0 is mainly a foundation release for add-ons: it adds documented, generic extension points so other plugins can add columns, filters and detail-screen panels without forking this one. Nothing in the plugin's own behaviour changes because of them, and no database change is involved. See \"Extending the plugin\" below.<\/p>\n\n<p>Since 0.2.0 each entry also keeps an <strong>Activity Timeline<\/strong> (\u5bfe\u5fdc\u5c65\u6b74) so you can see what has already been done about an inquiry -- when it arrived, who changed its status and to what, when notes were added, and when it was moved to trash, restored, or marked as spam -- instead of inferring the handling history from the current status alone.<\/p>\n\n<p><strong>Key features<\/strong><\/p>\n\n<ul>\n<li>Automatic capture of every Contact Form 7 submission into a dedicated table (<code>{prefix}nldcf7_entries<\/code>)<\/li>\n<li>The full submission payload is always stored as JSON, so nothing you asked users to type is lost<\/li>\n<li>Mapped columns for name, email, phone, and company are extracted automatically using a configurable candidate list<\/li>\n<li>Admin list screen with filtering by keyword, status, form, and date range, plus bulk actions (status change, trash, mark spam)<\/li>\n<li>Trash is reversible: trashed entries stay in the database behind a Trash view with per-row and bulk Restore, so a mis-click is undone from the admin instead of from SQL<\/li>\n<li>Detail screen with all submitted fields, submission metadata, status management, and internal team notes<\/li>\n<li>Per-entry Activity Timeline on the detail screen, recording when the entry was received, every status change (from which status to which), internal-note activity, Trash and Restore, and spam-state changes -- each with the acting user and a timestamp, newest first, paginated 50 events at a time<\/li>\n<li>For entries captured before 0.2.0, the timeline is reconstructed from what the database actually recorded: the original received timestamp and your existing internal notes. Status, trash, and spam changes made before the upgrade were never stored anywhere, so they are not invented -- the timeline says so plainly rather than guessing<\/li>\n<li>Your existing notes remain the authoritative record. The timeline links to them; it does not replace, rewrite, or duplicate them<\/li>\n<li>CSV export (UTF-8 with BOM, CRLF) with date\/status\/form\/spam filters \u2014 streamed in chunks for large datasets<\/li>\n<li>Attachment metadata capture (file name, MIME type, size). The files themselves remain with Contact Form 7's default handling<\/li>\n<li>Privacy-friendly defaults: IP capture is OFF by default<\/li>\n<li>Opt-in data deletion on uninstall (off by default so accidental deletes don't nuke your leads)<\/li>\n<li>Extensibility via action\/filter hooks: <code>nldcf7_after_entry_saved<\/code>, <code>nldcf7_after_note_added<\/code>, <code>nldcf7_after_status_changed<\/code>, <code>nldcf7_after_entry_trashed<\/code>, <code>nldcf7_after_entry_restored<\/code>, <code>nldcf7_after_spam_changed<\/code>, <code>nldcf7_entry_data_before_insert<\/code>, <code>nldcf7_export_columns<\/code>, <code>nldcf7_export_row<\/code>, <code>nldcf7_statuses<\/code>, <code>nldcf7_event_labels<\/code>, <code>nldcf7_event_render<\/code>, <code>nldcf7_required_capability<\/code><\/li>\n<li>Since 0.3.0, nine further extension points let an add-on place panels on the entry detail screen, add list columns and filter controls, keep its own filter state across list actions, and constrain the entries query -- all documented under \"Extending the plugin\"<\/li>\n<\/ul>\n\n<p><strong>Requirements<\/strong><\/p>\n\n<ul>\n<li>WordPress 6.0 or later<\/li>\n<li>PHP 7.4 or later<\/li>\n<li>Contact Form 7 plugin installed and active<\/li>\n<\/ul>\n\n<p><strong>Does NOT include (outside the scope of the free version)<\/strong><\/p>\n\n<ul>\n<li>Sending external notifications (Slack, Chatwork, email digests)<\/li>\n<li>Assignee \/ team routing<\/li>\n<li>Auto-follow-up reminders<\/li>\n<li>Analytics dashboards and reports beyond simple counters<\/li>\n<li>Storing actual uploaded file contents (only metadata is captured)<\/li>\n<\/ul>\n\n<p>These may be considered for a future Pro release. The free plugin is designed to be fully useful on its own.<\/p>\n\n<h3>Extending the plugin<\/h3>\n\n<p>Version 0.3.0 adds nine extension points for add-on developers. They are\ngeneric: this plugin knows nothing about what an add-on stores. All of them are\nno-ops when nothing is listening, so a site with no add-on behaves exactly as\nit did in 0.2.0.<\/p>\n\n<h4>nldcf7_entry_detail_main<\/h4>\n\n<p>Action. Introduced in 0.3.0. Fires on the entry detail screen after this\nplugin's own cards in the main column, before the column closes.<\/p>\n\n<pre><code>do_action( 'nldcf7_entry_detail_main', array $entry )\n\n$entry is the entry row as stored, passed by value. The listener prints its\n<\/code><\/pre>\n\n<p>own markup, including its own card wrapper, and is responsible for escaping it.\nOutput is not buffered or altered.<\/p>\n\n<h4>nldcf7_entry_detail_sidebar<\/h4>\n\n<p>Action. Introduced in 0.3.0. The same contract, for the sidebar column. Two\nhooks exist so an add-on can place content in both columns of one screen.<\/p>\n\n<pre><code>do_action( 'nldcf7_entry_detail_sidebar', array $entry )\n<\/code><\/pre>\n\n<h4>nldcf7_entry_list_columns<\/h4>\n\n<p>Filter. Introduced in 0.3.0. Adds columns to the entries list.<\/p>\n\n<pre><code>apply_filters( 'nldcf7_entry_list_columns', array $columns )\n<\/code><\/pre>\n\n<p>Return the column map with your own keys appended; prefix them to avoid\ncollisions. Core columns cannot be removed, renamed or repurposed -- every core\nkey is restored to its own label after the filter runs, and the checkbox column\nis forced back to the front. Labels are plain text and are escaped on output.<\/p>\n\n<h4>nldcf7_entry_list_column_content<\/h4>\n\n<p>Filter. Introduced in 0.3.0. Renders a cell for a column you added.<\/p>\n\n<pre><code>apply_filters( 'nldcf7_entry_list_column_content', string $html, string $column_name, array $item )\n<\/code><\/pre>\n\n<p>Return HTML for your own column, or the value you were given for anything else.\nEscape your own output; the plugin then passes the result through\n    wp_kses_post() as a second layer, so ordinary post markup survives while\nscripts and event handlers do not. A non-string return renders an empty cell.<\/p>\n\n<h4>nldcf7_entry_list_filters<\/h4>\n\n<p>Action. Introduced in 0.3.0. Fires inside the list's existing GET filter form,\nbefore the Filter button, so a plain select or input submits alongside the\nbuilt-in filters.<\/p>\n\n<pre><code>do_action( 'nldcf7_entry_list_filters', array $current_args )\n\n$current_args is this plugin's own sanitized filter state, for reference. You\n<\/code><\/pre>\n\n<p>own your field names, your values and your escaping. No nonce is involved: the\nfilter bar only reads.<\/p>\n\n<h4>nldcf7_entry_list_carried_args<\/h4>\n\n<p>Filter. Introduced in 0.3.0. Keeps your own filter state across the All and\nTrash views, the row actions, and the redirect after a row or bulk action.<\/p>\n\n<pre><code>apply_filters( 'nldcf7_entry_list_carried_args', array $args, array $core )\n<\/code><\/pre>\n\n<p>Add your own already-sanitized scalar values. The plugin re-checks the result\nafterwards: reserved keys (<code>page<\/code>, <code>paged<\/code>, <code>action<\/code>, <code>action2<\/code>, <code>entry_id<\/code>,\n    _wpnonce, <code>_wp_http_referer<\/code>, <code>view<\/code>, <code>event_page<\/code>, <code>status_view<\/code>) are\nstripped, keys are normalised, non-scalars are dropped, and both value length\nand argument count are capped. Core values always win. Do not attempt to\nforward the whole query string.<\/p>\n\n<h4>nldcf7_entry_query_args<\/h4>\n\n<p>Filter. Introduced in 0.3.0. Adjusts the entries query using arguments the\nrepository already understands, without writing SQL.<\/p>\n\n<pre><code>apply_filters( 'nldcf7_entry_query_args', array $args )\n<\/code><\/pre>\n\n<p>The most useful is <code>ids<\/code>, an array of entry IDs to restrict the query to.\n    $args['context'] says who is asking: <code>list<\/code> for the entries screen, <code>export<\/code>\nfor CSV, <code>default<\/code> otherwise. Check it -- both callers share the same\nrepository, so an unconditional constraint would also change what CSV exports.<\/p>\n\n<h4>nldcf7_entry_query_clauses<\/h4>\n\n<p>Filter. Introduced in 0.3.0. Constrains the entries query using a table of your\nown, resolved by the database rather than by loading matching IDs into PHP.<\/p>\n\n<pre><code>apply_filters( 'nldcf7_entry_query_clauses', array $parts, array $args )\n\n$parts has four keys:\n<\/code><\/pre>\n\n<ul>\n<li><code>join<\/code> -- a JOIN clause string.<\/li>\n<li><code>where<\/code> -- an array of condition strings, each using <code>%s<\/code> or <code>%d<\/code> placeholders.<\/li>\n<li><code>prepare_args<\/code> -- the values for those placeholders, in order.<\/li>\n<li><code>distinct<\/code> -- boolean, default false.<\/li>\n<\/ul>\n\n<p>Values must go in <code>prepare_args<\/code>, never inside the condition strings; the plugin\npasses them to <code>$wpdb-&gt;prepare()<\/code>. A single pre-built SQL string is not\naccepted. If the placeholder count and the value count disagree, the whole\ncontribution is discarded. Table and column identifiers inside <code>join<\/code> are your\nresponsibility. Set <code>distinct<\/code> when your JOIN can match a row more than once: it\nis applied to the row query and the count together, so the list total and\npagination stay correct. <code>$args['context']<\/code> applies here too.<\/p>\n\n<h4>nldcf7_entry_list_items_prepared<\/h4>\n\n<p>Action. Introduced in 0.3.0. Fires once per list page after the rows are known\nand before any cell is rendered.<\/p>\n\n<pre><code>do_action( 'nldcf7_entry_list_items_prepared', array $items )\n\n$items is the current page's rows only -- never the whole result set. Use it\n<\/code><\/pre>\n\n<p>to load everything your columns need in one query and keep it in a\nrequest-local cache, instead of querying once per cell. It is read-only, has no\nreturn value, and fires with an empty array when the page has no rows. It\nbelongs to the entries screen only and never fires during CSV export.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>neutrope-lead-desk-for-contact-form-7<\/code> folder to the <code>\/wp-content\/plugins\/<\/code> directory, or install it via the Plugins screen in WordPress (\"Upload Plugin\").<\/li>\n<li>Ensure Contact Form 7 is installed and activated.<\/li>\n<li>Activate \"Neutrope Lead Desk for Contact Form 7\" from the Plugins screen.<\/li>\n<li>Review defaults at <strong>\u304a\u554f\u3044\u5408\u308f\u305b &gt; \u8a2d\u5b9a<\/strong> (Contact &gt; Settings). The plugin's screens appear underneath the Contact Form 7 menu. In particular, verify the field mapping candidates match your form's field names.<\/li>\n<li>Submit a test entry through one of your Contact Form 7 forms, then open <strong>\u304a\u554f\u3044\u5408\u308f\u305b &gt; \u4e00\u89a7<\/strong> to confirm it was captured.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20work%20without%20contact%20form%207%3F\"><h3>Does this work without Contact Form 7?<\/h3><\/dt>\n<dd><p>No. The plugin depends on Contact Form 7. If CF7 is not active, the plugin will not capture submissions and will show a warning banner on its own admin screens (it does not nag elsewhere in wp-admin).<\/p><\/dd>\n<dt id=\"are%20uploaded%20files%20stored%3F\"><h3>Are uploaded files stored?<\/h3><\/dt>\n<dd><p>No \u2014 only metadata (file name, MIME type, file size). The actual files remain with Contact Form 7's default handling.<\/p><\/dd>\n<dt id=\"will%20this%20capture%20ip%20addresses%3F\"><h3>Will this capture IP addresses?<\/h3><\/dt>\n<dd><p>IP capture is disabled by default for privacy. You can enable it under <strong>\u304a\u554f\u3044\u5408\u308f\u305b &gt; \u8a2d\u5b9a &gt; IP \u4fdd\u5b58<\/strong>. If you enable it, make sure your site's privacy policy covers IP logging.<\/p><\/dd>\n<dt id=\"how%20do%20i%20export%20data%20to%20csv%3F\"><h3>How do I export data to CSV?<\/h3><\/dt>\n<dd><p>Open <strong>\u304a\u554f\u3044\u5408\u308f\u305b &gt; \u30a8\u30af\u30b9\u30dd\u30fc\u30c8<\/strong>, apply any filters (date range, status, form, include spam), and click the download button. The CSV is UTF-8 with BOM, so it opens correctly in Japanese Excel without manual encoding conversion.<\/p><\/dd>\n<dt id=\"how%20does%20field%20mapping%20work%3F\"><h3>How does field mapping work?<\/h3><\/dt>\n<dd><p>Each of the four mapped columns (name, email, phone, company) has a comma-separated candidate list. The first field name that exists in the submission wins and its value is copied to the mapped column. Unmapped fields still end up in the <code>raw_payload_json<\/code> column.<\/p><\/dd>\n<dt id=\"will%20deleting%20the%20plugin%20lose%20my%20captured%20leads%3F\"><h3>Will deleting the plugin lose my captured leads?<\/h3><\/dt>\n<dd><p>No, by default data is preserved. If you explicitly want a clean uninstall, enable <strong>\u8a2d\u5b9a &gt; \u30a2\u30f3\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u6642\u306b\u30c7\u30fc\u30bf\u524a\u9664<\/strong> first, then delete the plugin.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20send%20data%20to%20any%20external%20service%3F\"><h3>Does the plugin send data to any external service?<\/h3><\/dt>\n<dd><p>No. Nothing is sent outside your WordPress installation. There is no phone-home, no analytics, and no tracking.<\/p><\/dd>\n<dt id=\"what%20capability%20is%20required%3F\"><h3>What capability is required?<\/h3><\/dt>\n<dd><p>By default <code>manage_options<\/code> is required for all admin screens. The required capability can be changed via the <code>nldcf7_required_capability<\/code> filter.<\/p><\/dd>\n<dt id=\"can%20i%20add%20custom%20columns%20to%20the%20csv%20export%3F\"><h3>Can I add custom columns to the CSV export?<\/h3><\/dt>\n<dd><p>Yes. Use the <code>nldcf7_export_columns<\/code> filter to add\/remove header columns, and <code>nldcf7_export_row<\/code> to return custom values per row.<\/p><\/dd>\n<dt id=\"why%20is%20the%20activity%20history%20short%20for%20entries%20i%20received%20before%20updating%3F\"><h3>Why is the activity history short for entries I received before updating?<\/h3><\/dt>\n<dd><p>Because it is built only from what was actually recorded at the time. Before 0.2.0 the plugin stored each entry's received timestamp and your internal notes, but it did not keep a log of status changes, trash\/restore actions, or spam marking. Those older transitions cannot be recovered, and the plugin will not fabricate them. Entries received from 0.2.0 onward record the full set of activity as it happens.<\/p><\/dd>\n<dt id=\"how%20do%20i%20report%20a%20bug%20or%20request%20a%20feature%3F\"><h3>How do I report a bug or request a feature?<\/h3><\/dt>\n<dd><p>Please open an issue on the plugin's support forum or the project's issue tracker.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.3.0<\/h4>\n\n<ul>\n<li>Add: generic extension points for the entry detail screen -- <code>nldcf7_entry_detail_main<\/code> and <code>nldcf7_entry_detail_sidebar<\/code> -- so an add-on can place panels in either column without modifying this plugin.<\/li>\n<li>Add: generic list extension points -- <code>nldcf7_entry_list_columns<\/code> for columns and <code>nldcf7_entry_list_column_content<\/code> for their cells. Core columns are protected: an add-on cannot remove, rename or repurpose one, and returned cell markup passes through <code>wp_kses_post()<\/code>.<\/li>\n<li>Add: <code>nldcf7_entry_list_filters<\/code>, which places an add-on's own controls inside the existing filter bar.<\/li>\n<li>Add: <code>nldcf7_entry_list_carried_args<\/code>, so an add-on's own filter stays applied across the All and Trash views and after row and bulk actions. Reserved keys such as nonces, action names and entry IDs are refused, non-scalar values are dropped, and size and count are capped, so a careless listener cannot put unsafe state into a list URL.<\/li>\n<li>Add: <code>nldcf7_entry_query_args<\/code> for high-level query constraints, including the existing <code>ids<\/code> argument, and <code>nldcf7_entry_query_clauses<\/code> for constraints that live in an add-on's own table. Clauses are structured -- a JOIN, conditions with placeholders, and their values kept separate -- rather than a raw SQL string, and values always go through <code>$wpdb-&gt;prepare()<\/code>.<\/li>\n<li>Add: optional <code>distinct<\/code> handling for add-on joins that can match a row more than once. It is applied to the row query and the count together, so the list and its total can never disagree.<\/li>\n<li>Add: query context. The entries screen and the CSV exporter share one repository, so each query now says which it is. An add-on constraint meant for the list no longer reaches CSV export unless the add-on opts in.<\/li>\n<li>Add: <code>nldcf7_entry_list_items_prepared<\/code>, which hands an add-on the current page's rows once, before any cell is rendered, so custom columns can load their data in a single query instead of one per cell.<\/li>\n<li>Fix: the Activity preparation notice counted processing records (entries plus notes) but read as a number of inquiries. It now names the unit; the arithmetic is unchanged.<\/li>\n<li>Fix: the \"history from before this plugin was updated\" note no longer appears on sites that installed this version fresh and therefore have no earlier history to explain.<\/li>\n<li>No database change. The schema and database version (1.1.0) are identical to 0.2.0, no migration runs, and existing entries, notes, attachments, activity, settings, capabilities and URLs are untouched. With no add-on installed the plugin behaves exactly as 0.2.0 did.<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>Add: an <strong>Activity Timeline<\/strong> (\u5bfe\u5fdc\u5c65\u6b74) on the entry detail screen, showing what has already been done about an inquiry. It records the entry being received, status changes (including the previous and new status), internal-note activity, Trash and Restore, and spam-state changes -- each with the user who performed it and a timestamp, newest first and paginated 50 events at a time.<\/li>\n<li>Add: a dedicated activity-event table (<code>{prefix}nldcf7_entry_events<\/code>). The database version moves from 1.0.0 to 1.1.0; the table is created on upgrade and on fresh activation.<\/li>\n<li>Add: existing entries get a historical timeline built in the background from the two things the database already recorded -- each entry's received timestamp and its existing internal notes. The backfill runs in batches, is resumable, and shows a progress notice on the plugin's own screens while it works; you can keep using the plugin normally throughout.<\/li>\n<li>Historical status changes, trash\/restore actions, and spam marking are deliberately NOT inferred. Those transitions were never stored before this release, so the timeline shows what was genuinely recorded and explains the gap rather than reconstructing a plausible-looking history that never happened.<\/li>\n<li>Your existing notes stay authoritative: the timeline links to them rather than copying or replacing them. Notes are also now rejected if their parent entry does not exist, so an orphaned note can no longer appear in a timeline that belongs to nothing.<\/li>\n<li>Fix: entry mutations are now transition-aware. Status, trash, restore, and spam changes distinguish a real transition from a no-op and from a failed write, so the timeline records a change only when the stored value actually changed. Previously a no-op update and a failed update were indistinguishable to callers.<\/li>\n<li>Fix: the entries list now keeps your keyword, status, form, date range, spam toggle, and sort order after a row or bulk action, instead of dropping you back into an unfiltered list after every single action.<\/li>\n<li>Housekeeping: resolved the remaining Plugin Check warning (<code>WordPress.Security.ValidatedSanitizedInput.InputNotSanitized<\/code>) by restructuring how list-filter input is read, not by suppressing the check. Plugin Check reports 0 errors and 0 warnings.<\/li>\n<li>No change to how submissions are captured or to what is stored for them: existing entries, notes, attachments, statuses, settings, option names, page slugs, capabilities, and existing hooks are all unchanged. Adds the actions <code>nldcf7_after_entry_trashed<\/code>, <code>nldcf7_after_entry_restored<\/code>, and <code>nldcf7_after_spam_changed<\/code>, and the filter <code>nldcf7_event_render<\/code>.<\/li>\n<\/ul>\n\n<h4>0.1.5<\/h4>\n\n<ul>\n<li>Add: the entries list now has a <strong>Trash<\/strong> view alongside <strong>All<\/strong>, with a per-row \"Restore\" action and a \"Restore\" bulk action. Trashing an entry has always been a soft delete (an <code>is_deleted<\/code> flag, never a row deletion), but until now nothing in the admin could list or restore those entries, so recovering from an accidental Trash click meant editing the database by hand. v0.1.4 deliberately removed the <code>confirm()<\/code> gate from the row-level Trash link because that gate silently cancelled the click in browsers that suppress dialogs; this release supplies the recoverability that makes a one-click, unconfirmed Trash safe -- the same trade WordPress core makes with \"Move to Trash\".<\/li>\n<li>The Trash view keeps the active keyword \/ status \/ form \/ date filters and the \"Show spam\" toggle when you switch views, and the All \/ Trash counts show how many entries are in each bucket. Restoring from the Trash view leaves you in the Trash view instead of bouncing you back to All. The Trash link stays hidden while the trash is empty, matching core list screens.<\/li>\n<li>Restore is a plain nonce-protected link with no <code>confirm()<\/code> gate, for exactly the reason given in the v0.1.4 entry below.<\/li>\n<li>No database schema change: restore simply clears the existing <code>is_deleted<\/code> flag, and status, spam flag, notes, and attachments all survive a trash\/restore round trip. Adds the nonce action <code>nldcf7_restore_&lt;id&gt;<\/code> and the query var <code>status_view<\/code>; existing <code>?page=nldcf7-*<\/code> URLs, option names, page slugs, capabilities, and hooks are unchanged, and the Export screen's \"Include entries moved to trash\" option behaves exactly as before.<\/li>\n<\/ul>\n\n<h4>0.1.4<\/h4>\n\n<ul>\n<li>Fix: the row-level \"Trash\" link on the entries list did nothing when clicked -- no confirmation, no notice, and the entry was not moved to trash. The link carried an <code>onclick=\"return confirm(...)\"<\/code> gate; because <code>confirm()<\/code> returns false whenever the browser suppresses the dialog (Chrome's \"Prevent this page from creating additional dialogs\", embedded webviews, dialog-blocking extensions), the anchor's navigation was cancelled and no HTTP request was ever sent. The server-side GET route was therefore never reached, which is why bulk actions -- plain form posts with no <code>confirm()<\/code> -- kept working. The Trash row action is now a plain nonce-protected link, matching WordPress core's own \"Move to Trash\" row action.<\/li>\n<li>No database, option, page slug, capability, or hook contract changes. The GET trash route, its nonce action (<code>nldcf7_trash_&lt;id&gt;<\/code>), capability check, and redirect target are unchanged.<\/li>\n<\/ul>\n\n<h4>0.1.3<\/h4>\n\n<ul>\n<li>Fix: the entry detail screen did not surface flash notices after status updates or note additions. v0.1.2 had added the same per-user transient flash mechanism to the Settings page, but the detail screen still discarded notices because <code>NLDCF7_Entry_Detail_Page::render()<\/code> did not accept the consumed transient and its view template had no notice block. <code>render()<\/code> now mirrors <code>NLDCF7_Settings_Page::render()<\/code> and accepts an optional <code>$notice<\/code>; the detail view renders the standard <code>notice notice-success \/ notice-error is-dismissible<\/code> banner; and <code>NLDCF7_Admin_Menu::render_entries_route()<\/code> passes the consumed transient when routing to the detail screen.<\/li>\n<li>No database, option, page slug, capability, or hook contract changes.<\/li>\n<\/ul>\n\n<h4>0.1.2<\/h4>\n\n<ul>\n<li>Fix: the \"Settings saved.\" confirmation notice did not appear after saving on the Settings page (admin menu moved under Contact Form 7 in 0.1.1 changed the form's effective post target in some setups, suppressing the post-save redirect and notice flag). The settings form now posts to an explicit URL and the success notice is delivered via the same per-user transient flash mechanism the entries list uses, so the confirmation reliably appears on the next page render.<\/li>\n<li>No database, option, page slug, capability, or hook contract changes.<\/li>\n<\/ul>\n\n<h4>0.1.1<\/h4>\n\n<ul>\n<li>Admin menu relocated: the four screens (Entries \/ Export \/ Settings \/ Help) now appear as submenus directly under the existing Contact Form 7 menu (\"\u304a\u554f\u3044\u5408\u308f\u305b\" in Japanese), instead of as a standalone top-level menu.<\/li>\n<li>When Contact Form 7 is not active, no plugin submenu is registered (no broken\/orphan menu is produced). The missing-dependency warning is now also shown on the Dashboard and the Plugins screen, in addition to deep-link hits to plugin pages.<\/li>\n<li>Help screen: navigation hint updated to match the new location (\"Contact &gt; Entries\" \/ \u300c\u304a\u554f\u3044\u5408\u308f\u305b &gt; \u4e00\u89a7\u300d).<\/li>\n<li>No database, option, page slug, or capability changes. Existing <code>?page=nldcf7-*<\/code> URLs continue to resolve unchanged.<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Automatic capture of Contact Form 7 submissions into a dedicated DB table.<\/li>\n<li>Raw payload stored as JSON plus mapped columns for name\/email\/phone\/company.<\/li>\n<li>Admin list screen (search, status\/form\/date filtering, bulk actions).<\/li>\n<li>Detail screen with status management and internal notes.<\/li>\n<li>CSV export with date\/status\/form\/spam filters (UTF-8 + BOM, chunked streaming).<\/li>\n<li>Attachment metadata capture.<\/li>\n<li>Privacy-friendly defaults (IP capture off).<\/li>\n<li>Opt-in data deletion on uninstall.<\/li>\n<li>Extensibility hooks for future Pro integrations.<\/li>\n<\/ul>","raw_excerpt":"Save Contact Form 7 submissions to your database and manage them as leads in the WordPress admin (list, detail, status, notes, CSV export).","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/313747","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=313747"}],"author":[{"embeddable":true,"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/neutropeinc"}],"wp:attachment":[{"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=313747"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=313747"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=313747"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=313747"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=313747"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/ro.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=313747"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}