Location: PHPKode > scripts > Comment Timeout > comment-timeout/php/class.core.php
<?php

// For compatibility with WP 2.0

if (!function_exists('wp_die')) {
	function wp_die($msg) {
		die($msg);
	}
}


class jmct_Core
{
	/* ====== init ====== */

	/**
	 * Initialises the plugin, setting up the required hooks.
	 */

	private static $instance;

	public static function get_instance()
	{
		return jmct_Core::$instance;
	}


	public static function init()
	{
		/*
		 * Remove the default WordPress comment closing functionality
		 * since it interferes with ours.
		 */
		remove_filter('the_posts',     '_close_comments_for_old_posts');
		remove_filter('comments_open', '_close_comments_for_old_post', 10, 2);
		remove_filter('pings_open',    '_close_comments_for_old_post', 10, 2);

		$core = new jmct_Core();
		add_filter('the_posts', array(&$core, 'process_posts'));
		add_action('admin_init', array(&$core, 'admin_init'));
		add_action('admin_menu', array(&$core, 'admin_menu'));
		// Needs to be called before Akismet
		add_filter('preprocess_comment', array(&$core, 'preprocess_comment'), 0);
		add_action('comment_form', array(&$core, 'comment_form'));
		jmct_Core::$instance =& $core;
	}


	private $settings;
	private $defaultSettings;

	/* ====== Constructor ====== */

	/**
	 * Initialises the plugin, setting up the actions and filters.
	 */

	private function __construct()
	{
	}

	/* ====== get_settings ====== */

	/**
	 * Retrieves the settings from the WordPress settings database.
	 * This method may be called more than once.
	 * @return The settings.
	 */

	public function get_settings()
	{
		if (isset($this->settings)) return $this->settings;

		/*
		 * Get the WordPress native default comment closing settings.
		 */
		$this->wp_active = (bool)get_option('close_comments_for_old_posts');
		$this->wp_timeout = (int)get_option('close_comments_days_old');

		// Defaults for the settings

		$this->defaultSettings = array(
			// Number of days from last comment before post is stale
			'CommentAge' => 60,
			// Number of days from last comment before popular post is stale
			'CommentAgePopular' => 365,
			// Definition of a popular post (number of approved comments)
			'PopularityThreshold' => 20,
			// Indicates whether to 'close' (default) or 'moderate' comments on old posts
			'Mode' => 'close',
			// Whether to treat pings 'together' with posts (true or default),
			// 'independent' of posts, or 'ignore' (false)
			'DoPings' => 'together',
			// Whether to apply these rules to pages, images and file uploads
			'DoPages' => false,
			// Whether to allow overrides
			'AllowOverride' => true,
			// Whether to display when comments timeout as 'absolute' (default),
			// time remaining 'relative' or 'off'
			'DisplayTimeout' => 'date',
			// Date to time out across the board. 0 for none.
			'GlobalClose' => 0,
			// Date to re-open comments across the board. 0 for none.
			'GlobalReopen' => 0
		);

		$this->settings = get_option('jammycakes_comment_locking');
		if (FALSE === $this->settings) {
			$this->settings = $this->defaultSettings;
			add_option('jammycakes_comment_locking', $this->settings);
			return $this->settings;
		}

		$this->settings = array_merge($this->defaultSettings, $this->settings);
		$upgraded = false;

		/* Upgrade the settings from previous versions if necessary */

		if (isset($this->settings['UniqueID'])) {
			// CT 1.3 - need to sanitise and update
			$upgraded = true;
		}

		if (isset($this->settings['PostAge'])) {
			// CT 2.1 or earlier - PostAge is deprecated and should be moved into WP native
			$this->wp_active = true;
			$this->wp_timeout = $this->settings['PostAge'];
			unset($this->settings['PostAge']);
			$upgraded = true;
		}

		$this->sanitize_settings();
		if ($upgraded) {
			$this->save_settings();
		}

		return $this->settings;
	}


	/* ====== save_settings ====== */

	/**
	 * Saves the settings back to WordPress, without pre-processing.
	 */

