{"id":371651,"date":"2026-10-02T12:17:49","date_gmt":"2026-10-02T12:17:49","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/ghostlabs-dynamic-copyright\/"},"modified":"2026-10-02T12:17:19","modified_gmt":"2026-10-02T12:17:19","slug":"ghostlabs-dynamic-copyright-notice","status":"publish","type":"plugin","link":"https:\/\/ca.wordpress.org\/plugins\/ghostlabs-dynamic-copyright-notice\/","author":23277533,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.1.2","requires":"6.4","requires_php":"7.4","requires_plugins":null,"header_name":"Perennial","header_author":"GhostLabs","header_description":"Keeps your copyright notice current by dynamically updating the year and site name.","assets_banners_color":"575757","last_updated":"2026-10-02 12:17:19","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/theghostlab.io\/docs\/perennial","header_author_uri":"https:\/\/theghostlab.io","rating":0,"author_block_rating":0,"active_installs":0,"downloads":52,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"ghostlabs","date":"2026-10-02 12:17:19","revision":3724770}},"upgrade_notice":{"1.0.0":"<p>First release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3724770,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3724770,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3724770,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3724770,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3724770,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":{"ghostlabs\/perennial":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"ghostlabs\/perennial","version":"1.0.0","title":"Perennial: Copyright Notice","category":"widgets","icon":"editor-paragraph","description":"A copyright notice that keeps its year and site name current automatically.","keywords":["copyright","footer","year","legal"],"example":{},"attributes":{"from":{"type":"string","default":""},"owner":{"type":"string","default":""},"statementOfRights":{"type":"boolean","default":false},"yearColor":{"type":"string"},"customYearColor":{"type":"string"},"yearFontSize":{"type":"string"},"customYearFontSize":{"type":"string"},"yearFontWeight":{"type":"string"}},"supports":{"html":false,"align":true,"color":{"text":true,"background":true,"link":true},"spacing":{"margin":true,"padding":true},"typography":{"fontSize":true,"lineHeight":true}},"textdomain":"ghostlabs-dynamic-copyright-notice","editorScript":"file:.\/index.js","editorStyle":"file:.\/index.css","style":"file:.\/style-index.css"}},"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3724770,"resolution":"1","location":"assets","locale":"","width":2880,"height":1800},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3724770,"resolution":"2","location":"assets","locale":"","width":2880,"height":1800},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3724770,"resolution":"3","location":"assets","locale":"","width":2880,"height":1800},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3724770,"resolution":"4","location":"assets","locale":"","width":2880,"height":1800}},"screenshots":{"1":"The rendered notice in a site footer. The year is worked out when the page is served, so it turns over on 1 January by itself \u2014 nothing is stored in your content.","2":"Set a start year and the notice reads as a range \u2014 \u00a9 2016 \u2013 2026 \u2014 with the end always the current year. The Statement of rights toggle appends \"All rights reserved.\", punctuated for you.","3":"The year and its \u00a9 symbol get their own size, weight and color, set separately from the rest of the line \u2014 so it can carry the footer without the notice shouting.","4":"Add it once to your block theme's footer template part in the Site Editor, and every page that uses that footer carries the notice."}},"plugin_section":[],"plugin_tags":[2972,9796,140685,2640,523],"plugin_category":[],"plugin_contributors":[242362],"plugin_business_model":[],"class_list":["post-371651","plugin","type-plugin","status-publish","hentry","plugin_tags-copyright","plugin_tags-copyright-year","plugin_tags-current-year","plugin_tags-footer","plugin_tags-year","plugin_contributors-ghostlabs","plugin_committers-ghostlabs"],"banners":{"banner":"https:\/\/ps.w.org\/ghostlabs-dynamic-copyright-notice\/assets\/banner-772x250.png?rev=3724770","banner_2x":"https:\/\/ps.w.org\/ghostlabs-dynamic-copyright-notice\/assets\/banner-1544x500.png?rev=3724770","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/ghostlabs-dynamic-copyright-notice\/assets\/icon.svg?rev=3724770","icon":"https:\/\/ps.w.org\/ghostlabs-dynamic-copyright-notice\/assets\/icon.svg?rev=3724770","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/ghostlabs-dynamic-copyright-notice\/assets\/screenshot-1.png?rev=3724770","caption":"The rendered notice in a site footer. The year is worked out when the page is served, so it turns over on 1 January by itself \u2014 nothing is stored in your content."},{"src":"https:\/\/ps.w.org\/ghostlabs-dynamic-copyright-notice\/assets\/screenshot-2.png?rev=3724770","caption":"Set a start year and the notice reads as a range \u2014 \u00a9 2016 \u2013 2026 \u2014 with the end always the current year. The Statement of rights toggle appends \"All rights reserved.\", punctuated for you."},{"src":"https:\/\/ps.w.org\/ghostlabs-dynamic-copyright-notice\/assets\/screenshot-3.png?rev=3724770","caption":"The year and its \u00a9 symbol get their own size, weight and color, set separately from the rest of the line \u2014 so it can carry the footer without the notice shouting."},{"src":"https:\/\/ps.w.org\/ghostlabs-dynamic-copyright-notice\/assets\/screenshot-4.png?rev=3724770","caption":"Add it once to your block theme's footer template part in the Site Editor, and every page that uses that footer carries the notice."}],"raw_content":"<!--section=description-->\n<p>Every site has a copyright line in the footer, and every site eventually has the wrong one \u2014\nbecause the year was typed in by hand and nobody remembered to change it.<\/p>\n\n<p>This plugin adds a single block that works the year out when the page is served, so the notice\nis right on 1 January without anyone touching it.<\/p>\n\n<p><strong>What it does<\/strong><\/p>\n\n<ul>\n<li>Shows the current year, resolved in <strong>your site's timezone<\/strong> \u2014 not the visitor's browser.<\/li>\n<li>Optionally shows a range \u2014 <code>\u00a9 2001 \u2013 2026<\/code> in English. Set the start year to the current\nyear and it shows that year on its own rather than a range of one. The format is\ntranslatable, so a locale can set its own separator, numerals or placement for the \u00a9 symbol.<\/li>\n<li>Uses your <strong>site title<\/strong> as the copyright holder by default, so renaming the site updates\nevery notice at once. Type a different name if you want one.<\/li>\n<li>Optionally appends \"All rights reserved.\", punctuated correctly.<\/li>\n<li>Lets you style the <strong>year separately from the rest of the notice<\/strong> \u2014 its own color, font\nsize and weight. The \u00a9 symbol follows the year's styling.<\/li>\n<\/ul>\n\n<p><strong>Built to stay correct<\/strong><\/p>\n\n<p>The notice is rendered on the server, which matters more than it sounds:<\/p>\n\n<ul>\n<li>The year is never written into your post content, so it cannot go stale, and your saved\nposts never break when the year rolls over.<\/li>\n<li>Search engines see the finished text in the page source, with no JavaScript to run first.<\/li>\n<li><strong>No JavaScript is loaded on the front end at all<\/strong> \u2014 on any theme. On a block theme the\nstylesheet is inlined into only the pages that use the block; on a classic theme WordPress\nloads every registered block's stylesheet site-wide, including this one.<\/li>\n<\/ul>\n\n<p>The one thing server rendering cannot fix is somebody else's copy of the finished page. So when\nthe year turns over, the plugin clears the cache for you on <strong>WP Rocket, W3 Total Cache, WP Super\nCache and LiteSpeed Cache<\/strong> \u2014 those four. Any other cache can clear itself by hooking the rollover\naction; see the FAQ.<\/p>\n\n<p>Alignment, color, spacing, font size and line height all come from the standard WordPress block\ncontrols, so the notice inherits your theme's palette and type scale rather than fighting it.<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin contacts no external services. It makes no network requests of any kind \u2014 no license\ncheck, no update check of its own, no analytics, no telemetry, no remote fonts or assets. Nothing\nabout your site or your visitors leaves your server because of it.<\/p>\n\n<p>The one thing that might look like an exception is not one. When the year turns over the plugin\nclears the cache for WP Rocket, W3 Total Cache, WP Super Cache and LiteSpeed Cache \u2014 but it does\nthat by calling those plugins in PHP on your own site, if they happen to be installed. That is a\nfunction call inside WordPress, not a request to anybody.<\/p>\n\n<h3>Source code<\/h3>\n\n<p>The editor JavaScript this plugin ships is compiled. The sources it is compiled from are\npublished here, tagged to match each release:<\/p>\n\n<p>https:\/\/github.com\/theghostlab\/wp-ghostlabs-perennial<\/p>\n\n<p>That repository holds the plugin exactly as distributed, plus the <code>src\/<\/code> it was built from and\nthe lockfile, <code>package.json<\/code> and webpack config needed to rebuild it. A clean install and a\nrebuild reproduce the shipped bundle:<\/p>\n\n<pre><code>pnpm install --frozen-lockfile &amp;&amp; pnpm run build\n<\/code><\/pre>\n\n<p>The bundle that ships inside the plugin is minified, which is the whole reason that repository\nexists: the readable source is published there rather than padding every install with it. Nothing\nis obfuscated.<\/p>\n\n<p>The plugin loads no JavaScript on the front end at all \u2014 that bundle is the block editor's, and\nnothing else.<\/p>\n\n<!--section=installation-->\n<p><strong>From your dashboard<\/strong><\/p>\n\n<ol>\n<li>Go to <strong>Plugins<\/strong>, then the screen for adding one \u2014 <strong>Add Plugins<\/strong>.<\/li>\n<li>Search for <strong>Perennial<\/strong>.<\/li>\n<li>Click <strong>Install Now<\/strong>, then <strong>Activate<\/strong>.<\/li>\n<\/ol>\n\n<p><strong>From a downloaded .zip<\/strong><\/p>\n\n<ol>\n<li>Go to <strong>Plugins<\/strong> and open the <strong>Add Plugins<\/strong> screen.<\/li>\n<li>Click <strong>Upload Plugin<\/strong> at the top, choose the .zip file, and click <strong>Install Now<\/strong>.<\/li>\n<li>Click <strong>Activate Plugin<\/strong>.<\/li>\n<\/ol>\n\n<p><strong>By FTP<\/strong><\/p>\n\n<ol>\n<li>Unzip the file and upload the <code>ghostlabs-dynamic-copyright-notice<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate the plugin from the <strong>Plugins<\/strong> screen.<\/li>\n<\/ol>\n\n<h4>Then add the notice<\/h4>\n\n<p>In any post, page, or template, add the <strong>Perennial: Copyright Notice<\/strong> block.<\/p>\n\n<p>On a block theme, add it once to your footer template part in <strong>Appearance \u2192 Editor<\/strong> and every\npage that uses that footer carries it. On a classic theme there is no footer template part to add\nit to, so place the block wherever you want the notice.<\/p>\n\n<p>There is no settings screen. Everything the block does is in its own settings and styles in the\neditor sidebar.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20have%20to%20do%20anything%20on%20january%201%3F\"><h3>Do I have to do anything on January 1?<\/h3><\/dt>\n<dd><p>No. The year is worked out each time the page is served.<\/p><\/dd>\n<dt id=\"i%20use%20a%20caching%20plugin.%20will%20the%20year%20still%20update%3F\"><h3>I use a caching plugin. Will the year still update?<\/h3><\/dt>\n<dd><p>The notice itself is always right \u2014 it is worked out when the page is served. What can go stale\nis a cached copy of the finished page: one cached on 31 December keeps serving last year's\nnotice until that cache is cleared.<\/p>\n\n<p>So the plugin clears it, on four caching plugins by name. The first request of the new year that\nWordPress actually builds notices the year has changed and clears the cache. There is no\nscheduled task and nothing to configure \u2014 a cached page is served without WordPress ever loading\nthis plugin, so the only thing that can trigger the check is the next request that is not served\nfrom cache: an admin opening the dashboard, a logged-in reader, a crawler, or any page the cache\nis not already holding.<\/p>\n\n<p><strong>Cleared for you:<\/strong> WP Rocket, W3 Total Cache, WP Super Cache and LiteSpeed Cache \u2014 those four,\nand no others. Each is asked for a full flush, so on W3 Total Cache and LiteSpeed that clears\ntheir object caches too; once a year, deliberately. Each one ties this plugin to somebody else's\ncode, so the list stays deliberately short; the hook in the next question is what scales.<\/p>\n\n<p><strong>Any other cache:<\/strong> if it expires at least once a year, it corrects itself the next time it\nexpires \u2014 which with a twelve-month lifetime can be most of a year. With very long or indefinite\nlifetimes, clear your page cache once after New Year, or set your caching plugin to purge on a\nschedule.<\/p><\/dd>\n<dt id=\"can%20i%20clear%20my%20own%20cache%20when%20the%20year%20rolls%20over%3F\"><h3>Can I clear my own cache when the year rolls over?<\/h3><\/dt>\n<dd><p>Yes \u2014 two hooks, both reached on that same first request of the new year. Neither fires on a\nbrand-new install, which has no previous year on record to compare against.<\/p>\n\n<p>The <code>ghostlabs_perennial_year_rolled_over<\/code> action is passed the new year and the year\nbefore it. It fires whether or not this plugin clears anything, so it is the place to purge a\ncache, CDN or host layer this plugin does not know about.<\/p>\n\n<pre><code>add_action( 'ghostlabs_perennial_year_rolled_over', function ( $current, $stored ) {\n    \/\/ Clear your own cache here.\n}, 10, 2 );\n<\/code><\/pre>\n\n<p>The <code>ghostlabs_perennial_purge_on_rollover<\/code> filter defaults to <code>true<\/code>. Return <code>false<\/code>\nand the plugin clears nothing itself. The action above still fires, so you can decline the\nbuilt-in purge and still handle it your own way.<\/p><\/dd>\n<dt id=\"which%20year%20does%20it%20use%20if%20my%20visitors%20are%20in%20other%20countries%3F\"><h3>Which year does it use if my visitors are in other countries?<\/h3><\/dt>\n<dd><p>Your site's, as set in <strong>Settings \u2192 General \u2192 Timezone<\/strong>. Working it out in the visitor's\nbrowser instead would mean someone in Auckland and someone in Los Angeles could see different\nyears for a few hours around New Year.<\/p><\/dd>\n<dt id=\"what%20if%20i%20leave%20the%20name%20blank%3F\"><h3>What if I leave the name blank?<\/h3><\/dt>\n<dd><p>The notice uses your site title, and keeps using it \u2014 so if you rename the site later, every\nnotice updates. Type a name only if you want it to differ from the site title.<\/p><\/dd>\n<dt id=\"can%20i%20make%20the%20year%20a%20different%20color%20or%20size%20from%20the%20rest%20of%20the%20line%3F\"><h3>Can I make the year a different color or size from the rest of the line?<\/h3><\/dt>\n<dd><p>Yes. Select the block, open the <strong>Styles<\/strong> tab, and use <strong>Year typography<\/strong> and <strong>Year color<\/strong>.\nThese affect only the year and the \u00a9 symbol. The rest of the notice uses the block's normal\ncolor and typography controls.<\/p>\n\n<p>The year's font size is offered in <code>rem<\/code>, <code>em<\/code>, <code>ch<\/code> and <code>%<\/code> rather than pixels, so it scales\nwith your theme and with a reader's text-size settings. The block's own font size control offers\nwhatever units your theme does.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First release.<\/li>\n<li>The notice is rendered on the server, so a saved year can never go stale and posts do not\nbreak when the year changes.<\/li>\n<li>Separate color and typography controls for the year and \u00a9 symbol.<\/li>\n<li>The copyright holder follows the site title when left blank, rather than being fixed at the\nmoment the block was inserted.<\/li>\n<li>Alignment, color and typography settings apply on the front end.<\/li>\n<li>The cache is cleared when the year turns over, on WP Rocket, W3 Total Cache, WP Super Cache\nand LiteSpeed Cache. The check runs on the first request of the new year that WordPress\nhandles itself rather than serving from cache \u2014 a page view, an admin screen, a REST call or\na crawler. There is no scheduled task.<\/li>\n<li>Added an action, <code>ghostlabs_perennial_year_rolled_over<\/code>, passed the new and previous\nyear, so any other cache, CDN or host layer can clear itself.<\/li>\n<li>Added a filter, <code>ghostlabs_perennial_purge_on_rollover<\/code> (default true), to turn the\nplugin's own purging off. The action fires either way.<\/li>\n<li>The year range uses an en dash \u2014 \u00a9 2001 \u2013 2026 \u2014 which is the correct punctuation for a\nrange, and the year format is translatable.<\/li>\n<\/ul>","raw_excerpt":"Keeps your footer&#039;s copyright year current automatically \u2014 server-rendered, no JavaScript. Never edit a footer on New Year&#039;s Day again.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/371651","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=371651"}],"author":[{"embeddable":true,"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/ghostlabs"}],"wp:attachment":[{"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=371651"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=371651"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=371651"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=371651"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=371651"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=371651"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}