{"id":371911,"date":"2026-09-23T18:19:50","date_gmt":"2026-09-23T18:19:50","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/simple-ads-for-publishers\/"},"modified":"2026-09-23T18:19:27","modified_gmt":"2026-09-23T18:19:27","slug":"hooray-simple-ads","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/hooray-simple-ads\/","author":23565619,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.2.0","stable_tag":"1.2.0","tested":"7.1.2","requires":"6.2","requires_php":"8.0","requires_plugins":null,"header_name":"Hooray Simple Ads","header_author":"Hooray Plugins","header_description":"Direct-sold advertising for publishers who don't want an ad-tech platform.","assets_banners_color":"477e80","last_updated":"2026-09-23 18:19:27","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/profiles.wordpress.org\/hoorayplugins\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":55,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.2.0":{"tag":"1.2.0","author":"hoorayplugins","date":"2026-09-23 18:19:27","revision":3709944}},"upgrade_notice":{"1.2.0":"<p>Renames the plugin to Hooray Simple Ads. Ads, slots, schedules, reporting and\nsettings carry over automatically, and existing shortcodes and blocks keep\nworking. If a PHP template calls zra_ad(), change it to hsads_ad(). Purge your\npage cache afterwards.<\/p>","1.1.2":"<p>Adds privacy policy suggestions and fixes an ad-selection bug.<\/p>","1.1.1":"<p>Stops a signed view or click token being counted again on a later request when a\npersistent object cache is enabled. No schema change since 1.1.0. Purge your\npage cache after upgrading.<\/p>","1.1.0":"<p>Fixes an open redirect and forgeable view counts, repairs rotation across\nmultiple slots, and stops wide ads scrolling the page sideways on phones. Purge\nyour page cache after upgrading.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3709944,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3709944,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3709944,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3709944,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3709944,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.2.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3709944,"resolution":"1","location":"assets","locale":"","width":1280,"height":800},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3709944,"resolution":"2","location":"assets","locale":"","width":1280,"height":800},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3709944,"resolution":"3","location":"assets","locale":"","width":1280,"height":800},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3709944,"resolution":"4","location":"assets","locale":"","width":1280,"height":960},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3709944,"resolution":"5","location":"assets","locale":"","width":1280,"height":800},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3709944,"resolution":"6","location":"assets","locale":"","width":1280,"height":800}},"screenshots":{"1":"Manage your direct-sold ads from one straightforward screen.","2":"Add a creative, destination and schedule without configuring an ad-tech platform.","3":"Define reusable ad slots \u2014 the places ads appear on your site.","4":"Assign creatives to a slot, weight the rotation and set the dates.","5":"First-party impression and click reports you can hand to an advertiser.","6":"Ads appear in the reserved slot on the published page."}},"plugin_section":[],"plugin_tags":[2533,2635,321,368,4084],"plugin_category":[35],"plugin_contributors":[281372,281373],"plugin_business_model":[],"class_list":["post-371911","plugin","type-plugin","status-publish","hentry","plugin_tags-ad-manager","plugin_tags-ad-rotation","plugin_tags-ads","plugin_tags-advertising","plugin_tags-banner-ads","plugin_category-advertising","plugin_contributors-hoorayplugins","plugin_contributors-jbyrne123","plugin_committers-hoorayplugins"],"banners":{"banner":"https:\/\/ps.w.org\/hooray-simple-ads\/assets\/banner-772x250.png?rev=3709944","banner_2x":"https:\/\/ps.w.org\/hooray-simple-ads\/assets\/banner-1544x500.png?rev=3709944","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/hooray-simple-ads\/assets\/icon.svg?rev=3709944","icon":"https:\/\/ps.w.org\/hooray-simple-ads\/assets\/icon.svg?rev=3709944","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/hooray-simple-ads\/assets\/screenshot-1.png?rev=3709944","caption":"Manage your direct-sold ads from one straightforward screen."},{"src":"https:\/\/ps.w.org\/hooray-simple-ads\/assets\/screenshot-2.png?rev=3709944","caption":"Add a creative, destination and schedule without configuring an ad-tech platform."},{"src":"https:\/\/ps.w.org\/hooray-simple-ads\/assets\/screenshot-3.png?rev=3709944","caption":"Define reusable ad slots \u2014 the places ads appear on your site."},{"src":"https:\/\/ps.w.org\/hooray-simple-ads\/assets\/screenshot-4.png?rev=3709944","caption":"Assign creatives to a slot, weight the rotation and set the dates."},{"src":"https:\/\/ps.w.org\/hooray-simple-ads\/assets\/screenshot-5.png?rev=3709944","caption":"First-party impression and click reports you can hand to an advertiser."},{"src":"https:\/\/ps.w.org\/hooray-simple-ads\/assets\/screenshot-6.png?rev=3709944","caption":"Ads appear in the reserved slot on the published page."}],"raw_content":"<!--section=description-->\n<p>Display ads made simple. You sold the ad \u2014 now just put it on your website.<\/p>\n\n<p>Hooray Simple Ads was built by a small publisher who wanted an easier way to\nmanage direct-sold advertising in WordPress. Existing solutions offered far\nmore complexity than the job required.<\/p>\n\n<p>The job itself is straightforward: create an advertiser creative, choose where\nit appears, rotate ads, schedule them, and track basic impressions and clicks \u2014\nincluding on sites that already use aggressive page caching.<\/p>\n\n<p>That is all this plugin is for. It intentionally does less, because for many\npublishers less is exactly what they need.<\/p>\n\n<h4>Place, rotate, schedule and track<\/h4>\n\n<ul>\n<li>Create and manage ad creatives.<\/li>\n<li>Define reusable ad slots.<\/li>\n<li>Assign creatives and rotate them.<\/li>\n<li>Weight rotation when one advertiser should appear more often.<\/li>\n<li>Schedule campaigns so they start and stop on their own.<\/li>\n<li>Track first-party impressions and clicks.<\/li>\n<li>Responsive slots that reserve their space.<\/li>\n<li>Designed to work with cached WordPress pages.<\/li>\n<li>No SaaS account, no plugin-author telemetry, and no external ad-serving\nservice.<\/li>\n<\/ul>\n\n<h4>Why it keeps working behind a cache<\/h4>\n\n<p>Most ad plugins write the advertisement into the page HTML. A full-page cache\nthen stores whichever ad the first visitor happened to get and serves it to\neveryone until the entry expires, so rotation stops without any visible error.<\/p>\n\n<p>This plugin does not put an ad into cacheable HTML. The page contains only an\nempty, correctly sized box, and the advertisement is chosen per pageview by a\nseparate request served with no-store headers. Your cache hit ratio has no\neffect on rotation.<\/p>\n\n<p>There is nothing to configure for LiteSpeed, WP Rocket, Cloudflare or similar,\nand no ESI or fragment-caching setup is required. If a CDN in front of your site\ncaches REST responses by default, exclude this plugin's endpoints; the Settings\nscreen lists them.<\/p>\n\n<h4>What it is not<\/h4>\n\n<p>There is no bidding, no advertiser self-service, no billing and no targeting\nengine. There is no account to create and no service to subscribe to. Nothing is\nsent to any third-party server: it is your site, your database and your numbers.<\/p>\n\n<h4>Placing an ad<\/h4>\n\n<p>Use the <strong>Local Ad Slot<\/strong> block, the <code>[hsads_ad slot=\"...\"]<\/code> shortcode\n(anywhere shortcodes work, including page builders and widgets), or\n    hsads_ad( 'slot-slug' ) in a template.<\/p>\n\n<h4>What counts as a view<\/h4>\n\n<p>A view is counted at most once per ad, per placement, per page load, when at\nleast half of the advertisement has been continuously on screen for one second\nin a tab the reader is actually looking at. Ads below the fold that are never\nreached are not counted, and neither are background tabs or quick scroll-pasts.\nBoth thresholds are adjustable in Settings.<\/p>\n\n<p>The check runs in the reader's browser, so treat these as first-party publisher\nreporting rather than independently audited measurement. No third-party\naccreditation is claimed and none is implied. The aim is a number you can\nexplain to an advertiser and get the same answer twice.<\/p>\n\n<h4>Working alongside a programmatic network<\/h4>\n\n<p>The plugin touches only the elements it created. It uses one namespaced global,\nscopes all of its CSS to its own class names, does not use the <code>data-slot<\/code>\nattribute, adds no MutationObserver and no z-index, and makes no third-party\nrequests. It is intended to sit on the same page as a programmatic network\nwithout interfering with it.<\/p>\n\n<h4>Privacy<\/h4>\n\n<p>Hooray Simple Ads is designed to measure ad performance without building\nprofiles of your readers.<\/p>\n\n<p>Reporting consists of aggregate counters by day, slot and ad. No cookies are\nset and no browser storage is used. Raw IP addresses, user agents, user IDs\nand device identifiers are not stored. There is no plugin-author telemetry,\nand no third-party ad-serving service is contacted.<\/p>\n\n<p>To stop the same view being counted twice, a short-lived scrambled\ndeduplication record is kept and swept automatically, normally within a day.<\/p>\n\n<p>Suggested wording for your own privacy policy is added to <strong>Tools \u2192 Privacy<\/strong>.\nClicking an ad sends the reader to the advertiser's own site, which is outside\nthis plugin's control.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate the plugin.<\/li>\n<li>Go to <strong>Ads \u2192 Slots<\/strong> and create a slot: a place on your site where an ad can\nappear, with a size, for example a 728x90 leaderboard.<\/li>\n<li>Go to <strong>Ads<\/strong> and choose <strong>Add New Ad<\/strong>. Upload the image, paste the\nadvertiser's link, tick the slots it should run in, and set the dates.<\/li>\n<li>Place the slot on your site with the Local Ad Slot block, or with the\nshortcode the Slots screen gives you.<\/li>\n<\/ol>\n\n<p>Upgrading from an earlier version: your slots, ads and reporting history carry\nover unchanged, and so do your settings. Existing shortcodes and blocks keep\nworking. If you call this plugin from a PHP template, see the changelog \u2014 the\nfunction was renamed. Purge your page cache after upgrading.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"i%20upgraded%20and%20the%20plugin%20has%20a%20new%20name.%20did%20anything%20break%3F\"><h3>I upgraded and the plugin has a new name. Did anything break?<\/h3><\/dt>\n<dd><p>No. The ads, slots, schedules, reporting history and settings are all the same\nrecords as before. Existing <code>[webpostad]<\/code> shortcodes, ad slot blocks already in\nyour posts, and REST calls issued by pages cached before the upgrade keep\nworking. New placements use <code>[hsads_ad]<\/code> and <code>hsads_ad()<\/code>.<\/p><\/dd>\n<dt id=\"do%20i%20need%20litespeed%20esi%2C%20or%20a%20cache%20exclusion%20rule%3F\"><h3>Do I need LiteSpeed ESI, or a cache exclusion rule?<\/h3><\/dt>\n<dd><p>No. Earlier versions offered an ESI mode that did not work correctly, and it has\nbeen removed. The normal delivery path already works on cached pages. The only\nthing worth checking is that a CDN in front of WordPress is not caching the\nplugin's REST endpoints; Settings lists them.<\/p><\/dd>\n<dt id=\"why%20is%20my%20ad%20not%20showing%3F\"><h3>Why is my ad not showing?<\/h3><\/dt>\n<dd><p><strong>Ads \u2192 Diagnostics<\/strong> lists every ad assigned to every slot with the reason it\nis or is not eligible today. For a live page, add <code>?hsads_debug=1<\/code> to the URL\nwhile logged in as an administrator and check the browser console. Visitors\nnever see any of this.<\/p><\/dd>\n<dt id=\"does%20it%20collect%20personal%20data%3F\"><h3>Does it collect personal data?<\/h3><\/dt>\n<dd><p>See the privacy note in the description. The plugin is designed to measure ad\nperformance without building profiles of your readers.<\/p><\/dd>\n<dt id=\"does%20it%20slow%20the%20site%20down%3F\"><h3>Does it slow the site down?<\/h3><\/dt>\n<dd><p>A page with no ad slot on it loads none of the plugin's files. A page with ads\nloads a small script and stylesheet. Filling a slot is a separate request that\ndoes not depend on the page cache, and counting a view is one more request.<\/p><\/dd>\n<dt id=\"can%20one%20advertiser%20get%20a%20larger%20share%20of%20the%20rotation%3F\"><h3>Can one advertiser get a larger share of the rotation?<\/h3><\/dt>\n<dd><p>Yes. Every ad-to-slot assignment has a share. Leave them all at 1 for even\nrotation, or raise one to give that advertiser proportionally more impressions.<\/p><\/dd>\n<dt id=\"will%20it%20interfere%20with%20my%20programmatic%20network%3F\"><h3>Will it interfere with my programmatic network?<\/h3><\/dt>\n<dd><p>It should not. It only reads and modifies the elements it created itself, and it\ncontacts only your own site, so containers belonging to another ad script are\nleft alone.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20my%20data%20if%20i%20uninstall%20it%3F\"><h3>What happens to my data if I uninstall it?<\/h3><\/dt>\n<dd><p>Nothing is deleted unless you first tick the option in Settings. Deactivating or\ndeleting the plugin otherwise leaves your slots, ads and reporting history in\nplace, so they return if you reinstall.<\/p><\/dd>\n<dt id=\"can%20i%20use%20it%20on%20multisite%3F\"><h3>Can I use it on multisite?<\/h3><\/dt>\n<dd><p>Yes. Each site gets its own slots, ads and reporting, including sites created\nafter a network activation.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>The plugin is now published as Hooray Simple Ads. Your ads, slots, schedules,\nreporting history and settings are untouched.<\/li>\n<li>Renamed the plugin's internal identifiers \u2014 functions, constants, settings,\nadmin pages, script handles, CSS classes and REST routes \u2014 onto a single\ndistinctive prefix, so nothing this plugin registers can collide with another\nplugin on the same site.<\/li>\n<li>Existing <code>[webpostad]<\/code> shortcodes, ad slot blocks already in your posts, and\nREST calls from pages cached before the upgrade keep working. New placements\nuse <code>[hsads_ad]<\/code> and <code>hsads_ad()<\/code>.<\/li>\n<li>If you call this plugin from a PHP template, <code>zra_ad()<\/code>, <code>zra_the_ad()<\/code> and\n  zra_plugin() have been renamed to <code>hsads_ad()<\/code>, <code>hsads_the_ad()<\/code> and\n  hsads_plugin(), with no alias left behind. Change the call and it behaves\nexactly as before. Shortcodes and blocks are unaffected.<\/li>\n<li>The <code>?zra_debug=1<\/code> troubleshooting switch is now <code>?hsads_debug=1<\/code>, and the\nplugin's admin screens are reached from the Ads menu rather than from any\nbookmarked address that contains the old prefix.<\/li>\n<li>Your settings are carried over automatically the first time the new version\nloads. Nothing to re-enter.<\/li>\n<li>For developers: the <code>zra_click_params<\/code> filter was renamed to\n  hsads_click_params with no alias. The frontend's single global is now\n  window.HooraySimpleAds.<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Added suggested wording for your own privacy policy under Tools -&gt; Privacy,\ndescribing what the plugin records and what it does not.<\/li>\n<li>Fixed: a very large rotation offset in an ad request could select an invalid\nposition, so no ad was returned and a PHP warning was logged.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Security: view and click replay protection is now a unique database insert, so\na token cannot be counted twice across separate requests on sites running a\npersistent object cache.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Security: the click endpoint no longer accepts a redirect destination from the\nrequest. It reads the advertiser's URL from the database, which closes an open\nredirect on your own domain.<\/li>\n<li>Security: view and click counts now require a signed token issued when the ad\nwas served.<\/li>\n<li>Security: deleting an ad or a slot now requires a POST and a nonce.<\/li>\n<li>Security: ad markup is built with DOM APIs, so text stored with an ad cannot\nbecome script.<\/li>\n<li>Fixed: every slot on a page chose the same position in the rotation, and a\nslot placed twice always showed the same ad.<\/li>\n<li>Fixed: schema upgrades could never apply, because of how the tables were\ndeclared.<\/li>\n<li>Fixed: view counting. Previously one visible pixel for 100ms counted, in any\ntab. Now half the ad, for a second, in a foreground tab.<\/li>\n<li>Fixed: a fixed pixel width made wide ads scroll the page sideways on phones.<\/li>\n<li>Fixed: an unfilled slot collapsed after layout and pushed the page around.<\/li>\n<li>Fixed: auto-refresh timers ran forever, including in background tabs.<\/li>\n<li>Fixed: dates and duplicate slot slugs are validated instead of failing quietly.<\/li>\n<li>Removed: the LiteSpeed ESI mode, which left ads blank when switched on.<\/li>\n<li>Removed: unconditional console logging on every page view.<\/li>\n<li>Added: the Local Ad Slot block, a Diagnostics screen, an opt-in debug mode,\nrotation shares, an uninstall routine, and a simpler Ads screen.<\/li>\n<\/ul>\n\n<h4>1.0.0 - 1.0.2<\/h4>\n\n<ul>\n<li>Initial release, rate limiting on ad requests, and reporting fixes.<\/li>\n<\/ul>","raw_excerpt":"Direct-sold advertising for publishers who don&#039;t want an ad-tech platform. Placement, rotation, scheduling and first-party reporting.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/371911","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=371911"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/hoorayplugins"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=371911"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=371911"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=371911"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=371911"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=371911"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=371911"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}