Adding a Notification to Old WordPress Posts

While some articles may be timeless, depending on the type of content being published, many posts have a definite expiry date. It is the double edged sword of rapidly evolving technologies – they improve swiftly, but articles written about them become outdated just as fast. This site, for instance, is primarily about cloud computing and servers – as such, many of the posts, from even a few months ago, may no longer be applicable.

When searching for technology related articles, I usually restrict the search to the past year. Articles without a date are simply annoying, and those where the date is in some obscure location aren’t much better.

A common approach to dealing with outdated posts is to add a notice to them. The idea being that there is likely some useful information in them, despite their age, but that readers should be aware that the post was from some time ago and some things may have changed in the interim.

I’d suggest there are (at least) three ways of accomplishing the above:

  1. Manually edit posts
    • When you feel that a post merits such a notice, add one in. This may be a good approach if there are only one or two posts that actually need it. For any site that generates more than a few of these, a more automated approach would be better.
  2. Edit your theme.
    • This seems to be the commonly proposed solution, add a few lines of code to the theme to display the notification. It is quite easy to implement, although, it may take a few moments to find the right file. The problem is that any updates to the theme will overwrite your modifications. Arguably, the solution may lie in the form of a child theme, but really, you only want to be modifying a small part of an existing function, and not completely replacing that function. This site uses a child theme with Twenty Eleven, and I added the following to content-single.php, immediately preceding <div class="entry-content">:
      	$interval = "";
      	if ($diff->y){$interval .= $diff->y . " year" . ($diff->y == 1?"":"s");}
      	if ($diff->m){$interval .= ($interval?", ":"") . $diff->m . " month" . ($diff->m == 1?"":"s");} ?>
      This article was published ago. Due to the rapidly evolving world of technology, some concepts may no longer be applicable.
  3. Use a plugin. This would be the way to go – it will withstand updates, and offer a degree of customization – without having to hardcode values into your theme. The problem is, it is rather difficult to come across such a plugin. At least one, however exists – Old Posts Notifier. However, it was written for the 2.x versions of WordPress, hasn’t been updated in over 2 years, and has a bit of undesired tracking included in it.

I had a bit of spare time earlier in the week, so I extracted my in-line modifications into a plugin – ‘Aged Posts’, and added a few things to make it more useable. Essentially, I wanted to be able to:

  • Change the displayed text and style from a settings page
  • Change the post age limit for displaying the notification.
  • Exclude individual posts from displaying the notification.