	private function save_settings()
	{
		update_option('jammycakes_comment_locking', $this->settings);
		update_option('close_comments_for_old_posts', $this->wp_active);
		update_option('close_comments_days_old', $this->wp_timeout);
	}


	/* ====== save_settings_from_postback ====== */

	/**
	 * Updates the settings from the admin page postback, and saves them.
	 */

	public function save_settings_from_postback()
	{
		$this->get_settings();

		// Insert the new settings, with validation and type coercion

		foreach ($this->defaultSettings as $k=>$v) {
			$this->settings[$k] = $_POST[$k];
		}
		$this->wp_active = (bool)$_POST['Active'];
		$this->wp_timeout = (int)$_POST['PostAge'];
		$this->sanitize_settings();
		$this->save_settings();
		return $this->settings;
	}

	/* ====== parse_date ====== */

	/**
	 * Parses date and time in the format DD/MM/YYYY [hh:mm].
	 * 
	 * This is needed because strptime is not implemented on Windows (!) and PHP doesn't get any
	 * other date/time parsing functions till the DateTime class in PHP 5.3.
	 * 
	 * @param type $date A date string to parse.
	 * @return type 
	 */

	private function parse_date($date)
	{
		if (is_int($date)) return $date;
		$match = preg_match
			('/(?P<d>[0-9]{1,2})\\/(?P<M>[0-9]{1,2})\\/(?P<y>[0-9]{4})' .
				'(\\s+(?P<h>[0-9]{1,2})\\:(?P<m>[0-9]{1,2}))?/',
				$date, $matches);
		if (!$match) return 0;
		return mktime(
			isset($matches['h']) ? (int)$matches['h'] : 12,
			(int)$matches['m'],
			0,
			(int)$matches['M'],
			(int)$matches['d'],
			(int)$matches['y']
		);
	}


	/* ====== sanitize_settings ====== */

	/**
	 * Makes sure settings are all in the correct format,
	 * also converts CT 1.0 versions to CT 2.0
	 */

	private function sanitize_settings()
	{
		foreach (array_keys($this->settings) as $k) { // iterator safe
			$v = $this->settings[$k];
			switch ($k) {
				case 'CommentAge':
				case 'CommentAgePopular':
				case 'PopularityThreshold':
					$this->settings[$k] = (int) $v;
					break;
				case 'AllowOverride':
				case 'DoPages':
					$this->settings[$k] = (bool) $v;
					break;
				case 'DoPings':
					if ('ignore' !== $v && 'independent' !== $v && 'together' !== $v) {
						$this->settings[$k] = 'together';
					}
					break;
				case 'Mode':
					$v = (string) $v;
					if ($v != 'moderate') {
						$this->settings['Mode'] = 'close';
					}
					break;
				case 'DisplayTimeout':
					$v = (string) $v;
					if ($v !== 'absolute' && $v !== 'relative' && $v !== 'off') {
						$this->settings['DisplayTimeout'] = 'absolute';
					}
					break;
				case 'GlobalClose':
				case 'GlobalReopen':
					$this->settings[$k] = $this->parse_date($v);
					break;
				default:
					unset ($this->settings[$k]);
			}
		}
	}


	/* ====== process_posts ====== */

	/**
	 * Goes through the list of posts, checking each one to see if it should
	 * have comments closed.
	 */

	public function process_posts($posts)
	{
		if (is_admin()) {
			return $posts;
		}

		// Check that we have an array of posts
		if (!is_array($posts)) {
			// Is it a single post? If so, process it as an array of posts
			if (is_object($posts) && isset($posts->comment_status)) {
				$p = $this->process_posts(array($posts));
				return $p[0];
			}
			else {
				// Otherwise don't do anything
				return $posts;
			}
		}

		require_once(dirname(__FILE__) . '/class.post-processor.php');
		$processor = new jmct_PostProcessor($this, $posts);
		return $processor->process_posts();
	}


	/* ====== preprocess_comment filter ====== */

	/**
	 * Process a submitted comment. Die if it's not OK
	 */

