{"id":337282,"date":"2026-07-17T23:56:18","date_gmt":"2026-07-17T23:56:18","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/for-welcart\/"},"modified":"2026-07-17T23:55:57","modified_gmt":"2026-07-17T23:55:57","slug":"hosuke-welcart","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/hosuke-welcart\/","author":23529156,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.1.31","stable_tag":"0.1.31","tested":"7.0.2","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"\u5831\u52a9 for Welcart","header_author":"\u682a\u5f0f\u4f1a\u793e\u5c0f\u6797\u8eca\u8f0c","header_description":"Welcart e-Commerce \u5c02\u7528\u306e\u518d\u5165\u8377\u304a\u77e5\u3089\u305b\u30d7\u30e9\u30b0\u30a4\u30f3\u3002SKU \u5358\u4f4d\u306e\u767b\u9332\u3001\u30e1\u30fc\u30eb\u30c6\u30f3\u30d7\u30ec\u306e\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3001\u518d\u5165\u8377\u5546\u54c1\u4e00\u89a7\u30da\u30fc\u30b8\u3001reCAPTCHA \u5bfe\u5fdc\u3002\u682a\u5f0f\u4f1a\u793e\u5c0f\u6797\u8eca\u8f0c \u304c\u72ec\u7acb\u3057\u3066\u958b\u767a\u3057\u305f\u7b2c\u4e09\u8005\u30d7\u30e9\u30b0\u30a4\u30f3\u3067\u3059\u3002","assets_banners_color":"303030","last_updated":"2026-07-17 23:55:57","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/hosuke.kbsr.co.jp\/","header_author_uri":"https:\/\/kbsr.co.jp\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":28,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.1.31":{"tag":"0.1.31","author":"kbsrco","date":"2026-07-17 23:55:57"}},"upgrade_notice":{"0.1.7":"<p>Replaces Welcart-specific save hooks with a transport-agnostic <code>updated_post_meta<\/code> hook, so restock detection fires no matter which save mechanism Welcart uses (Gutenberg \/ legacy editor \/ per-SKU AJAX \/ REST \/ other plugins).<\/p>","0.1.6":"<p>Corrects the AJAX action name for detecting per-SKU stock changes in the Welcart legacy editor. v0.1.5&#039;s hook name was wrong (was <code>updateitemsku<\/code>, correct is <code>item_sku_ajax<\/code>), so per-SKU restock detection did not fire.<\/p>","0.1.5":"<p>Adds detection for the Welcart legacy editor&#039;s per-SKU AJAX update path, so restock notifications trigger within seconds instead of waiting 15 minutes for the periodic scanner.<\/p>","0.1.4":"<p>Ensures v0.1.3 template migration also runs when the plugin is upgraded via file replacement (not just full deactivate\/reactivate). Adds unconditional mail-send logging for deliverability diagnosis.<\/p>","0.1.3":"<p>Adds RFC-compliant <code>List-Unsubscribe<\/code> \/ <code>Auto-Submitted<\/code> headers and reworks the default restock subject to significantly improve inbox delivery at Gmail\/Outlook.<\/p>","0.1.2":"<p>Adds a dedicated unsubscribe page (removes theme banner leakage) and catches stock changes from Welcart&#039;s legacy product editor.<\/p>","0.1.1":"<p>Improves restock notification delivery timing and matches the notify button to Welcart Basic theme colors.<\/p>","0.1.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3612077,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3612077,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3612077,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3612077,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.1.31"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"The \"Notify me when back in stock\" button auto-injected next to the Welcart sold-out label on the product page. Same size and hover behavior as the Welcart \"Add to cart\" button, but with an outlined design so shoppers can tell at a glance that this is a notification signup, not a purchase.","2":"The registration modal \u2014 email address input, consent checkbox, single-click submit. The email address auto-fills for logged-in Welcart members.","3":"The admin registration list. Supports status filters (registered \/ queued \/ sent \/ unsubscribed \/ expired \/ failed), CSV export, and bulk actions.","4":"The email template editor: three templates (registration confirmation \/ restock notification \/ admin alert), buttons to insert template variables at the cursor position, and a test send form at the bottom.","5":"The basic settings tab: button label, reCAPTCHA v3 site key \/ secret, Welcart my-page auto-injection toggle, and privacy consent settings in one place."}},"plugin_section":[],"plugin_tags":[11101,282,1159,150169,36061],"plugin_category":[45],"plugin_contributors":[272095],"plugin_business_model":[],"class_list":["post-337282","plugin","type-plugin","status-publish","hentry","plugin_tags-ec","plugin_tags-ecommerce","plugin_tags-notification","plugin_tags-restock","plugin_tags-welcart","plugin_category-ecommerce","plugin_contributors-kbsrco","plugin_committers-kbsrco"],"banners":{"banner":"https:\/\/ps.w.org\/hosuke-welcart\/assets\/banner-772x250.png?rev=3612077","banner_2x":"https:\/\/ps.w.org\/hosuke-welcart\/assets\/banner-1544x500.png?rev=3612077","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/hosuke-welcart\/assets\/icon-128x128.png?rev=3612077","icon_2x":"https:\/\/ps.w.org\/hosuke-welcart\/assets\/icon-256x256.png?rev=3612077","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Hosuke is an independent restock notification plugin designed specifically for Welcart e-Commerce. It is developed by Kobayashi Sharyo Co., Ltd. and is not officially affiliated with Welcart Inc.<\/p>\n\n<p>When a shopper visits a product page whose SKU is currently sold out, Hosuke inserts a \"Notify me when back in stock\" button. The shopper enters their email address, and once the SKU's stock transitions from 0 back to 1 or more, Hosuke automatically dispatches a notification email so the shopper can return to buy. Turns sold-out moments into recovered sales opportunities.<\/p>\n\n<h4>Key features<\/h4>\n\n<ul>\n<li>SKU-level registration (works with both single-SKU and multi-SKU products)<\/li>\n<li>Automatic injection of the notify button next to the Welcart sold-out label via the standard <code>usces_filters_single_sku_zaiko_message<\/code> filter<\/li>\n<li>Real-time stock change detection on product save<\/li>\n<li>15-minute WP-Cron background scan (catches stock changes made outside the admin UI)<\/li>\n<li>Three customizable email templates: registration confirmation, restock notification, admin alert<\/li>\n<li><code>[hosuke_restock_list]<\/code> shortcode and sidebar widget to display recently restocked items<\/li>\n<li>Both guest and Welcart-member registration flows (member email auto-fills)<\/li>\n<li>Google reCAPTCHA v3 integration for spam protection<\/li>\n<li>Per-IP rate limiting on the registration endpoint<\/li>\n<li>Send queue with exponential-backoff retry (up to 3 attempts)<\/li>\n<li>Automatic cleanup of expired notifications<\/li>\n<li>GDPR \/ Japanese Personal Information Protection Act compliance via the WordPress Privacy Tools (Export \/ Erase)<\/li>\n<li>One-click unsubscribe for shoppers (via email link or Welcart my-page)<\/li>\n<li>CSV export from the admin panel<\/li>\n<li>WP-CLI command: <code>wp hosuke send-queue<\/code><\/li>\n<li>REST API: <code>POST \/wp-json\/hosuke\/v1\/send-queue<\/code>, <code>GET \/wp-json\/hosuke\/v1\/restock-list<\/code><\/li>\n<li>Japanese and English translation files bundled<\/li>\n<\/ul>\n\n<h4>Requirements<\/h4>\n\n<ul>\n<li>WordPress 6.0 or higher<\/li>\n<li>PHP 7.4 or higher<\/li>\n<li>Welcart e-Commerce 2.9 or higher<\/li>\n<\/ul>\n\n<h4>About the author<\/h4>\n\n<p>Hosuke is developed and maintained by <a href=\"https:\/\/kbsr.co.jp\/?utm_source=hosuke&amp;utm_medium=plugin&amp;utm_campaign=readme\">Kobayashi Sharyo Co., Ltd.<\/a> as part of the kbsr product line for Welcart and WordPress.<\/p>\n\n<p>Other kbsr products:<\/p>\n\n<ul>\n<li><strong>Banto for Welcart<\/strong> \u2014 Amazon Pay V2 payment gateway + 5-carrier shipping label integration for Welcart (paid)<\/li>\n<li><strong>Bunsuke<\/strong> \u2014 Japanese-focused AI writing assistance plugin for WordPress (paid)<\/li>\n<\/ul>\n\n<p>See the <a href=\"https:\/\/kbsr.co.jp\/products\/?utm_source=hosuke&amp;utm_medium=plugin&amp;utm_campaign=readme\">full product lineup<\/a> for details.<\/p>\n\n<h3>Privacy Policy<\/h3>\n\n<p>Hosuke stores the following personal data:<\/p>\n\n<ul>\n<li>Email address of subscribers<\/li>\n<li>Optionally, Welcart member ID (if the subscriber is logged in at registration time)<\/li>\n<li>Hashed IP address at registration (SHA-256, salted with WP <code>nonce_salt<\/code>)<\/li>\n<li>User agent string<\/li>\n<li>Timestamps: registration, notification sent, unsubscription<\/li>\n<\/ul>\n\n<p>This data is used solely for the purpose of delivering the requested restock notification.<\/p>\n\n<p>Data is automatically deleted after the configured retention period (default: 90 days after notification, 365 days for unfulfilled registrations).<\/p>\n\n<p>WordPress Privacy Tools integration is provided for GDPR-style data export and deletion requests.<\/p>\n\n<h3>Third-Party Services<\/h3>\n\n<p>Hosuke can optionally integrate with <strong>Google reCAPTCHA v3<\/strong> for spam protection.<\/p>\n\n<ul>\n<li>When enabled, the reCAPTCHA JavaScript library is loaded on product pages that display the notification button.<\/li>\n<li>The reCAPTCHA token is sent to Google's servers for verification.<\/li>\n<li>Google's terms and privacy policy apply: https:\/\/policies.google.com\/privacy<\/li>\n<\/ul>\n\n<p>This integration is off by default and must be explicitly enabled in Settings with your own site key and secret.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>hosuke-welcart<\/code> folder to <code>\/wp-content\/plugins\/<\/code>, or install via the Plugins screen in WordPress admin.<\/li>\n<li>Activate the plugin through the \"Plugins\" menu.<\/li>\n<li>Confirm that Welcart e-Commerce is active. A warning will appear if it is not.<\/li>\n<li>Go to \"Hosuke \u2192 Settings\" in the WordPress admin to configure reCAPTCHA, email templates, and other options.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"is%20welcart%20required%3F\"><h3>Is Welcart required?<\/h3><\/dt>\n<dd><p>Yes. Hosuke is designed to work in conjunction with the Welcart e-Commerce plugin. If Welcart is inactive, a warning is displayed and Hosuke's own hooks are not registered.<\/p><\/dd>\n<dt id=\"can%20i%20customize%20where%20the%20notify%20button%20appears%3F\"><h3>Can I customize where the notify button appears?<\/h3><\/dt>\n<dd><p>By default, the button is auto-injected next to the Welcart sold-out label via the standard <code>usces_filters_single_sku_zaiko_message<\/code> filter. You can turn auto-injection off in the settings and place the button anywhere via the <code>hosuke_button_html<\/code> filter or other Welcart hooks.<\/p><\/dd>\n<dt id=\"will%20notifications%20be%20sent%20for%20products%20that%20have%20never%20been%20out%20of%20stock%3F\"><h3>Will notifications be sent for products that have never been out of stock?<\/h3><\/dt>\n<dd><p>No. The notify button only appears on SKUs that are currently sold out and do not have \"sellable while out of stock\" enabled. Even if a shopper somehow registers on an in-stock SKU, the notification only fires at the moment stock transitions from 0 to 1 or more.<\/p><\/dd>\n<dt id=\"does%20it%20support%20multi-sku%20products%3F\"><h3>Does it support multi-SKU products?<\/h3><\/dt>\n<dd><p>Yes. Notifications are managed at the SKU level, not the product level. Each SKU's stock is monitored independently.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20an%20email%20delivery%20fails%3F\"><h3>What happens when an email delivery fails?<\/h3><\/dt>\n<dd><p>Hosuke retries with exponential backoff, up to 3 times (configurable). If the maximum retry count is exceeded, the notification is marked as failed and an alert email is sent to the site administrator.<\/p><\/dd>\n<dt id=\"is%20hosuke%20gdpr%20%2F%20japanese%20personal%20information%20protection%20act%20compliant%3F\"><h3>Is Hosuke GDPR \/ Japanese Personal Information Protection Act compliant?<\/h3><\/dt>\n<dd><p>Yes. Hosuke integrates with the standard WordPress Privacy Tools:<\/p>\n\n<ul>\n<li>Shoppers can request an export of their data via \"Tools \u2192 Export Personal Data\"<\/li>\n<li>Shoppers can request erasure via \"Tools \u2192 Erase Personal Data\"<\/li>\n<\/ul>\n\n<p>Both are keyed by email address. Consent capture at registration time is also configurable (enabled by default).<\/p><\/dd>\n<dt id=\"how%20do%20i%20test%20email%20delivery%3F\"><h3>How do I test email delivery?<\/h3><\/dt>\n<dd><p>The \"Hosuke \u2192 Restock Notifications\" admin page has a \"Test send\" section at the bottom that lets you send any template to any address as a preview.<\/p><\/dd>\n<dt id=\"emails%20are%20not%20being%20delivered%20%2F%20go%20to%20the%20spam%20folder.%20what%20should%20i%20do%3F\"><h3>Emails are not being delivered \/ go to the spam folder. What should I do?<\/h3><\/dt>\n<dd><p>Hosuke sends all notifications through the standard WordPress <code>wp_mail()<\/code> function. Whether messages actually reach the inbox depends on your server's mail configuration and the DNS records (SPF\/DKIM\/DMARC) of your sending domain. Both are outside of Hosuke's control, so Hosuke cannot guarantee or measure deliverability.<\/p>\n\n<p>Small operations may work fine with the default configuration, but if you are sending to Gmail \/ Outlook \/ other strict providers, or dozens of messages per day, some may be flagged as spam or silently discarded on the receiving side.<\/p>\n\n<p><strong>Recommended<\/strong>: install a major SMTP plugin (<a href=\"https:\/\/wordpress.org\/plugins\/wp-mail-smtp\/\">WP Mail SMTP<\/a> \/ <a href=\"https:\/\/wordpress.org\/plugins\/fluent-smtp\/\">FluentSMTP<\/a> \/ <a href=\"https:\/\/wordpress.org\/plugins\/post-smtp\/\">Post SMTP<\/a> etc.) and connect it to an authenticated sending service (Amazon SES \/ SendGrid \/ Mailgun \/ Postmark \/ Google Workspace \/ Microsoft 365 etc.). SMTP plugins transparently intercept <code>wp_mail()<\/code> calls and re-send via the authenticated route. No changes to Hosuke are required.<\/p>\n\n<p>Publishing proper SPF \/ DKIM \/ DMARC records for your sending domain is also the single biggest factor determining Gmail deliverability.<\/p><\/dd>\n<dt id=\"is%20there%20a%20page%20where%20members%20can%20see%20their%20notification%20history%3F\"><h3>Is there a page where members can see their notification history?<\/h3><\/dt>\n<dd><p>Yes. Logged-in Welcart members can view and manage their notifications at <code>\/?hosuke_my_notifications=1<\/code>. Add a link from the Welcart my-page to this URL (or enable auto-injection in the settings).<\/p><\/dd>\n<dt id=\"is%20data%20preserved%20when%20the%20plugin%20is%20deactivated%3F\"><h3>Is data preserved when the plugin is deactivated?<\/h3><\/dt>\n<dd><p>Yes. Deactivating the plugin does not delete data. Data deletion is opt-in: only when \"Delete all data on uninstall\" is enabled in the settings and the plugin is uninstalled will custom tables and options be removed.<\/p><\/dd>\n<dt id=\"where%20do%20i%20get%20support%3F\"><h3>Where do I get support?<\/h3><\/dt>\n<dd><p>For questions and bug reports, please use the <a href=\"https:\/\/wordpress.org\/support\/plugin\/hosuke-welcart\/\">WordPress.org support forum<\/a> or the <a href=\"https:\/\/kbsr.co.jp\/contact\/?src=hosuke\">Kobayashi Sharyo contact form<\/a>.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.1.31<\/h4>\n\n<ul>\n<li><strong>Security hardening for legacy Welcart editor observer<\/strong>: <code>Stock\\ChangeDetector::onAdminInitDetectLegacyEditor()<\/code> now requires <code>edit_posts<\/code> before it does anything, verifies the Welcart <code>_wpnonce<\/code> field is present and valid, and additionally checks <code>edit_post<\/code> for the specific post before scheduling a stock recheck at shutdown. The GET-only fallback for reading <code>post<\/code> has been removed, so the observer will only ever react to properly authenticated POST submissions from the Welcart legacy item editor.<\/li>\n<\/ul>\n\n<h4>0.1.30<\/h4>\n\n<ul>\n<li><strong>Text Domain aligned with plugin slug<\/strong>: Renamed the plugin's text domain from <code>hosuke<\/code> to <code>hosuke-welcart<\/code> across all 269 i18n calls, the plugin header, the <code>load_textdomain()<\/code> bootstrap, and the language file names (<code>hosuke-welcart-ja.mo\/po<\/code>, <code>hosuke-welcart.pot<\/code>). Required for translations at translate.wordpress.org to associate with the correct plugin slug.<\/li>\n<li><strong>Description translated to English<\/strong>: The <code>readme.txt<\/code> <code>== Description ==<\/code>, <code>== Installation ==<\/code>, <code>== Frequently Asked Questions ==<\/code>, and <code>== Screenshots ==<\/code> sections have been rewritten in English. Japanese translations remain available via the bundled <code>.mo<\/code> file and translate.wordpress.org.<\/li>\n<li><strong>Inline scripts converted to <code>wp_enqueue_script<\/code><\/strong>: The three inline <code>&lt;script&gt;<\/code> blocks in the admin templates editor and the frontend member-notifications component have been extracted to dedicated files under <code>assets\/js\/<\/code> and are now loaded via <code>wp_enqueue_script()<\/code>, with translated toast strings passed through <code>wp_localize_script()<\/code>.<\/li>\n<li><strong>Sanitization hardening<\/strong>: <code>Admin\\TemplatesPage::handleSave<\/code> now passes the decoded email body through <code>sanitize_textarea_field( wp_check_invalid_utf8( ... ) )<\/code> before saving, so template content is normalized to plain text. <code>Notification\\Registrar<\/code> now wraps the <code>HTTP_USER_AGENT<\/code> fallback in <code>sanitize_text_field( wp_unslash( ... ) )<\/code> instead of taking the raw server value.<\/li>\n<li><strong>Cross-promo admin notice scoped<\/strong>: The <code>Admin\\CrossPromoNotice<\/code> in-admin notice now checks <code>get_current_screen()-&gt;id<\/code> and only renders on screens whose id contains <code>hosuke<\/code>, preventing the notice from appearing on unrelated admin pages (Guideline 11 compliance).<\/li>\n<\/ul>\n\n<h4>0.1.29<\/h4>\n\n<ul>\n<li><strong>Japanese-first documentation<\/strong>: The plugin file <code>Description:<\/code> header, the <code>readme.txt<\/code> short description, and the <code>== Description ==<\/code> \/ <code>== Installation ==<\/code> \/ <code>== Frequently Asked Questions ==<\/code> \/ <code>== Screenshots ==<\/code> sections have all been rewritten in Japanese. Welcart is a Japan-only e-commerce plugin, so the target audience of \u5831\u52a9 is 100 %% Japanese-speaking; keeping the primary documentation in Japanese matches the audience. The <code>== Changelog ==<\/code> section is intentionally left in English for cross-project consistency.<\/li>\n<li><strong>Author name<\/strong>: Changed the plugin header <code>Author:<\/code> field from the English <code>Kobayashi Sharyo Co., Ltd.<\/code> to the Japanese <code>\u682a\u5f0f\u4f1a\u793e\u5c0f\u6797\u8eca\u8f0c<\/code>, matching the display convention of the sister products <code>\u756a\u982d for Welcart<\/code> and <code>\u6587\u52a9 for WordPress<\/code>.<\/li>\n<\/ul>\n\n<h4>0.1.28<\/h4>\n\n<ul>\n<li><strong>Plugin display name<\/strong>: Switched to the Japanese short form <code>\u5831\u52a9 for Welcart<\/code> in both the plugin header and the <code>readme.txt<\/code> heading, matching the family branding convention shared with <code>\u756a\u982d for Welcart<\/code> and <code>\u6587\u52a9 for WordPress<\/code> (all sister products under <code>\u682a\u5f0f\u4f1a\u793e\u5c0f\u6797\u8eca\u8f0c<\/code>). The WordPress.org slug remains <code>hosuke-welcart<\/code>.<\/li>\n<\/ul>\n\n<h4>0.1.27<\/h4>\n\n<ul>\n<li><strong>Plugin Check warnings \u2014 critical fixes<\/strong>: Addressed all Plugin Check warnings that WordPress.org reviewers typically flag as blockers:\n\n<ul>\n<li><strong>Plugin name consistency<\/strong>: Aligned the <code>Plugin Name:<\/code> header in <code>hosuke.php<\/code> from the Japanese <code>\u5831\u52a9 - Restock Notify for Welcart<\/code> to <code>Hosuke - Restock Notify for Welcart<\/code>, matching the <code>=== Hosuke - Restock Notify for Welcart ===<\/code> heading in <code>readme.txt<\/code> and the WordPress.org slug <code>hosuke-welcart<\/code>.<\/li>\n<li><strong><code>load_plugin_textdomain()<\/code> removed<\/strong> from <code>Plugin::init()<\/code> and <code>hosuke.php<\/code> per WordPress 4.6+ automatic language pack loading. The early <code>load_textdomain()<\/code> call in <code>hosuke.php<\/code> remains to guarantee Japanese defaults during <code>register_activation_hook<\/code> (before <code>init<\/code>).<\/li>\n<li><strong>Input sanitization<\/strong> for <code>$_SERVER[REMOTE_ADDR]<\/code> in <code>RateLimiter::currentIp()<\/code> and <code>$_SERVER[REQUEST_METHOD]<\/code> in <code>ChangeDetector::onAdminInitDetectLegacyEditor()<\/code> \u2014 now wrapped with <code>wp_unslash()<\/code> + <code>sanitize_text_field()<\/code>.<\/li>\n<li><strong><code>TemplatesPage<\/code><\/strong>: Added a targeted <code>phpcs:ignore<\/code> with justification for the multi-field array <code>$_POST[ $option_key ]<\/code> assignment (each field \u2014 subject, from_name, from_email, body\/body_b64 \u2014 is sanitized individually downstream).<\/li>\n<li><strong><code>NotificationsListTable<\/code><\/strong>: Added <code>WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber<\/code> to the existing <code>phpcs:ignore<\/code> on the paginated results query where the placeholder count in the WHERE clause is dynamic.<\/li>\n<\/ul><\/li>\n<\/ul>\n\n<h4>0.1.26<\/h4>\n\n<ul>\n<li><strong>Plugin Check compliance<\/strong>: Resolved all 14 errors flagged by the WordPress.org Plugin Check tool as blockers for the initial submission:\n\n<ul>\n<li>i18n: Merged three concatenated multi-line email template strings in <code>Activator.php<\/code> into single string literals so that translation extractors can pick them up (<code>WordPress.WP.I18n.NonSingularStringLiteralText<\/code>).<\/li>\n<li>i18n: Added <code>\/* translators: *\/<\/code> comments before three placeholder-bearing <code>__()<\/code> calls in <code>templates-editor.php<\/code> and <code>modal.php<\/code> (<code>WordPress.WP.I18n.MissingTranslatorsComment<\/code>).<\/li>\n<li>Security: Refactored <code>RestockListWidget::widget()<\/code> so the shortcode output is captured into a variable before being echoed, allowing the <code>phpcs:ignore<\/code> directive to attach cleanly to a single-line <code>echo<\/code> statement (<code>WordPress.Security.EscapeOutput.OutputNotEscaped<\/code>).<\/li>\n<li>Security: Wrapped exception messages that interpolate user-derived data in <code>MailSender.php<\/code> with <code>esc_html()<\/code> in case they surface in error output (<code>WordPress.Security.EscapeOutput.ExceptionNotEscaped<\/code>).<\/li>\n<li>File I\/O: Added targeted <code>phpcs:ignore<\/code> directives with justification comments on the <code>fwrite()<\/code> and <code>fclose()<\/code> calls in <code>CsvExporter.php<\/code> that stream to <code>php:\/\/output<\/code> \u2014 <code>WP_Filesystem<\/code> is not applicable to output streams (<code>WordPress.WP.AlternativeFunctions.file_system_operations_fwrite\/fclose<\/code>).<\/li>\n<\/ul><\/li>\n<\/ul>\n\n<h4>0.1.25<\/h4>\n\n<ul>\n<li><strong>Meta<\/strong>: Updated <code>Contributors:<\/code> field in readme.txt from the legacy <code>kbsr<\/code> handle to the new <code>kbsrco<\/code> WordPress.org account created for plugin distribution.<\/li>\n<\/ul>\n\n<h4>0.1.24<\/h4>\n\n<ul>\n<li><strong>Docs<\/strong>: Updated the <code>== Screenshots ==<\/code> section descriptions to accurately match the 5 captured screenshots that will be uploaded to the WordPress.org SVN <code>assets\/<\/code> directory alongside the plugin.<\/li>\n<\/ul>\n\n<h4>0.1.23<\/h4>\n\n<ul>\n<li><strong>Plugin URI<\/strong>: Changed the plugin homepage header from <code>https:\/\/kbsr.co.jp\/products\/<\/code> to the new dedicated subdomain <code>https:\/\/hosuke.kbsr.co.jp\/<\/code>. The \"\u30d7\u30e9\u30b0\u30a4\u30f3\u306e\u30b5\u30a4\u30c8\u3092\u8868\u793a\" link on the WordPress plugins list now points there.<\/li>\n<li><strong>Localization<\/strong>: Status column values in the registrations list and send history (<code>pending<\/code> \/ <code>queued<\/code> \/ <code>notified<\/code> \/ <code>unsubscribed<\/code> \/ <code>expired<\/code> \/ <code>failed<\/code>) are now rendered with their Japanese labels (<code>\u767b\u9332\u4e2d<\/code> \/ <code>\u9001\u4fe1\u5f85\u3061<\/code> \/ <code>\u9001\u4fe1\u6e08\u307f<\/code> \/ <code>\u89e3\u9664\u6e08\u307f<\/code> \/ <code>\u671f\u9650\u5207\u308c<\/code> \/ <code>\u5931\u6557<\/code>) on Japanese sites \u2014 previously they showed the raw English enum values. The two \"default\" filter dropdown entries at the top of each list are also translated: <code>\u767b\u9332\u4e2d\/\u9001\u4fe1\u5f85\u3061 (\u30c7\u30d5\u30a9\u30eb\u30c8)<\/code> on the registrations list and <code>\u9001\u4fe1\u6e08\/\u89e3\u9664\/\u671f\u9650\u5207\/\u5931\u6557 (\u30c7\u30d5\u30a9\u30eb\u30c8)<\/code> on the send history.<\/li>\n<li><strong>Sender name \/ email<\/strong>: The \"From name\" and \"From email\" fields on the Notification Emails page are now optional. If left blank, at send time the plugin resolves them dynamically \u2014 first from Welcart's own <code>sender_name<\/code> \/ <code>sender_mail<\/code> settings, then from WordPress's <code>blogname<\/code> \/ <code>admin_email<\/code>. This means Hosuke automatically follows any change site owners make to Welcart's sender settings, without having to re-visit the Notification Emails page. Both fields now show the currently-resolved value as a placeholder and a description line (\"Leave blank to inherit from Welcart \/ WordPress. Currently resolves to: ...\") so operators can see at a glance what will be used.<\/li>\n<\/ul>\n\n<h4>0.1.22<\/h4>\n\n<ul>\n<li><strong>Localization fix<\/strong>: The \"invalid unsubscribe link\" error message on the notify-off page was rendering the English source text (\"This unsubscribe link is no longer valid. It may have already been processed...\") because that specific string was missing from the Japanese <code>.po<\/code>. The Japanese-locale rendering now reads\u300c\u3053\u306e\u89e3\u9664\u30ea\u30f3\u30af\u306f\u6709\u52b9\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u65e2\u306b\u89e3\u9664\u6e08\u307f\u304b\u3001\u901a\u77e5\u30c7\u30fc\u30bf\u304c\u524a\u9664\u3055\u308c\u3066\u3044\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002\u300dconsistent with the surrounding \"\u89e3\u9664\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\" title.<\/li>\n<\/ul>\n\n<h4>0.1.21<\/h4>\n\n<ul>\n<li><strong>My-page table now matches Welcart cart exactly<\/strong>. The v0.1.20 table used generic dark-header styling I had picked from memory; the actual Welcart Basic cart uses a light-gray header (<code>#efefef<\/code>), a dotted table border (<code>1px dotted #ccc<\/code>), 5px cell padding, and 14px cells. Those computed styles are now applied verbatim so the \"\u767b\u9332\u4e2d\u306e\u518d\u5165\u8377\u901a\u77e5\" table is visually indistinguishable from <code>\/usces-cart\/<\/code>.<\/li>\n<li><strong>Cart-style columns<\/strong>: added thumbnail (48x48, WordPress featured image with Welcart Basic <code>crystal\/default.svg<\/code> fallback), item name, and unit price (via Welcart's <code>usces_crform()<\/code> for correct currency formatting). Columns now are <code>No. \/ thumbnail \/ \u5546\u54c1 \/ \u4fa1\u683c \/ \u30b9\u30c6\u30fc\u30bf\u30b9 \/ \u89e3\u9664<\/code>, using the same semantic HTML classes as Welcart (<code>num<\/code> \/ <code>thumbnail<\/code> \/ <code>productname<\/code> \/ <code>unitprice<\/code> \/ <code>stock<\/code> \/ <code>action<\/code>) plus the <code>aleft<\/code> \/ <code>aright<\/code> alignment classes, so custom child themes that already style the cart will style this table too.<\/li>\n<li><strong>Extensibility<\/strong>: the outer <code>hosuke-my-notifications__*<\/code> classes are preserved on the section, heading, table and status\/action elements so site owners can layer their own CSS on top without touching Welcart theme files.<\/li>\n<\/ul>\n\n<h4>0.1.20<\/h4>\n\n<ul>\n<li><strong>Fix: my-page notification list rendered without styles.<\/strong> The frontend stylesheet is only registered by the product-page <code>Assets<\/code> class, so on the Welcart my-page it was neither registered nor enqueued in v0.1.16-v0.1.19 \u2014 the injected section fell back to unstyled default browser layout. <code>MemberNotifications::maybeEnqueueMountStyles()<\/code> now <code>wp_register_style()<\/code> + <code>wp_enqueue_style()<\/code> the frontend CSS itself when it detects the Welcart my-page, so the section renders with the intended dark-header table styling regardless of what else is loaded on the page.<\/li>\n<li><strong>Heading now matches Welcart \u8cfc\u5165\u5c65\u6b74<\/strong>: the section heading is now <code>&lt;h3&gt;<\/code> (was <code>&lt;h2&gt;<\/code>), styled to Welcart Basic's h3 spec \u2014 <code>font-size: 14px<\/code>, <code>font-weight: 700<\/code>, <code>border-bottom: 1px solid #ccc<\/code>, <code>margin: 30px 0 20px<\/code>. It sits at the same visual level as \u8cfc\u5165\u5c65\u6b74 and \u4f1a\u54e1\u60c5\u5831\u7de8\u96c6.<\/li>\n<\/ul>\n\n<h4>0.1.19<\/h4>\n\n<ul>\n<li><strong>Fix: button label was still <code>\u5165\u8377\u3057\u305f\u3089\u901a\u77e5\u3092\u53d7\u3051\u53d6\u308b<\/code> on the settings screen after upgrading to v0.1.18.<\/strong> The button-label migration was only wired to fire for installations upgrading from before v0.1.11 \u2014 anyone who was already on v0.1.11 through v0.1.17 (with the old Japanese default persisted in <code>wp_options<\/code>) never ran it. The check now also runs as part of the v0.1.19 template-refresh migration, so anyone upgrading to this release picks up the new default <code>\u518d\u5165\u8377\u304a\u77e5\u3089\u305b\u901a\u77e5<\/code>. Custom labels are still preserved.<\/li>\n<li><strong>Fix: restock email body contradicted the plugin's actual behavior.<\/strong> The v0.1.18 default body contained a mixed-model line that said \"\u672c\u5546\u54c1\u306e\u3054\u8cfc\u5165\u5f8c\u3082\u3001\u518d\u5165\u8377\u304a\u77e5\u3089\u305b\u30e1\u30fc\u30eb\u306f\u81ea\u52d5\u914d\u4fe1\u3055\u308c\u307e\u3059\" (implying a continuous \/ re-arm-until-cancelled model), which is not how Hosuke actually works. Hosuke fires exactly once per registration and then marks the notification as sent. The body has been corrected to <code>\u4e00\u5ea6\u306e\u5165\u8377\u306b\u3064\u304d\u3001\u304a\u77e5\u3089\u305b\u30e1\u30fc\u30eb\u306f1\u56de\u306e\u914d\u4fe1\u3068\u306a\u308a\u307e\u3059\u3002\u305d\u306e\u5f8c\u3082\u914d\u4fe1\u3092\u3054\u5e0c\u671b\u306e\u5834\u5408\u306f\u3001\u518d\u5ea6\u5546\u54c1\u30da\u30fc\u30b8\u304b\u3089\u304a\u77e5\u3089\u305b\u306e\u3054\u767b\u9332\u3092\u304a\u9858\u3044\u3044\u305f\u3057\u307e\u3059\u3002<\/code> \u2014 this matches what the plugin actually does. The upgrade migration detects the short-lived v0.1.18 body via marker and replaces it.<\/li>\n<\/ul>\n\n<h4>0.1.18<\/h4>\n\n<ul>\n<li><strong>Button label<\/strong>: Default frontend label is now <code>\u518d\u5165\u8377\u304a\u77e5\u3089\u305b\u901a\u77e5<\/code> (was <code>\u5165\u8377\u3057\u305f\u3089\u901a\u77e5\u3092\u53d7\u3051\u53d6\u308b<\/code>). On upgrade, sites whose stored label matches either of the two previous defaults (<code>Notify me when back in stock<\/code> or <code>\u5165\u8377\u3057\u305f\u3089\u901a\u77e5\u3092\u53d7\u3051\u53d6\u308b<\/code>) are migrated to the new default. Custom labels are preserved.<\/li>\n<li><strong>Admin sidebar<\/strong>: Sub-menu item renamed from <code>\u901a\u77e5\u30e1\u30fc\u30eb<\/code> to <code>\u518d\u5165\u8377\u901a\u77e5<\/code> to align with the \"\u518d\u5165\u8377\u901a\u77e5\" terminology used across the plugin. The English label remains <code>Notification Emails<\/code>.<\/li>\n<li><strong>Email defaults refreshed<\/strong>: Default subject lines and body copy have been rewritten in the format commonly used by mainstream Japanese e-commerce stores. New subjects are <code>[shop_name] \u518d\u5165\u8377\u304a\u77e5\u3089\u305b\u30e1\u30fc\u30eb\u3092\u53d7\u4ed8\u307e\u3057\u305f<\/code> for the registration confirmation, and <code>[shop_name] \u518d\u5165\u8377\u306e\u304a\u77e5\u3089\u305b - {item_name}<\/code> for the restock notification. Bodies use the \u25c7\/\u25a0\/* section markers, structured product-detail block, and standard disclaimer copy that Japanese shoppers already recognize. An upgrade migration replaces stored defaults from any earlier version (English v0.1.0\u2013v0.1.10, Japanese v0.1.10\u2013v0.1.17) with the new copy, based on marker phrases in the body. Edited templates are left untouched.<\/li>\n<li><strong>My-page notification list<\/strong>: Redesigned as a Welcart cart-style table (<code>No \/ Item \/ SKU \/ Status \/ Unsubscribe<\/code> columns, dark <code>#333<\/code> header row, bordered cells, orange-outline unsubscribe button) to visually match <code>\/usces-cart\/<\/code> and the purchase history table on <code>\/usces-member\/<\/code>. Mobile viewports collapse to a single-column card layout automatically.<\/li>\n<\/ul>\n\n<h4>0.1.17<\/h4>\n\n<ul>\n<li><strong>Fix: Welcart my-page auto-injection now actually works.<\/strong> v0.1.16 relied on <code>the_content<\/code> and a handful of Welcart action hooks (<code>usces_action_member_completion<\/code> etc.), none of which fire on Welcart Basic \u2014 the theme calls <code>usces_member()<\/code> directly from <code>page-uscesmember.php<\/code> and never routes through <code>the_content()<\/code>. This release adds a <code>wp_footer<\/code>-based fallback that server-renders the notifications HTML into a hidden container and then a small inline script moves it to the end of <code>#wc_member<\/code> \/ <code>#memberpages<\/code> \/ <code>.member-page<\/code> (whichever it finds first). Works on Welcart Basic, custom themes, and older\/newer Welcart versions equally. The three earlier injection paths are kept in place \u2014 the shared <code>static<\/code> flag prevents duplicate rendering if any of them also fire.<\/li>\n<li>Frontend stylesheet (<code>hosuke-frontend<\/code>) is now force-enqueued on the Welcart my-page whenever the notifications section renders there \u2014 the my-page normally does not enqueue product-page assets, which meant the injected section could render unstyled in v0.1.16.<\/li>\n<\/ul>\n\n<h4>0.1.16<\/h4>\n\n<ul>\n<li><strong>Welcart my-page integration<\/strong>: Registered members now see their active restock notifications directly on the Welcart my-page (<code>\/usces-member\/<\/code>). Each row shows the item title, SKU code, current status (Awaiting restock \/ Sending \/ Sent), and a one-click Unsubscribe link. This uses the same repository as the existing <code>?hosuke_my_notifications=1<\/code> view, so member unsubscribe tokens continue to work.<\/li>\n<li>Auto-injection is on by default and can be turned off from Settings \u2192 Basic \u2192 \"Show notifications on Welcart my-page\". Even when off, site owners can place the list anywhere via the new <code>[hosuke_my_notifications]<\/code> shortcode.<\/li>\n<li>The auto-injection routes through <code>the_content<\/code> (works with any theme that renders the member page through <code>the_content()<\/code>) plus a set of Welcart action hooks (<code>usces_action_member_completion<\/code>, <code>usces_action_member_form<\/code>, <code>usces_action_member_page_bottom<\/code>) so themes that expose those hooks work equally well. A per-request flag prevents duplicate rendering even if multiple routes fire.<\/li>\n<\/ul>\n\n<h4>0.1.15<\/h4>\n\n<ul>\n<li><strong>About page<\/strong>: Bunsuke card description is now translated to Japanese (was left in English in 0.1.14). Primary CTA button renamed from <code>View all kbsr products<\/code> to <code>View all products<\/code> \/ \u300c\u5168\u30d7\u30ed\u30c0\u30af\u30c8\u3092\u898b\u308b\u300d. Button text inside cards is now horizontally centered (previously left-aligned because of the default WP <code>.button<\/code> <code>text-align: start<\/code>).<\/li>\n<li><strong>Unsubscribe page<\/strong>: All page copy is now properly localized for Japanese sites (previously the h1 title and the \"click the link in the email\" description rendered as English). The page title stored in <code>wp_posts.post_title<\/code> is auto-migrated from <code>Restock Notifications<\/code> to <code>\u901a\u77e5\u306e\u89e3\u9664<\/code> on Japanese sites \u2014 customized page titles are preserved.<\/li>\n<li><strong>Unsubscribe page slug<\/strong>: renamed the default slug from <code>hosuke-unsubscribe<\/code> to <code>notify-off<\/code> (shorter, action-oriented, no plugin-name prefix). The migration renames the existing page in place. Old sent emails still work \u2014 the redirect handler already sends any request that includes an <code>?hosuke_unsubscribe=TOKEN<\/code> query string to the current page permalink via a 302, so old email links from before the rename resolve correctly.<\/li>\n<li>Added a <code>hosuke_unsubscribe_page_slug<\/code> filter so site owners can override the slug if <code>notify-off<\/code> conflicts with another page.<\/li>\n<\/ul>\n\n<h4>0.1.14<\/h4>\n\n<ul>\n<li><strong>About page<\/strong>: Renamed the cross-promo section title from <code>Other products by kbsr<\/code> to <code>Related products<\/code> for a shorter, less self-referential heading. The subtitle now reads <code>More tools from the same team, for Welcart stores and WordPress-powered sites.<\/code> Japanese translations added.<\/li>\n<li><strong>About page<\/strong>: Reduced product card size to roughly half. The grid now caps each card at 260px wide (previously stretched full width when only two cards were present), with tighter padding, smaller heading, and lighter button. Cards now line up compactly rather than dominating the page.<\/li>\n<\/ul>\n\n<h4>0.1.13<\/h4>\n\n<ul>\n<li><strong>Docs<\/strong>: Added an FAQ entry on email deliverability. Hosuke sends through the standard <code>wp_mail()<\/code> and cannot guarantee inbox delivery on its own. The FAQ now recommends installing an SMTP plugin (WP Mail SMTP, FluentSMTP, Post SMTP, etc.) connected to an authenticated sending service, and reminds site operators to publish correct SPF, DKIM and DMARC records. This mirrors the guidance given by the official WooCommerce Back In Stock Notifications extension and matches accepted practice for automated store notifications.<\/li>\n<li><strong>Metadata<\/strong>: Bumped <code>Tested up to<\/code> to 7.0 (previous: 6.7) to reflect the currently supported WordPress line. <code>Requires at least<\/code> remains 6.0.<\/li>\n<\/ul>\n\n<h4>0.1.12<\/h4>\n\n<ul>\n<li><strong>Notify button visual redesign<\/strong>: The frontend notify button now inherits Welcart cart-button sizing (font-size 14px, padding 15px 24px, 3px radius, 1px letter-spacing, uppercase-ish CTA weight) and adds <code>.skubutton<\/code> alongside <code>.hosuke-notify-button<\/code> so themes that style the cart button will pick this one up too. Visually it is an outline pattern (transparent fill, orange border and label) that inverts to solid orange on hover, matching the cart button color exactly while remaining distinguishable from it. A small bell icon (inline SVG) sits at the left to signal \"email notification\".<\/li>\n<\/ul>\n\n<h4>0.1.11<\/h4>\n\n<ul>\n<li><strong>UX<\/strong>: The default frontend button label \"Notify me when back in stock\" is now localized. Existing Japanese-locale sites that had the English default persisted in the database will be migrated to <code>\u5165\u8377\u3057\u305f\u3089\u901a\u77e5\u3092\u53d7\u3051\u53d6\u308b<\/code> on upgrade (customized labels are preserved).<\/li>\n<li><strong>About page<\/strong>: Fixed dead cross-promotion links \u2014 Banto now points to <code>https:\/\/banto.kbsr.co.jp\/<\/code> and Bunsuke to <code>https:\/\/bunsuke.kbsr.co.jp\/<\/code> (previous URLs 404'd).<\/li>\n<li><strong>About page<\/strong>: Added dark, minimal SVG thumbnails for each cross-promoted product, matching the tone of the actual product landing pages. Cards now have a hover elevation effect.<\/li>\n<\/ul>\n\n<h4>0.1.10<\/h4>\n\n<ul>\n<li><strong>Bug fix: variable buttons no longer insert into the first Subject field when nothing is focused.<\/strong> The JavaScript initializer was pre-seeding the \"last focused\" tracker to the first Subject field on page load, so clicking a variable badge without ever focusing anywhere inserted into <code>hosuke_templates_registration[subject]<\/code>. This has been removed \u2014 the tracker now only updates on genuine focus events. If no field has been focused, the variable is copied to the clipboard as documented.<\/li>\n<li><strong>Bug fix: existing Japanese sites now get Japanese template defaults on upgrade.<\/strong> Two problems combined to leave defaults in English: (a) WordPress 6.7+ defers <code>load_plugin_textdomain()<\/code> until <code>init<\/code> when called earlier, so <code>__()<\/code> during activation returned the source (English) string; and (b) <code>add_option()<\/code> never overwrites existing values, so v0.1.3 \u2192 v0.1.9 sites retained the English defaults even after we fixed the loading. This release loads the <code>.mo<\/code> file directly via <code>load_textdomain()<\/code> at plugin file load (bypassing the 6.7 deferral), and adds an upgrade migration that replaces English defaults with the current locale's translations if \u2014 and only if \u2014 the current template exactly matches the known English default (customized templates are never touched). Japanese translations for all three template bodies (registration confirmation, restock notification, admin alert) have been added to <code>hosuke-ja.mo<\/code>.<\/li>\n<\/ul>\n\n<h4>0.1.9<\/h4>\n\n<ul>\n<li>Admin UX improvements based on feedback:<\/li>\n<li><strong>Notification Emails<\/strong> (renamed from \"Email Templates\"): \"Available variables\" now shows as clickable buttons that insert the variable at the cursor position in the last focused Subject or Body field, with a Japanese description on each button. If no field is focused it falls back to copying the variable to the clipboard, with a toast confirmation.<\/li>\n<li><strong>Settings<\/strong>: Reorganized into a Basic \/ Advanced tab pattern. Basic tab shows General, Privacy, reCAPTCHA and Restock list page settings that most stores adjust. Advanced tab shows retry\/queue tuning, retention days, spam thresholds, and uninstall behaviour that rarely need touching.<\/li>\n<li><strong>Sidebar menu<\/strong>: renamed the \"\u30e1\u30fc\u30eb\u30c6\u30f3\u30d7\u30ec\" item to \"\u901a\u77e5\u30e1\u30fc\u30eb\" (Notification Emails) for a more consistent, business-oriented label.<\/li>\n<li><strong>Japanese defaults<\/strong>: <code>load_plugin_textdomain()<\/code> is now called synchronously in the plugin bootstrap and inside the activation hook, so <code>__()<\/code> resolves to Japanese during <code>Activator::seedOptions()<\/code>. Sites with Japanese locale now get Japanese default email subjects and bodies out of the box, while other locales stay with the English defaults.<\/li>\n<\/ul>\n\n<h4>0.1.8<\/h4>\n\n<ul>\n<li>Added a defensive <code>admin_init<\/code> fallback that scans all SKUs with pending notifications and reverifies them at shutdown of every admin request. This guarantees restock detection even if the <code>updated_post_meta<\/code> hook fails to fire for any reason (direct SQL, cache-only writes, etc.).<\/li>\n<li>Added unconditional diagnostic logging via <code>error_log<\/code>: each <code>processSku<\/code> call now logs <code>post_id<\/code>, <code>sku<\/code>, <code>new_stock<\/code>, <code>prev_stock<\/code>, <code>is_restock<\/code> decision, and pending notification count. The shutdown handler also logs which post_ids it is checking.<\/li>\n<\/ul>\n\n<h4>0.1.7<\/h4>\n\n<ul>\n<li>Redesigned stock change detection to be transport-agnostic. Previously v0.1.2 \u2192 v0.1.6 tried to identify each Welcart save mechanism (<code>save_post<\/code>, <code>usces_action_save_product<\/code>, <code>admin.php?page=usces_itemedit<\/code> POST, <code>wp_ajax_item_sku_ajax<\/code>, etc.) and hook into each one individually. Every one of these paths ends in a postmeta write, so this release hooks <code>updated_post_meta<\/code>, <code>added_post_meta<\/code>, and <code>deleted_post_meta<\/code> instead \u2014 capturing the change once, at the moment the write actually lands, regardless of which surface triggered it. The captured post IDs are then re-checked at <code>shutdown<\/code> (fastcgi_finish_request first, so admin UX is unaffected). Non-Welcart posts pass through <code>isWelcartItem()<\/code> and are ignored, so this broad hook has no side effects.<\/li>\n<\/ul>\n\n<h4>0.1.6<\/h4>\n\n<ul>\n<li>Corrected the AJAX action name used to detect per-SKU stock changes from the Welcart legacy product editor. v0.1.5 hooked <code>wp_ajax_updateitemsku<\/code> \/ <code>additemsku<\/code> \/ <code>deleteitemsku<\/code> based on the sub-command passed to <code>itemSku.post()<\/code>, but the actual WordPress AJAX action name is <code>item_sku_ajax<\/code> (the sub-command is only a body parameter). Confirmed by intercepting the actual XHR request. The hook is now <code>wp_ajax_item_sku_ajax<\/code> at priority 1 (so it runs before Welcart's handler calls <code>wp_die()<\/code>).<\/li>\n<\/ul>\n\n<h4>0.1.5<\/h4>\n\n<ul>\n<li>Restock detection now fires reliably from the Welcart legacy product editor's per-SKU update button. Investigation revealed that the per-SKU \"\u66f4\u65b0\" button is a non-submit <code>&lt;input type=\"button\"&gt;<\/code> that triggers an AJAX call (<code>admin-ajax.php?action=updateitemsku<\/code>), not a form POST to <code>admin.php?page=usces_itemedit<\/code>. The v0.1.2\/v0.1.4 detection hooks were missing this path entirely, so stock changes made from that button were only picked up 15 minutes later by the periodic scanner. This release adds hooks for <code>wp_ajax_updateitemsku<\/code>, <code>wp_ajax_additemsku<\/code>, and <code>wp_ajax_deleteitemsku<\/code>, so per-SKU stock changes are detected within seconds instead of up to 15 minutes.<\/li>\n<\/ul>\n\n<h4>0.1.4<\/h4>\n\n<ul>\n<li>Upgrade migrations now also run on plugin file replacement (in addition to explicit reactivation). Previously the v0.1.3 email template migration required the site owner to deactivate and reactivate the plugin, which many installations did not do. As a result, sites upgrading from v0.1.2 could remain on the old, spam-prone default subject\/body. The migration now fires automatically via <code>admin_init<\/code> when <code>hosuke_db_version<\/code> is behind the current release.<\/li>\n<li>Mail sending now writes unconditional log entries (<code>error_log<\/code>) for every <code>wp_mail()<\/code> call \u2014 both the return value (TRUE\/FALSE) and the subject line. In addition, <code>wp_mail_failed<\/code> errors from PHPMailer (SMTP errors, invalid addresses, etc.) are captured and logged with the raw error data. This makes deliverability triage possible without turning on <code>WP_DEBUG<\/code>.<\/li>\n<\/ul>\n\n<h4>0.1.3<\/h4>\n\n<ul>\n<li>Email deliverability improvements for the restock notification:\n\n<ul>\n<li>Added <code>List-Unsubscribe<\/code> and <code>List-Unsubscribe-Post: List-Unsubscribe=One-Click<\/code> headers (RFC 2369, RFC 8058). Gmail specifically favors messages with these headers and delivers them to the inbox at a much higher rate than automated mail without them.<\/li>\n<li>Added <code>Auto-Submitted: auto-generated<\/code> header (RFC 3834) to declare the message is machine-generated, which reduces spam scoring and suppresses vacation-reply loops.<\/li>\n<li>Default restock subject changed from <code>[shop] {item_name} is back in stock!<\/code> to <code>[shop] {item_name} is available again<\/code> (removed the exclamation mark and the \"back in stock\" phrase, both of which are strong spam-filter signals).<\/li>\n<li>Default restock body reworded to remove promotional urgency phrases (\"Good news!\", \"stock is limited\", \"sell out again quickly\") that measurably increase spam classification at Gmail\/Outlook.<\/li>\n<\/ul><\/li>\n<li>Upgrade migration: existing installations whose restock template still contains the v0.1.2 defaults are automatically updated to the new copy. Customized templates are left untouched.<\/li>\n<\/ul>\n\n<h4>0.1.2<\/h4>\n\n<ul>\n<li>Unsubscribe page now uses a dedicated auto-created page (<code>\/hosuke-unsubscribe\/<\/code>) with the shortcode <code>[hosuke_unsubscribe]<\/code>, so it renders inside the theme's normal <code>page.php<\/code> template \u2014 no more front-page hero visuals leaking into the unsubscribe view. Existing unsubscribe URLs in previously sent emails are automatically 302-redirected to the new page for backward compatibility.<\/li>\n<li>Stock changes made from the Welcart legacy product editor (<code>admin.php?page=usces_itemedit<\/code>, including the per-SKU update button) are now detected and trigger restock notifications. This closes a gap where SKU-only meta updates bypassed the standard <code>save_post<\/code> hook.<\/li>\n<li>Deferred SKU meta checks: SKU meta filters are now evaluated at <code>shutdown<\/code> (after all meta writes complete) so the stock snapshot reads the fresh value rather than the pre-save value.<\/li>\n<li>Admin \"Registrations\" list now links the product column to the Welcart product editor instead of the Gutenberg block editor.<\/li>\n<li>Improved messaging on invalid\/expired unsubscribe tokens.<\/li>\n<\/ul>\n\n<h4>0.1.1<\/h4>\n\n<ul>\n<li>Restock notifications are now sent immediately when stock is restored (previously waited up to 5 minutes for the next cron tick).<\/li>\n<li>WP-Cron self-heal: send queue is re-scheduled automatically if the event was lost due to site migration or deactivation.<\/li>\n<li>Notify button and modal submit now use the Welcart Basic orange to match the theme. Colors can be overridden via the <code>--hosuke-primary<\/code> CSS custom property.<\/li>\n<li>Unsubscribe page redesigned as a centered card with clearer status icon, item details, and call-to-action button.<\/li>\n<li>Frontend CSS is now loaded on the unsubscribe page (previously only on product pages).<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Independent restock notification plugin for Welcart e-Commerce. SKU-level registration, customizable email templates, restock listing page, and reCAPT &hellip;","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/337282","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=337282"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/kbsrco"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=337282"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=337282"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=337282"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=337282"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=337282"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=337282"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}