{"id":318229,"date":"2026-05-29T08:02:10","date_gmt":"2026-05-29T08:02:10","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/postvibe-newsletter-studio-for-sendy\/"},"modified":"2026-05-29T08:00:44","modified_gmt":"2026-05-29T08:00:44","slug":"quillrush-newsletter-studio-for-sendy","status":"publish","type":"plugin","link":"https:\/\/th.wordpress.org\/plugins\/quillrush-newsletter-studio-for-sendy\/","author":23298972,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.6.2","stable_tag":"1.6.2","tested":"7.0.2","requires":"5.8","requires_php":"7.4","requires_plugins":null,"header_name":"Quillrush Newsletter Studio for Sendy","header_author":"Gunjan Jaswal","header_description":"Connects WordPress to Sendy (via Amazon SES) to create and send newsletters from your content. Visual builder, scheduling, multi-list, and editorial newsletter formats.","assets_banners_color":"57bcb8","last_updated":"2026-05-29 08:00:44","external_support_url":"","external_repository_url":"","donate_link":"https:\/\/ko-fi.com\/gunjanjaswal","header_plugin_uri":"https:\/\/wordpress.org\/plugins\/quillrush-newsletter-studio-for-sendy\/","header_author_uri":"https:\/\/gunjanjaswal.me","rating":0,"author_block_rating":0,"active_installs":0,"downloads":120,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.6.2":{"tag":"1.6.2","author":"gunjanjaswal","date":"2026-05-29 08:00:44"}},"upgrade_notice":{"1.6.2":"<p>Security hardening: per-field POST sanitization + dedicated email-HTML kses allowlist for newsletter content. Remote-loaded social icons replaced with self-contained styled buttons.<\/p>","1.6.1":"<p>Fixes duplicate &quot;View details&quot; entry on the Plugins screen.<\/p>","1.6.0":"<p>WordPress 7.0 tested; PHP 7.4 minimum. Adds one-time auto-migration from predecessor installs (settings, campaigns, post-meta, list-cache, and pending scheduled sends), Ko-fi support link, Plugin Support + Contact Developer row meta, and a Support card on the Settings screen.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3584157,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3584158,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500-es.png":{"filename":"banner-1544x500-es.png","revision":3584154,"resolution":"1544x500","location":"assets","locale":"es","width":1544,"height":500},"banner-1544x500-es_ES.png":{"filename":"banner-1544x500-es_ES.png","revision":3584155,"resolution":"1544x500","location":"assets","locale":"es_ES","width":1544,"height":500},"banner-1544x500-rtl.png":{"filename":"banner-1544x500-rtl.png","revision":3584156,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3584151,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250-es.png":{"filename":"banner-772x250-es.png","revision":3584148,"resolution":"772x250","location":"assets","locale":"es","width":772,"height":250},"banner-772x250-es_ES.png":{"filename":"banner-772x250-es_ES.png","revision":3584149,"resolution":"772x250","location":"assets","locale":"es_ES","width":772,"height":250},"banner-772x250-rtl.png":{"filename":"banner-772x250-rtl.png","revision":3584150,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3584146,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.6.2"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"Newsletter Builder \u2014 search for posts, drag them into the layout, watch the live preview.","2":"Settings \u2192 Sendy Connection \u2014 Installation URL, API Key, Brand ID, defaults.","3":"Settings \u2192 The Insider Brief Texts \u2014 every editorial line customisable.","4":"Campaigns CPT \u2014 status colours at a glance (draft \/ scheduled \/ sent \/ failed).","5":"Responsive email preview \u2014 2-column desktop \u2192 single-column mobile."}},"plugin_section":[],"plugin_tags":[265,264,455,46118,264894],"plugin_category":[41,42],"plugin_contributors":[245263],"plugin_business_model":[],"class_list":["post-318229","plugin","type-plugin","status-publish","hentry","plugin_tags-amazon-ses","plugin_tags-email-marketing","plugin_tags-newsletter","plugin_tags-sendy","plugin_tags-sendy-ses","plugin_category-communication","plugin_category-contact-forms","plugin_contributors-gunjanjaswal","plugin_committers-gunjanjaswal"],"banners":{"banner":"https:\/\/ps.w.org\/quillrush-newsletter-studio-for-sendy\/assets\/banner-772x250.png?rev=3584146","banner_2x":"https:\/\/ps.w.org\/quillrush-newsletter-studio-for-sendy\/assets\/banner-1544x500.png?rev=3584151","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/quillrush-newsletter-studio-for-sendy\/assets\/icon-128x128.png?rev=3584157","icon_2x":"https:\/\/ps.w.org\/quillrush-newsletter-studio-for-sendy\/assets\/icon-256x256.png?rev=3584158","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>\ud83d\udce7 <strong>Quillrush Newsletter Studio for Sendy<\/strong> turns your WordPress dashboard into a full-blown newsletter creation studio for the <strong>Sendy + Amazon SES<\/strong> stack. Drag your latest posts into a beautiful responsive HTML email, pick the Sendy lists\/segments to ship to, and send via your self-hosted Sendy installation, which forwards every message through Amazon SES. No HTML coding. No external SaaS. No paid tier.<\/p>\n\n<blockquote>\n  <p>\u26a0\ufe0f <strong>Requires a self-hosted Sendy install backed by Amazon SES.<\/strong> This plugin is the WordPress front-end \u2014 it does not replace Sendy or SES. If you don't have Sendy + SES set up yet, see <a href=\"https:\/\/sendy.co\/\">sendy.co<\/a> and <a href=\"https:\/\/aws.amazon.com\/ses\/\">aws.amazon.com\/ses<\/a>.<\/p>\n<\/blockquote>\n\n<h4>\u2728 Headline features<\/h4>\n\n<ul>\n<li>\ud83c\udfa8 <strong>Visual newsletter builder<\/strong> \u2014 drag posts in, see the rendered email update live.<\/li>\n<li>\ud83d\udce8 <strong>Two newsletter formats per campaign<\/strong> \u2014 <em>The Roundup<\/em> (subscriber-facing) and <em>The Insider Brief<\/em> (editorial pitch for media &amp; partners).<\/li>\n<li>\ud83d\udccb <strong>Auto-fetched Sendy lists &amp; segments<\/strong> \u2014 pulled live via the Sendy API, shown as checkboxes with active subscriber counts. Cached 10 minutes; one-click refresh.<\/li>\n<li>\ud83e\udde0 <strong>Remembers your last selection<\/strong> \u2014 the lists you sent to last time are pre-checked next time.<\/li>\n<li>\ud83d\udd0d <strong>Infinite-scroll post search<\/strong> \u2014 AJAX-loads posts in batches of 10 as you scroll.<\/li>\n<li>\ud83d\uddbc\ufe0f <strong>Smart hero image<\/strong> \u2014 uses your uploaded banner if present, otherwise falls back to the first post's featured image.<\/li>\n<li>\ud83d\udcf1 <strong>Mobile-first responsive layout<\/strong> \u2014 2 columns on desktop, single column on mobile (&lt; 600px), auto-height cards.<\/li>\n<li>\ud83d\udcc5 <strong>Three send modes<\/strong> \u2014 Save as Draft in Sendy, Send Immediately, or Schedule for a future date\/time.<\/li>\n<li>\ud83d\udd50 <strong>Timezone-aware scheduling<\/strong> \u2014 uses your WordPress timezone; shows current server time + zone next to the picker.<\/li>\n<li>\u267b\ufe0f <strong>Auto-recovery for overdue campaigns<\/strong> \u2014 if WP-Cron didn't fire on time, overdue scheduled campaigns are auto-sent on next admin page-load.<\/li>\n<li>\ud83d\udee0\ufe0f <strong>Retry on failure<\/strong> \u2014 failed sends show the exact Sendy error + a one-click Retry Send button.<\/li>\n<li>\u2699\ufe0f <strong>Optional cron trigger<\/strong> \u2014 after each send, optionally hit <code>scheduled.php?i=BRAND_ID<\/code> on your Sendy host so queued campaigns process without a server cron.<\/li>\n<li>\u270d\ufe0f <strong>Custom footer block<\/strong> \u2014 extra text\/HTML above the footer in a highlighted box. Supports anchor tags + auto <code>nl2br<\/code>.<\/li>\n<li>\ud83c\udf10 <strong>Social footer icons<\/strong> \u2014 Instagram, LinkedIn, X (Twitter), YouTube.<\/li>\n<li>\ud83d\uddc3\ufe0f <strong>Campaign history<\/strong> \u2014 every campaign stored as a <code>qrnss_campaign<\/code> custom-post-type entry with Status \/ Scheduled For \/ Error columns.<\/li>\n<li>\ud83d\udd12 <strong>WordPress-native security<\/strong> \u2014 nonces on every action, <code>manage_options<\/code> capability checks, <code>wp_safe_redirect()<\/code> for all redirects.<\/li>\n<\/ul>\n\n<h4>\ud83d\udce8 The two newsletter formats<\/h4>\n\n<p>\ud83d\uddde\ufe0f <strong>The Roundup<\/strong> \u2014 visual hero + 2-column story grid for your subscribers. Uses the \"Custom Footer Text\" highlighted box.<\/p>\n\n<p>\u2709\ufe0f <strong>The Insider Brief<\/strong> \u2014 personal greeting, lead paragraph, centered hero with featured image, \"What Else We're Seeing\" 2-column grid, \"Why this matters\" callout, \"For Media &amp; Collaborations\" CTA block, and a centered About Us block. Built for media pitches &amp; partner updates. All copy editable from <em>Settings \u2192 The Insider Brief \u2014 Template Texts<\/em>.<\/p>\n\n<p>Pick the format per-campaign on the Create Newsletter page (Design Settings \u2192 Newsletter Format). Header and dark footer (logo, social, copyright, unsubscribe) are shared across both formats.<\/p>\n\n<h4>\ud83d\udccb Full settings reference<\/h4>\n\n<p>\ud83d\udd0c <strong>Sendy Connection Settings<\/strong><\/p>\n\n<ul>\n<li><strong>Sendy Installation URL<\/strong> \u2014 base URL of your Sendy install (e.g. <code>https:\/\/sendy.yourdomain.com\/<\/code>).<\/li>\n<li><strong>API Key<\/strong> \u2014 from Sendy \u2192 Settings \u2192 Your API Key.<\/li>\n<li><strong>Brand ID (Optional)<\/strong> \u2014 from Sendy \u2192 Settings \u2192 Your Brand \u2192 ID. Required by some Sendy versions and used for auto-fetching lists.<\/li>\n<li><strong>Default From Name<\/strong> \u2014 pre-filled into every new campaign.<\/li>\n<li><strong>Default From Email<\/strong> \u2014 pre-filled into every new campaign.<\/li>\n<li><strong>Auto-Trigger Cron<\/strong> \u2014 checkbox. After sending, hit <code>&lt;sendy-url&gt;\/scheduled.php?i=BRAND_ID<\/code> so queued campaigns process without a system cron.<\/li>\n<li><strong>Show Article Excerpt<\/strong> \u2014 checkbox. Insert a 20-word excerpt between the post title and the \"Read More\" button.<\/li>\n<\/ul>\n\n<p>\ud83c\udfa8 <strong>Footer &amp; Social Settings<\/strong><\/p>\n\n<ul>\n<li><strong>Footer Logo URL<\/strong> \u2014 logo shown in the dark footer band.<\/li>\n<li><strong>Copyright Text<\/strong> \u2014 footer copyright line. <code>{year}<\/code> is replaced with the current year.<\/li>\n<li><strong>Custom Footer Text<\/strong> \u2014 textarea, HTML allowed. Shown in a highlighted box above the footer in <em>The Roundup<\/em>. Newlines \u2192 <code>&lt;br&gt;<\/code> automatically.<\/li>\n<li><strong>\"Read More Articles\" Link<\/strong> \u2014 optional link below the post grid.<\/li>\n<li><strong>Instagram URL<\/strong> \/ <strong>LinkedIn URL<\/strong> \/ <strong>X (Twitter) URL<\/strong> \/ <strong>YouTube URL<\/strong> \u2014 social icons in footer.<\/li>\n<\/ul>\n\n<p>\u2709\ufe0f <strong>The Insider Brief \u2014 Template Texts<\/strong> <em>(used only by The Insider Brief format)<\/em><\/p>\n\n<ul>\n<li><strong>Greeting<\/strong> \u2014 e.g. <code>Hi [First Name],<\/code><\/li>\n<li><strong>Intro Paragraph<\/strong> \u2014 lead paragraph above the hero story (HTML allowed).<\/li>\n<li><strong>Hero Section Label<\/strong> \u2014 small label above the hero (e.g. <code>Hero Story<\/code>).<\/li>\n<li><strong>Grid Section Heading<\/strong> \u2014 e.g. <code>\ud83d\udd0d What Else We're Seeing<\/code><\/li>\n<li><strong>\"Why This Matters\" Heading + Body<\/strong><\/li>\n<li><strong>Collaboration Heading + Body<\/strong> \u2014 e.g. <code>\ud83d\udce9 For Media &amp; Collaborations<\/code> + CTA bullets and contact info (HTML allowed).<\/li>\n<li><strong>About Us Heading + Body<\/strong> \u2014 centered About block above the footer.<\/li>\n<\/ul>\n\n<h4>\ud83d\udcc5 Send modes<\/h4>\n\n<ul>\n<li>\ud83d\udcbe <strong>Save as Draft in Sendy<\/strong> \u2014 POSTs to <code>create-campaign.php<\/code> with <code>send_campaign=0<\/code>. Campaign appears in your Sendy dashboard as a draft. WP logs status: <code>draft<\/code>.<\/li>\n<li>\ud83d\ude80 <strong>Send Immediately<\/strong> \u2014 POSTs to <code>create-campaign.php<\/code> with <code>send_campaign=1<\/code>. Sendy queues + dispatches via SES. WP logs status: <code>sent<\/code>. If <em>Auto-Trigger Cron<\/em> is on, also hits <code>scheduled.php?i=BRAND_ID<\/code>.<\/li>\n<li>\u23f0 <strong>Schedule<\/strong> \u2014 stored as a <code>qrnss_campaign<\/code> post with status <code>scheduled<\/code>. WordPress registers a one-off <code>wp_schedule_single_event<\/code> for the chosen datetime. When the event fires, the plugin sends via Sendy. Datetime picker is timezone-aware and uses your WP timezone setting.<\/li>\n<\/ul>\n\n<h4>\ud83d\udedf Failure handling<\/h4>\n\n<p>Failed sends never silently disappear:<\/p>\n\n<ul>\n<li>\u274c Red admin notice at the top of the Campaigns screen.<\/li>\n<li>\ud83d\udccb Exact Sendy error in the <strong>Error<\/strong> column.<\/li>\n<li>\ud83d\udd01 One-click <strong>Retry Send<\/strong> button (CSRF-nonced).<\/li>\n<li>\u267b\ufe0f Auto-recovery \u2014 overdue scheduled campaigns automatically send on next admin page-load.<\/li>\n<\/ul>\n\n<h4>\ud83d\uddc4\ufe0f Campaign history (CPT)<\/h4>\n\n<p>Every campaign is stored as a <code>qrnss_campaign<\/code> custom-post-type entry. Admin columns:<\/p>\n\n<ul>\n<li><strong>Title<\/strong> \u2014 subject line.<\/li>\n<li><strong>Status<\/strong> \u2014 <code>draft<\/code> (grey), <code>scheduled<\/code> (yellow), <code>sent<\/code> (green), <code>failed<\/code> (red).<\/li>\n<li><strong>Scheduled For<\/strong> \u2014 datetime if scheduled.<\/li>\n<li><strong>Error<\/strong> \u2014 Sendy error message if the send failed.<\/li>\n<\/ul>\n\n<h4>\ud83d\udd0c Sendy API endpoints used<\/h4>\n\n<p>All requests go straight to <strong>your own self-hosted Sendy installation<\/strong> at the URL you set in Settings. The plugin never talks to any third-party SaaS \u2014 Sendy itself fans out to Amazon SES from your host.<\/p>\n\n<ul>\n<li><code>api\/lists\/get-lists.php<\/code> \u2014 fetch lists for the Create Newsletter screen (cached 10 min). Sends: <code>api_key<\/code>, <code>brand_id<\/code>.<\/li>\n<li><code>api\/subscribers\/active-subscriber-count.php<\/code> \u2014 per-list subscriber counts. Sends: <code>api_key<\/code>, <code>list_id<\/code>.<\/li>\n<li><code>api\/campaigns\/create.php<\/code> \u2014 Save as Draft, Send Immediately, scheduled fire. Sends: <code>api_key<\/code>, <code>from_name<\/code>, <code>from_email<\/code>, <code>reply_to<\/code>, <code>title<\/code>, <code>subject<\/code>, <code>html_text<\/code>, <code>plain_text<\/code>, <code>list_ids<\/code>, <code>brand_id<\/code>, <code>send_campaign<\/code>.<\/li>\n<li><code>scheduled.php<\/code> (your Sendy host) \u2014 only when <em>Auto-Trigger Cron<\/em> is ticked. Sends: <code>i=BRAND_ID<\/code> query param.<\/li>\n<\/ul>\n\n<h4>\ud83d\udd12 Requirements<\/h4>\n\n<ul>\n<li>WordPress 5.8 or higher (tested up to 7.0).<\/li>\n<li>PHP 7.4 or higher.<\/li>\n<li>A reasonably recent self-hosted Sendy installation.<\/li>\n<li>Amazon SES configured inside Sendy (out of scope for this plugin).<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin files to <code>\/wp-content\/plugins\/quillrush-newsletter-studio-for-sendy<\/code>, or install via Plugins \u2192 Add New.<\/li>\n<li>Activate the plugin through the Plugins screen.<\/li>\n<li>Open <strong>Quillrush Newsletter<\/strong> in the admin sidebar.<\/li>\n<li>Fill in <strong>Sendy Installation URL<\/strong>, <strong>API Key<\/strong>, and (recommended) <strong>Brand ID<\/strong>. Hit <strong>Save Settings<\/strong>.<\/li>\n<li>Go to <strong>Quillrush Newsletter \u2192 Create Newsletter<\/strong> \u2014 your Sendy lists appear as checkboxes with subscriber counts. Build away!<\/li>\n<\/ol>\n\n<h4>\ud83c\udd99 Migrating from a predecessor install<\/h4>\n\n<p>If you previously ran an earlier release line under a different option\/CPT\/meta prefix (e.g. <code>sssb_*<\/code> or <code>pvnss_*<\/code>), the plugin auto-migrates everything on first load:<\/p>\n\n<ul>\n<li>All matching options \u2192 <code>qrnss_*<\/code> (including dynamic list-cache transients)<\/li>\n<li>Custom-post-type rows \u2192 <code>qrnss_campaign<\/code><\/li>\n<li>Every legacy post-meta key \u2192 <code>_qrnss_*<\/code><\/li>\n<li>Any pending legacy <code>*_send_scheduled_campaign<\/code> cron event \u2192 <code>qrnss_send_scheduled_campaign<\/code><\/li>\n<li>Rewrite rules flushed<\/li>\n<\/ul>\n\n<p>Each legacy prefix is guarded by a one-shot <code>qrnss_migrated_from_&lt;prefix&gt;<\/code> flag \u2014 runs at most once per install. Existing campaigns, drafts, scheduled sends, list-cache, and settings come across without manual intervention.<\/p>\n\n<p>Steps:<\/p>\n\n<ol>\n<li>Deactivate the previous plugin in WP Admin.<\/li>\n<li>Delete it (your data lives in <code>wp_options<\/code> \/ <code>wp_posts<\/code> \/ <code>wp_postmeta<\/code>, safe).<\/li>\n<li>Install + Activate Quillrush Newsletter Studio for Sendy.<\/li>\n<li>Migration fires automatically on first load. Existing campaigns appear under the new top-level menu.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"why%20didn%27t%20my%20scheduled%20campaign%20send%20on%20time%3F\"><h3>Why didn't my scheduled campaign send on time?<\/h3><\/dt>\n<dd><p>WP-Cron only runs on page-loads. The plugin auto-recovers overdue campaigns on next admin page-load (you'll see a green success notice). For deterministic timing on production sites, replace WP-Cron with a system cron:<\/p>\n\n<pre><code>define('DISABLE_WP_CRON', true); in `wp-config.php`, then add a server cron:\n\n* * * * * wget -q -O - https:\/\/yourdomain.com\/wp-cron.php?doing_wp_cron &gt;\/dev\/null 2&gt;&amp;1\n<\/code><\/pre><\/dd>\n<dt id=\"my%20campaign%20is%20stuck%20on%20%22preparing%20to%20send...%22%20in%20sendy.\"><h3>My campaign is stuck on \"Preparing to send...\" in Sendy.<\/h3><\/dt>\n<dd><p>Sendy's own cron isn't running. Either:<\/p>\n\n<ul>\n<li>Tick <strong>Auto-Trigger Cron<\/strong> in plugin settings, OR<\/li>\n<li><p>Add a server cron on the Sendy host:<\/p>\n\n<p>*\/5 * * * * php \/path\/to\/sendy\/scheduled.php &gt; \/dev\/null 2&gt;&amp;1<\/p><\/li>\n<\/ul><\/dd>\n<dt id=\"my%20lists%20don%27t%20appear%20in%20create%20newsletter.\"><h3>My lists don't appear in Create Newsletter.<\/h3><\/dt>\n<dd><p>Check <strong>Sendy Installation URL<\/strong>, <strong>API Key<\/strong>, and <strong>Brand ID<\/strong> in Settings. The plugin fetches lists via <code>api\/lists\/get-lists.php<\/code> which requires the Brand ID on most Sendy versions. Use the <strong>Refresh lists from Sendy<\/strong> link on the Create Newsletter page to bust the 10-minute cache.<\/p><\/dd>\n<dt id=\"a%20campaign%20failed.%20how%20do%20i%20retry%3F\"><h3>A campaign failed. How do I retry?<\/h3><\/dt>\n<dd><p>Open <strong>Quillrush Newsletter \u2192 Campaigns<\/strong> in the admin sidebar. Failed campaigns show the exact Sendy error and a <strong>Retry Send<\/strong> button. The retry clears the previous error before re-sending.<\/p><\/dd>\n<dt id=\"can%20i%20customise%20the%20editorial%20copy%20without%20touching%20code%3F\"><h3>Can I customise the editorial copy without touching code?<\/h3><\/dt>\n<dd><p>Yes. Every line of \"The Insider Brief\" (greeting, intro, hero label, grid heading, \"Why this matters\", collaboration block, About Us) lives under <strong>Settings \u2192 The Insider Brief \u2014 Template Texts<\/strong>. HTML allowed where appropriate.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20wordpress%207.0%20%2F%20php%207.4%2B%3F\"><h3>Does it work with WordPress 7.0 \/ PHP 7.4+?<\/h3><\/dt>\n<dd><p>Yes. Tested up to WordPress 7.0. PHP 7.4 minimum.<\/p><\/dd>\n<dt id=\"where%20does%20the%20plugin%20send%20data%3F\"><h3>Where does the plugin send data?<\/h3><\/dt>\n<dd><p>Only to <strong>your own self-hosted Sendy installation<\/strong> at the URL you set in Settings. No third-party SaaS. Sendy itself handles the SES handoff from your host.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.6.2<\/h4>\n\n<ul>\n<li>Security: every <code>$_POST['campaign']<\/code> field is now sanitized individually before use (subject, from_name, from_email, plain_text, list_id, send_type, schedule_date). The <code>html_text<\/code> field is run through a dedicated email-safe <code>wp_kses<\/code> allowlist (tables, inline styles, images, anchors, headings, lists \u2014 but no <code>&lt;script&gt;<\/code>, <code>&lt;iframe&gt;<\/code>, <code>&lt;form&gt;<\/code>, or <code>on*<\/code> event attributes) before it is stored to <code>post_content<\/code> or sent to the Sendy API. New filter <code>qrnss_email_kses_allowed_html<\/code> lets third parties extend the allowlist.<\/li>\n<li>Required-field validation: subject, from_email, and html_text must be non-empty; send_type must be one of <code>draft<\/code> \/ <code>send<\/code> \/ <code>schedule<\/code> or it falls back to <code>draft<\/code>.<\/li>\n<li>Removed remote-loaded social icons. The footer in the rendered newsletter and the admin preview no longer fetch Instagram\/LinkedIn\/X\/YouTube logos from flaticon.com \/ wikimedia.org \/ freepik.com \u2014 they now use self-contained styled letter-buttons (<code>IG<\/code>, <code>in<\/code>, <code>X<\/code>, <code>YT<\/code>) so the plugin has zero remote-image dependencies and the newsletter renders identically offline \/ in restricted email clients.<\/li>\n<\/ul>\n\n<h4>1.6.1<\/h4>\n\n<ul>\n<li>Fix: removed the plugin's own injected \"View details\" row-meta link to prevent a duplicate entry, since WordPress auto-injects \"View details\" for wp.org-hosted plugins. Row meta is now <code>View details | Plugin Support | Contact Developer<\/code>.<\/li>\n<\/ul>\n\n<h4>1.6.0<\/h4>\n\n<ul>\n<li><strong>WordPress 7.0 tested<\/strong> and audited; PHP minimum bumped to 7.4.<\/li>\n<li>Added <code>Requires at least<\/code>, <code>Tested up to<\/code>, and <code>Requires PHP<\/code> headers to the main plugin file.<\/li>\n<li>Added one-time auto-migration on first load (priority 1) for predecessor installs: sweeps every legacy option, custom-post-type row, post-meta key, and pending scheduled cron event to the current <code>qrnss_*<\/code> namespace. Per-prefix guard flag so each migration path runs at most once.<\/li>\n<li>Added <strong>Support on Ko-fi<\/strong> action link next to Deactivate on the Plugins screen.<\/li>\n<li>Added <strong>Plugin Support<\/strong> (wordpress.org\/support\/plugin\/quillrush-newsletter-studio-for-sendy) and <strong>Contact Developer<\/strong> (mailto:hello@gunjanjaswal.me) row-meta entries.<\/li>\n<li>Added \"Support the developer\" card on the Settings screen with branded Ko-fi button, Plugin Support Forum link, and Contact Developer mailto.<\/li>\n<li>Donate link set to Ko-fi (https:\/\/ko-fi.com\/gunjanjaswal).<\/li>\n<\/ul>\n\n<h4>1.5.2<\/h4>\n\n<ul>\n<li>Fix: Infinite scroll in the \"Add Posts\" panel now actually triggers. The scroll handler was using event delegation which doesn't work for scroll events; it's now bound directly to the results container.<\/li>\n<\/ul>\n\n<h4>1.5.1<\/h4>\n\n<ul>\n<li>Improvement: \"About Us\" body in The Insider Brief footer block is now centered (heading was already centered).<\/li>\n<li>Cleanup: Removed all \"Buy Me A Coffee\" links and the Support card from the settings page, newsletter builder, plugin row meta, and readme files.<\/li>\n<\/ul>\n\n<h4>1.5.0<\/h4>\n\n<ul>\n<li>Feature: \"Add Posts\" panel now supports infinite scroll. Older posts load automatically as you scroll the results list (10 at a time).<\/li>\n<li>Internal: <code>qrnss_search_posts<\/code> AJAX endpoint now accepts a <code>page<\/code> parameter and returns <code>{ posts, page, has_more }<\/code>.<\/li>\n<\/ul>\n\n<h4>1.4.x<\/h4>\n\n<ul>\n<li>Feature: Auto-fetched Sendy lists with active subscriber counts. Cached 10 minutes; one-click refresh.<\/li>\n<li>Feature: Plugin remembers the lists used in your last send and pre-checks them next time.<\/li>\n<li>Feature: Editorial format (\"The Insider Brief\") added alongside The Roundup. All copy editable from settings.<\/li>\n<\/ul>\n\n<h4>1.3.x<\/h4>\n\n<ul>\n<li>Feature: Scheduled sending with timezone-aware datetime picker.<\/li>\n<li>Feature: Failed-campaign retry and auto-recovery for overdue campaigns.<\/li>\n<li>Fix: Schedule datetime picker with proper z-index for calendar visibility.<\/li>\n<li>Fix: Reply-to email correctly passed for all campaign types.<\/li>\n<li>Fix: Resolved \"cURL error 28: SSL connection timeout\".<\/li>\n<li>Security: All inputs properly sanitized and validated.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Newsletter studio for the Sendy + Amazon SES stack. Visual builder, two formats, scheduling, multi-list, auto-fetched lists.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/318229","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=318229"}],"author":[{"embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/gunjanjaswal"}],"wp:attachment":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=318229"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=318229"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=318229"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=318229"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=318229"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=318229"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}