Commit 6fd64e09 authored by Rolf Forst's avatar Rolf Forst
Browse files

Add custom post status (expired). Refactoring

parent 96406ab3
<?php
namespace RRZE\PostExpiration;
defined('ABSPATH') || exit;
class Expiration
{
protected $option_name;
protected $options;
protected $meta;
protected $cron_hook;
protected $expiration_post_status = 'expired';
protected $expiration_date_key = 'expiration_date';
protected $expiration_date_gmt_key = 'expiration_date_gmt';
public function __construct()
{
$opt = new Options();
$this->option_name = $opt->get_option_name();
$this->options = $opt->get_options();
if (empty($this->options->post_types)) {
return;
}
foreach ($this->options->post_types as $post_type) {
add_filter('manage_' . $post_type . '_posts_columns', array($this, 'expiration_date_column'));
add_action('manage_' . $post_type . '_posts_custom_column', array($this, 'expiration_date_custom_column'), 10, 2);
add_filter('manage_edit-' . $post_type . '_sortable_columns', array($this, 'expiration_date_sortable_column'));
}
add_action('init', [$this, 'register_post_status']);
add_action('admin_footer-post.php', [$this, 'append_post_status_postbox']);
add_action('admin_footer-edit.php', [$this, 'append_post_status_quick_edit']);
add_action('pre_get_posts', array($this, 'expiration_date_orderby'));
add_action('post_submitbox_misc_actions', array($this, 'exp_meta_box'));
add_action('save_post', array($this, 'update_post_expiration_date'));
add_filter('cron_schedules', array($this, 'add_cron_schedule'));
$this->cron_hook = sprintf('%s_%s', $this->option_name, get_current_blog_id());
add_action($this->cron_hook, array($this, 'set_expired_posts'));
}
public function expiration_date_column($columns)
{
$columns['expiration_date'] = __('Expiration', 'rrze-post-expiration');
return $columns;
}
public function expiration_date_custom_column($column, $post_id)
{
if ($column != 'expiration_date') {
return;
}
$post = get_post($post_id);
$expiration_date = get_post_meta($post->ID, $this->expiration_date_key, true);
$expiration_date_gmt = get_post_meta($post->ID, $this->expiration_date_gmt_key, true);
if ($post->post_date == '0000-00-00 00:00:00' || !$expiration_date) {
echo '&#8212;';
} else {
$t_time = date(__('Y/m/d g:i:s A'), mysql2date('U', $expiration_date));
$m_time = $expiration_date;
$time = mysql2date('G', $expiration_date_gmt);
$time_diff = $time - time();
if ($time_diff > 0 && $time_diff < 24 * 60 * 60) {
$h_time = sprintf(__('in %s'), human_time_diff($time));
} elseif ($time_diff < 0 && abs($time_diff) < 24 * 60 * 60) {
$h_time = sprintf(__('%s ago'), human_time_diff($time));
} else {
$h_time = mysql2date(__('Y/m/d'), $m_time);
}
echo '<abbr title="' . $t_time . '">' . $h_time . '</abbr>';
if ($time_diff < 0) {
echo '<br/>', __('expired', 'rrze-post-expiration');
}
}
}
public function expiration_date_sortable_column($columns)
{
$columns['expiration_date'] = 'expiration_date';
return $columns;
}
public function expiration_date_orderby($query)
{
if (!is_admin()) {
return;
}
$orderby = $query->get('orderby');
if ('expiration_date' == $orderby) {
$query->set('orderby', 'meta_value');
$query->set(
'meta_query',
array(
'relation' => 'OR',
array(
'key' => $this->expiration_date_key,
'compare' => 'NOT EXISTS'
),
array(
'key' => $this->expiration_date_key,
'compare' => 'EXISTS'
),
)
);
}
}
public function register_post_status()
{
register_post_status($this->expiration_post_status, [
'label' => _x('Expired', 'post', 'rrze-post-expiration'),
'public' => false,
'private' => false,
'exclude_from_search' => true,
'show_in_admin_all_list' => false,
'show_in_admin_status_list' => true,
'label_count' => _n_noop('Expired <span class="count">(%s)</span>', 'Expired <span class="count">(%s)</span>', 'rrze-post-expiration')
]);
}
public function append_post_status_postbox()
{
$post = get_post();
if (! in_array($post->post_type, $this->options->post_types)) {
return;
}
$selected = '';
$post_status_display = '';
$title = __('Expired', 'rrze-post-expiration');
if ($post->post_status == $this->expiration_post_status) {
$post_status_display = '$(".misc-pub-post-status span#post-status-display").text("' . $title . '");';
$selected = ' selected=\"selected\"';
}
$script = '
<script>
jQuery(document).ready(function($){
$("select#post_status").append("<option value=\"expired\"' . $selected . '>' . $title. '</option>");
' . $post_status_display . '
});
</script>
';
echo str_replace(PHP_EOL, '', trim(preg_replace('/\s+/', ' ', $script)));
}
public function append_post_status_quick_edit()
{
if (! in_array(get_post_type(), $this->options->post_types)) {
return;
}
$title = __('Expired', 'rrze-post-expiration');
$script = "<script>
jQuery(document).ready(function($) {
$('select[name=\"_status\"]').append('<option value=\"expired\">" . $title . "</option>');
});
</script>";
echo str_replace(PHP_EOL, '', trim(preg_replace('/\s+/', ' ', $script)));
}
public function exp_meta_box()
{
global $post, $post_type, $post_type_object;
if (!in_array($post_type, $this->options->post_types)) {
return;
}
$can_publish = current_user_can($post_type_object->cap->publish_posts);
if ($can_publish) :
$cur_time = strtotime(current_time('mysql'));
$datef = __('M j, Y @ H:i');
$date = date_i18n($datef, $cur_time);
$stamp = __('Expiration <b>disabled</b>', 'rrze-post-expiration');
if (0 != $post->ID) {
$expiration_date = get_post_meta($post->ID, $this->expiration_date_key, true);
if ($expiration_date) {
$exp_time = strtotime($expiration_date);
if ($exp_time > $cur_time) {
$stamp = __('Expires on: <b>%s</b>', 'rrze-post-expiration');
} else {
$stamp = __('Expired on: <b>%s</b>', 'rrze-post-expiration');
}
$enabled = ' checked="checked"';
$date = date_i18n($datef, strtotime($expiration_date));
}
} ?>
<div class="misc-pub-section curtime misc-pub-curtime">
<span id="timestamp" class="exp_timestamp">
<?php printf($stamp, $date); ?></span>
<a href="#edit_exp_timestamp" class="edit-exp-timestamp hide-if-no-js" tabindex="4"><?php _e('Edit') ?></a>
<div id="exp_timestampdiv" class="hide-if-js">
<?php $this->select_expiration_time(); ?>
</div>
</div>
<?php
endif;
}
private static function select_expiration_time()
{
global $wp_locale, $post;
$expiration_date = get_post_meta($post->ID, 'expiration_date', true);
$expiration_date_gmt = get_post_meta($post->ID, 'expiration_date_gmt', true);
$enabled = '';
if ($expiration_date) {
$enabled = ' checked="checked"';
}
$edit = !(!$expiration_date);
$time_adj = current_time('timestamp');
$jj = ($edit) ? mysql2date('d', $expiration_date, false) : gmdate('d', $time_adj);
$mm = ($edit) ? mysql2date('m', $expiration_date, false) : gmdate('m', $time_adj);
$aa = ($edit) ? mysql2date('Y', $expiration_date, false) : gmdate('Y', $time_adj);
$hh = ($edit) ? mysql2date('H', $expiration_date, false) : gmdate('H', $time_adj);
$mn = ($edit) ? mysql2date('i', $expiration_date, false) : gmdate('i', $time_adj);
$ss = ($edit) ? mysql2date('s', $expiration_date, false) : gmdate('s', $time_adj);
$cur_jj = gmdate('d', $time_adj);
$cur_mm = gmdate('m', $time_adj);
$cur_aa = gmdate('Y', $time_adj);
$cur_hh = gmdate('H', $time_adj);
$cur_mn = gmdate('i', $time_adj);
$month = "<select id=\"exp_mm\" name=\"exp_mm\" tabindex=\"4\" style=\"height:20px; line-height:14px; padding:0; vertical-align:top;\">\n";
for ($i = 1; $i < 13; $i = $i +1) {
$monthnum = zeroise($i, 2);
$monthtext = $wp_locale->get_month_abbrev($wp_locale->get_month($i));
$month .= "\t\t\t" . '<option value="' . $monthnum . '" data-text="' . $monthtext . '" ' . selected($monthnum, $mm, false) . '>';
/* translators: 1: month number (01, 02, etc.), 2: month abbreviation */
$month .= sprintf(__('%1$s-%2$s'), $monthnum, $monthtext) . "</option>\n";
}
$month .= '</select>';
$day = '<input type="text" id="exp_jj" name="exp_jj" value="' . $jj . '" size="2" maxlength="2" tabindex="4" autocomplete="off" style="font-size:12px; padding:1px; width:2em;" />';
$year = '<input type="text" id="exp_aa" name="exp_aa" value="' . $aa . '" size="4" maxlength="4" tabindex="4" autocomplete="off" style="font-size:12px; padding:1px; width:3.4em;" />';
$hour = '<input type="text" id="exp_hh" name="exp_hh" value="' . $hh . '" size="2" maxlength="2" tabindex="4" autocomplete="off" style="font-size:12px; padding:1px; width:2em;" />';
$minute = '<input type="text" id="exp_mn" name="exp_mn" value="' . $mn . '" size="2" maxlength="2" tabindex="4" autocomplete="off" style="font-size:12px; padding:1px; width:2em;" />';
echo '<div class="exp-timestamp-wrap">';
echo '<p style="margin:0.5em 0;"><input type="checkbox" name="enable_expiration" id="enable_expiration" value="checked"' . $enabled . ' />';
echo '<label class="selectit" for="enable_expiration">' . __('Enable expiration', 'rrze-post-expiration') . '</label></p>';
/* translators: 1: month, 2: day, 3: year, 4: hour, 5: minute */
printf(__('%1$s %2$s, %3$s @ %4$s:%5$s'), $month, $day, $year, $hour, $minute);
echo '</div><input type="hidden" id="exp_ss" name="exp_ss" value="' . $ss . '" />';
echo "\n\n";
if ($enabled) {
echo '<input type="hidden" id="exp_enabled" name="exp_enabled" value="1" />';
} else {
echo '<input type="hidden" id="exp_enabled" name="exp_enabled" value="0" />';
}
echo "\n\n";
foreach (array('mm', 'jj', 'aa', 'hh', 'mn') as $timeunit) {
echo '<input type="hidden" id="exp_hidden_' . $timeunit . '" name="hidden_' . $timeunit . '" value="' . $$timeunit . '" />' . "\n";
$cur_timeunit = 'cur_' . $timeunit;
echo '<input type="hidden" id="exp_' . $cur_timeunit . '" name="exp_' . $cur_timeunit . '" value="' . $$cur_timeunit . '" />' . "\n";
} ?>
<p>
<a href="#edit_exp_timestamp" class="save-exp-timestamp hide-if-no-js button"><?php _e('OK'); ?></a>
<a href="#edit_exp_timestamp" class="cancel-exp-timestamp hide-if-no-js"><?php _e('Cancel'); ?></a>
</p>
<?php
}
public function update_post_expiration_date()
{
global $current_blog, $post;
if (!$post || !in_array($post->post_type, $this->options->post_types)) {
return;
}
delete_post_meta($post->ID, $this->expiration_date_key);
delete_post_meta($post->ID, $this->expiration_date_gmt_key);
if (isset($_POST['enable_expiration'])) {
$aa = $_POST['exp_aa'];
$mm = $_POST['exp_mm'];
$jj = $_POST['exp_jj'];
$hh = $_POST['exp_hh'];
$mn = $_POST['exp_mn'];
$ss = $_POST['exp_ss'];
$aa = ($aa <= 0) ? date('Y') : $aa;
$mm = ($mm <= 0) ? date('n') : $mm;
$jj = ($jj > 31) ? 31 : $jj;
$jj = ($jj <= 0) ? date('j') : $jj;
$hh = ($hh > 23) ? $hh - 24 : $hh;
$mn = ($mn > 59) ? $mn - 60 : $mn;
$ss = ($ss > 59) ? $ss - 60 : $ss;
$ts = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss);
update_post_meta($post->ID, $this->expiration_date_key, $ts, true);
$ts_gmt = get_gmt_from_date($ts);
update_post_meta($post->ID, $this->expiration_date_gmt_key, $ts_gmt, true);
wp_clear_scheduled_hook($this->cron_hook);
wp_schedule_event(time(), 'two-minutes', $this->cron_hook);
}
}
public function add_cron_schedule($schedules)
{
$schedules['two-minutes'] = array(
'interval' => 120,
'display' => __('Every Two Minutes')
);
return $schedules;
}
public function set_expired_posts()
{
global $wpdb;
$current_date = current_time('mysql');
$pt_sql = [];
foreach ($this->options->post_types as $post_type) {
$pt_sql[] = $wpdb->prepare('posts.post_type = %s', $post_type);
}
$pt_sql = implode(' OR ', $pt_sql);
$result = $wpdb->get_results(
$wpdb->prepare(
"SELECT post_id FROM {$wpdb->postmeta} as postmeta
LEFT JOIN {$wpdb->posts} as posts ON postmeta.post_id = posts.ID
WHERE posts.post_status = 'publish' AND ({$pt_sql})
AND postmeta.meta_key = %s
AND postmeta.meta_value <= %s",
$this->expiration_date_key,
$current_date
)
);
if (!empty($result)) {
foreach ($result as $row) {
wp_update_post(['ID' => $row->post_id, 'post_status' => $this->expiration_post_status]);
// rrze cache plugin
$this->flush_cache(get_permalink($row->post_id));
}
}
}
protected function flush_cache($url)
{
if (empty($url)) {
return;
}
if (has_action('rrzecache_flush_cache_url')) {
do_action('rrzecache_flush_cache_url', $url);
}
}
}
<?php
namespace RRZE\PostExpiration;
defined('ABSPATH') || exit;
class Main
{
protected $plugin_basename;
public function __construct($plugin_basename)
{
$this->plugin_basename = $plugin_basename;
add_action('admin_enqueue_scripts', [$this, 'admin_enqueue_scripts']);
$settings = new Settings();
$expiration = new Expiration();
}
public function admin_enqueue_scripts($hook)
{
wp_register_style('rrze-post-expiration', plugins_url('css/post-expiration.min.css', $this->plugin_basename));
if ($hook == 'post.php') {
wp_register_script('rrze-post-expiration', plugins_url('js/post-hook-suffix.min.js', $this->plugin_basename), ['jquery']);
wp_localize_script('rrze-post-expiration', 'expiration', [
'expiresOn' => __('Expires on', 'rrze-post-expiration'),
'expiredOn' => __('Expired on:', 'rrze-post-expiration'),
'expirationDate' => __('Expiration <b>disabled</b>', 'rrze-post-expiration')
]);
wp_enqueue_script('rrze-post-expiration');
}
}
}
<?php
namespace RRZE\PostExpiration;
defined('ABSPATH') || exit;
class Options
{
protected $option_name = 'rrze_post_expiration';
protected function default_options()
{
$options = [
'post_types' => []
];
return $options;
}
public function get_options()
{
$defaults = $this->default_options();
$options = (array) get_option($this->option_name);
$options = wp_parse_args($options, $defaults);
$options = array_intersect_key($options, $defaults);
return (object) $options;
}
public function get_option_name()
{
return $this->option_name;
}
}
<?php
namespace RRZE\PostExpiration;
defined('ABSPATH') || exit;
class Settings
{
const allowed_post_types = [
'post',
'page'
];
protected $option_name;
protected $options;
protected $admin_settings_page;
protected $allowed_post_types;
public function __construct()
{
$opt = new Options();
$this->option_name = $opt->get_option_name();
$this->options = $opt->get_options();
add_action('admin_menu', [$this, 'admin_settings_page']);
add_action('admin_init', [$this, 'admin_settings']);
}
public function admin_settings_page()
{
$this->admin_settings_page = add_options_page(__('Expiration', 'rrze-post-expiration'), __('Expiration', 'rrze-post-expiration'), 'manage_options', 'post-expiration', [$this, 'settings_page']);
//add_action('load-' . $this->admin_settings_page, [$this, 'admin_help_menu']);
}
public function settings_page()
{
?>
<div class="wrap">
<h2><?php echo __('Settings &rsaquo; Expiration', 'rrze-post-expiration'); ?></h2>
<form method="post" action="options.php">
<?php
settings_fields('post_expiration_options');
do_settings_sections('post_expiration_options');
submit_button(); ?>
</form>
</div>
<?php
}
public function admin_settings()
{
register_setting('post_expiration_options', $this->option_name, [$this, 'options_validate']);
add_settings_section('post_expiration_section', false, '__return_false', 'post_expiration_options');
add_settings_field('post_types_field', __('Enable', 'rrze-post-expiration'), [$this, 'post_types_field'], 'post_expiration_options', 'post_expiration_section');
}
public function options_validate($input)
{
if (! empty($input['post_types']) && is_array($input['post_types'])) {
$post_types = array_unique($input['post_types']);
foreach ($post_types as $key => $value) {
if (! in_array($value, self::allowed_post_types)) {
unset($post_types[$key]);
}
}
$input['post_types'] = array_values($post_types);
} else {
$input['post_types'] = [];
}
return $input;
}
public function post_types_field()
{
$last_key = $this->array_key_last(self::allowed_post_types);
foreach (self::allowed_post_types as $key => $post_type): ?>
<label for="<?php echo $post_type; ?>">
<input type="checkbox" <?php checked(in_array($post_type, $this->options->post_types), true); ?> name="<?php printf('%s[post_types][]', $this->option_name); ?>" value="<?php echo $post_type; ?>" id="<?php echo $post_type; ?>" />
<?php echo $this->post_type_label($post_type); ?>
</label>
<?php if ($key != $last_key) : ?>
<br/>
<?php endif;
endforeach; ?>
<p class="description"><?php _e('Type of document to which an expiry date can be assigned.', 'rrze-post-expiration'); ?></p>
<?php
}
public function admin_help_menu()
{
$content = [
'<p>' . __('Here comes the Context Help content.', 'rrze-post-expiration') . '</p>',
];
$help_tab = [
'id' => $this->admin_settings_page,
'title' => __('Overview', 'rrze-post-expiration'),
'content' => implode(PHP_EOL, $content),
];
$help_sidebar = sprintf('<p><strong>%1$s:</strong></p><p><a href="http://blogs.fau.de/webworking">RRZE-Webworking</a></p><p><a href="https://github.com/RRZE-Webteam">%2$s</a></p>', __('For more information', 'rrze-post-expiration'), __('RRZE Webteam on Github', 'rrze-post-expiration'));
$screen = get_current_screen();
if ($screen->id != $this->admin_settings_page) {
return;
}
$screen->add_help_tab($help_tab);
$screen->set_help_sidebar($help_sidebar);
}
private function post_type_label($post_type = 'post')
{
$post_types = get_post_types(array('show_in_menu' => true), 'objects');
$labels = wp_list_pluck($post_types, 'labels');
$labels = wp_list_pluck($labels, 'name');
return isset($labels[$post_type]) ? $labels[$post_type] : '';
}
public function array_key_last($array)
{
$key = null;
if (is_array($array)) {
end($array);
$key = key($array);
}
return $key;
}
}