Source: wpt-pro-functions.php

<?php
/**
 * XPoster Pro, premium add-on for XPoster
 *
 * @package     XPoster Pro
 * @author      Joe Dolson
 * @copyright   2014-2024 Joe Dolson
 * @license     GPL-2.0+
 *
 * @wordpress-plugin
 * Plugin Name: XPoster Pro
 * Plugin URI: https://www.wptweetspro.com/wp-tweets-pro
 * Description: Adds great new features to extend XPoster.
 * Author: Joe Dolson
 * Author URI: https://www.joedolson.com
 * Text Domain: wp-tweets-pro
 * License:     GPL-2.0+
 * License URI: https://www.gnu.org/license/gpl-2.0.txt
 * Domain Path: lang
 * Version:     3.2.2
 * Requires Plugins: wp-to-twitter
 */

/*
	Copyright 2014-2024  Joe Dolson (email : joe@joedolson.com)

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

global $wptp_version;
$wptp_version = '3.2.2';

add_action( 'init', 'wptp_load_textdomain' );
/**
 * Load internationalization.
 */
function wptp_load_textdomain() {
	load_plugin_textdomain( 'wp-tweets-pro', false, dirname( plugin_basename( __FILE__ ) ) . '/lang' );
}

// The URL of the site with EDD installed.
define( 'EDD_WPT_STORE_URL', 'https://xposterpro.com' );
define( 'EDD_WPT_ITEM_ID', 47131 );

if ( ! class_exists( 'EDD_SL_Plugin_Updater' ) ) {
	// load our custom updater if it doesn't already exist.
	require_once __DIR__ . '/updates/EDD_SL_Plugin_Updater.php';
}

// retrieve our license key from the DB.
$license_key = trim( get_option( 'wpt_license_key' ) );
// setup the updater.
$edd_updater = new EDD_SL_Plugin_Updater(
	EDD_WPT_STORE_URL,
	__FILE__,
	array(
		'version' => $wptp_version, // current version number.
		'license' => $license_key, // license key (used get_option above to retrieve from DB).
		'item_id' => EDD_WPT_ITEM_ID, // name of this plugin.
		'author'  => 'Joe Dolson', // author of this plugin.
		'url'     => home_url(),
	)
);

register_activation_hook( __FILE__, 'wpt_activate' );
register_deactivation_hook( __FILE__, 'wpt_deactivation' );
/**
 * Action to perform on deactivation.
 */
function wpt_deactivation() {
	wp_clear_scheduled_hook( 'wpt_recurring_tweets' );
	wp_clear_scheduled_hook( 'wptcron' );
}

/**
 * Action to perform on activation.
 */
function wpt_activate() {
	// Set media upload option to enabled by default unless already set otherwise.
	$media_option = get_option( 'wpt_media', 'unset' );
	if ( 'unset' === $media_option ) {
		update_option( 'wpt_media', '1' );
	}
}

require plugin_dir_path( __FILE__ ) . 'wpt-users.php';
require plugin_dir_path( __FILE__ ) . 'wpt-auto-repost.php';
require plugin_dir_path( __FILE__ ) . 'wpt-scheduled-tweets.php';
require plugin_dir_path( __FILE__ ) . 'wpt-past-tweets.php';
require plugin_dir_path( __FILE__ ) . 'wpt-failed-tweets.php';
require plugin_dir_path( __FILE__ ) . 'wpt-pro-settings.php';
require plugin_dir_path( __FILE__ ) . 'wpt-player-card.php';

add_filter( 'wpt_status', 'wpt_filter_tweet', 10, 3 );
/**
 * Filter Tweet text to replace tag values with hashtags in title or post excerpt
 *
 * @param string $tweet_text Text of the Tweet.
 * @param int    $id post id.
 * @param string $context whether checking post content or title.
 *
 * @return string Update text of field being searched.
 */
function wpt_filter_tweet( $tweet_text, $id, $context ) {
	if ( ( get_option( 'wpt_filter_title' ) && 'title' === $context ) || ( 1 === (int) get_option( 'wpt_filter_post' ) && 'post' === $context ) ) {
		$term_meta = false;
		$tags      = get_the_tags( $id );
		if ( $tags > 0 ) {
			foreach ( $tags as $value ) {
				if ( 'slug' === get_option( 'wpt_tag_source' ) ) {
					$tag = $value->slug;
				} else {
					$tag = $value->name;
				}
				$replace = get_option( 'jd_replace_character' );
				$strip   = get_option( 'jd_strip_nonan' );
				$search  = '/[^a-zA-Z0-9]/';
				if ( '[ ]' === $replace || '' === $replace ) {
					$replace = '';
				}
				$newtag    = str_ireplace( ' ', $replace, trim( $tag ) );
				$t_id      = $value->term_id;
				$term_meta = get_option( "wpt_taxonomy_$t_id" );
				if ( '1' === $strip ) {
					$newtag = preg_replace( $search, $replace, $newtag );
				}
				switch ( $term_meta ) {
					case 1:
						$newtag = "#$tag";
						break;
					case 2:
						$newtag = "$$tag";
						break;
					case 3:
						$newtag = '';
						break;
					case 4:
						$newtag = $tag;
						break;
					case 5:
						$newtag = "@$tag";
						break;
					default:
						/**
						 * Change the default tag character when replacing tags in titles & descriptions. Default '#'.
						 *
						 * @hook wpt_tag_default
						 * @param {string} $char Character used to convert tags into hashtags.
						 * @param {int}    $t_id Term ID.
						 * @param {string} $context Flag indicating whether this is post content or a title.
						 *
						 * @return {string}
						 */
						$newtag = apply_filters( 'wpt_tag_default', '#', $t_id, $context ) . $tag;
				}
				if ( mb_strlen( $newtag ) > 2 ) {
					// replaces whole words only.
					$tag    = preg_replace( '/[\/]/', '', $tag ); // need to remove slashes.
					$string = preg_replace( '/\b' . $tag . '\b/i', $newtag, $tweet_text );
				}
			}
		}
	}

	return $string;
}

/**
 * Return a path relative to the XPoster Pro plugin regardless of calling location.
 *
 * @param string $filename The name of the file called.
 *
 * @return string
 */
function wpt_img_path( $filename ) {
	return plugins_url( 'images/' . $filename, __FILE__ );
}

add_action( 'split_shared_term', 'wpt_update_term_meta', 10, 4 );
/**
 * Ensure that newly edited split terms get same settings as old term.
 *
 * @param int $old_term_id Term ID for old term.
 * @param int $new_term_id Term ID for new term.
 * @param int $term_taxonomy_id Old Term Taxonomy.
 * @param int $taxonomy New Term Taxonomy.
 */
function wpt_update_term_meta( $old_term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
	$value = get_option( "wpt_taxonomy_$old_term_id" );
	add_option( "wpt_taxonomy_$new_term_id", $value );
	$value = get_option( "wpt_taxonomy_revive_$old_term_id" );
	add_option( "wpt_taxonomy_revive_$new_term_id", $value );
}

add_filter( 'wpt_schedule_retweet', 'wpt_blackout_period', 10, 4 );
/**
 * Manipulate time to avoid blackout periods.
 *
 * @param string            $time Timestamp.
 * @param mixed int/boolean $acct Account being sent to.
 * @param int               $i Retweet value.
 * @param array             $post_info Post data.
 *
 * @return new timestamp.
 */