	public function preprocess_comment($comment)
	{
		require_once(dirname(__FILE__) . '/class.comment-processor.php');
		$processor = new jmct_CommentProcessor($this, $comment);
		return $processor->process_comment();
	}


	/* ====== admin_init ====== */
	
	/**
	 * Initialises the admin section
	 */
	
	function admin_init()
	{
		wp_register_script(
			'comment-timeout-admin',
			plugins_url('/js/admin.js', dirname(__FILE__)),
			'jquery',
			COMMENT_TIMEOUT_VERSION
		);
	}

	/* ====== admin_menu ====== */

	/**
	 * Adds the configuration page to the admin submenu;
	 * also initialises the other admin-related hooks.
	 */

	function admin_menu()
	{
		require_once(dirname(__FILE__) . '/class.admin.php');
		$adm = new jmct_Admin($this);
		$adm->init();
	}


	public function render_template_tag
		($relative, $dateformat = false, $before = '', $after = '', $moderated = '')
	{
		global $post;
		$timeout = get_comment_timeout();
		if ($timeout === false) {
			return;
		}
		$ct = $post->cutoff_comments - time();
		if ($ct < 0 && $this->settings['Mode'] == 'moderate') {
			echo $moderated;
		}
		elseif ($ct >= 0 && $this->settings['Mode'] == 'close') {
			echo $before;
			if ($relative) {
				if ($ct >= 63072000) {
					echo (int)($ct/31536000) . _(' years');
				}
				elseif($ct >= 5184000) {
					echo (int)($ct/2592000) . _(' months');
				}
				elseif($ct >= 1209600) {
					echo (int)($ct/604800) . _(' weeks');
				}
				elseif ($ct >= 172800) {
					echo (int) ($ct/86400) . _(' days');
				}
				else if ($ct >= 7200) {
					echo (int) ($ct/3600) . _(' hours');
				}
				else if ($ct >= 60) {
					echo (int) ($ct/60) . _(' minutes');
				}
				else {
					echo _('within one minute');
				}
			}
			else {
				$format = $dateformat === false ? get_option('date_format') : $dateformat;
				echo date($format, get_comment_timeout() + (get_option('gmt_offset') * 3600));
			}
			echo $after;
		}
	}

	private function render_comment_timeout($relative)
	{
		$this->render_template_tag(
			$relative,
			false,
			'<p class="comment-timeout">'
				. _('Comments will be closed ' . ($relative ? 'in ' : 'on ')),
			'.</p>',
			'<p class="comment-timeout">'
				. _('Comments will be sent to the moderation queue.')
				. '</p>'
		);
	}


	/* ====== comment_form ====== */

	public function comment_form()
	{
		$settings = $this->get_settings();
		switch($settings['DisplayTimeout'])  {
			case 'absolute':
				$this->render_comment_timeout(false);
				break;
			case 'relative':
				$this->render_comment_timeout(true);
				break;
		}
	}
}

jmct_Core::init();


/* ====== get_comment_timeout ====== */

/**
 * @returns
 *     the date and time that the comments for the current post will be cutoff,
 *     or false if they will remain open indefinitely. Date is returned as a Unix
 *     timestamp.
 */

function get_comment_timeout()
{
	global $post;
	if (isset ($post->cutoff_comments)) {
		return $post->cutoff_comments;
	}
	else {
		return false;
	}
}


/* ====== the_comment_timeout ====== */

/**
 * Displays the date and time that the comments for the current post will be cutoff.
 * @param $relative
 *     true to display the time in relative format, otherwise false.
 * @param $dateformat
 *     The PHP date() format used to print the (absolute) date. If not set,
 *     use the WordPress default. Ignored if $relative is true.
 * @param $before
 *     The HTML to render before the date (absolute or relative).
 * @param $after
 *     The HTML to render after the date (absolute or relative).
 * @param $moderated
 *     The HTML to render if late comments are being sent to the moderation queue.
 */

function the_comment_timeout
	($relative, $dateformat = false, $before = '', $after = '', $moderated = '')
{
	jmct_Core::get_instance()->render_template_tag
		($relative, $dateformat, $before, $after, $moderated);
}
Return current item: Comment Timeout