The result is fairly simple – it doesn’t have a lot of options, but it is functional. The plugin saves the style to a css file – which allows it to be included in any minification performed.

  • Note: This plugin requires PHP > 5.3, since it uses DateTime::diff().
  • Tested with WordPress 3.2 and 3.3, with the TwentyTen and TwentyEleven themes.
  • This plugin is NOT internationalized – I might get around to if people find it useful.Likewise, I haven’t yet posted on WordPress’ plugins site, but may do so in the future.
    • Update (Oct 9, 2012): Added some form of i18n to the plugin at the prompting of ‘giacomo’ (commenter, below) – might be a bit rough (and is somewhat untested), but it appears to work.

    Undoubtedly there are some non-standard code practices used (it is my first WordPress plugin), but hopefully nothing of major concern.

    If you find a bug, have an improvement or suggestion, or simply found it useful, please let me know.


    If you are using the i18n version, translations are supported through the use of PO/MO files. You can add PO/MO files to the plugin’s languages folder, or under WP_LANG_DIR/agedposts/ (which will be used in preference to the plugin’s language folder). Using a directory external to the plugin’s own directory allows for upgrades to not overwrite custom translations.

    Italian (courtesy of Giacomo)

    The Code

    Download (no i18n): [39.2kB, MD5: 683B0D1F79C7ABA2749F3233EA6F8D7B])
    Download (with i18n): agedposts-i18n [43.8kB, MD5: 7780659593F181626CCDCFDCC9558053])

    				$prefix . 'age_units' => 'months',
    				$prefix . 'priority' => 20,
    				$prefix . 'display_text' => 'This post was published @@INTERVAL@@ ago. Some material it contains may no longer be applicable.'
    			foreach ($default_options as $option_name => $option_value) {
    				if (get_option($option_name) === FALSE) {
    					add_option($option_name, $option_value, '', 'no');
    			$agedposts_style = get_option($prefix . 'style');
    			if ($agedposts_style === FALSE) {
    				$agedposts_style = file_get_contents(plugin_dir_path(__FILE__) . "style.css.orig");
    				add_option($prefix . 'style', $agedposts_style, '', 'no');
    			file_put_contents(plugin_dir_path(__FILE__) . "style.css", $agedposts_style);
    		function main()
    			if (is_single()) {
    				if (get_post_meta(get_the_ID(), $this->prefix . 'include', true) !== '0') {
    					$priority       = get_option($this->prefix . 'priority');
    					$timestamp      = get_the_time('U');
    					$age            = intval(get_option($this->prefix . 'age'));
    					$age_units      = get_option($this->prefix . 'age_units');
    					$this->interval = "$age $age_units ago";
    					if ($timestamp < strtotime($this->interval)) {
    						add_filter('the_content', array(&$this,	'display'), $priority);
    						add_action('wp_enqueue_scripts', array(&$this,'add_stylesheet'));
    						$now  = new DateTime();
    						//Todo: Add PHP 5.2 compatibility
    						$diff = $now->diff(new DateTime('@' . $timestamp));
    						if ($diff->y) {
    							$this->disp_interval .= $diff->y . " year" . ($diff->y == 1 ? "" : "s");
    						if ($diff->m) {
    							$this->disp_interval .= ($this->disp_interval ? ", " : "") . $diff->m . " month" . ($diff->m == 1 ? "" : "s");
    		function display($content)
    			$display_text = get_option($this->prefix . 'display_text');
    			$content      = '
    ' . str_replace("@@INTERVAL@@", $this->disp_interval, $display_text) . '
    ' . $content; return $content; } function add_stylesheet() { wp_register_style($this->prefix . 'style', plugins_url('style.css', __FILE__)); wp_enqueue_style($this->prefix . 'style'); } function add_ap_meta_box() { add_meta_box($this->prefix . 'meta', __('Aged Posts'), array(&$this,'render_meta_box_content'), 'post', 'side'); } function render_meta_box_content($post) { wp_nonce_field(plugin_basename(__FILE__), $this->prefix . 'nonce'); echo ''; } function meta_save($post_id) { if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (!wp_verify_nonce($_POST[$this->prefix . 'nonce'], plugin_basename(__FILE__))) { return; } if ('page' == $_POST['post_type']) { if (!current_user_can('edit_page', $post_id)) { return; } } else { if (!current_user_can('edit_post', $post_id)) { return; } } $agedposts_include = ($_POST[$this->prefix . 'include'] ? 1 : 0); if (!add_post_meta($post_id, $this->prefix . 'include', $agedposts_include, true)) { update_post_meta($post_id, $this->prefix . 'include', $agedposts_include); } } function admin_menu() { add_options_page('Aged Posts Options', 'Aged Posts', 'manage_options', $this->prefix , array(&$this,'admin_options')); add_action('add_meta_boxes', array(&$this,'add_ap_meta_box')); } function admin_options() { if (!current_user_can('manage_options')) { wp_die(__('You do not have sufficient permissions to access this page.')); } if (isset($_POST[$this->prefix . 'submit'])) { update_option($this->prefix . 'age', $_POST[$this->prefix . 'age']); update_option($this->prefix . 'age_units', $_POST[$this->prefix . 'age_units']); update_option($this->prefix . 'priority', $_POST[$this->prefix . 'priority']); update_option($this->prefix . 'display_text', $_POST[$this->prefix . 'display_text']); update_option($this->prefix . 'style', $_POST[$this->prefix . 'style']); if(file_put_contents(plugin_dir_path(__FILE__) . "style.css", $_POST[$this->prefix . 'style'])===FALSE){ ?>

    Unable to write stylesheet. Please manually update

    Settings saved.

    Aged Posts Options

    Post Age

    Display notice on posts older than:


    The priority is used, by WordPress, to determine the order in which filter functions are run. Lower values result in later execution. The default for most filters is 10; the default for this plugin is 20. Only change this value if you find other plugins are conflicting with this one.


    Text to Display

    Text to display (@@INTERVAL@@ will be replaced with the number of months/years):


    The following is the CSS class definition will be used to style the display. It has been loaded from the database, and will be saved to a file.:

    Download (no i18n): [39.2kB, MD5: 683B0D1F79C7ABA2749F3233EA6F8D7B])
    Download (with i18n): agedposts-i18n [43.8kB, MD5: 7780659593F181626CCDCFDCC9558053])

By cyberx86

Just a random guy who dabbles with assorted technologies yet works in a completely unrelated field.


  1. Fantastic. I had just been looking at Old Post Notifier, and saw the warning about the trackbacks it sends, so it was a huge relief to find your post. I was able to copy your smaller code sample and put it in my functions.php to conditionally insert into the header of posts in a particular category, like so:

    function my_post_header() {
    	if( is_singular('post') && in_category( 'webdev' ) ) {
    		if((get_the_time('U') diff($ref);
    			$interval = "";
    			if ($diff->y){$interval .= $diff->y . " year" . ($diff->y == 1?"":"s");}
    			if ($diff->m){$interval .= ($interval?", ":"") . $diff->m . " month" . ($diff->m == 1?"":"s");} ?>
    			<div class="warning old-post">
    				This article was published <strong><?php echo $interval; ?> ago</strong>. Due to the rapidly evolving nature of web development, some concepts may no longer be applicable.
    		<?php }
    1. Offhand, a few ways come to mind – this page describes an approach for disabling edits 24hrs after publication (should be easy enough to adapt). Alternatively, look for some of the plugins that allow you to specify permissions on a per post basis (like User Permissions, although I am not sure if it works with v3). (For a plugin that is simply changing the status of the post, consider something like: Post Expirator). I would recommend asking on the WordPress StackExchange if you don’t manage to find what you want.

  2. Hello there, thanks for this fantastic plugin. I was wondering if there is a chance to localize the words Years or Year and Month or Months which I’d like to translate to “Anno” e “Mese” and relative plural form.
    Thanks for your support

    1. Glad you found it useful. It is fairly easy for you to change the language, although, it does require editing the code. Just make the following change in the file agedposts.php:

      The original lines 73-78 (display # year(s), # month(s)):

      if ($diff->y) {
          $this->disp_interval .= $diff->y . " year" . ($diff->y == 1 ? "" : "s");
      if ($diff->m) {
          $this->disp_interval .= ($this->disp_interval ? ", " : "") . $diff->m . " month" . ($diff->m == 1 ? "" : "s");

      Presuming that you want anno/anni and mese/mese (I don’t know the plurals – that is my best guest based on Google Translate) and an ‘e’ instead of a comma:

      if ($diff->y) {
          $this->disp_interval .= $diff->y . ($diff->y == 1 ? "anno" : "anni");
      if ($diff->m) {
          $this->disp_interval .= ($this->disp_interval ? " e " : "") . $diff->m . ($diff->m == 1 ? "mese" : "mese");

      Of course, for ‘mese’ you could simplify the code if the plural is the same as the singluar (I just left it so that it is easy for you to modify). Make the change, save the file and you should be good to go. Admittedly not localization in the proper way, but it gets the job done. If I have some time later today, I might look into do proper i18n localization.

  3. Hello, thanks for your support, now everything works ok! Just a quick note on the plural form of mese which is “mesi” like “anno” “anni”.
    Let me know if you need support for Italian translation with po-mo files

    1. At your prompting, I have implemented i18n. If you wish to give it a try, I have linked a copy with i18n in the post. I didn’t do too much testing of it – but it does appear to update the strings from the po/mo files. If you do test it, let me know how things work out.

    1. Thanks for testing it out – good to know it works.

      Giving your translation a quick try on my site, I see the following entries are not translated:

      • On the Posts pages
        • The meta box still reads ‘Display “old post” notice’
      • On the Settings page, two headings remain unchanged:
        • Post Age
        • Text to Display

      Also, the display text itself is not affected by the translation if the plugin was already installed. The reason for this is because the text is user-editable and stored in the database. (Essentially, the translation of that line will only affect new installs).

      Of the above, I can confirm that translations do work for for both the ‘meta box’ and the text ‘Post Age’ (it appears you opted not to translate these two phrases in the file).

      The translation of ‘Text to Display’ although modified in the po/mo files was not working. The cause of the problem was a missing text domain for that string in the plugin. Not too bad for my first attempt at implementing i18n I suppose.

      I have fixed the issue, and uploaded a new copy of the i18n version of the plugin (you need only replace agedposts.php for the change to take effect).

      With regard to your translation, would you like me to host a copy here (attributing it to you of course), or would you like me to link to a page on your site with the translation, or do you wish to keep the translation private?

        1. I have my uploads cached on a CDN, which holds them for 1 day by default. I forgot to invalidate the file, so the old file was still being served (which could be confirmed with the MD5 sum posted above). I have invalidated the file, and can confirm that the new file is being served.

          I’ll post a copy of your translation on the main page in a few hours, attributing it to you.

  4. hello Cyber, i’m here just to point out a strange incompatibility bug between your plugin and platinum popup (lite version) which I start using today just to welcome my readers.
    The problem affects the posts where the “old post” notice is shown , where appear also in the top of welcome pop-up whindow, please see the link below

    What do you think?
    Let me know if you need temporary access to my blog

    1. I have never used ‘Platinum Popup’, so I can’t really say how it works (and therefore why it is behaving as it is). I know that this behaviour is not seen on normal ‘lightbox’ popups (e.g. I use lightboxes for the images on my posts, and the message is not displayed). I might suggest trying to change the priority of AgedPosts (from the settings page), or if you are asking ‘Platinum Popup’ to display a post, you should be able to disable AgedPosts on a per-post basis.

      1. hey, I decided to solve the problem uninstalling the Platinum-popup, which was causing alot of problems also with my theme. In my opinion there was a sort of problem with jquery, actually I’m not a specialist in java stuff, but the problem I noticed on my theme was the same I had some time ago…in this case the support guys told me was something with Jquery.
        thanks for your support

Leave a comment

Your email address will not be published. Required fields are marked *