function wpt_blackout_period( $time, $acct, $i, $post_info ) {
	$blackout = get_option( 'wpt_blackout' );
	if ( ! $blackout ) {
		return $time;
	}
	/**
	 * Filter blackout window based on accounts, reposts, and post information.
	 *
	 * @hook wpt_blackout_period
	 *
	 * @param {array} $blackout Array of parameters indicating from and to daily blackout times.
	 * @param {int|bool} $acct Account being posted to. User ID or false.
	 * @param {int}      $i Retweet value if this is being reposted.
	 * @param {array}    $post_info Array of post data.
	 *
	 * @return {array}
	 */
	$blackout = apply_filters( 'wpt_blackout_period', $blackout, $acct, $i, $post_info );
	$from     = $blackout['from'];
	$to       = $blackout['to'];

	if ( $from === $to ) {
		return $time;
	}
	$hour = date( 'G', current_time( 'timestamp' ) + $time ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested, WordPress.DateTime.RestrictedFunctions.date_date
	if ( $from < $to ) {
		$jump     = ( ( 24 - $from ) + $to ) - 24;
		$blackout = ( $hour > $from && $hour < $to ) ? true : false;
	} else {
		$jump     = ( ( 24 - $from ) + $to );
		$blackout = ( $hour > $from || $hour < $to ) ? true : false;
	}
	if ( $blackout ) {
		$time = $time + ( $jump * 60 * 60 );
	}

	return $time;
}

add_filter( 'wpt_insert_post', 'wpt_insert_post_values', 10, 2 );
/**
 * Save XPoster Pro meta values on post save
 *
 * @param array $post POST data.
 * @param int   $post_id Post ID.
 *
 * @return boolean Whether an update was performed.
 */
function wpt_insert_post_values( $post, $post_id ) {
	$update = false;
	if ( isset( $post['_wpt_delay_tweet'] ) && '' !== $post['_wpt_delay_tweet'] ) {
		$wpt_delay_tweet = (int) $post['_wpt_delay_tweet'];
		$update          = update_post_meta( $post_id, '_wpt_delay_tweet', $wpt_delay_tweet );
	}
	if ( isset( $post['_wpt_noautopost'] ) && 1 === (int) $post['_wpt_noautopost'] ) {
		$update = update_post_meta( $post_id, '_wpt_noautopost', 1 );
	} elseif ( isset( $post['_wpt_noautopost'] ) && 1 !== (int) $post['_wpt_noautopost'] || ! isset( $post['_wpt_noautopost'] ) ) {
		delete_post_meta( $post_id, '_wpt_noautopost' );
	}
	if ( isset( $post['_wpt_retweet_repeat'] ) && '' !== $post['_wpt_retweet_repeat'] ) {
		$wpt_retweet_repeat = (int) $post['_wpt_retweet_repeat'];
		$update             = update_post_meta( $post_id, '_wpt_retweet_repeat', $wpt_retweet_repeat );
	}
	if ( isset( $post['_wpt_retweet_after'] ) && '' !== $post['_wpt_retweet_after'] ) {
		$wpt_retweet_after = (float) $post['_wpt_retweet_after'];
		$update            = update_post_meta( $post_id, '_wpt_retweet_after', $wpt_retweet_after );
	}
	if ( isset( $post['_wpt_twitter_card'] ) && '' !== $post['_wpt_twitter_card'] ) {
		switch ( $post['_wpt_twitter_card'] ) {
			case 'photo':
			case 'summary_large_image':
				$wpt_twitter_card = 'summary_large_image';
				break;
			case 'player':
				$wpt_twitter_card = 'player';
				break;
			default:
				$wpt_twitter_card = 'summary';
		}
		$update = update_post_meta( $post_id, '_wpt_twitter_card', $wpt_twitter_card );
	}
	if ( isset( $post['_wpt_video_subtitle'] ) ) {
		$update = update_post_meta( $post_id, '_wpt_video_subtitle', $post['_wpt_video_subtitle'] );
	}
	if ( isset( $post['_wpt_video_ratio'] ) ) {
		$update = update_post_meta( $post_id, '_wpt_video_ratio', $post['_wpt_video_ratio'] );
	}
	if ( isset( $post['_wpt_video_source'] ) ) {
		$update = update_post_meta( $post_id, '_wpt_video_source', $post['_wpt_video_source'] );
	}
	if ( isset( $post['_wpt_cotweet'] ) && 'on' === $post['_wpt_cotweet'] ) {
		$update = update_post_meta( $post_id, '_wpt_cotweet', 1 );
	} else {
		delete_post_meta( $post_id, '_wpt_cotweet' );
	}
	if ( isset( $post['_wpt_image'] ) && 1 === (int) $post['_wpt_image'] ) {
		$update = update_post_meta( $post_id, '_wpt_image', 1 );
	} else {
		delete_post_meta( $post_id, '_wpt_image' );
	}
	if ( isset( $post['_wpt_custom_image'] ) ) {
		$update = update_post_meta( $post_id, '_wpt_custom_image', absint( $post['_wpt_custom_image'] ) );
	} else {
		delete_post_meta( $post_id, '_wpt_custom_image' );
	}
	if ( isset( $post['_wpt_authorized_users'] ) ) {
		$update = update_post_meta( $post_id, '_wpt_authorized_users', $post['_wpt_authorized_users'] );
	} else {
		delete_post_meta( $post_id, '_wpt_authorized_users' );
	}
	if ( isset( $post['_wpt_retweet_text'] ) ) {
		$update = update_post_meta( $post_id, '_wpt_retweet_text', $post['_wpt_retweet_text'] );
	} else {
		delete_post_meta( $post_id, '_wpt_retweet_text' );
	}
	if ( isset( $post['_wpt_retweet_delay'] ) ) {
		$update = update_post_meta( $post_id, '_wpt_retweet_delay', $post['_wpt_retweet_delay'] );
	} else {
		delete_post_meta( $post_id, '_wpt_retweet_delay' );
	}

	return $update;
}

/**
 * Insert coTweeting into My Calendar
 *
 * @return string
 */
function wpt_my_calendar_options() {
	$cotweet_enabled = get_option( 'wpt_cotweet' );
	$return          = '';
	if ( $cotweet_enabled ) {
		$return = '<input type="hidden" name="_wpt_cotweet" value="on" />';
	}

	return $return;
}
add_filter( 'mc_insert_custom_fields', 'wpt_my_calendar_options' );

/**
 * Setup custom post filters
 *
 * @return string
 */
function wpt_setup_filters() {
	$filters   = get_option( 'wpt_filters' );
	$available = array(
		'postTitle'   => __( 'Post Title', 'wp-tweets-pro' ),
		'postContent' => __( 'Post Content', 'wp-tweets-pro' ),
		'postLink'    => __( 'Permalink', 'wp-tweets-pro' ),
		'shortUrl'    => __( 'Shortened URL', 'wp-tweets-pro' ),
		'postStatus'  => __( 'Post Status', 'wp-tweets-pro' ),
		'postType'    => __( 'Post Type', 'wp-tweets-pro' ),
		'id'          => __( 'Post ID', 'wp-tweets-pro' ),
		'authId'      => __( 'Author ID', 'wp-tweets-pro' ),
		'postExcerpt' => __( 'Post Excerpt', 'wp-tweets-pro' ),
	);
	$return    = "<table class='widefat fixed'>
		<thead>
			<tr>
				<th scope='col' id='wpt_filter_field'>" . __( 'Filter field', 'wp-tweets-pro' ) . "</th>
				<th scope='col' id='wpt_filter_type'>" . __( 'Filter type', 'wp-tweets-pro' ) . "</th>
				<th scope='col' id='wpt_filter_value'>" . __( 'Filter value', 'wp-tweets-pro' ) . "</th>
				<th scope='col' id='wpt_filter_delete'>" . __( 'Delete filter', 'wp-tweets-pro' ) . '</th>
			</tr>
		</thead>
		<tbody>';
	$key       = 0;
	if ( is_array( $filters ) ) {
		foreach ( $filters as $key => $value ) {
			$key     = absint( $key );
			$return .= "
			<tr><td>
			<select name='wpt_filters[ $key ][field]' aria-labelledby='wpt_filter_field'>";
			foreach ( $available as $k => $v ) {
				if ( $k === $value['field'] ) {
					$selected = ' selected="selected"';
				} else {
					$selected = '';
				}
				$return .= "<option value='$k'$selected>$v</option>";
			}
			$return .= "</select></td>
			<td><select name='wpt_filters[ $key ][type]' aria-labelledby='wpt_filter_type'>
				<option value='equals'" . ( ( 'equals' === $value['type'] ) ? ' selected="selected"' : '' ) . ">is equal to</option>
				<option value='notin'" . ( ( 'notin' === $value['type'] ) ? ' selected="selected"' : '' ) . ">does not contain</option>
				<option value='in'" . ( ( 'in' === $value['type'] ) ? ' selected="selected"' : '' ) . ">contains</option>
				<option value='notequals'" . ( ( 'notequals' === $value['type'] ) ? ' selected="selected"' : '' ) . ">is not equal to</option>
			</select></td>
			<td><input type='text' aria-labelledby='wpt_filter_value' name='wpt_filters[ $key ][value]' value='$value[value]' /></td>
			<td><input type='checkbox' aria-labelledby='wpt_filter_delete' name='wpt_filters[ $key ][delete]' value='on' /></td>
			</tr>";
		}
	}
	$key     = $key + 1;
	$return .= "
	<tr>
	<td><select name='wpt_filters[ $key ][field]' aria-labelledby='wpt_filter_field'>
		<option value='0'> -- </option>";
	foreach ( $available as $k => $v ) {
		$return .= "<option value='$k'>$v</option>";
	}
	$return .= "</select></td>
	<td><select name='wpt_filters[ $key ][type]' aria-labelledby='wpt_filter_type'>
		<option value='0'> -- </option>
		<option value='equals'>is equal to</option>
		<option value='notin'>does not contain</option>
		<option value='in'>contains</option>
		<option value='notequals'>is not equal to</option>
	</select></td>
	<td><input type='text' aria-labelledby='wpt_filter_value' name='wpt_filters[ $key ][value]' value='' /></td>
	</tr></tbody></table>";

	return $return;
}

/**
 * Save custom post filters
 */
function wpt_build_filters() {
	$filters = get_option( 'wpt_filters' );
	if ( ! is_array( $filters ) ) {
		$filters = array();
	}
	if ( isset( $_POST['wpt_filters'] ) ) {
		foreach ( $_POST['wpt_filters'] as $key => $value ) {
			if ( isset( $value['delete'] ) && 'on' === $value['delete'] ) {
				unset( $filters[ $key ] );
				continue;
			}
			if ( ! in_array( $value['type'], array( 'in', 'notin', 'equals', 'notequals' ), true ) ) {
				continue;
			}
			$filters[ $key ] = $value;
		}
	}

	update_option( 'wpt_filters', $filters );
}

/**
 * Apply custom post filters
 *
 * @param bool  $filter Should the current post be filtered.
 * @param array $post_info Array of Post data.
 *
 * @return boolean true: Tweet this; false: don't.
 */
function wpt_filter_post_info( $filter, $post_info ) {
	$filters = get_option( 'wpt_filters' );
	if ( is_array( $filters ) ) {
		foreach ( $filters as $filter => $rule ) {
			$comparison = $rule['type'];
			switch ( $comparison ) {
				case 'equals':
					if ( $post_info[ $rule['field'] ] === $rule['value'] ) {
						return true;
					}
					break;
				case 'notin':
					if ( false === strpos( $post_info[ $rule['field'] ], $rule['value'] ) ) {
						return true;
					}
					break;
				case 'in':
					if ( false !== strpos( $post_info[ $rule['field'] ], $rule['value'] ) ) {
						return true;
					}
					break;
				case 'notequals':
					if ( $post_info[ $rule['field'] ] !== $rule['value'] ) {
						return true;
					}
					break;
				default:
					return true;
			}
		}
		return false;
	}
	return $filter;
}
add_filter( 'wpt_should_block_status', 'wpt_filter_post_info', 10, 2 );

/**
 * Process shortcodes inside a Tweet.
 *
 * @param string $tweet Tweet text.
 * @param int    $post_ID Post ID.
 *
 * @return string New tweet text.
 */
function wpt_process_shortcodes( $tweet, $post_ID ) {
	/**
	 * Filter Tweet text prior to processing WordPress shortcodes.
	 *
	 * @hook wpt_process_shortcodes
	 * @param {string} $tweet Text of Tweet.
	 * @param {int}    $post_ID Post ID.
	 *
	 * @return {string}
	*/
	$tweet = apply_filters( 'wpt_process_shortcodes', $tweet, $post_ID );

	return do_shortcode( $tweet );
}
add_filter( 'wpt_tweet_sentence', 'wpt_process_shortcodes', 10, 2 );

/**
 * Handle recurring Tweets.
 *
 * @param int    $auth Author ID.
 * @param string $sentence Tweet text.
 * @param int    $rt repost count.
 * @param int    $post_id post ID.
 */
function wpt_recurring_tweet_handler( $auth, $sentence, $rt, $post_id ) {
	wpt_mail( "Recurring Tweet Happening: #$post_id", "$sentence, $rt, $post_id", $post_id ); // DEBUG.

	// set up sentence.
	$post_info = wpt_post_info( $post_id );
	$sentence  = jd_truncate_tweet( $sentence, $post_info, $post_id, false, $auth );

	// set up media.
	$media = ( ( '1' === get_option( 'wpt_media' ) ) && ( has_post_thumbnail( $post_id ) || wpt_post_attachment( $post_id ) ) ) ? true : false;
	/**
	 * Customize whether media should be uploaded for the current Tweet action.
	 *
	 * @hook wpt_scheduled_media
	 *
	 * @param {bool} $media True to post media; false to not.
	 * @param {int}  $post_id Post ID.
	 * @param {int}  $rt Which time this is being reposted, if a repost.
	 *
	 * @return {bool}
	 */
	$media = apply_filters( 'wpt_scheduled_media', $media, $post_id, $rt ); // filter based on post ID.

	// send Tweet.
	wpt_post_to_service( $sentence, $auth, $post_id, $media );
}
add_action( 'wpt_recurring_tweets', 'wpt_recurring_tweet_handler', 10, 4 );

add_filter( 'wpt_post_info', 'wpt_insert_post_info', 10, 2 );
/**
 * Add XPoster Pro post meta values into post_info array
 *
 * @param array $values Existing values.
 * @param int   $post_ID Post ID.
 *
 * @return array New values.
 */
function wpt_insert_post_info( $values, $post_ID ) {
	if ( is_array( $values ) ) {
		$delay       = ( isset( $_POST['_wpt_delay_tweet'] ) && is_numeric( $_POST['_wpt_delay_tweet'] ) ) ? $_POST['_wpt_delay_tweet'] : get_post_meta( $post_ID, '_wpt_delay_tweet', true );
		$after       = ( isset( $_POST['_wpt_retweet_after'] ) && is_numeric( $_POST['_wpt_retweet_after'] ) ) ? $_POST['_wpt_retweet_after'] : get_post_meta( $post_ID, '_wpt_retweet_after', true );
		$auth_repeat = ( '' !== get_user_meta( $values['authId'], 'wpt_retweet_repeat', true ) ) ? get_user_meta( $values['authId'], 'wpt_retweet_repeat', true ) : false;
		$repeat      = ( isset( $_POST['_wpt_retweet_repeat'] ) && is_numeric( $_POST['_wpt_retweet_repeat'] ) ) ? $_POST['_wpt_retweet_repeat'] : get_post_meta( $post_ID, '_wpt_retweet_repeat', true );

		$no_delay             = ( isset( $_POST['wpt-no-delay'] ) ) ? 'on' : false;
		$no_repost            = ( isset( $_POST['wpt-no-repost'] ) ) ? 'on' : false;
		$image                = ( isset( $_POST['_wpt_image'] ) && 1 === (int) $_POST['_wpt_image'] ) ? 1 : false;
		$cotweet              = ( isset( $_POST['wpt_cotweet'] ) ) ? 1 : get_post_meta( $post_ID, '_wpt_cotweet', true );
		$wpt_authorized_users = ( isset( $_POST['_wpt_authorized_users'] ) ) ? $_POST['_wpt_authorized_users'] : array();

		$values['wpt_cotweet']          = $cotweet;
		$values['wpt_authorized_users'] = $wpt_authorized_users;
		$values['wpt_no_delay']         = $no_delay;
		$values['wpt_image']            = $image;
		$values['wpt_no_repost']        = $no_repost;
		$values['wpt_delay_tweet']      = ( '' !== $delay ) ? (int) $delay : get_option( 'wpt_delay_tweets' );
		$values['wpt_retweet_after']    = ( '' !== $after ) ? (float) $after : get_option( 'wpt_retweet_after' );
		$values['wpt_retweet_repeat']   = ( '' !== $repeat ) ? (int) $repeat : get_option( 'wpt_retweet_repeat' );
	}

	return $values;
}

add_filter( 'wpt_allow_reposts', 'wpt_test_user_reposts', 10, 4 );
/**
 * Test how many times this user is allowed to repost.
 *
 * @param boolean $should_continue True = allowed to continue.
 * @param int     $rt Number of retweets so far.
 * @param int     $post_ID Post ID of current post.
 * @param int     $auth_id ID of current user.
 *
 * @return boolean Allowed to continue.
 */
function wpt_test_user_reposts( $should_continue, $rt, $post_ID, $auth_id ) {
	if ( $auth_id ) {
		$auth_value  = get_user_meta( $auth_id, 'wpt_retweet_repeat', true );
		$auth_repeat = ( '' !== $auth_value ) ? $auth_value : false;
		// if author has a defined repost value & this retweet # is higher than their value, cancel it.
		if ( $auth_repeat && ( $auth_repeat > $rt ) ) {
			return false;
		}
	}

	return $should_continue;
}


/**
 * Notify users who have disabled or uninstalled XPoster
 */
function wpt_warning() {
	echo "<div class='notice error'><p>" . __( '<strong>XPoster Pro</strong> requires that the current version of XPoster is also activated. Please re-activate or update XPoster! Thank you!', 'wp-tweets-pro' ) . '</p></div>';
}

/**
 * Add Twitter 3-legged authentication to user account
 *
 * Need to update to latest TwitterOAuth to do this.

add_filter( 'wpt_twitter_user_fields', 'wpt_twitter_oauth3' );
function wpt_twitter_oauth3() {
	// Build TwitterOAuth object with client credentials.
	$current_user = wp_get_current_user();
	$user_edit = ( isset( $_GET['user_id'] ) ) ? (int) $_GET['user_id'] : $current_user->ID;

	$ack = get_option( 'app_consumer_key' );
	$acs = get_option( 'app_consumer_secret' );
	$connection = new Wpt_TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);

	// Get temporary credentials.
	$request_token = $connection->oauth( 'oauth/request_token', array( 'oauth_callback' => home_url() ) );

	print_r($request_token);
}
 */

/**
 * Filter Tweet template to check for any term-specific template.
 * Term-specific templates are implemented before other changes.
 *
 * @param string $tweet Current tweet text.
 * @param int    $post_ID Current post ID.
 *
 * @return string New tweet.
 */
function wpt_taxonomy_template( $tweet, $post_ID ) {
	$taxonomies = get_post_taxonomies( $post_ID );
	foreach ( $taxonomies as $tax ) {
		$terms = get_the_terms( $post_ID, $tax );
		if ( is_array( $terms ) ) {
			foreach ( $terms as $term ) {
				$template = get_term_meta( $term->term_id, '_wpt_term_template', true );
				if ( '' !== $template ) {
					/**
					 * Filter the Tweet template for Tweets in a specific term.
					 *
					 * @hook wpt_term_template_filter
					 *
					 * @param {string} $template The template to use to generate Tweets.
					 * @param {int}  $term_id Term ID.
					 *
					 * @return {string}
					 */
					return apply_filters( 'wpt_term_template_filter', $template, $term->term_id );
				}
			}
		}
	}

	return $tweet;
}
add_filter( 'wpt_tweet_sentence', 'wpt_taxonomy_template', 9, 2 );

/**
 * Add Twitter user settings to user account profile.
 *
 * @return string
 */
function wpt_twitter_user_fields() {
	$current_user = wp_get_current_user();
	$edit_id      = ( isset( $_GET['user_id'] ) ) ? (int) $_GET['user_id'] : $current_user->ID;

	$templates   = get_user_meta( $edit_id, 'wpt_templates', true );
	$reposts     = get_user_meta( $edit_id, 'wpt_retweet_repeat', true );
	$edit        = ( isset( $templates['edit'] ) ) ? $templates['edit'] : '';
	$new         = ( isset( $templates['new'] ) ) ? $templates['new'] : '';
	$num_reposts = ( '' === $reposts ) ? get_option( 'wpt_retweet_repeat', '' ) : $reposts;

	return sprintf(
		"<tr><th scope='row'><label for='wpt_new'>" . __( 'Tweet Template for new posts:', 'wp-tweets-pro' ) . '</label></th><td><input type="text" class="regular-text" name="wpt_templates[new]" id="wpt_new" value="%1$s" /></td></tr>' . "
		<tr><th scope='row'><label for='wpt_edit'>" . __( 'Tweet Template for edited posts:', 'wp-tweets-pro' ) . '</label></th><td><input type="text" class="regular-text" name="wpt_templates[edit]" id="wpt_edit" value="%2$s" /></td></tr>
		<tr><th scope="row"><label for="wpt_retweet_repeat">' . __( 'Number of reposts', 'wp-tweets-pro' ) . '</label></th><td><select id="wpt_retweet_repeat" name="wpt_retweet_repeat">
			<option value="">' . __( 'Default', 'wp-tweets-pro' ) . '</option>
			<option value="0"' . selected( $num_reposts, 0, false ) . '>0</option>
			<option value="1"' . selected( $num_reposts, 1, false ) . '>1</option>
			<option value="2"' . selected( $num_reposts, 2, false ) . '>2</option>
			<option value="3"' . selected( $num_reposts, 3, false ) . '>3</option>
		</select></td></tr>',
		$new,
		$edit
	);
}
add_filter( 'wpt_twitter_user_fields', 'wpt_twitter_user_fields' );

/**
 * Filter Tweet to use current user's defined template.
 *
 * @param string  $text Current text.
 * @param string  $status Current publication status.
 * @param boolean $alt Use alternate.
 * @param int     $auth Current author.
 *
 * @return string new text.
 */
function wpt_filter_user_text( $text, $status, $alt = false, $auth = false ) {
	global $current_user;
	if ( '' !== $text && ! $alt ) {
		return $text;
	}
	$auth      = ( ! $auth ) ? $current_user->ID : intval( $auth );
	$user_text = get_user_meta( $auth, 'wpt_templates', true );
	if ( 'publish' !== $status ) {
		if ( isset( $user_text['new'] ) && '' !== trim( $user_text['new'] ) ) {
			$text = stripcslashes( $user_text['new'] );
		}
	} else {
		if ( isset( $user_text['edit'] ) && '' !== trim( $user_text['edit'] ) ) {
			$text = stripcslashes( $user_text['edit'] );
		}
	}

	return $text;
}
add_filter( 'wpt_user_text', 'wpt_filter_user_text', 10, 3 );

/**
 * Handle scheduled Tweets
 *
 * @param int    $id Author ID.
 * @param string $sentence Tweet text.
 * @param int    $rt repost count.
 * @param int    $post_id post ID.
 */
function wpt_schedule_tweet( $id, $sentence, $rt, $post_id ) {
	wpt_mail( "Scheduled Action Happening: #$id", "$sentence, $rt, $post_id", $post_id ); // DEBUG.
	// check whether the last autopost Tweet was the same as this one.
	$last_autopost_tweet = get_option( 'wpt_last_autopost_tweet' );

	/**
	 * Render the template of a scheduled Tweet only at the time it's sent.
	 *
	 * @hook wpt_postpone_rendering
	 * @param {bool} $postpone True to postpone rendering.
	 *
	 * @return {bool}
	 */
	$postpone_rendering = apply_filters( 'wpt_postpone_rendering', get_option( 'wpt_postpone_rendering', 'false' ) );
	if ( 'false' !== $postpone_rendering ) {
		$post_info = wpt_post_info( $post_id );
		$sentence  = jd_truncate_tweet( $sentence, $post_info, $post_id );
		wpt_mail( "Postponed Tweet Rendering: #$id", "$sentence, $rt, $post_id", $post_id ); // DEBUG.
	}
	if ( $sentence === $last_autopost_tweet ) {
		// If this Tweet is the same as the last autoposted Tweet, do not send it.
		// Prevents runaway cron jobs. Possibly duplicates existing check, but earlier.
		die;
	}
	$media = ( ( '1' === get_option( 'wpt_media' ) ) && ( has_post_thumbnail( $post_id ) || wpt_post_attachment( $post_id ) ) ) ? true : false;
	/**
	 * Customize whether media should be uploaded for the current Tweet action.
	 *
	 * @hook wpt_scheduled_media
	 *
	 * @param {bool} $media True to post media; false to not.
	 * @param {int}  $post_id Post ID.
	 * @param {int}  $rt Which time this is being reposted, if a repost.
	 *
	 * @return {bool}
	 */
	$media = apply_filters( 'wpt_scheduled_media', $media, $post_id, $rt ); // filter based on post ID.
	// generate hash of this Tweet's data.
	$attachment = wpt_post_attachment( $post_id );
	$hash       = md5( "$sentence, $id, $post_id, $media, $attachment" );
	// check whether this exact Tweet has already occurred.
	$action = wpt_check_action( $hash );
	if ( ! $action ) {
		wpt_post_to_service( $sentence, $id, $post_id, $media );
		wpt_register_action( $hash );
	}
}
add_action( 'wpt_schedule_tweet_action', 'wpt_schedule_tweet', 10, 4 );

/**
 * Filter upload to send custom attachment to Twitter.
 *
 * @param integer $attachment Attachment to send.
 * @param integer $post_ID Post ID.
 *
 * @return integer
 */
function wpt_custom_attachment( $attachment, $post_ID ) {
	$custom_image = get_post_meta( $post_ID, '_wpt_custom_image', true );
	if ( $custom_image ) {
		return $custom_image;
	}

	return $attachment;
}
add_filter( 'wpt_post_attachment', 'wpt_custom_attachment', 10, 2 );

/**
 * Get stored options of last 100 scheduled Tweets and check against it. This is protection against run away cron jobs.
 *
 * @param string $hash hash of Tweet text, author, post ID, and media configuration.
 *
 * @return boolean true if found
 */
function wpt_check_action( $hash ) {
	$stored = get_option( 'wpt_scheduled_tweets' );
	if ( ! is_array( $stored ) ) {
		// If nothing is stored, no Tweet will be found.
		return false;
	}
	$check = ( in_array( $hash, $stored, true ) ) ? true : false;

	return $check;
}

/**
 * Store hash of last scheduled Tweet.
 *
 * @param string $hash hash of Tweet text, author, post ID, and media configuration.
 */
function wpt_register_action( $hash ) {
	$stored = get_option( 'wpt_scheduled_tweets' );
	if ( is_array( $stored ) ) {
		// trim array to 99 items; removed oldest, add to end.
		$stored   = array_slice( $stored, 1, 99 );
		$stored[] = $hash;
	} else {
		$stored = array( $hash );
	}

	update_option( 'wpt_scheduled_tweets', $stored );
}

add_filter( 'wpt_scheduled_media', 'wpt_filter_scheduled_media', 10, 3 );
/**
 * Handle individual repost's media settings
 *
 * @param boolean $media Whether to attach media to post.
 * @param int     $post_ID Current post ID.
 * @param int     $rt Current retweet value.
 *
 * @return boolean Whether to attach media.
 */
function wpt_filter_scheduled_media( $media, $post_ID, $rt ) {
	switch ( $rt ) {
		case 1:
			$rt1    = get_option( 'wpt_rt_media' );
			$return = ( 'true' === $rt1 ) ? false : $media;
			break;
		case 2:
			$rt2    = get_option( 'wpt_rt_media2' );
			$return = ( 'true' === $rt2 ) ? false : $media;
			break;
		case 3:
			$rt3    = get_option( 'wpt_rt_media3' );
			$return = ( 'true' === $rt3 ) ? false : $media;
			break;
		default:
			$return = $media;
	}
	return $return;
}

add_filter( 'wpt_upload_media', 'wpt_filter_upload_media', 10, 2 );
/**
 * If this post is configured to skip media, skip media.
 *
 * @param boolean $media Whether to attach media.
 * @param int     $post_ID Post ID.
 *
 * @return boolean
 */
function wpt_filter_upload_media( $media, $post_ID ) {
	$skip = get_post_meta( $post_ID, '_wpt_image', true );
	if ( 1 === (int) $skip ) {
		return false;
	}
	return $media;
}

add_filter( 'wpt_custom_retweet_fields', 'wpt_retweet_custom_tweets', 10, 2 );
/**
 * Setup individual fields for each custom Tweet text field.
 *
 * @param string $output HTML output of fields.
 * @param int    $post_ID Post ID.
 *
 * @return boolean
 */
function wpt_retweet_custom_tweets( $output, $post_ID = false ) {
	$repeat        = get_post_meta( $post_ID, '_wpt_retweet_repeat', true );
	$repeat        = ( $repeat ) ? $repeat : get_option( 'wpt_retweet_repeat' );
	$custom_tweets = ( $post_ID ) ? get_post_meta( $post_ID, '_wpt_retweet_text', true ) : false;
	$custom_times  = ( $post_ID ) ? get_post_meta( $post_ID, '_wpt_retweet_delay', true ) : false;
	if ( $repeat > 0 ) {
		$output = "<p class='panel-toggle'><a href='#wpt_custom_retweets' class='tweet-toggle'><span class='dashicons dashicons-plus' aria-hidden='true'></span>" . __( 'Add custom retweets', 'wp-tweets-pro' ) . "</a></p><div class='expandable' id='wpt_custom_retweets'>";
		for ( $i = 0; $i < $repeat; $i++ ) {
			$n = $i + 1;
			if ( $custom_tweets && ! empty( $custom_tweets ) ) {
				$tweet = ( isset( $custom_tweets[ $i ] ) ) ? $custom_tweets[ $i ] : '';
			} else {
				if ( 'prefix' === get_option( 'wpt_custom_type' ) ) {
					$tweet = '';
				} else {
					$x     = ( 1 === $n ) ? '' : $n;
					$tweet = get_option( "wpt_prepend_rt$x" );
				}
			}
			if ( $custom_times && ! empty( $custom_times ) ) {
				$time = ( isset( $custom_times['time'][ $i ] ) ) ? $custom_times['time'][ $i ] : '';
				$date = ( isset( $custom_times['date'][ $i ] ) ) ? $custom_times['date'][ $i ] : '';
			} else {
				$time = '';
				$date = '';
			}
			// Translators: retweet number.
			$output .= '<fieldset><legend>' . sprintf( __( 'Retweet %d', 'wp-tweets-pro' ), $n ) . "</legend><p class='jtw'><label for='wpt_retweet_$i'>" . sprintf( __( 'Custom Tweet', 'wp-tweets-pro' ), $n ) . "</label> <textarea class='wpt_tweet_box' name='_wpt_retweet_text[]' id='wpt_retweet_$i'>" . esc_attr( stripslashes( $tweet ) ) . '</textarea></p>';
			// Translators: retweet number.
			$output .= "<p class='jtw2'><label for='wpt_retweet_delay_date_$i'>" . sprintf( __( 'Date (%d)', 'wp-tweets-pro' ), $n ) . "</label> <input type='text' class='wpt_date wpt_delay_time' name='_wpt_retweet_delay[date][]' id='wpt_retweet_delay_date_$i' value='" . esc_attr( $date ) . "'><br />";
			// Translators: retweet number.
			$output .= "<label for='wpt_retweet_delay_time_$i'>" . sprintf( __( 'Time (%d)', 'wp-tweets-pro' ), $n ) . "</label> <input type='text' class='wpt_time wpt_delay_time' name='_wpt_retweet_delay[time][]' id='wpt_retweet_delay_time_$i' value='" . esc_attr( $time ) . "'></p></fieldset>";
		}
		$output .= '</div>';
	}

	return $output;
}

/**
 * Form to input XPoster Pro settings in XPoster meta box
 *
 * @param int    $post_id Post ID.
 * @param string $display Controls or hidden inputs.
 */
function wpt_schedule_values( $post_id, $display = 'normal' ) {
	$delay   = get_post_meta( $post_id, '_wpt_delay_tweet', true );
	$retweet = get_post_meta( $post_id, '_wpt_retweet_after', true );
	// this looks awkward, but it makes sense, really.
	$cotweet    = get_post_meta( $post_id, '_wpt_cotweet', true );
	$cotweet    = ( $cotweet ) ? true : get_option( 'wpt_cotweet' );
	$cotweet    = ( $cotweet ) ? true : false;
	$repeat     = ( false === (bool) get_post_meta( $post_id, '_wpt_retweet_repeat', true ) ) ? get_option( 'wpt_retweet_repeat' ) : get_post_meta( $post_id, '_wpt_retweet_repeat', true );
	$upload     = ( 1 === (int) get_post_meta( $post_id, '_wpt_image', true ) ) ? 'no' : 'yes';
	$wpt_images = ( 1 === (int) get_option( 'wpt_media' ) ) ? 'yes' : 'no';
	$noautopost = get_post_meta( $post_id, '_wpt_noautopost', true );

	if ( 'hidden' === $display ) {
		?>
		<input type='hidden' name='_wpt_cotweet' value='<?php echo ( $cotweet ) ? 'on' : ''; ?>' />
		<input type='hidden' name='_wpt_delay_tweet' value='<?php echo ( $delay ) ? $delay : get_option( 'wpt_delay_tweets' ); ?>' />
		<input type='hidden' name='_wpt_retweet_after' value='<?php echo ( $retweet ) ? $retweet : get_option( 'wpt_retweet_after' ); ?>' />
		<input type='hidden' name='_wpt_retweet_repeat' value='<?php echo ( $repeat ) ? $repeat : get_option( 'wpt_retweet_repeat' ); ?>' />
		<input type='hidden' name='_wpt_noautopost' value='<?php echo $noautopost; ?>' />
		<?php
	} else {
		?>
		<h3><?php _e( 'Reposting Rules', 'wp-tweets-pro' ); ?></h3>
		<p>
		<label for="wtd"><?php _e( 'Delay posting (in minutes)', 'wp-tweets-pro' ); ?></label><br /><input type="text" name="_wpt_delay_tweet" size="3" value="<?php echo ( false !== (bool) $delay ) ? $delay : get_option( 'wpt_delay_tweets' ); ?>" id="wtd" /> <input type='checkbox' value='on' name='wpt-no-delay' id='wpt-no-delay' /> <label for='wpt-no-delay'><?php _e( 'No delay', 'wp-tweets-pro' ); ?></label>
		</p>
		<p>
		<label for="wtr"><?php _e( 'Repost after (hours)', 'wp-tweets-pro' ); ?></label><br /><input type="text" name="_wpt_retweet_after" size="3" value="<?php echo ( false !== (bool) $retweet ) ? $retweet : get_option( 'wpt_retweet_after' ); ?>" id="wtr" /> <input type='checkbox' value='on' name='wpt-no-repost' id='wpt-no-repost' /> <label for='wpt-no-repost'><?php _e( 'No repost', 'wp-tweets-pro' ); ?></label>
		</p>
		<?php
		if ( 1 === (int) get_option( 'jd_individual_twitter_users' ) && wpt_get_authorized_users() ) {
			?>
			<p>
			<?php
			$checked = ( $cotweet ) ? ' checked="checked"' : '';
			?>
			<input type='checkbox' value='on' name='_wpt_cotweet' id='wpt_cotweet'<?php echo $checked; ?> /> <label for='wpt_cotweet'><?php _e( 'Co-tweet to site Twitter account', 'wp-tweets-pro' ); ?></label>
			</p>
			<?php
		}
		?>
		<p>
		<label for="wrr"><?php _e( 'Number of reposts', 'wp-tweets-pro' ); ?></label>
			<select name="_wpt_retweet_repeat" id="wrr">
		<?php
		/**
		 * Adjust the values available to choose for setting the number of times a Tweet can be reposted. Default `4`.
		 *
		 * @hook wpt_tweet_repeat_count
		 *
		 * @param {int} $count Maximum number of times a Tweet can be reposted.
		 *
		 * @return {int}
		 */
		$retweet_repeat_count = apply_filters( 'wpt_tweet_repeat_count', 4 );
		for ( $i = 0; $i < $retweet_repeat_count; $i++ ) {
			print( '<option value="' . $i . '"' . selected( $repeat, $i, false ) . '>' . $i . ' </option>' );
		}
		?>
			</select>
		</p>
		<?php
		if ( '' !== get_option( 'wpt_schedule' ) ) {
			?>
		<p>
		<input type='checkbox' value='1' id='wpt_noautopost' name='_wpt_noautopost'<?php checked( $noautopost, 1 ); ?> /> <label for='wpt_noautopost'><?php _e( 'Omit from autoposting', 'wp-tweets-pro' ); ?></label>
		</p>
			<?php
		}
		$cards               = ( 1 === (int) get_option( 'wpt_twitter_card' ) || 1 === (int) get_option( 'wpt_og_card' ) ) ? true : false;
		$images              = ( 1 === (int) get_option( 'wpt_media' ) ) ? true : false;
		$player_card_enabled = get_option( 'wpt_player_card', '0' );
		$selector            = ( 1 === (int) get_option( 'wpt_media' ) || '1' === $player_card_enabled ) ? true : false;
		if ( $cards || $images || $selector ) {
			?>
			<h3><?php _e( 'Media Settings', 'wp-tweets-pro' ); ?></h3>
			<?php
			if ( $cards ) {
				$card      = ( '' !== get_post_meta( $post_id, '_wpt_twitter_card', true ) ) ? get_post_meta( $post_id, '_wpt_twitter_card', true ) : get_option( 'wpt_twitter_card_type' );
				$video_url = ( '' !== get_post_meta( $post_id, '_wpt_video_source', true ) ) ? get_post_meta( $post_id, '_wpt_video_source', true ) : '';
				$subtitle  = ( '' !== get_post_meta( $post_id, '_wpt_video_subtitle', true ) ) ? get_post_meta( $post_id, '_wpt_video_subtitle', true ) : '';
				$ratio     = ( '' !== get_post_meta( $post_id, '_wpt_video_ratio', true ) ) ? get_post_meta( $post_id, '_wpt_video_ratio', true ) : '';
				?>
				<p>
				<label for='wpt_twitter_card'><?php _e( 'Preview Card', 'wp-tweets-pro' ); ?></label>
				<select name='_wpt_twitter_card' id='wpt_twitter_card' />
					<option value='summary'<?php selected( $card, 'summary' ); ?>><?php _e( 'Summary', 'wp-tweets-pro' ); ?></option>
					<option value='summary_large_image'<?php selected( $card, 'summary_large_image' ); ?>><?php _e( 'Summary, Large Image', 'wp-tweets-pro' ); ?></option>
					<option value='player'<?php selected( $card, 'player' ); ?>><?php _e( 'Player', 'wp-tweets-pro' ); ?></option>
				</select>
				</p>
				<?php
				if ( '1' === $player_card_enabled ) {
					?>
			<div class="wpt-player-card-settings">
				<p id="wpt_player_instructions">
					<?php
					_e( 'Add links to Vimeo, YouTube, or upload <code>.mp4</code> videos. Caption file only used with uploaded videos.', 'wp-tweets-pro' );
					$test_url = wpt_get_player_video( $post_id );
					if ( $test_url ) {
						echo '<p class="wpt-test"><a href="' . esc_url( add_query_arg( 'test', 'true', $test_url ) ) . '">' . __( 'Check your video embed', 'wp-tweets-pro' ) . '</a></p>';
					}
					?>
				</p>
				<div>
					<label for="wpt_video_source"><?php _e( 'Video URL (.mp4, YouTube, Vimeo)', 'wp-tweets-pro' ); ?></label>
					<div class='wpt-wrap'>
						<input type="url" name="_wpt_video_source" id="wpt_video_source" placeholder="e.g. https://vimeo.com/video_ID" aria-describedby="wpt_player_instructions" value="<?php echo esc_url( $video_url ); ?>" /> <button class="button-secondary" type="button" id="wpt_video_select"><span class="dashicons dashicons-upload" aria-hidden="true"></span><span class="screen-reader-text"><?php _e( 'Upload or Select', 'wp-tweets-pro' ); ?></span></button>
					</div>
				</div>
				<div>
					<label for="wpt_video_subtitle"><?php _e( 'Captions URL (.vtt)', 'wp-tweets-pro' ); ?></label>
					<div class='wpt-wrap'>
						<input type="url" name="_wpt_video_subtitle" id="wpt_video_subtitle" placeholder="e.g. <?php echo home_url(); ?>/captions.vtt" value="<?php echo esc_url( $subtitle ); ?>" /> <button class="button-secondary" type="button" id="wpt_caption_select"><span class="dashicons dashicons-upload" aria-hidden="true"></span><span class="screen-reader-text"><?php _e( 'Upload or Select', 'wp-tweets-pro' ); ?></span></button>
					</div>
				</div>
				<p>
					<label for="wpt_video_ratio"><?php _e( 'Video aspect ratio', 'wp-tweets-pro' ); ?></label>
					<select name="_wpt_video_ratio" id="wpt_video_ratio">
						<option value='16:9'<?php selected( $ratio, '16:9' ); ?>>16:9 (<?php _e( 'Standard TV, common', 'wp-tweets-pro' ); ?>)</option>
						<option value='4:3'<?php selected( $ratio, '4:3' ); ?>>4:3 (<?php _e( 'Classic TV/film', 'wp-tweets-pro' ); ?>)</option>
						<option value='1.85'<?php selected( $ratio, '1.85' ); ?>>1.85 (<?php _e( 'Cinema/widescreen', 'wp-tweets-pro' ); ?>)</option>
						<option value='2.39'<?php selected( $ratio, '2.39' ); ?>>2.39 (<?php _e( 'Cinema/anamorphic', 'wp-tweets-pro' ); ?>)</option>
					</select>
				</p>
			</div>
					<?php
				}
			}
			$checked      = ( 'no' === $upload && 'no' === $wpt_images ) ? 'no' : $upload;
			$checked      = ( 'yes' !== $checked && 'no' !== $checked ) ? 'no' : $checked;
			$custom_image = get_post_meta( $post_id, '_wpt_custom_image', true );
			$alt          = ( $custom_image ) ? get_post_meta( $custom_image, '_wp_attachment_image_alt', true ) : '';
			$image_html   = ( $custom_image ) ? wp_get_attachment_image( $custom_image, 'medium', false, array( 'alt' => $alt ) ) : '';
			if ( $images ) {
				/**
				 * Set the default state of the upload image toggle input when setting Tweet status. Default depends on post meta data.
				 *
				 * @hook wpt_default_upload_image
				 *
				 * @param {string} $checked 'No' to not upload; 'yes' to upload.
				 * @param {string} $upload The setting for this post.
				 *
				 * @return {string}
				 */
				$checked = apply_filters( 'wpt_default_upload_image', $checked, $upload );
				?>
				<p class='toggle-btn-group'>
					<input type='radio' name='_wpt_image' id='wpt_image_no' value='1'<?php checked( $checked, 'no' ); ?> /> <label for='wpt_image_no'><?php _e( 'No upload', 'wp-tweets-pro' ); ?></label>
					<input type='radio' name='_wpt_image' id='wpt_image_yes' value='0'<?php checked( $checked, 'yes' ); ?> /> <label for='wpt_image_yes'><?php _e( 'Upload image', 'wp-tweets-pro' ); ?></label>
				</p>
				<?php
			}
			if ( $selector ) {
				?>
			<div class='wpt_custom_image field-holder'>
				<div id='wpt_selected_image'><?php echo $image_html; ?></div>
				<button id='wpt_custom_image_select' type='button' class='button-secondary'><?php _e( 'Choose Custom Image', 'wp-tweets-pro' ); ?></button>
				<input type='hidden' name='_wpt_custom_image' id='wpt_image_id' value='<?php echo $custom_image; ?>' />
			</div>
				<?php
			}
		}
	}
}

if ( ! function_exists( 'wpt_pro_exists' ) ) {
	/**
	 * Define functional existence.
	 */
	function wpt_pro_exists() {
		return true;
	}
}

add_action( 'admin_notices', 'wpt_admin_notice' );
/**
 * Create admin notices when license not entered.
 */
function wpt_admin_notice() {
	global $current_screen;
	if ( stripos( $current_screen->id, 'wp-tweets-pro' ) || stripos( $current_screen->id, 'wp-to-twitter' ) ) {
		if ( ! ( 'active' === get_option( 'wpt_license_valid' ) || 'valid' === get_option( 'wpt_license_valid' ) || 'true' === get_option( 'wpt_license_valid' ) ) ) {
			if ( ! isset( $_POST['wpt_license_key'] ) ) {
				// Translators: URL to Pro Settings screen.
				$message = sprintf( __( "You must <a href='%s'>enter your XPoster Pro license key</a> for support & updates to XPoster Pro features.", 'wp-tweets-pro' ), admin_url( 'admin.php?page=wp-tweets-pro&tab=pro' ) );
				if ( ! current_user_can( 'manage_options' ) ) {
					return;
				} else {
					echo "<div class='error'><p>$message</p></div>";
				}
			}
		}
	}
}

/**
 * Generate a list of active post types.
 *
 * @param string $root URL.
 *
 * @return string
 */
function wpt_types_list( $root ) {
	$settings   = ( is_array( get_option( 'wpt_post_types' ) ) ) ? get_option( 'wpt_post_types' ) : array();
	$post_types = array_keys( $settings );
	$types      = '';
	$i          = 0;
	foreach ( $post_types as $pt ) {
		if ( '1' === (string) $settings[ $pt ]['post-published-update'] || '1' === (string) $settings[ $pt ]['post-edited-update'] ) {
			++$i;
			$post_type = get_post_type_object( $pt );
			if ( ! $post_type ) {
				// translators: Post type label.
				$post_type_name = sprintf( __( '%s (inactive)', 'wp-tweets-pro' ), $pt );
			} else {
				$post_type_name = ( '' !== $post_type->label ) ? $post_type->label : $post_type->labels->singular_name;
			}
			$active = ( isset( $_GET['ptype'] ) ) ? $_GET['ptype'] : 'post';
			if ( $pt === $active ) {
				$types .= "<a href='$root&ptype=$pt' class='nav-tab nav-tab-active' aria-current='true'>$post_type_name</a>";
			} else {
				$types .= "<a href='$root&ptype=$pt' class='nav-tab'>$post_type_name</a>";
			}
		}
	}
	$types = ( $i > 1 ) ? '<h3 id="wpt-nav">' . __( 'Filter by post type', 'wp-tweets-pro' ) . "</h3>
	<nav class='nav-tab-wrapper' aria-labelledby='wpt-nav'>
		$types
	</nav>" : '';

	return $types;
}

/**
 * Get the default enabled post type.
 *
 * @return string
 */
function wpt_default_type() {
	$settings   = ( is_array( get_option( 'wpt_post_types' ) ) ) ? get_option( 'wpt_post_types' ) : array();
	$post_types = array_keys( $settings );
	foreach ( $post_types as $pt ) {
		if ( '1' === (string) $settings[ $pt ]['post-published-update'] || '1' === (string) $settings[ $pt ]['post-edited-update'] ) {
			return $pt;
		}
	}
	// Default is 'post' if nothing active.
	return 'post';
}

/**
 * Provide feedback about user accounts, when features are enabled that depend on that option.
 */
function wpt_notes() {
	$is_enabled = get_option( 'jd_individual_twitter_users' );
	if ( $is_enabled ) {
		$message = '<em>' . __( 'Individual Author accounts are enabled.', 'wp-tweets-pro' ) . '</em>';
	} else {
		$admin_url = admin_url( 'admin.php?page=wp-tweets-pro&tab=advanced#indauthors' );
		// translators: URL for advanced settings.
		$message = sprintf( __( "<em>Enable individual Author accounts in <a href='%s'>Advanced Settings</a>.</em>", 'wp-tweets-pro' ), $admin_url );
	}
	print( '
	<div class="ui-sortable meta-box-sortables wp-tweets-notes">
		<div class="postbox">
			<h3><span>' . __( 'XPoster Pro Notes', 'wp-tweets-pro' ) . '</span></h3>
			<div class="inside">
				<p>' . __( 'Most XPoster Pro settings can also be set on a per-post basis. Leave empty for instant posting and no re-post.', 'wp-tweets-pro' ) . '</p>
				<p>' . __( 'Twitter blocks identical Tweets. Prepend text to differentiate reposts.', 'wp-tweets-pro' ) . '</p>
				<p>' . __( 'Additional Twitter accounts are added in user profiles.', 'wp-tweets-pro' ) . ' ' . $message . '</p>
			</div>
		</div>
	</div>' );
}

/**
 * Get array of users authorized to post to Twitter.
 *
 * @return bool|array
 */
function wpt_get_authorized_users() {
	$args = array(
		'meta_query' => array(
			array(
				'key'     => 'wtt_twitter_username',
				'compare' => 'EXISTS',
			),
		),
	);
	// get all authorized users.
	$users            = get_users( $args );
	$authorized_users = array();
	if ( is_array( $users ) ) {
		foreach ( $users as $this_user ) {
			if ( wtt_oauth_test( $this_user->ID, 'verify' ) ) {
				$twitter            = get_user_meta( $this_user->ID, 'wtt_twitter_username', true );
				$authorized_users[] = array(
					'ID'      => $this_user->ID,
					'name'    => $this_user->display_name,
					'twitter' => $twitter,
				);
			}
		}
	} else {
		$authorized_users = false;
	}

	return $authorized_users;
}

/**
 * Get list of users authorized to post to Twitter
 *
 * @param array $selected Authors selected in this context.
 *
 * @return string HTML select field.
 */
function wpt_authorized_users( $selected = array() ) {
	/**
	 * Override authors available to select to send Tweets to. Default `false`.
	 *
	 * @hook wpt_override_author_selection
	 * @param {bool|string} $override False or completely realized `select` field with name `_wpt_authorized_users[]`.
	 *
	 * @return {bool|string}
	*/
	$override = apply_filters( 'wpt_override_author_selection', false );
	if ( $override ) {
		return $override;
	}
	if ( ! is_array( $selected ) ) {
		return $override;
	}

	global $user_ID;
	$users = get_option( 'wpt_authorized_users' );
	if ( ! $users ) {
		$authorized_users = wpt_get_authorized_users();
		update_option( 'wpt_authorized_users', $authorized_users );
		$users = $authorized_users;
	}
	$main_account = get_option( 'wtt_twitter_username' );
	$select       = "<p class='wpt_auth_users'><label for='wpt_authorized_users'>" . __( 'Tweet to:', 'wp-tweets-pro' ) . "</label><br /><select multiple='multiple' name='_wpt_authorized_users[]' id='wpt_authorized_users'>
		<option value='main'>" . __( 'Main:', 'wp-tweets-pro' ) . " @$main_account</option>";

	if ( ! empty( $users ) ) {
		foreach ( $users as $user ) {
			$current = $user_ID;
			$active  = '';
			// if this has been directly pulled, these are objects. Otherwise, arrays.
			if ( is_object( $user ) ) {
				$id      = $user->ID;
				$name    = $user->display_name;
				$twitter = get_user_meta( $id, 'wtt_twitter_username', true );
			} else {
				$id      = $user['ID'];
				$name    = $user['name'];
				$twitter = $user['twitter'];
			}
			global $post;
			if ( ( $id === $current && $current === $post->post_author ) || in_array( $id, $selected, true ) ) {
				$active = ' selected="selected"';
			}
			$select .= " <option value='$id'$active>$name (@$twitter)</option>\n";
		}
	}
	$select .= '</select></p>';

	return $select;
}

/**
 * Add custom JS
 */
function wpt_add_js() {
	global $current_screen;
	if ( 'xposter-pro_page_wp-to-twitter-tweets' === $current_screen->id || 'xposter-pro_page_wp-to-twitter-errors' === $current_screen->id ) {
		echo '
<script type="text/javascript">
(function ($) {
	$(function() {
		$("#wpt ul").hide();
		$("#wpt button").attr( "aria-expanded", "false" );
		$("#wpt button .dashicons" ).addClass( "dashicons-plus" );
		$("#wpt th > button").on( "click", function(e) {
			e.preventDefault();
			var next = $(this).next("ul");
			next.toggle();
			if ( next.is( ":visible" ) ) {
				$(this).find( ".dashicons" ).addClass( "dashicons-minus" );
				$(this).find( ".dashicons" ).removeClass( "dashicons-plus" );
				$(this).attr( "aria-expanded", "true" );
			} else {
				$(this).find( ".dashicons" ).addClass( "dashicons-plus" );
				$(this).find( ".dashicons" ).removeClass( "dashicons-minus" );
				$(this).attr( "aria-expanded", "false" );
			}
		});
	})
})(jQuery);
</script>
';
	}
}

add_filter( 'wpt_set_retweet_text', 'wpt_set_retweet_text', 10, 3 );
/**
 * Define custom retweet text
 *
 * @param string $template Default template.
 * @param int    $rt Retweet number.
 * @param int    $post_id Post ID being tweeted.
 *
 * @return string new template.
 */
function wpt_set_retweet_text( $template, $rt, $post_id ) {
	$prepend = '';
	$append  = '';
	$option  = (int) get_option( 'wpt_prepend' );
	switch ( $rt ) {
		case 1:
			$prepend = ( 1 === $option ) ? '' : get_option( 'wpt_prepend_rt' );
			$append  = ( 1 !== $option ) ? '' : get_option( 'wpt_prepend_rt' );
			break;
		case 2:
			$prepend = ( 1 === $option ) ? '' : get_option( 'wpt_prepend_rt2' );
			$append  = ( 1 !== $option ) ? '' : get_option( 'wpt_prepend_rt2' );
			break;
		case 3:
			$prepend = ( 1 === $option ) ? '' : get_option( 'wpt_prepend_rt3' );
			$append  = ( 1 !== $option ) ? '' : get_option( 'wpt_prepend_rt3' );
			break;
	}
	if ( 'template' === get_option( 'wpt_custom_type' ) ) {
		$retweet = stripslashes( $prepend . $append );
	} else {
		$retweet = stripslashes( $prepend ) . $template . stripslashes( $append );
	}

	// get custom value.
	$retweet_texts = get_post_meta( $post_id, '_wpt_retweet_text', true );
	$prev_retweet  = $retweet;
	if ( $retweet_texts || ( isset( $_POST['_wpt_retweet_text'] ) ) ) {
		$test_value = '';
		$templates  = ( isset( $_POST['_wpt_retweet_text'] ) ) ? $_POST['_wpt_retweet_text'] : $retweet_texts;
		if ( isset( $templates[ ( $rt - 1 ) ] ) && '' !== trim( $templates[ ( $rt - 1 ) ] ) ) {
			$retweet = trim( stripslashes( $templates[ ( $rt - 1 ) ] ) );
		}
		if ( '' === trim( $retweet ) || ! $retweet || is_array( $retweet ) ) {
			$retweet = $prev_retweet;
		}
	}

	return $retweet;
}

add_filter( 'wpt_schedule_retweet', 'wpt_schedule_retweet', 10, 4 );
/**
 * Determine time for a retweet.
 *
 * @param string $time Timestamp.
 * @param int    $acct User account ID.
 * @param int    $rt Retweet number.
 * @param array  $post_info Array of post info.
 *
 * @return string time.
 */
function wpt_schedule_retweet( $time, $acct, $rt, $post_info ) {
	// get custom value.
	$post_id = $post_info['id'];
	$times   = get_post_meta( $post_id, '_wpt_retweet_delay', true );
	if ( $times || ( isset( $_POST['_wpt_retweet_delay'] ) && ! empty( $_POST['_wpt_retweet_delay'] ) ) ) {
		$prev_time = $time;
		$times     = ( isset( $_POST['_wpt_retweet_delay'] ) ) ? $_POST['_wpt_retweet_delay'] : $times;
		if ( isset( $times['time'][ ( $rt - 1 ) ] ) && '' !== trim( $times['time'][ ( $rt - 1 ) ] ) ) {
			// time is a numeric value indicating an amount of time ahead of the current time.
			$time = trim( stripslashes( $times['time'][ ( $rt - 1 ) ] ) );
			$date = ( isset( $times['date'][ ( $rt - 1 ) ] ) ) ? trim( stripslashes( $times['date'][ ( $rt - 1 ) ] ) ) : date( 'Y-m-d', current_time( 'timestamp' ) ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested, WordPress.DateTime.RestrictedFunctions.date_date
			// convert time and date to diff.
			if ( '' !== $date . $time ) {
				$realtime = strtotime( $date . ' ' . $time );
				$diff     = $realtime - current_time( 'timestamp' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
				$time     = $diff;
			} else {
				$time = '';
			}
		}
		if ( '' === $time || ! $time || is_array( $time ) ) {
			$time = $prev_time;
		}
	}

	return $time;
}

/**
 * Assume is approved, unless otherwise informed by comment validator.
 *
 * @param int $comment_id Comment ID.
 * @param int $approved Comment status.
 *
 * @return comment post ID.
 */
function wpt_set_comment_tweet( $comment_id, $approved ) {
	$_t              = get_comment( $comment_id );
	$post_ID         = $_t->comment_post_ID;
	$commenter       = $_t->comment_author;
	$comment         = $_t->comment_content;
	$user_id         = $_t->user_id;
	$excerpt_length  = ( '' !== get_option( 'jd_post_excerpt', '' ) ) ? absint( get_option( 'jd_post_excerpt' ) ) : 140;
	$comment_excerpt = @mb_substr( strip_tags( strip_shortcodes( $comment ) ), 0, $excerpt_length ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
	$comment_date    = $_t->comment_date;
	$dateformat      = ( '' === get_option( 'jd_date_format', '' ) ) ? get_option( 'date_format' ) : get_option( 'jd_date_format' );
	$comment_date    = mysql2date( $dateformat, $comment_date );
	$post_info       = wpt_post_info( $post_ID );
	$sentence        = '';
	/**
	 * Customize the URL shortening of a comment link.
	 *
	 * @hook wptt_shorten_link
	 *
	 * @param {string} $comment_url The comment link.
	 * @param {string} $title The post title.
	 * @param {int}    $post_ID The post ID.
	 * @param {bool}   $test True means this is a test run.
	 *
	 * @return {string}
	 */
	$comment_url = apply_filters( 'wptt_shorten_link', get_comment_link( $comment_id ), $post_info['postTitle'], $post_ID, false );
	$sentence    = stripcslashes( get_option( 'comment-published-text' ) );
	$sentence    = str_replace( '#commenter#', $commenter, $sentence );
	$sentence    = str_replace( '#comment#', $comment_excerpt, $sentence );
	$sentence    = str_replace( '#comment_date#', $comment_date, $sentence );
	$sentence    = str_replace( '#comment_url#', $comment_url, $sentence );
	$sentence    = jd_truncate_tweet( $sentence, $post_info, $post_ID );

	if ( '' !== $sentence ) {
		/**
		 * Modify the Tweet saved to comment meta prior to Tweeting.
		 *
		 * @hook wpt_filter_comment_tweet
		 *
		 * @param {string} $sentence The Tweet text to be sent.
		 * @param {object} $_t The comment object.
		 *
		 * @return {string}
		 */
		$comment_tweet = apply_filters( 'wpt_filter_comment_tweet', $sentence, $_t );
		add_comment_meta( $comment_id, 'wpt_comment_tweet', $comment_tweet, true );
	}
	if ( user_can( $user_id, 'moderate_comments' ) || 1 === (int) $approved ) {
		wpt_twit_comment( $_t );
	}

	return $post_ID;
}

/**
 * Filter comment info to check whether this comment can be Tweeted.
 *
 * @param object $comment Comment object.
 *
 * @return boolean.
 */
function wpt_filter_comment_info( $comment ) {
	$filters = get_option( 'wpt_filters' );
	if ( is_array( $filters ) ) {
		foreach ( $filters as $filter => $rule ) {
			$comparison = $rule['type'];
			$field      = $rule['field'];
			switch ( $field ) {
				case 'postTitle':
					$value = get_the_title( $comment->comment_post_ID );
					break;
				case 'postLink':
					$value = get_the_permalink( $comment->comment_post_ID );
					break;
				case 'shortUrl':
					$short = wpt_short_url( $comment->comment_post_ID );
					break;
				case 'postStatus':
					$value = 'publish';
					break; // comments are only on published posts.
				case 'postType':
					$value = get_post_type( $comment->comment_post_ID );
					break;
				case 'id':
					$value = $comment->comment_post_ID;
					break;
				case 'authId':
					$value = $comment->user_id;
					break;
				case 'postExcerpt':
					$value = wpt_get_excerpt_by_id( $comment->comment_post_ID );
					break;
			}
			switch ( $comparison ) {
				case 'equals':
					if ( $value === $rule['value'] ) {
						return true;
					}
					break;
				case 'notin':
					if ( false === strpos( $value, $rule['value'] ) ) {
						return true;
					}
					break;
				case 'in':
					if ( false !== strpos( $value, $rule['value'] ) ) {
						return true;
					}
					break;
				case 'notequals':
					if ( $value !== $rule['value'] ) {
						return true;
					}
					break;
				default:
					return true;
			}
		}
		return false;
	}
	return false;
}

/**
 * Tweet a comment.
 *
 * @param object $comment Comment object.
 */
function wpt_twit_comment( $comment ) {
	if ( isset( $_REQUEST['tweet'] ) && 'false' === $_REQUEST['tweet'] ) {
		return;
	}
	$block = wpt_filter_comment_info( $comment );
	$delay = ( '' === get_option( 'wpt_comment_delay' ) ) ? false : get_option( 'wpt_comment_delay' );
	// If $block is true block this comment.
	if ( ! $block ) {
		$comment_id = $comment->comment_ID;
		$post_ID    = $comment->comment_post_ID;
		$sentence   = get_comment_meta( $comment_id, 'wpt_comment_tweet', true );
		if ( $sentence && ! $delay ) {
			wpt_post_to_service( $sentence, false, $post_ID );
		} else {
			/**
			 * Modify the delay before posting a comment Tweet.
			 *
			 * @hook wpt_schedule_comment_delay
			 *
			 * @param {int} $delay An amount of time in minutes to delay Tweets of comments.
			 * @param {int} $post_ID Post ID for the post receiving a comment.
			 *
			 * @return {int}
			 */
			$delay = apply_filters( 'wpt_schedule_comment_delay', ( (int) $delay ) * 60, $post_ID );
			wp_schedule_single_event(
				time() + $delay,
				'wpt_schedule_tweet_action',
				array(
					'id'       => false,
					'sentence' => $sentence,
					'rt'       => 0,
					'post_id'  => $post_ID,
				)
			);
		}
	}
}

if ( 1 === (int) get_option( 'comment-published-update' ) && ( get_option( 'comment_moderation' ) || 1 === (int) get_option( 'comment_previously_approved' ) ) ) {
	add_action( 'comment_post', 'wpt_set_comment_tweet', 10, 2 );
	add_action( 'comment_unapproved_to_approved', 'wpt_twit_comment', 10, 2 );
	add_filter( 'manage_edit-comments_columns', 'wpt_comment_columns' );
	add_filter( 'manage_comments_custom_column', 'wpt_comment_column', 10, 2 );
}

/**
 * Set up comment columns.
 *
 * @param array $columns Columns.
 *
 * @return array new columns.
 */
function wpt_comment_columns( $columns ) {
	$columns['wpt_comment_tweet'] = __( 'Comment Tweet', 'wp-tweets-pro' );
	return $columns;
}

/**
 * Fetch comment column information.
 *
 * @param string $column Column name.
 * @param int    $comment_id Comment ID.
 */
function wpt_comment_column( $column, $comment_id ) {
	if ( 'wpt_comment_tweet' === $column ) {
		$comment = get_comment( $comment_id );
		$meta    = get_comment_meta( $comment_id, $column, true );
		if ( $meta ) {
			echo $meta;
			if ( 1 !== (int) $comment->comment_approved ) {
				$approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "approve-comment_$comment->comment_ID" ) );
				$url           = "comment.php?c=$comment_id&#038;action=approvecomment&#038;tweet=false&#038;$approve_nonce";
				echo "<p><span class='approve'>";
				// Translators: 1) comment approval URL, 2) Comment ID.
				printf( __( '<a href="%1$s" data-wp-lists="dim:the-comment-list:comment-%2$d:unapproved:e7e7d3:tweet=false:new=approved" class="vim-a">Approve without Tweeting</a>', 'wp-tweets-pro' ), $url, $comment_id );
				echo '</span></p>';
			}
		} else {
			_e( 'No Tweet saved for this comment.', 'wp-tweets-pro' );
		}
	}
}

/**
 * Set up stylesheets.
 */
function wpt_add_styles() {
	global $current_screen, $wptp_version;
	if ( SCRIPT_DEBUG ) {
		$wptp_version .= '-' . wp_rand( 10000, 99999 );
	}
	wp_register_style( 'xposter-pro', plugins_url( 'css/style.css', __FILE__ ), array(), $wptp_version );
	$cs = $current_screen->id;
	if ( 'profile' === $cs || 'xposter-pro_page_wp-to-twitter-tweets' === $cs || 'xposter-pro_page_wp-to-twitter-errors' === $cs || 'toplevel_page_xposter-pro' === $cs || 'xposter-pro_page_wp-to-twitter-schedule' === $cs ) {
		wp_enqueue_style( 'xposter-pro' );
	}
}

add_action( 'admin_enqueue_scripts', 'wpt_add_styles' );
add_action( 'admin_head', 'wpt_add_js' );
add_action( 'admin_enqueue_scripts', 'wpt_enqueue_js' );
if ( 1 === (int) get_option( 'wpt_twitter_card' ) ) {
	// Disable Yoast SEO card if using XPoster cards.
	add_filter( 'wpseo_output_twitter_card', '__return_false' );
	add_action( 'wp_head', 'wpt_twitter_card' );
}
if ( 1 === (int) get_option( 'wpt_og_card' ) ) {
	add_action( 'wp_head', 'wpt_og_card' );
}


/**
 * Determine type of twitter card to show
 * photo cards deprecated by Twitter July 3, 2015
 *
 * @param int $id Post ID.
 *
 * @return string card type.
 */
function wpt_twitter_card_type( $id ) {
	$default = get_option( 'wpt_twitter_card_type' );
	$has_img = ( wp_get_attachment_url( get_post_meta( $id, '_wpt_custom_image', true ) ) || wp_get_attachment_url( get_post_thumbnail_id( $id ) ) ) ? true : false;
	if ( 'photo' === get_post_meta( $id, '_wpt_twitter_card', true ) && $has_img ) {
		return 'summary_large_image';
	} elseif ( 'summary_large_image' === get_post_meta( $id, '_wpt_twitter_card', true ) && $has_img ) {
		return 'summary_large_image';
	} elseif ( 'player' === get_post_meta( $id, '_wpt_twitter_card', true ) && esc_url( get_post_meta( $id, '_wpt_video_source', true ) ) && $has_img ) {
		// Player cards need to have a video URL & a poster image.
		return 'player';
	} else {
		$post         = get_post( $id );
		$content      = $post->post_content;
		$length_limit = ( get_option( 'wpt_toggle_card' ) ) ? get_option( 'wpt_toggle_card' ) : 0;
		if ( strlen( $content ) <= $length_limit && wp_get_attachment_url( get_post_thumbnail_id( $id ) ) ) {
			update_post_meta( $id, '_wpt_twitter_card', 'summary_large_image' );
			return 'summary_large_image';
		}
	}

	return ( 'summary' === $default ) ? 'summary' : 'summary_large_image';
}

/**
 * Generate Twitter Card
 */
function wpt_twitter_card() {
	$meta = '';
	if ( is_singular() ) {
		$post_ID = get_the_ID();
		$type    = wpt_twitter_card_type( $post_ID );
		$excerpt = wpt_get_excerpt_by_id( $post_ID );
		$meta    = '
	<!-- XPoster Pro -->
	<meta name="twitter:card" content="' . $type . '" />';
		$meta   .= '
	<meta name="twitter:site" content="@' . esc_attr( get_option( 'wtt_twitter_username' ) ) . '" />
	<meta name="twitter:title" content="' . esc_attr( strip_tags( get_the_title( $post_ID ) ) ) . '" />
	<meta name="twitter:description" content="' . esc_attr( $excerpt ) . '" />
	';
		if ( 'player' === $type ) {
			$url   = wpt_get_player_video( $post_ID );
			$ratio = get_post_meta( $post_ID, '_wpt_video_ratio', true );
			switch ( $ratio ) {
				// classic film/tv.
				case '4:3':
					$height = round( 640 / ( 4 / 3 ), 0 );
					break;
				// anamorphic cinema.
				case '2.39':
					$height = round( 640 / 2.39, 0 );
					break;
				// cinema widescreen.
				case '1.85':
					$height = round( 640 / 1.85, 0 );
					break;
				// Standard european/modern TV, consumer cameras.
				default:
					$height = round( 640 / ( 16 / 9 ), 0 );
			}
			// Calculate the proportional height needed for controls.
			$prop   = 436 / 640 * $height;
			$add    = round( 52 / ( $prop / $height ), 0 );
			$height = $height + $add;
			$meta  .= '
			<meta name="twitter:player" content="' . esc_url( $url ) . '" />
			<meta name="twitter:player:width" content="640" />
			<meta name="twitter:player:height" content="' . $height . '" />';
		}
		$custom_image = get_post_meta( $post_ID, '_wpt_custom_image', true );
		if ( $custom_image ) {
			$alt   = get_post_meta( $custom_image, '_wp_attachment_image_alt', true );
			$meta .= '<meta name="twitter:image" content="' . esc_url( wp_get_attachment_url( $custom_image ) ) . '">' . PHP_EOL;
			$meta .= '<meta name="twitter:image:alt" content="' . esc_attr( $alt ) . '">';
		} else {
			if ( wp_get_attachment_url( get_post_thumbnail_id( $post_ID ) ) ) {
				$thumb_id = get_post_thumbnail_id( $post_ID );
				$alt      = get_post_meta( $thumb_id, '_wp_attachment_image_alt', true );
				$meta    .= '<meta name="twitter:image" content="' . esc_url( wp_get_attachment_url( $thumb_id ) ) . '">' . PHP_EOL;
				$meta    .= '<meta name="twitter:image:alt" content="' . esc_attr( $alt ) . '">' . PHP_EOL;
			}
		}
		$meta .= '<!-- XPoster Pro -->' . "\n";
	} else {
		$title       = ( is_archive() ) ? get_the_archive_title() : get_bloginfo( 'name' );
		$description = ( is_archive() ) ? get_the_archive_description() : get_bloginfo( 'description' );
		$meta        = '
	<!-- XPoster Pro -->
	<meta name="twitter:card" content="summary" />
	<meta name="twitter:title" content="' . esc_attr( strip_tags( $title ) ) . '" />
	<meta name="twitter:description" content="' . esc_attr( strip_tags( $description ) ) . '" />' . PHP_EOL;
		if ( get_theme_mod( 'custom_logo' ) ) {
			$thumb_id = get_theme_mod( 'custom_logo' );
			$alt      = get_post_meta( $thumb_id, '_wp_attachment_image_alt', true );
			$meta    .= '
	<meta name="twitter:image" content="' . esc_url( wp_get_attachment_url( $thumb_id ) ) . '">' . PHP_EOL;
			$meta    .= '
	<meta name="twitter:image:alt" content="' . esc_attr( $alt ) . '">' . PHP_EOL;
		}
		$meta .= '
	<!-- XPoster Pro -->' . "\n";
	}
	echo $meta;
}

/**
 * Generate Open Graph Card
 */
function wpt_og_card() {
	$meta = '';
	if ( is_singular() ) {
		$post_ID = get_the_ID();
		$type    = wpt_twitter_card_type( $post_ID );
		$excerpt = wpt_get_excerpt_by_id( $post_ID );
		$meta    = '
	<!-- XPoster Pro -->
	<meta name="og:type" content="article" />';
		$meta   .= '
	<meta name="og:site_name" content="' . esc_attr( get_bloginfo( 'name' ) ) . '" />
	<meta name="og:title" content="' . esc_attr( strip_tags( get_the_title( $post_ID ) ) ) . '" />
	<meta name="og:description" content="' . esc_attr( $excerpt ) . '" />
	';
		if ( 'player' === $type ) {
			$url   = wpt_get_player_video( $post_ID );
			$ratio = get_post_meta( $post_ID, '_wpt_video_ratio', true );
			switch ( $ratio ) {
				// classic film/tv.
				case '4:3':
					$height = round( 640 / ( 4 / 3 ), 0 );
					break;
				// anamorphic cinema.
				case '2.39':
					$height = round( 640 / 2.39, 0 );
					break;
				// cinema widescreen.
				case '1.85':
					$height = round( 640 / 1.85, 0 );
					break;
				// Standard european/modern TV, consumer cameras.
				default:
					$height = round( 640 / ( 16 / 9 ), 0 );
			}
			// Calculate the proportional height needed for controls.
			$prop   = 436 / 640 * $height;
			$add    = round( 52 / ( $prop / $height ), 0 );
			$height = $height + $add;
			$meta  .= '
			<meta name="og:video" content="' . esc_url( $url ) . '" />
			<meta name="og:video:width" content="640" />
			<meta name="og:video:height" content="' . $height . '" />';
		}
		$custom_image = get_post_meta( $post_ID, '_wpt_custom_image', true );
		if ( $custom_image ) {
			$alt   = get_post_meta( $custom_image, '_wp_attachment_image_alt', true );
			$meta .= '<meta name="og:image" content="' . esc_url( wp_get_attachment_url( $custom_image ) ) . '">' . PHP_EOL;
			$meta .= '<meta name="og:image:alt" content="' . esc_attr( $alt ) . '">';
		} else {
			if ( wp_get_attachment_url( get_post_thumbnail_id( $post_ID ) ) ) {
				$thumb_id = get_post_thumbnail_id( $post_ID );
				$alt      = get_post_meta( $thumb_id, '_wp_attachment_image_alt', true );
				$meta    .= '<meta name="og:image" content="' . esc_url( wp_get_attachment_url( $thumb_id ) ) . '">' . PHP_EOL;
				$meta    .= '<meta name="og:image:alt" content="' . esc_attr( $alt ) . '">' . PHP_EOL;
			}
		}
		$meta .= '<!-- XPoster Pro -->' . "\n";
	} else {
		$title       = ( is_archive() ) ? get_the_archive_title() : get_bloginfo( 'name' );
		$description = ( is_archive() ) ? get_the_archive_description() : get_bloginfo( 'description' );
		$meta        = '
	<!-- XPoster Pro -->
	<meta name="og:type" content="website" />
	<meta name="og:title" content="' . esc_attr( strip_tags( $title ) ) . '" />
	<meta name="og:description" content="' . esc_attr( strip_tags( $description ) ) . '" />' . PHP_EOL;
		if ( get_theme_mod( 'custom_logo' ) ) {
			$thumb_id = get_theme_mod( 'custom_logo' );
			$alt      = get_post_meta( $thumb_id, '_wp_attachment_image_alt', true );
			$meta    .= '
	<meta name="og:image" content="' . esc_url( wp_get_attachment_url( $thumb_id ) ) . '">' . PHP_EOL;
			$meta    .= '
	<meta name="og:image:alt" content="' . esc_attr( $alt ) . '">' . PHP_EOL;
		}
		$meta .= '
	<!-- XPoster Pro -->' . "\n";
	}
	echo $meta;
}

/**
 * Generate video URL for player cards.
 *
 * @param int $post_ID Post ID.
 *
 * @return string
 */
function wpt_get_player_video( $post_ID ) {
	$video = get_post_meta( $post_ID, '_wpt_video_source', true );
	$url   = '';
	// For remote player video cards, use URL directly. Otherwise, use local.
	if ( stripos( $video, 'youtube.com' ) || stripos( $video, 'youtu.be' ) ) {
		preg_match( "/^(?:http(?:s)?:\/\/)?(?:www\.)?(?:m\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?v(?:i)?=|(?:embed|v|vi|user)\/))([^\?&\"'>]+)/", $video, $matches );

		$video_id = $matches[1];
		$url      = 'https://youtube.com/embed/' . $video_id;
	} elseif ( stripos( $video, 'vimeo.com' ) ) {
		preg_match( '%^https?:\/\/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)(\d+)(?:$|\/|\#?)(?:[?]?.*)$%im', $video, $matches );

		$video_id = $matches[3];
		$url      = 'https://player.vimeo.com/' . $video_id;
	} else {
		if ( $video ) {
			$url = add_query_arg( 'card', 'true', get_the_permalink( $post_ID ) );
		}
	}

	return $url;
}

/**
 * Get excerpt for use in Tweets.
 *
 * @param int    $post Post ID.
 * @param int    $length Length of excerpt.
 * @param string $tags Allowed tags.
 * @param string $extra 'More' string.
 *
 * @return mixed boolean/string.
 */
function wpt_get_excerpt_by_id( $post, $length = 15, $tags = '<a><em><strong>', $extra = ' &hellip;' ) {
	if ( is_int( $post ) ) {
		// get the post object of the passed ID.
		$post = get_post( $post );
	} elseif ( ! is_object( $post ) ) {
		return false;
	}

	if ( has_excerpt( $post->ID ) ) {
		$the_excerpt = $post->post_excerpt;
	} else {
		$the_excerpt = $post->post_content;
	}
	$the_excerpt = strip_shortcodes( strip_tags( $the_excerpt ), $tags );
	$the_excerpt = preg_split( '/\b/', $the_excerpt, $length * 2 + 1 );
	array_pop( $the_excerpt );
	$the_excerpt  = implode( $the_excerpt );
	$the_excerpt .= $extra;
	return preg_replace( '/\s+/', ' ', trim( $the_excerpt ) );
}

/**
 * Enqueue JavaScript.
 */
function wpt_enqueue_js() {
	global $current_screen;
	if ( ( isset( $_GET['page'] ) && 'wp-to-twitter-schedule' === $_GET['page'] ) || 'post' === $current_screen->base ) {
		wp_enqueue_script( 'wpt.mediaselector', plugins_url( 'js/media.js', __FILE__ ), array( 'jquery' ) );
		wp_localize_script(
			'wpt.mediaselector',
			'wptp',
			array(
				'thumbHeight' => get_option( 'thumbnail_size_h' ),
			)
		);

		if ( function_exists( 'wp_enqueue_media' ) && ! did_action( 'wp_enqueue_media' ) ) {
			wp_enqueue_media();
		}
		wp_enqueue_script( 'jquery-ui-autocomplete' );
		wp_enqueue_script( 'wpt.suggest', plugins_url( 'js/jquery.suggest.js', __FILE__ ), array( 'jquery', 'jquery-ui-autocomplete' ) );
		wp_enqueue_script( 'wpt.general', plugins_url( 'js/general.js', __FILE__ ), array( 'jquery' ), false, true );
		wp_localize_script(
			'wpt.suggest',
			'wpta',
			array(
				'ajax_action' => 'wpt_post_lookup',
			)
		);
	}
}

add_action( 'wp_ajax_wpt_post_lookup', 'wpt_post_lookup' );
/**
 * Look up a post. Generic AJAX post lookup.
 */
function wpt_post_lookup() {
	if ( isset( $_REQUEST['term'] ) ) {
		$posts       = get_posts(
			array(
				's'         => $_REQUEST['term'],
				'post_type' => wpt_allowed_post_types(),
			)
		);
		$suggestions = array();
		global $post;
		foreach ( $posts as $post ) {
			setup_postdata( $post );
			$suggestion          = array();
			$suggestion['value'] = esc_html( $post->post_title );
			$suggestion['id']    = $post->ID;
			$suggestions[]       = $suggestion;
		}

		echo $_GET['callback'] . '(' . json_encode( $suggestions ) . ')';
		exit;
	}
}

/**
 * Show message confirmation of OAuth connection.
 *
 * @param int $id Post ID.
 */
function wpt_connect_oauth_message( $id ) {
	$message = get_user_meta( $id, 'wpt-connection-message', true );
	echo ( '' === $message ) ? '' : "<div id='message' class='updated'><p>$message</p></div>";
}

add_action( 'init', 'wpt_edit_terms_fields' );
/**
 * Set up actions for editing terms.
 */
function wpt_edit_terms_fields() {
	$args       = apply_filters( 'wpt_revive_taxonomies', array() );
	$taxonomies = get_taxonomies( $args );
	if ( ! is_array( $taxonomies ) ) {
		$taxonomies = array();
	}
	foreach ( $taxonomies as $value ) {
		add_action( $value . '_add_form_fields', 'wpt_add_term', 10, 1 );
		add_action( $value . '_edit_form_fields', 'wpt_edit_term', 10, 2 );
		add_action( 'edit_' . $value, 'wpt_save_term', 10, 2 );
		add_action( 'created_' . $value, 'wpt_save_term', 10, 2 );
	}
}

/**
 * Save custom fields for a term.
 *
 * @param int $term_id Term ID.
 * @param int $tax_id Taxonomy ID.
 */
function wpt_save_term( $term_id, $tax_id ) {
	$option_set = (int) get_option( "wpt_taxonomy_revive_$term_id" );
	if ( isset( $_POST['taxonomy'] ) ) {
		if ( isset( $_POST['wpt_term_template'] ) ) {
			update_term_meta( $term_id, '_wpt_term_template', trim( strip_tags( sanitize_textarea_field( $_POST['wpt_term_template'] ) ) ) );
		}
		$taxonomy = sanitize_text_field( $_POST['taxonomy'] );
		if ( isset( $_POST['wpt_term_revive'] ) && 1 !== $option_set ) {
			update_option( "wpt_taxonomy_revive_$term_id", 1 );
			$args  = array(
				'tax_query'      => array(
					array(
						'taxonomy' => $taxonomy,
						'field'    => 'id',
						'terms'    => $term_id,
					),
				),
				'fields'         => 'ids',
				'posts_per_page' => -1,
			);
			$posts = new WP_Query( $args );
			foreach ( $posts->posts as $post ) {
				update_post_meta( $post, '_wpt_noautopost', 1 );
			}
		} elseif ( ! isset( $_POST['wpt_term_revive'] ) && 1 === $option_set ) {
			delete_option( "wpt_taxonomy_revive_$term_id" );
			$args  = array(
				'tax_query'      => array(
					array(
						'taxonomy' => $taxonomy,
						'field'    => 'id',
						'terms'    => $term_id,
					),
				),
				'fields'         => 'ids',
				'posts_per_page' => -1,
			);
			$posts = new WP_Query( $args );
			foreach ( $posts->posts as $post ) {
				delete_post_meta( $post, '_wpt_noautopost' );
			}
		}
	}
}

/**
 * Fields to edit on term editor.
 *
 * @param object $term Term object.
 * @param object $taxonomy Taxonomy object. [not used].
 */
function wpt_edit_term( $term, $taxonomy ) {
	$t_id      = $term->term_id;
	$term_meta = get_option( "wpt_taxonomy_revive_$t_id" );
	$template  = get_term_meta( $t_id, '_wpt_term_template', true );
	?>
	<tr class="form-field">
		<th valign="top" scope="row">
			<label for="wpt_term_revive"><?php _e( "Don't autotweet this term", 'wp-tweets-pro' ); ?></label>
		</th>
		<td>
			<input type='checkbox' value='1' name='wpt_term_revive' id='wpt_term_revive'<?php checked( $term_meta, 1 ); ?> />
		</td>
	</tr>
	<tr class="form-field">
		<th valign="top" scope="row">
			<label for="wpt_term_template"><?php _e( 'Term Tweet Template', 'wp-tweets-pro' ); ?></label>
		</th>
		<td>
			<input type='text' value='<?php echo esc_attr( $template ); ?>' name='wpt_term_template' id='wpt_term_template' />
		</td>
	</tr>
	<?php
}

/**
 * Custom fields on new term screen.
 *
 * @param object $tag Not used.
 */
function wpt_add_term( $tag ) {
	?>
	<div class="form-field">
		<input type='checkbox' value='1' id='wpt_term_revive' name='wpt_term_revive' /> <label for="wpt_term_revive" style='display: inline;'><?php _e( "Don't autotweet this term", 'wp-tweets-pro' ); ?></label>
	</div>
	<div class="form-field">
		<label for="wpt_term_template" style='display: inline;'><?php _e( 'Term Tweet Template', 'wp-tweets-pro' ); ?></label>
		<input type='text' value='' id='wpt_term_template' name='wpt_term_template' />
	</div>
	<?php
}

if ( '1' === get_option( 'wpt_use_cats' ) ) {
	add_action( 'post_category_add_form_fields', 'wpt_add_tag' );
	add_action( 'post_category_edit_form_fields', 'wpt_edit_tag' );
	add_action( 'edited_post_category', 'wpt_save_tag', 10, 2 );
	add_action( 'created_post_category', 'wpt_save_tag', 10, 2 );
} else {
	add_action( 'post_tag_add_form_fields', 'wpt_add_tag' );
	add_action( 'post_tag_edit_form_fields', 'wpt_edit_tag' );
	add_action( 'edited_post_tag', 'wpt_save_tag', 10, 2 );
	add_action( 'created_post_tag', 'wpt_save_tag', 10, 2 );
}

/**
 * Enable terms other than post and category to customize tags for hashtags. Return an array of taxonomy names to enable those taxonomies.
 *
 * @hook wpt_hash_tag_sources
 *
 * @param {bool|array} $taxonomies Additional taxonomies that should be supported for Tweet customization fields.
 *
 * @return {bool|array}
 */
$wpt_additional_taxonomies = apply_filters( 'wpt_hash_tag_sources', false );
if ( is_array( $wpt_additional_taxonomies ) && ! empty( $wpt_additional_taxonomies ) ) {
	foreach ( $wpt_additional_taxonomies as $key => $taxonomy ) {
		add_action( $taxonomy . '_add_form_fields', 'wpt_add_tag' );
		add_action( $taxonomy . '_edit_form_fields', 'wpt_edit_tag' );
		add_action( 'edited_' . $taxonomy, 'wpt_save_tag', 10, 2 );
		add_action( 'created_' . $taxonomy, 'wpt_save_tag', 10, 2 );
	}
}

/**
 * Save tag information.
 *
 * @param int $term_id Term ID.
 */
function wpt_save_tag( $term_id ) {
	if ( isset( $_POST['wpt_tag'] ) ) {
		$wpt_tag = sanitize_text_field( $_POST['wpt_tag'] );
		update_option( "wpt_taxonomy_$term_id", $wpt_tag );
	}
}

/**
 * Edit tag fields.
 *
 * @param object $term Term Object.
 */
function wpt_edit_tag( $term ) {
	$t_id      = $term->term_id;
	$term_meta = (int) get_option( "wpt_taxonomy_$t_id" );
	?>
	<tr class="form-field">
		<th valign="top" scope="row">
			<label for="wpt_tag"><?php _e( 'Tweet tag as', 'wp-tweets-pro' ); ?></label>
		</th>
		<td>
			<select name="wpt_tag" id="wpt_tag">
				<option value='1'<?php echo ( 1 === $term_meta ) ? "selected='selected'" : ''; ?>>#tag</option>
				<option value='2'<?php echo ( 2 === $term_meta ) ? "selected='selected'" : ''; ?>>$tag</option>
				<option value='5'<?php echo ( 5 === $term_meta ) ? "selected='selected'" : ''; ?>>@tag</option>
				<option value='4'<?php echo ( 4 === $term_meta ) ? "selected='selected'" : ''; ?>>tag</option>
				<option value='3'<?php echo ( 3 === $term_meta ) ? "selected='selected'" : ''; ?>><?php _e( 'ignore', 'wp-tweets-pro' ); ?></option>
			</select>
		</td>
	</tr>
	<?php
}

/**
 * Form when adding new tag.
 */
function wpt_add_tag() {
	?>
	<tr class="form-field">
		<th valign="top" scope="row">
			<label for="wpt_tag"><?php _e( 'Tweet tag as', 'wp-tweets-pro' ); ?></label>
		</th>
		<td>
			<select name="wpt_tag" id="wpt_tag">
				<option value='1'>#tag</option>
				<option value='2'>$tag</option>
				<option value='5'>@tag</option>
				<option value='3'><?php _e( 'ignore', 'wp-tweets-pro' ); ?></option>
			</select>
		</td>
	</tr>
	<?php
}

add_filter( 'wpt_settings', 'wpt_set_filter_terms', 10, 2 );
/**
 * Set term filters.
 *
 * @param string $message Notification message.
 * @param array  $post POST data.
 *
 * @return string
 */
function wpt_set_filter_terms( $message, $post ) {
	if ( isset( $post['wpt_terms'] ) ) {
		// if setting term filters, delete old filters.
		delete_option( 'wpt_tweet_cats' );
		delete_option( 'limit_categories' );
		delete_option( 'tweet_categories' );
		foreach ( $post['wpt_terms'] as $tax => $terms ) {
			$terms             = array_unique( $terms );
			$wpt_terms[ $tax ] = $terms;
		}
		update_option( 'wpt_terms', $wpt_terms );
		$message .= ' ' . __( 'Term filters updated.', 'wp-tweets-pro' );
	} else {
		delete_option( 'wpt_terms' );
	}
	if ( isset( $post['wpt_term_filters'] ) ) {
		update_option( 'wpt_term_filters', $post['wpt_term_filters'] );
		$message .= ' ' . __( 'Term filtering method reversed.', 'wp-tweets-pro' );
	} else {
		delete_option( 'wpt_term_filters' );
	}
	return $message;
}

add_filter( 'wpt_filter_terms', 'wpt_apply_term_filters', 10, 2 );
/**
 * Test against term filters.
 *
 * @param bool  $filter Is post being filtered.
 * @param array $args Post data.
 */
function wpt_apply_term_filters( $filter, $args ) {
	$post_type = ( isset( $args['type'] ) ) ? $args['type'] : false;
	$post_ID   = ( isset( $args['id'] ) ) ? $args['id'] : false;
	// If the $filter equals true, allowed.
	$term_ids = array();
	$filters  = get_option( 'wpt_terms' );
	if ( is_array( $filters ) ) {
		$filtered_taxonomies = array_keys( $filters );
		$taxonomies          = get_object_taxonomies( $post_type, 'names' );
		$terms               = wp_get_object_terms( $post_ID, $taxonomies );
		foreach ( $terms as $term ) {
			$term_ids[ $term->taxonomy ][] = $term->term_id;
			// term IDs are unique, so I don't care which taxonomy this is.
		}
		$positive = get_option( 'wpt_term_filters' );
		// items in array are checked positively.
		foreach ( $filters as $key => $value ) {
			// if there are terms in both sets.
			// this keeps going unless any test comes up as false.
			if ( ! empty( $filters[ $key ] ) ) {
				if ( isset( $term_ids[ $key ] ) ) {
					$result = array_intersect( $term_ids[ $key ], $filters[ $key ] );
					if ( isset( $positive[ $key ] ) && count( $result ) >= 1 ) {
						$filter = true;
					} elseif ( isset( $positive[ $key ] ) && 0 === count( $result ) ) {
						$filter = false;
					} elseif ( count( $result ) >= 1 && ! isset( $positive[ $key ] ) ) {
						$filter = false;
					}
				}
			}
		}
	}

	/**
	 * Run filters based on taxonomy terms. Used to exclude or include particular terms from Tweets. A true value means continue, but does not mean that a Tweet will be sent; a Tweet could still be filtered out for a different reason.
	 *
	 * @hook wpt_modify_term_filters
	 *
	 * @param {bool}  $filter Boolean true to continue, false to prevent Tweets.
	 * @param {array} $args Data about the current post.
	 *
	 * @return {bool}
	 */
	$filter = apply_filters( 'wpt_modify_term_filters', $filter, $args );
	wpt_mail( '3d: Taxonomy limits executed', $filter . "\n\n" . print_r( $args, 1 ), $post_ID );

	return $filter;
}

/**
 * Generate list of terms and filtering status.
 *
 * @param string $post_type Post Type internal name.
 * @param string $post_name Display name for post type.
 */
function wpt_list_terms( $post_type, $post_name ) {
	$selected     = '';
	$taxonomies   = get_object_taxonomies( $post_type, 'object' );
	$term_filters = get_option( 'wpt_terms' );
	$filter_type  = get_option( 'wpt_term_filters' );
	$nonce        = wp_nonce_field( 'wp-to-twitter-nonce', '_wpnonce', true, false );
	$input        = '';
	if ( ! empty( $taxonomies ) ) {
		foreach ( $taxonomies as $taxonomy ) {
			$name  = $taxonomy->labels->name;
			$slug  = $taxonomy->name;
			$count = wp_count_terms( $slug );
			echo "<input type='hidden' name='wpt_term_taxonomies[]' value='$slug' />";
			if ( $count > 500 ) {
				_e( 'There are more than 500 terms in this taxonomy. Use the <code>wpt_filter_terms</code> filter to apply custom limits on this taxonomy.', 'wp-tweets-pro' );
			} else {
				$terms = get_terms( $slug, array( 'hide_empty' => false ) );
				if ( 0 === count( $terms ) ) {
					continue;
				}
				$checked = ( isset( $filter_type[ $slug ] ) ) ? ' checked="checked"' : '';
				if ( ! $checked ) {
					$exclude = __( 'Exclude', 'wp-tweets-pro' );
				} else {
					$exclude = __( 'Include', 'wp-tweets-pro' );
				}
				// translators: 1) Taxonomy label 2) Current state (exclude or include) 3) Post type name.
				$input = "<fieldset class='wpt-terms'><legend>" . sprintf( __( '%3$s %1$s by %2$s', 'wp-tweets-pro' ), $post_name, $name, $exclude ) . '</legend>';
				// translators: Taxonomy name.
				$input .= '<p><input type="checkbox" name="wpt_term_filters[' . $slug . '][]" id="wpt_term_filters_' . $slug . '" value="1"' . $checked . ' /> <label for="wpt_term_filters_' . $slug . '">' . sprintf( __( 'Checked %s will be Tweeted', 'wp-tweets-pro' ), strtolower( $name ) ) . '</label></p>';
				$input .= "
				<ul class='wpt-terms'>\n";
				$class  = '';
				if ( ! empty( $terms ) ) {
					foreach ( $terms as $term ) {
						if ( is_array( $term_filters ) ) {
							$filter = ( isset( $term_filters[ $slug ] ) ) ? $term_filters[ $slug ] : array();
							if ( is_array( $filter ) && in_array( (string) $term->term_id, $filter, true ) ) {
								$selected = ' checked="checked"';
								$class    = ( $checked ) ? 'tweet' : 'notweet';
							} else {
								$selected = '';
								$class    = 'unchecked';
							}
						}
						$input .= '<li class="' . $class . '"><input' . $selected . ' type="checkbox" name="wpt_terms[' . $slug . '][]" value="' . $term->term_id . '" id="' . $term->slug . $term->term_id . '" /> <label for="' . $term->slug . $term->term_id . '">' . $term->name . "</label></li>\n";
					}
				} else {
					$input .= __( 'No terms in this taxonomy.', 'wp-tweets-pro' );
				}
				$input .= '</ul>
				</fieldset>';
				echo $input;
			}
		}
	} else {
		_e( 'No taxonomies found.', 'wp-tweets-pro' );
	}
}

/**
 * Add the screen option for num per page
 */
function wpt_add_screen_option() {
	$items_per_page = ( get_option( 'wpt_num_per_page' ) ) ? get_option( 'wpt_num_per_page' ) : 50;
	$option         = 'per_page';
	$args           = array(
		'label'   => 'Tweets',
		'default' => $items_per_page,
		'option'  => 'wpt_num_per_page',
	);
	add_screen_option( $option, $args );
}

add_filter( 'set-screen-option', 'wpt_set_screen_option', 10, 3 );
/**
 * Set the num per page value
 *
 * @param string $status Status.
 * @param string $option Option name.
 * @param string $value New value.
 *
 * @return string $value
 */
function wpt_set_screen_option( $status, $option, $value ) {
	if ( 'wpt_num_per_page' === $option ) {
		update_user_meta( get_current_user_ID(), 'wpt_num_per_page', $value );
	}

	return $value;
}