Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

initial commit

  • Loading branch information...
commit c8072573a8055c39a8eed56e58c5b7abecbf2cb3 0 parents
Austin Matzko authored

Showing 2 changed files with 477 additions and 0 deletions. Show diff stats Hide diff stats

  1. +30 0 readme.txt
  2. +447 0 wp-appearance-date.php
30 readme.txt
... ... @@ -0,0 +1,30 @@
  1 +=== Appearance Date ===
  2 +Contributors: filosofo
  3 +Donate link: http://austinmatzko.com/wordpress-plugins/wp-appearance-date/
  4 +Tags: posts, publish date, appearance, magazine
  5 +Requires at least: 2.9
  6 +Tested up to: 3.0
  7 +Stable tag: 1.0
  8 +
  9 +Show a post on a date separate from its publish date.
  10 +
  11 +== Description ==
  12 +
  13 +Show a post on a date separate from its publish date.
  14 +
  15 +== Installation ==
  16 +
  17 +1. Upload the `wp-appearance-date` directory to the `/wp-content/plugins/` directory
  18 +1. Activate the plugin through the 'Plugins' menu in WordPress
  19 +1. Set an appearance date for a post when editing that post.
  20 +
  21 +== Frequently Asked Questions ==
  22 +
  23 += Why would someone want to do this? =
  24 +
  25 +If you’re a content publisher, such as a magazine, you may want to show a post on a date different from when it’s associated. For example, a post for a March issue might show up in February.
  26 +
  27 +== Changelog ==
  28 +
  29 += 1.0 =
  30 +* Introduced the plugin.
447 wp-appearance-date.php
... ... @@ -0,0 +1,447 @@
  1 +<?php
  2 +/*
  3 +Plugin Name: Appearance Date
  4 +Plugin URI: http://austinmatzko.com/wordpress-plugins/wp-appearance-date/
  5 +Description: Show a post on a date distinct from its publish date.
  6 +Author: Austin Matzko
  7 +Author URI: http://austinmatzko.com
  8 +Version: 1.0
  9 +*/
  10 +
  11 +class Filosofo_Appearance_Date_Factory {
  12 +
  13 + public function __construct()
  14 + {
  15 + $query = new Filosofo_Appearance_Date_Query_Handler;
  16 + if ( is_admin() ) {
  17 + $admin = new Filosofo_Appearance_Date_Admin;
  18 + $admin->query = $query;
  19 + add_action('admin_head', array(&$admin, 'print_style'));
  20 + add_action('admin_init', array(&$admin, 'event_admin_init'));
  21 + add_action('post_submitbox_misc_actions', array(&$admin, 'print_appearance_date_chooser'));
  22 + add_action('wp_insert_post', array(&$admin, 'event_wp_insert_post'), 10, 2);
  23 + } else {
  24 + $installed = (bool) get_option('_filosofo_ap_date_installed');
  25 + // check to make sure the table exists for this site's posts before joining
  26 + if ( $installed ) {
  27 + add_filter('posts_fields', array(&$query, 'filter_posts_fields'));
  28 + add_filter('posts_join', array(&$query, 'filter_posts_join'));
  29 + add_filter('posts_results', array(&$query, 'filter_posts_results'));
  30 + add_filter('posts_where', array(&$query, 'filter_posts_where'));
  31 + add_filter('the_posts', array(&$query, 'filter_the_posts'));
  32 + }
  33 + }
  34 +
  35 + add_action('init', array(&$query, 'event_init'));
  36 + }
  37 +
  38 +}
  39 +
  40 +
  41 +class Filosofo_Appearance_Date_Query_Handler {
  42 +
  43 + private $_appearance_table_name = 'object_appearance_dates';
  44 + private $_posts_save;
  45 +
  46 + public function __construct()
  47 + {
  48 + $this->_posts_save = array();
  49 + }
  50 +
  51 + /**
  52 + * Determine whether the appearance table exists.
  53 + *
  54 + * @param string $prefix Optional. The prefix of the site in question. If empty uses the current site's prefix.
  55 + * @return bool Whether the appearance table exists for the given site.
  56 + */
  57 + private function _appearance_table_exists($prefix = '')
  58 + {
  59 + global $wpdb;
  60 + if ( ! empty( $prefix ) ) {
  61 + $wpdb->set_prefix($prefix);
  62 + }
  63 +
  64 + $tables = (array) $wpdb->get_col('SHOW TABLES;');
  65 + return in_array($wpdb->prefix . $this->_appearance_table_name, $tables);
  66 + }
  67 +
  68 + /**
  69 + * Install the appearance date table, if it doesn't exist.
  70 + *
  71 + * @param string $prefix Optional. The prefix of the site in question. If empty uses the current site's prefix.
  72 + * @return bool Whether the installation was successful.
  73 + */
  74 + private function _install_appearance_table($prefix = '')
  75 + {
  76 + global $wpdb;
  77 + if ( ! empty( $prefix ) ) {
  78 + $wpdb->set_prefix($prefix);
  79 + }
  80 +
  81 + $app_table = $wpdb->prefix . $this->_appearance_table_name;
  82 +
  83 + if ( ! $this->_appearance_table_exists() ) {
  84 + if ( ! empty($wpdb->charset) )
  85 + $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
  86 + if ( ! empty($wpdb->collate) )
  87 + $charset_collate .= " COLLATE $wpdb->collate";
  88 +
  89 + $query = "
  90 + CREATE TABLE {$app_table} (
  91 + appearance_object_id bigint(20) unsigned NOT NULL auto_increment,
  92 + appearance_date datetime NOT NULL default '0000-00-00 00:00:00',
  93 + PRIMARY KEY (appearance_object_id)
  94 + ) {$charset_collate};
  95 + ";
  96 +
  97 + $wpdb->query($query);
  98 +
  99 + return $this->_appearance_table_exists();
  100 + } else {
  101 + return true;
  102 + }
  103 + }
  104 +
  105 + public function event_init()
  106 + {
  107 + load_plugin_textdomain('appearance-date');
  108 + }
  109 +
  110 + public function filter_posts_fields($f = '')
  111 + {
  112 + $f .= ", appear_date.appearance_date ";
  113 + return $f;
  114 + }
  115 +
  116 + /**
  117 + * Extend the join clause to include the appearance date where appropos.
  118 + *
  119 + * @param string $j The join clause.
  120 + * @return string The join clause, filtered.
  121 + */
  122 + public function filter_posts_join($j = '')
  123 + {
  124 + global $wpdb;
  125 + $app_table = $wpdb->prefix . $this->_appearance_table_name;
  126 +
  127 + $j .= " LEFT JOIN {$app_table} AS appear_date ON {$wpdb->posts}.ID = appear_date.appearance_object_id ";
  128 + return $j;
  129 + }
  130 +
  131 + /**
  132 + * Filter posts results. Meant mainly to counteract hard-coded unset of future posts, when applicable.
  133 + *
  134 + * @param array $posts The posts returned from the query.
  135 + * @return array The posts, filtered.
  136 + */
  137 + public function filter_posts_results($posts = array())
  138 + {
  139 + // WP as of 2.9.2 at least unsets the results if singular and user not logged in.
  140 + if (
  141 + ! is_user_logged_in() &&
  142 + ! empty( $posts ) &&
  143 + 'future' == get_post_status($posts[0]) &&
  144 + ! empty( $posts[0]->appearance_date ) &&
  145 + ( $posts[0]->appearance_date < date('Y-m-d H:i:s') )
  146 +
  147 + ) {
  148 + array_unshift($this->_posts_save, $posts);
  149 + }
  150 + return $posts;
  151 + }
  152 +
  153 + /**
  154 + * Extend the where clause where appropos.
  155 + *
  156 + * @param string $w The Where clause.
  157 + * @return string The Where clause, filtered.
  158 + */
  159 + public function filter_posts_where($w = '')
  160 + {
  161 + global $wpdb;
  162 +
  163 + // handle possibly early-appearing future posts
  164 + $w = str_replace(
  165 + "{$wpdb->posts}.post_status = 'publish'",
  166 +
  167 + "( {$wpdb->posts}.post_status = 'publish' OR
  168 + (
  169 + {$wpdb->posts}.post_status = 'future' AND
  170 + NOW() > appear_date.appearance_date
  171 + )
  172 + )",
  173 +
  174 + $w
  175 + );
  176 +
  177 + // handle possibly late-appearing published posts
  178 + $w .= " AND ( ( appear_date.appearance_date IS NULL ) OR ( NOW() > appear_date.appearance_date ) ) ";
  179 + return $w;
  180 + }
  181 +
  182 + /**
  183 + * Filter finalized posts results. Meant mainly to counteract hard-coded unset of future posts, when applicable.
  184 + *
  185 + * @param array $posts The posts returned from the query and modified.
  186 + * @return array The posts, filtered.
  187 + */
  188 + public function filter_the_posts($posts = array())
  189 + {
  190 + // WP as of 2.9.2 at least unsets the results if singular and user not logged in.
  191 + if (
  192 + empty( $posts ) &&
  193 + ! is_user_logged_in()
  194 + ) {
  195 + $_posts = array_shift($this->_posts_save);
  196 + if (
  197 + is_array($_posts) &&
  198 + isset($_posts[0]) &&
  199 + ! empty( $_posts[0]->appearance_date ) &&
  200 + ( $_posts[0]->appearance_date < date('Y-m-d H:i:s') )
  201 + ) {
  202 + $posts = $_posts;
  203 + }
  204 + }
  205 + return $posts;
  206 + }
  207 +
  208 + /**
  209 + * Get the appearance date of a given object.
  210 + *
  211 + * @param int $object_id The ID of the object for which to retreive the date.
  212 + * @return string The MySQL date formatted appearance date if one exists, or false if one does not.
  213 + */
  214 + public function get_appearance_date($post_id = 0)
  215 + {
  216 + global $wpdb;
  217 + $post_id = (int) $post_id;
  218 + $id = '_f_ap_date_for_' . $post_id;
  219 + $app_table = $wpdb->prefix . $this->_appearance_table_name;
  220 +
  221 + if ( ! $date = get_transient($id) ) {
  222 + $date = $wpdb->get_var("SELECT appearance_date FROM {$app_table} WHERE appearance_object_id = {$post_id} LIMIT 1");
  223 +
  224 + if ( empty( $date ) ) {
  225 + $date = false;
  226 + } else {
  227 + set_transient($id, $date);
  228 + }
  229 + }
  230 +
  231 + return $date;
  232 + }
  233 +
  234 + public function maybe_install_table()
  235 + {
  236 + // check to make sure everything is installed for this particular site
  237 + $installed = (bool) get_option('_filosofo_ap_date_installed');
  238 + if ( ! $installed ) {
  239 + $result = $this->_install_appearance_table();
  240 + if ( $result ) {
  241 + update_option('_filosofo_ap_date_installed', true);
  242 + }
  243 + }
  244 + }
  245 +
  246 + /**
  247 + * Set the appearance date of a given object.
  248 + *
  249 + * @param int $object_id The ID of the object for which to set the date.
  250 + * @param string $date The MySQL-formatted date string to set the appearance date to.
  251 + * If $date is an empty string, will delete the appearance date row.
  252 + * @return bool Whether the saving was successful.
  253 + */
  254 + public function set_appearance_date($post_id = 0, $date = '')
  255 + {
  256 + global $wpdb;
  257 + $post_id = (int) $post_id;
  258 +
  259 + $id = '_f_ap_date_for_' . $post_id;
  260 +
  261 + $app_table = $wpdb->prefix . $this->_appearance_table_name;
  262 + $date_data = array(
  263 + 'appearance_date' => $date,
  264 + );
  265 + $date_where = array(
  266 + 'appearance_object_id' => $post_id,
  267 + );
  268 +
  269 + delete_transient($id);
  270 +
  271 + if ( empty( $date ) ) {
  272 + $result = (int) $wpdb->query("DELETE FROM {$app_table} WHERE appearance_object_id = {$post_id}");
  273 + } else {
  274 + $result = (int) $wpdb->update(
  275 + $app_table,
  276 + $date_data,
  277 + $date_where
  278 + );
  279 +
  280 + if ( 0 == $result ) {
  281 + $result = (int) $wpdb->insert(
  282 + $app_table,
  283 + array_merge(
  284 + $date_data,
  285 + $date_where
  286 + )
  287 + );
  288 + }
  289 + }
  290 + return ( 0 < $result );
  291 + }
  292 +
  293 +}
  294 +
  295 +class Filosofo_Appearance_Date_Admin {
  296 +
  297 + public function event_admin_init()
  298 + {
  299 + $this->query->maybe_install_table();
  300 + }
  301 +
  302 + public function event_wp_insert_post($post_id = 0, $post_obj = null)
  303 + {
  304 + $post_id = (int) $post_id;
  305 + if (
  306 + ! empty( $post_id ) &&
  307 + isset( $_POST['saving-ap-date-settings'] )
  308 + ) {
  309 + $use_it = (bool) $_POST['use-ap-date'];
  310 +
  311 + if ( $use_it ) {
  312 + $Y = zeroise((int) $_POST['ap-aa'], 4);
  313 + $m = zeroise((int) $_POST['ap-mm'], 2);
  314 + $d = zeroise((int) $_POST['ap-jj'], 2);
  315 +
  316 + $H = zeroise((int) $_POST['ap-hh'], 2);
  317 + $i = zeroise((int) $_POST['ap-mn'], 2);
  318 + $s = '00';
  319 +
  320 + $date = "{$Y}-{$m}-{$d} {$H}:{$i}:{$s}";
  321 + } else {
  322 + $date = false;
  323 + }
  324 +
  325 + $this->query->set_appearance_date($post_id, $date);
  326 + }
  327 + }
  328 +
  329 + public function print_appearance_date_chooser()
  330 + {
  331 + global $post;
  332 +
  333 + if ( ! current_user_can('publish_posts') || ! isset( $post->ID ) ) {
  334 + return false;
  335 + }
  336 +
  337 + $post_id = (int) $post->ID;
  338 +
  339 + $current_ap_date = $this->query->get_appearance_date($post_id);
  340 +
  341 + if ( empty( $current_ap_date ) ) {
  342 + $use_ap_date = false;
  343 + $current_ap_date = get_post_time('Y-m-d H:i:s', false, $post_id);
  344 + } else {
  345 + $use_ap_date = true;
  346 + }
  347 +
  348 + ?>
  349 + <div id="ap-date-wrap">
  350 + <label for="use-ap-date">
  351 + <?php _e('Show starting on appearance date?', 'appearance-date'); ?>
  352 + <input type="hidden" name="saving-ap-date-settings" value="1" />
  353 + <input type="checkbox" <?php
  354 + if ( true === $use_ap_date ) {
  355 + echo ' checked="checked"';
  356 + }
  357 + ?> value="1" id="use-ap-date" name="use-ap-date" />
  358 + </label>
  359 +
  360 + <div id="ap-date-selects">
  361 + <p><strong><?php _e('Appearance date:', 'appearance-date'); ?></strong></p>
  362 + <?php
  363 + $this->_print_time_selects($current_ap_date);
  364 + ?>
  365 + </div>
  366 +
  367 + <script type="text/javascript">
  368 + // <![CDATA[
  369 + (function() {
  370 + var useCheckbox = document.getElementById('use-ap-date'),
  371 + dateSelects = document.getElementById('ap-date-selects');
  372 +
  373 + if ( dateSelects && useCheckbox ) {
  374 + if ( ! useCheckbox.checked )
  375 + dateSelects.style.display = 'none';
  376 +
  377 + useCheckbox.onclick = function() {
  378 + dateSelects.style.display = this.checked ? 'block' : 'none';
  379 + }
  380 + }
  381 + })();
  382 + // ]]>
  383 + </script>
  384 + </div>
  385 + <?php
  386 + }
  387 +
  388 + public function print_style()
  389 + {
  390 + ?>
  391 + <style type="text/css">
  392 + #ap-date-wrap {
  393 + padding:.5em;
  394 + }
  395 + </style>
  396 + <?php
  397 + }
  398 +
  399 + private function _print_time_selects( $post_date = null ) {
  400 + global $wp_locale;
  401 +
  402 + $time_adj = current_time('timestamp');
  403 +
  404 + $jj = empty( $post_date ) ? gmdate( 'd', $time_adj ) : mysql2date( 'd', $post_date, false );
  405 + $mm = empty( $post_date ) ? gmdate( 'm', $time_adj ) : mysql2date( 'm', $post_date, false );
  406 + $aa = empty( $post_date ) ? gmdate( 'Y', $time_adj ) : mysql2date( 'Y', $post_date, false );
  407 + $hh = empty( $post_date ) ? gmdate( 'H', $time_adj ) : mysql2date( 'H', $post_date, false );
  408 + $mn = empty( $post_date ) ? gmdate( 'i', $time_adj ) : mysql2date( 'i', $post_date, false );
  409 + $ss = empty( $post_date ) ? gmdate( 's', $time_adj ) : mysql2date( 's', $post_date, false );
  410 +
  411 + $month = "<select id=\"ap-mm\" name=\"ap-mm\">\n";
  412 + for ( $i = 1; $i < 13; $i = $i +1 ) {
  413 + $month .= "\t\t\t" . '<option value="' . zeroise($i, 2) . '"';
  414 + if ( $i == $mm )
  415 + $month .= ' selected="selected"';
  416 + $month .= '>' . $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) ) . "</option>\n";
  417 + }
  418 + $month .= '</select>';
  419 +
  420 + $day = '<input type="text" id="ap-jj" name="ap-jj" value="' . $jj . '" size="2" maxlength="2" autocomplete="off" />';
  421 + $year = '<input type="text" id="ap-aa" name="ap-aa" value="' . $aa . '" size="4" maxlength="4" autocomplete="off" />';
  422 + $hour = '<input type="text" id="ap-hh" name="ap-hh" value="' . $hh . '" size="2" maxlength="2" autocomplete="off" />';
  423 + $minute = '<input type="text" id="ap-mn" name="ap-mn" value="' . $mn . '" size="2" maxlength="2" autocomplete="off" />';
  424 +
  425 + echo '<div class="timestamp-wrap">';
  426 + /* translators: 1: month input, 2: day input, 3: year input, 4: hour input, 5: minute input */
  427 + printf(__('%1$s%2$s, %3$s @ %4$s : %5$s', 'appearance-date'), $month, $day, $year, $hour, $minute);
  428 +
  429 + echo '</div>';
  430 + }
  431 +}
  432 +
  433 +function init_filosofo_appearance_date()
  434 +{
  435 + new Filosofo_Appearance_Date_Factory;
  436 +}
  437 +
  438 +function uninstall_filosofo_appearance_date()
  439 +{
  440 + global $wpdb;
  441 + $app_table = $wpdb->prefix . 'object_appearance_dates';
  442 + $wpdb->query(sprintf('DROP TABLE %s', $app_table));
  443 + delete_option('_filosofo_ap_date_installed');
  444 +}
  445 +
  446 +add_action('plugins_loaded', 'init_filosofo_appearance_date');
  447 +register_uninstall_hook(__FILE__, 'uninstall_filosofo_appearance_date');

0 comments on commit c807257

Please sign in to comment.
Something went wrong with that request. Please try again.