HEX
Server: nginx/1.27.1
System: Linux in-4 5.15.0-131-generic #141-Ubuntu SMP Fri Jan 10 21:18:28 UTC 2025 x86_64
User: ilikadirect (1186)
PHP: 7.4.33
Disabled: exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file,show_source
Upload Files
File: /storage/v6964/mangomitra/public_html/wp-content/plugins/totalcontest-lite/src/Contest/Model.php
<?php

namespace TotalContest\Contest;

use TotalContest\Contracts\Contest\Model as ModelContract;
use TotalContest\Form\ParticipateForm;
use TotalContestVendors\TotalCore\Contracts\Form\Field;
use TotalContestVendors\TotalCore\Contracts\Form\Form;
use TotalContestVendors\TotalCore\Helpers\Arrays;
use TotalContestVendors\TotalCore\Helpers\Misc;
use TotalContestVendors\TotalCore\Helpers\Strings;
use TotalContestVendors\TotalCore\Traits\Metadata;

/**
 * Contest Model
 * @package TotalContest\Contest
 * @since   1.0.0
 */
class Model implements ModelContract {
	use Metadata;

	/**
	 * Contest ID.
	 *
	 * @var int|null
	 * @since 1.0.0
	 */
	protected $id = null;

	/**
	 * Contest attributes.
	 *
	 * @var array
	 * @since 1.0.0
	 */
	protected $attributes = [];

	/**
	 * Contest action.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	protected $action = 'landing';

	/**
	 * Contest settings.
	 *
	 * @var array|null
	 * @since 1.0.0
	 */
	protected $settings = null;

	/**
	 * Contest seo attributes.
	 *
	 * @var array|null
	 * @since 1.0.0
	 */
	protected $seo = null;

	/**
	 * Received votes.
	 *
	 * @var int
	 * @since 1.0.0
	 */
	protected $receivedVotes = 0;

	/**
	 * Contest WordPress post.
	 *
	 * @var array|null|\WP_Post
	 * @since 1.0.0
	 */
	protected $contestPost = null;

	/**
	 * Contest submissions.
	 * @var string
	 * @since 1.0.0
	 */
	protected $submissions = [];

	/**
	 * Contest submissions count.
	 * @var string
	 * @since 1.0.0
	 */
	protected $submissionsCount = null;

	/**
	 * Submission per page.
	 * @var string
	 * @since 1.0.0
	 */
	protected $submissionsPerPage = 10;

	/**
	 * Contest total pages.
	 *
	 * @var int|null
	 * @since 1.0.0
	 */
	protected $pagesCount = 0;

	/**
	 * Contest current page.
	 *
	 * @var int|null
	 * @since 1.0.0
	 */
	protected $currentPage = 1;

	/**
	 * Contest upload form.
	 *
	 * @var \TotalContestVendors\TotalCore\Contracts\Form\Form|callable $form
	 * @since 1.0.0
	 */
	protected $form = null;

	/**
	 * Contest current screen
	 * @var string
	 * @since 1.0.0
	 */
	protected $screen = 'contest.landing';

	/**
	 * Contest sub screen
	 * @var string
	 * @since 1.0.0
	 */
	protected $customPage = '';

	/**
	 * Sort by field.
	 * @var string
	 * @since 1.0.0
	 */
	protected $sortBy = 'date';

	/**
	 * Sort direction.
	 * @var string
	 * @since 1.0.0
	 */
	protected $sortDirection = 'desc';

	/**
	 * Filter value.
	 * @var string
	 * @since 2.0.0
	 */
	protected $filter = null;

	/**
	 * Filter by field.
	 * @var string
	 * @since 2.0.0
	 */
	protected $filterBy = null;

	/**
	 * Context.
	 * @var string
	 * @since 2.1.3
	 */
	protected $context = null;

	/**
	 * Contest menu visibility.
	 *
	 * @var boolean $menu
	 * @since 1.0.0
	 */
	protected $menu = true;

	/**
	 * Contest menu items visibility.
	 *
	 * @var array $menuItemsVisibility
	 * @since 1.1.0
	 */
	protected $menuItemsVisibility = [
		'landing'     => true,
		'participate' => true,
		'submissions' => true,
		'pages'       => true,
	];

	/**
	 * Limitations
	 *
	 * @var \TotalContestVendors\TotalCore\Contracts\Limitations\Bag
	 * @since 1.0.0
	 */
	protected $limitations;

	/**
	 * Restrictions
	 *
	 * @var \TotalContestVendors\TotalCore\Contracts\Restrictions\Bag
	 * @since 1.0.0
	 */
	protected $restrictions;

	/**
	 * Error.
	 * @var null|\WP_Error
	 * @since 1.0.0
	 */
	protected $error;

	/**
	 * Model constructor.
	 *
	 * @param $attributes array Contest attributes.
	 *
	 * @since 1.0.0
	 */
	public function __construct( $attributes ) {
		/**
		 * Filters the contest attributes.
		 *
		 * @param array $attributes Contest model attributes.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return array
		 * @since 2.0.0
		 */
		$attributes       = apply_filters( 'totalcontest/filters/contest/attributes', $attributes, $this );
		$this->attributes = $attributes;

		$this->id          = $attributes['id'];
		$this->contestPost = $attributes['post'];

		// Parse settings JSON.
		$this->settings = (array) json_decode( $this->contestPost->post_content, true );

		/**
		 * Filters the contest attributes.
		 *
		 * @param array $settings Contest settings.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return array
		 * @since 2.0.0
		 */
		$this->settings = apply_filters( 'totalcontest/filters/contest/settings', $this->settings, $this );

		// Current page
		$this->currentPage = empty( $attributes['currentPage'] ) ? $this->currentPage : (int) $attributes['currentPage'];

		// Submission per page
		$this->submissionsPerPage = (int) $this->getSettingsItem( 'contest.submissions.perPage', 10 );

		// Sort
		$this->sortBy        = (string) $attributes['sortBy'] ?: $this->getSettingsItem( 'design.sorting.field', 'date' );
		$this->sortDirection = (string) $attributes['sortDirection'] ?: $this->getSettingsItem( 'design.sorting.direction', 'desc' );

		// Filter
		$this->filter   = (string) $attributes['filter'];
		$this->filterBy = (string) $attributes['filterBy'];

		// Context
		$this->context = (string) $attributes['context'];

		// Content Id
		$this->customPage = (string) $attributes['customPage'] ?: '';

		// Menu visibility
		$this->menu = $attributes['menu'];

		// Action
		if ( $attributes['contestId'] != $this->id ) {
			$attributes['action'] = '';
		}
		$this->action = (string) $attributes['action'] ?: $this->getDefaultPage();
		if ( ! $this->hasLandingPage() && $this->action === 'landing' ):
			$this->action = 'participate';
		endif;

		// Map of action => screen
		$actionScreenMap = [
			'landing'     => $this->hasLandingPage() ? 'contest.landing' : 'contest.participate',
			'submissions' => 'contest.submissions',
			'participate' => 'contest.participate',
			'content'     => 'contest.content',
			'submission'  => 'submission.view',
		];

		// Screen
		$this->screen = isset( $actionScreenMap[ $this->action ] ) ? $actionScreenMap[ $this->action ] : 'contest.participate';

		// Limitations
		$this->limitations = new \TotalContestVendors\TotalCore\Limitations\Bag();

		$periodArgs = $this->getSettingsItem( 'contest.limitations.period' );
		if ( ! empty( $periodArgs['enabled'] ) ):
			$periodArgs['context'] = 'participate';
			$this->limitations->add( 'period', new \TotalContest\Limitations\Period( $periodArgs ) );
		endif;

		$membershipArgs = $this->getSettingsItem( 'contest.limitations.membership' );
		if ( ! empty( $membershipArgs['enabled'] ) ):
			$membershipArgs['context'] = 'participate';
			$this->limitations->add( 'membership', new \TotalContest\Limitations\Membership( $membershipArgs ) );
		endif;

		$quotaArgs = $this->getSettingsItem( 'contest.limitations.quota' );
		if ( ! empty( $quotaArgs['enabled'] ) ):
			$quotaArgs['context']      = 'participate';
			$quotaArgs['currentValue'] = $this->getSubmissionsCount();
			$this->limitations->add( 'quota', new \TotalContest\Limitations\Quota( $quotaArgs ) );
		endif;

		/**
		 * Fires after limitations setup.
		 *
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @since 2.0.0
		 */
		do_action( 'totalcontest/actions/contest/limitations', $this );

		// Restrictions
		$this->restrictions = new \TotalContestVendors\TotalCore\Restrictions\Bag();

		$frequencyArgs              = $this->getSettingsItem( 'contest.frequency' );
		$frequencyArgs['contest']   = $this;
		$frequencyArgs['action']    = 'submission';
		$frequencyArgs['fullCheck'] = TotalContest()->option( 'performance.fullChecks.enabled' );
		$frequencyArgs['message']   = esc_html__( 'You cannot submit new entries in this contest.', 'totalcontest' );

		if ( ! empty( $frequencyArgs['cookies']['enabled'] ) ):
			$this->restrictions->add( 'cookies', new \TotalContest\Restrictions\Cookies( $frequencyArgs ) );
		endif;

		if ( ! empty( $frequencyArgs['ip']['enabled'] ) ):
			$this->restrictions->add( 'ip', new \TotalContest\Restrictions\IPAddress( $frequencyArgs ) );
		endif;

		if ( ! empty( $frequencyArgs['user']['enabled'] ) ):
			$this->restrictions->add( 'user', new \TotalContest\Restrictions\LoggedInUser( $frequencyArgs ) );
		endif;

		/**
		 * Fires after restrictions setup.
		 *
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 * @param array $frequencyArgs Frequency arguments.
		 *
		 * @since 2.0.0
		 */
		do_action( 'totalcontest/actions/contest/restrictions', $this, $frequencyArgs );

		/**
		 * Fires after contest model setup is completed.
		 *
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @since 2.0.0
		 */
		do_action( 'totalcontest/actions/contest/setup', $this );
	}

	/**
	 * Has landing page.
	 *
	 * @return bool
	 */
	public function hasLandingPage() {
		$landingContent = $this->getSettingsItem( 'pages.landing.content' );

		return ! empty( $landingContent );
	}

	/**
	 * Get default page.
	 *
	 * @return string
	 */
	public function getDefaultPage( $default = 'landing' ) {
		return $this->getSettingsItem( 'pages.default', $default );
	}

	/**
	 * Get settings item.
	 *
	 * @param bool $needle Settings name.
	 * @param bool $default Default value.
	 *
	 * @return mixed|array|null
	 * @since 1.0.0
	 */
	public function getSettingsItem( $needle, $default = null ) {
		/**
		 * Filters the contest settings item.
		 *
		 * @param array $settings Contest settings.
		 * @param string $default Default value.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return mixed
		 * @since 2.0.0
		 */
		return apply_filters( "totalcontest/filters/contest/settings-item/{$needle}", Arrays::getDotNotation( $this->settings, $needle, $default ), $this->settings, $default, $this );
	}

	/**
	 * Get settings section or item.
	 *
	 * @param bool $section Settings section.
	 * @param bool $args Path to setting.
	 *
	 * @return mixed|array|null
	 * @since 1.0.0
	 */
	public function getSettings( $section = false, $args = false ) {
		// Deep selection.
		if ( $args !== false && $section && isset( $this->settings[ $section ] ) ):
			$paths = func_get_args();
			unset( $paths[0] );

			return Arrays::getDeep( $this->settings[ $section ], $paths );
		endif;

		// Return specific settings section, otherwise, return all settings.
		if ( $section ):
			return isset( $this->settings[ $section ] ) ? $this->settings[ $section ] : null;
		endif;

		return $this->settings;
	}

	/**
	 * Get submissions count.
	 *
	 * @return int
	 */
	public function getSubmissionsCount() {
		if ( $this->submissionsCount === null ):
			$this->submissionsCount = (int) TotalContest( 'submissions.repository' )->count( [ 'contest' => $this->id ] );
		endif;

		return $this->submissionsCount;
	}

	/**
	 * Get contest id.
	 *
	 * @return int
	 * @since 1.0.0
	 */
	public function getId() {
		return (int) $this->id;
	}

	/**
	 * Get action.
	 *
	 * @return string
	 * @since 1.0.0
	 */
	public function getAction() {
		return $this->action;
	}

	/**
	 * Get seo attributes.
	 *
	 * @return array
	 * @since 1.0.0
	 */
	public function getSeoAttributes() {
		if ( $this->seo === null ):
			$bindings = [
				'title'    => $this->getTitle(),
				'sitename' => get_bloginfo( 'name' ),
			];

			$this->seo = [
				'title'       => Strings::template( $this->getSettingsItem( 'seo.contest.title' ), $bindings ) ?: $this->getTitle(),
				'description' => Strings::template( $this->getSettingsItem( 'seo.contest.description' ), $bindings ),
			];

			$this->seo = array_map( 'wp_strip_all_tags', $this->seo );
		endif;

		/**
		 * Filters the contest seo attributes.
		 *
		 * @param array $seo SEO attributes.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return array
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/seo', $this->seo, $this );
	}

	/**
	 * Get contest title.
	 *
	 * @return string
	 * @since 1.0.0
	 */
	public function getTitle() {
		return $this->contestPost->post_title;
	}

	/**
	 * Get share attributes.
	 *
	 * @return array
	 * @since 1.0.0
	 */
	public function getShareAttributes() {
		$websites     = array_filter( (array) TotalContest()->option( 'share.websites', [] ) );
		$websitesUrls = [
			'facebook'   => 'https://www.facebook.com/sharer.php?u={{url}}',
			'twitter'    => 'https://twitter.com/intent/tweet?url={{url}}',
			'googleplus' => 'https://plus.google.com/share?url={{url}}',
			'pinterest'  => 'https://pinterest.com/pin/create/bookmarklet/?url={{url}}',
			'whatsapp'   => 'whatsapp://send?text={{url}}',
		];

		$url = $this->getPermalink();

		foreach ( $websitesUrls as $website => $websiteUrl ):
			$shareUrl = add_query_arg( [
				'utm_source'   => $website,
				'utm_medium'   => 'contest-share-button',
				'utm_campaign' => $this->getTitle(),
			], $url );

			$websitesUrls[ $website ] = Strings::template( $websiteUrl, [ 'url' => urlencode( $shareUrl ) ] );
		endforeach;

		/**
		 * Filters the contest sharing attributes.
		 *
		 * @param array $attributes Sharing attributes.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return array
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/share', array_intersect_key( $websitesUrls, $websites ), $this );
	}

	/**
	 * Get contest thumbnail.
	 *
	 * @return false|string
	 * @since 1.0.0
	 */
	public function getThumbnail() {
		$thumbnail = wp_get_attachment_image_src( get_post_thumbnail_id( $this->id ), 'post-thumbnail' );

		$thumbnail = empty( $thumbnail[0] ) ? TotalContest()->env( 'url' ) . 'assets/dist/images/no-preview.png' : $thumbnail[0];

		/**
		 * Filters the contest thumbnail.
		 *
		 * @param array $thumbnail Contest thumbnail.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return string
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/thumbnail', $thumbnail, $this );
	}

	/**
	 * Get time left to start.
	 *
	 * @param string $type Either 'contest' or 'vote'
	 *
	 * @return int|\DateInterval
	 * @since 1.0.0
	 */
	public function getTimeLeftToStart( $type = 'contest' ) {
		$startDate = $this->getStartDate( $type );
		$now       = TotalContest( 'datetime', [ 'now' ] );

		if ( $startDate && $startDate->getTimestamp() > current_time( 'timestamp' ) ):
			return $startDate->diff( $now, true );
		endif;

		return 0;
	}

	/**
	 * Get time left to end.
	 *
	 * @param string $type Either 'contest' or 'vote'
	 *
	 * @return int|\DateInterval
	 * @since 1.0.0
	 */
	public function getTimeLeftToEnd( $type = 'contest' ) {
		$endDate = $this->getEndDate( $type );
		$now     = TotalContest( 'datetime', [ 'now' ] );

		if ( $endDate && $endDate->getTimestamp() > current_time( 'timestamp' ) ):
			return $endDate->diff( $now, true );
		endif;

		return 0;
	}

	/**
	 * @param string $type
	 *
	 * @return null|\TotalContestVendors\TotalCore\Application|\TotalContestVendors\TotalCore\Contracts\Helpers\DateTime
	 */
	public function getStartDate( $type = 'contest' ) {
		$startDate = $this->getSettingsItem( "{$type}.limitations.period.start" );

		return $startDate ? TotalContest( 'datetime', [ $startDate ] ) : null;
	}

	/**
	 * @param string $type
	 *
	 * @return null|\TotalContestVendors\TotalCore\Application|\TotalContestVendors\TotalCore\Contracts\Helpers\DateTime
	 */
	public function getEndDate( $type = 'contest' ) {
		$endDate = $this->getSettingsItem( "{$type}.limitations.period.end" );

		return $endDate ? TotalContest( 'datetime', [ $endDate ] ) : null;
	}

	/**
	 * Get form fields.
	 *
	 * @return Field[]
	 * @since 2.0.0
	 */
	public function getFormFields() {
		$fields = [];
		foreach ( $this->getForm() as $page ):
			foreach ( $page as $field ):
				$fields[ $field->getName() ] = $field;
			endforeach;
		endforeach;

		/**
		 * Filters the contest form fields.
		 *
		 * @param array $fields Contest custom fields.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return array
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/fields', $fields, $this );
	}

	/**
	 * Get form fields definitions.
	 *
	 * @return array
	 * @since 2.0.0
	 */
	public function getFormFieldsDefinitions() {
		$fields = [];
		foreach ( $this->getSettingsItem( 'contest.form.fields', [] ) as $field ):
			$fields[ $field['name'] ] = $field;
		endforeach;

		return $fields;
	}

	/**
	 * Get blocks definitions.
	 *
	 * @return array
	 * @since 2.1.0
	 */
	public function getBlocksDefinitions() {
		$context = $this->isSubmissionsScreen() ? 'submissions' : 'submission';

		return $this->getSettingsItem( "contest.submissions.blocks.{$context}", [] );
	}

	/**
	 * @return boolean
	 * @since 2.1.0
	 */
	public function isUsingBlocks() {
		return (boolean) $this->getSettingsItem( 'contest.submissions.blocks.enabled', false );
	}

	/**
	 * Get upload form.
	 *
	 * @return ParticipateForm Form object
	 * @since 1.0.0
	 */
	public function getForm() {
		if ( is_callable( $this->form ) ) {
			$this->form = call_user_func( $this->form, $this );
		}

		return $this->form;
	}

	/**
	 * Set upload form.
	 *
	 * @param Form $form
	 *
	 * @return Form Form object
	 * @since 1.0.0
	 */
	public function setForm( Form $form ) {
		return $this->form = $form;
	}

	/**
	 * Set upload form resolver.
	 *
	 * @param callable $resolver
	 *
	 * @return self
	 * @since 1.0.0
	 */
	public function setFormResolver( $resolver ) {
		$this->form = $resolver;

		return $this;
	}

	/**
	 * @return array|mixed|null|\WP_Post
	 */
	public function getContestPost() {
		return $this->contestPost;
	}

	/**
	 * Get categories terms objects.
	 *
	 * @return \WP_Term[]|int|\WP_Error
	 * @since 2.0.0
	 */
	public function getCategories() {
		$categories = [];

		foreach ( $this->getFormFieldsDefinitions() as $field ):
			if ( $field['type'] === 'category' ):
				$categories = get_terms( [
					'taxonomy'   => TC_SUBMISSION_CATEGORY_TAX_NAME,
					'fields'     => 'id=>name',
					'hide_empty' => false,
					'include'    => $field['options'],
				] );

				break;
			endif;
		endforeach;

		/**
		 * Filters the contest categories.
		 *
		 * @param array $categories Contest categories.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return array
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/categories', $categories, $this );
	}

	/**
	 * Has category field.
	 *
	 * @return bool
	 * @since 2.1.0
	 */
	public function hasCategoryField() {
		foreach ( $this->getFormFieldsDefinitions() as $field ):
			if ( $field['type'] === 'category' ):
				return true;
			endif;
		endforeach;

		return false;
	}

	/**
	 * Get menu items.
	 *
	 * @return array
	 * @since 1.0.0
	 */
	public function getMenuItems() {
		$items = [];

		if ( $this->hasLandingPage() && $this->getMenuItemVisibility( 'landing' ) ):
			$items['landing'] = [
				'label'  => $this->getSettingsItem( 'pages.landing.title' ) ?: esc_html__( 'Home', 'totalcontest' ),
				'url'    => $this->getLandingUrl(),
				'ajax'   => $this->getLandingAjaxUrl(),
				'active' => $this->isLandingScreen(),
			];
		endif;

		if ( $this->getMenuItemVisibility( 'participate' ) ):
			$items['participate'] = [
				'label'  => $this->getSettingsItem( 'pages.participate.title' ) ?: esc_html__( 'Participate', 'totalcontest' ),
				'url'    => $this->getParticipateUrl(),
				'ajax'   => $this->getParticipateAjaxUrl(),
				'active' => $this->isParticipateScreen(),
			];
		endif;

		if ( $this->getMenuItemVisibility( 'submissions' ) ):
			$items['submissions'] = [
				'label'  => $this->getSettingsItem( 'pages.submissions.title' ) ?: esc_html__( 'Submissions', 'totalcontest' ),
				'url'    => $this->getSubmissionsUrl(),
				'ajax'   => $this->getSubmissionsAjaxUrl(),
				'active' => $this->isSubmissionsScreen() || $this->isSubmissionScreen(),
			];
		endif;

		if ( $this->getMenuItemVisibility( 'pages' ) ):
			$pages = (array) $this->getSettingsItem( 'pages.other' );
			foreach ( $pages as $page ):

				$items[ $page['id'] ] = [
					'label'  => $page['title'],
					'url'    => $this->getCustomPageUrl( $page['id'] ),
					'ajax'   => $this->getCustomPageAjaxUrl( $page['id'] ),
					'active' => $this->isCustomPageScreen( $page['id'] ),
				];

			endforeach;
		endif;


		/**
		 * Filters the contest menu items.
		 *
		 * @param array $items Contest menu items.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return array
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/menu', $items, $this );
	}

	/**
	 * Get menu item visibility.
	 *
	 * @param $item
	 *
	 * @return boolean
	 * @since    1.1.0
	 */
	public function getMenuItemVisibility( $item ) {
		return ! empty( $this->menuItemsVisibility[ $item ] );
	}

	/**
	 * Get url.
	 *
	 * @param array $args
	 *
	 * @return string
	 */
	public function getUrl( $args = [] ) {
		$args = Arrays::parse( $args, [
			'contestId' => $this->id,
			'action'    => $this->getAction(),
			'context'   => $this->getContext(),
			'menu'      => (int) $this->getMenuVisibility(),
		] );

		wp_parse_str( $_SERVER['QUERY_STRING'], $queryParameters );
		$base = Misc::isDoingAjax() ? wp_get_referer() : add_query_arg( $queryParameters, home_url( $GLOBALS['wp']->request ) );

		$prettyPermalinks = (bool) get_option( 'permalink_structure' );
		$urlParameters    = [ 'totalcontest' => $args ];

		if ( ! Misc::isDoingAjax() && is_admin() ):
			$base = $this->getPermalink();

			if ( strpos( $this->getPermalink(), '&' ) !== false ):
				$prettyPermalinks = false;
			endif;
		endif;

		if ( $prettyPermalinks ):
			$isSingular = in_array( $this->getContext(), [ TC_CONTEST_CPT_NAME, TC_SUBMISSION_CPT_NAME ] );

			if ( $isSingular || Misc::isRestRequest() ):
				$base = $this->getPermalink();
			endif;

			$currentUrl = wp_parse_url( $base );
			$basePath   = preg_replace( '#(landing|participate|submissions|submission|content)/(.*)/?#i', '', empty( $currentUrl['path'] ) ? '/' : $currentUrl['path'] );

			$path = array_filter( explode( '/', $basePath ) );
			if ( $isSingular ):
				$path[] = $args['action'];
				if ( $args['action'] === 'content' && ! empty( $args['customPage'] ) ):
					$path[] = $args['customPage'];
					unset( $urlParameters['totalcontest']['customPage'] );
				elseif ( $args['action'] === 'submission' && ! empty( $args['submissionId'] ) ):
					$path[] = $args['submissionId'];
					unset( $urlParameters['totalcontest']['submissionId'] );
				elseif ( $args['action'] === 'submissions' ):
					$urlParameters['totalcontest']['sortDirection'] = empty( $args['sortDirection'] ) ? $this->sortDirection : $args['sortDirection'];
					$urlParameters['totalcontest']['sortBy']        = empty( $args['sortBy'] ) ? $this->sortBy : $args['sortBy'];
					$urlParameters['totalcontest']['filter']        = empty( $args['filter'] ) ? $this->filter : $args['filter'];
					$urlParameters['totalcontest']['filterBy']      = empty( $args['filterBy'] ) ? $this->filterBy : $args['filterBy'];
					$urlParameters['totalcontest']['page']          = empty( $args['page'] ) ? $this->currentPage : $args['page'];

					$urlParameters['totalcontest'] = array_filter( $urlParameters['totalcontest'] );
				endif;

				unset( $urlParameters['totalcontest']['action'], $urlParameters['totalcontest']['context'] );
			endif;

			$path = '/' . implode( '/', $path ) . '/';
			$base = "${currentUrl['scheme']}://{$currentUrl['host']}";

			if ( isset( $currentUrl['port'] ) ) {
				$base .= ':' . $currentUrl['port'];
			}

			$base .= $path;

			$base = user_trailingslashit( $base );

//			unset( $urlParameters['totalcontest']['contestId'] );
		elseif ( ! empty( $urlParameters['totalcontest']['submissionId'] ) ):
			$urlParameters['post_type'] = TC_SUBMISSION_CPT_NAME;
			$urlParameters['p']         = (int) $urlParameters['totalcontest']['submissionId'];
		else :
			$urlParameters['post_type'] = TC_CONTEST_CPT_NAME;
			$urlParameters['p']         = $this->id;
		endif;

		$urlParameters = TotalContest( 'url' )->compactParameters( $urlParameters );

		$url = add_query_arg( $urlParameters, $base );


		/**
		 * Filters the contest urls.
		 *
		 * @param string $url URL.
		 * @param array $args Arguments.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return string
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/url', $url, $args, $this );
	}

	/**
	 * Get AJAX url.
	 *
	 * @param array $args
	 *
	 * @return string
	 */
	public function getAjaxUrl( $args = [] ) {
		$args          = Arrays::parse( $args, [
			'contestId' => $this->id,
			'action'    => $this->getAction(),
			'context'   => $this->getContext()
		] );
		$base          = admin_url( 'admin-ajax.php' );
		$urlParameters = [ 'action' => 'totalcontest', 'totalcontest' => $args ];

		if ( $args['action'] === 'submissions' ):
			$urlParameters['totalcontest']['sortDirection'] = empty( $args['sortDirection'] ) ? $this->sortDirection : $args['sortDirection'];
			$urlParameters['totalcontest']['sortBy']        = empty( $args['sortBy'] ) ? $this->sortBy : $args['sortBy'];
			$urlParameters['totalcontest']['filter']        = empty( $args['filter'] ) ? $this->filter : $args['filter'];
			$urlParameters['totalcontest']['filterBy']      = empty( $args['filterBy'] ) ? $this->filterBy : $args['filterBy'];
			$urlParameters['totalcontest']['page']          = empty( $args['page'] ) ? $this->currentPage : $args['page'];

			$urlParameters['totalcontest'] = array_filter( $urlParameters['totalcontest'] );
		endif;

		$url = add_query_arg( $urlParameters, $base );

		/**
		 * Filters the contest urls.
		 *
		 * @param string $url URL.
		 * @param array $args Arguments.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return string
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/ajax-url', $url, $args, $this );
	}


	/**
	 * Get limitations bag.
	 *
	 * @return \TotalContestVendors\TotalCore\Contracts\Limitations\Bag
	 */
	public function getLimitations() {
		return $this->limitations;
	}

	/**
	 * Get restrictions bag.
	 *
	 * @return \TotalContestVendors\TotalCore\Contracts\Restrictions\Bag
	 */
	public function getRestrictions() {
		return $this->restrictions;
	}

	/**
	 * Get submissions divided per row.
	 *
	 * @param array $args
	 *
	 * @return array
	 */
	public function getSubmissionsRows( $args = [] ) {
		$perRow      = $this->getSettingsItem( 'design.layout.columns' ) ?: 4;
		$submissions = $this->getSubmissions( $args );

		return $perRow === 0 ? [ $submissions ] : array_chunk( $submissions, $perRow, true );
	}

	/**
	 * Get submissions with pagination.
	 *
	 * @param array $args
	 *
	 * @return mixed
	 */
	public function getSubmissionsWithPagination( $args = [] ) {

		if ( $this->filterBy === 'category' && ! empty( $this->filter ) ):
			$ids = array_keys( $this->getCategories() );

			if ( in_array( (int) $this->filter, $ids, true ) ):
				$args['category'] = $this->filter;
			endif;
		endif;

		$result = TotalContest( 'submissions.repository' )->paginate( [
			'contest'        => $this->id,
			'perPage'        => $this->submissionsPerPage,
			'page'           => $this->currentPage,
			'orderBy'        => $this->sortBy,
			'orderDirection' => $this->sortDirection,
		], $args );

		// Count submissions
		$this->submissionsCount = (int) $result['count'];

		// Count available pages
		$this->pagesCount = (int) $result['pages'];

		$result ['pagination'] = $this->getPaginationItems();

		// Return back the submissions
		return $result;
	}

	/**
	 * Get submissions.
	 *
	 * @param array $args
	 *
	 * @return mixed
	 */
	public function getSubmissions( $args = [] ) {
		$result = TotalContest( 'submissions.repository' )->paginate(
			Arrays::parse( $args, [
				'contest'        => $this->id,
				'perPage'        => $this->submissionsPerPage,
				'page'           => $this->currentPage,
				'orderBy'        => $this->sortBy,
				'orderDirection' => $this->sortDirection,
				'filterBy'       => $this->filterBy,
				'filter'         => $this->filter
			] )
		);

		// Count submissions
		$this->submissionsCount = (int) $result['count'];

		// Count available pages
		$this->pagesCount = (int) $result['pages'];

		$result['pagination'] = $this->getPaginationItems();

		// Return back the submissions
		return $result['items'];
	}

	/**
	 * Get column width in percentage.
	 *
	 * @return float|int
	 */
	public function getColumnWidth() {
		$perRow = $this->getSettingsItem( 'design.layout.columns' ) ?: 4;

		return 100 / $perRow;
	}

	/**
	 * Get pagination for current query.
	 *
	 * @return array
	 */
	public function getPaginationItems() {
		$pages = [];

		for ( $page = 1; $page <= $this->pagesCount; $page ++ ):
			$pages[ $page ] = [
				'url'    => $this->getUrl( [ 'action' => 'submissions', 'page' => $page ] ),
				'ajax'   => $this->getAjaxUrl( [ 'action' => 'submissions', 'page' => $page ] ),
				'active' => $page === $this->currentPage,
				'number' => $page,
				'label'  => $page,
			];
			if ( $page === $this->currentPage ):
				if ( $page !== 1 ):
					$previous = $page - 1;
				endif;
				if ( $page + 1 < $this->pagesCount ):
					$next = $page;
				endif;
			endif;
		endfor;

		return $pages;
	}

	/**
	 * Check if there is previous page for current query.
	 *
	 * @return bool
	 */
	public function hasPreviousPage() {
		return $this->currentPage > 1;
	}

	/**
	 * Get previous page for current query.
	 *
	 * @return array
	 */
	public function getPreviousPagePaginationItem() {
		return [
			'url'    => $this->getUrl( [ 'action' => 'submissions', 'page' => $this->currentPage - 1 ] ),
			'ajax'   => $this->getAjaxUrl( [ 'action' => 'submissions', 'page' => $this->currentPage - 1 ] ),
			'active' => $this->hasPreviousPage(),
			'number' => $this->currentPage - 1,
			'label'  => esc_html__( 'Previous', 'totalcontest' ),
		];
	}

	/**
	 * Check if there is next page for current query.
	 *
	 * @return bool
	 */
	public function hasNextPage() {
		return $this->currentPage + 1 <= $this->pagesCount;
	}

	/**
	 * Get next page for current query.
	 *
	 * @return array
	 */
	public function getNextPagePaginationItem() {
		return [
			'url'    => $this->getUrl( [ 'action' => 'submissions', 'page' => $this->currentPage + 1 ] ),
			'ajax'   => $this->getAjaxUrl( [ 'action' => 'submissions', 'page' => $this->currentPage + 1 ] ),
			'active' => $this->hasNextPage(),
			'number' => $this->currentPage + 1,
			'label'  => esc_html__( 'Next', 'totalcontest' ),
		];
	}

	/**
	 * Get error object.
	 *
	 * @return null|\WP_Error
	 */
	public function getError() {
		return $this->error;
	}

	/**
	 * @param string|\WP_Error $error
	 */
	public function setError( $error ) {
		$this->error = is_wp_error( $error ) ? $error : new \WP_Error( 'error', $error );
	}

	/**
	 * @return bool
	 */
	public function hasError() {
		return ! empty( $this->error );
	}

	/**
	 * Get error message.
	 *
	 * @return null|string
	 */
	public function getErrorMessage() {
		return $this->error instanceof \WP_Error ? $this->error->get_error_message() : null;
	}

	/**
	 * Get sort by items.
	 *
	 * @return array
	 */
	public function getSortByItems() {
		$sortByItems = [
			'date'  => [
				'label'  => esc_html__( 'Date', 'totalcontest' ),
				'url'    => $this->getUrl( [
					'action'        => 'submissions',
					'sortDirection' => $this->sortDirection,
					'sortBy'        => 'date',
				] ),
				'ajax'   => $this->getAjaxUrl( [
					'action'        => 'submissions',
					'sortDirection' => $this->sortDirection,
					'sortBy'        => 'date',
				] ),
				'active' => $this->sortBy === 'date',
			],
			'views' => [
				'label'  => esc_html__( 'Views', 'totalcontest' ),
				'url'    => $this->getUrl( [
					'action'        => 'submissions',
					'sortDirection' => $this->sortDirection,
					'sortBy'        => 'views',
				] ),
				'ajax'   => $this->getAjaxUrl( [
					'action'        => 'submissions',
					'sortDirection' => $this->sortDirection,
					'sortBy'        => 'views',
				] ),
				'active' => $this->sortBy === 'views',
			],
			'votes' => [
				'label'  => esc_html__( 'Votes', 'totalcontest' ),
				'url'    => $this->getUrl( [
					'action'        => 'submissions',
					'sortDirection' => $this->sortDirection,
					'sortBy'        => 'votes',
				] ),
				'ajax'   => $this->getAjaxUrl( [
					'action'        => 'submissions',
					'sortDirection' => $this->sortDirection,
					'sortBy'        => 'votes',
				] ),
				'active' => $this->sortBy === 'votes',
			],
		];

		/**
		 * Filters the contest sort by items.
		 *
		 * @param array $items Contest sort-by items.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return array
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/sort-by', $sortByItems, $this );
	}

	/**
	 * Get sort directions items.
	 *
	 * @return array
	 */
	public function getSortDirectionItems() {
		$sortDirectionItems = [
			'asc'  => [
				'label'  => esc_html__( 'Ascending', 'totalcontest' ),
				'url'    => $this->getUrl( [
					'action'        => 'submissions',
					'sortDirection' => 'asc',
					'sortBy'        => $this->sortBy,
				] ),
				'ajax'   => $this->getAjaxUrl( [
					'action'        => 'submissions',
					'sortDirection' => 'asc',
					'sortBy'        => $this->sortBy,
				] ),
				'active' => $this->sortDirection === 'asc',
			],
			'desc' => [
				'label'  => esc_html__( 'Descending', 'totalcontest' ),
				'url'    => $this->getUrl( [
					'action'        => 'submissions',
					'sortDirection' => 'desc',
					'sortBy'        => $this->sortBy,
				] ),
				'ajax'   => $this->getAjaxUrl( [
					'action'        => 'submissions',
					'sortDirection' => 'desc',
					'sortBy'        => $this->sortBy,
				] ),
				'active' => $this->sortDirection === 'desc',
			],
		];

		return $sortDirectionItems;
	}

	/**
	 * Get filter by items.
	 *
	 * @return array
	 */
	public function getFilterByItems() {
		$filterByItems = [
			[
				'label'  => esc_html__( 'Choose', 'totalcontest' ),
				'url'    => $this->getUrl( [
					'action'        => 'submissions',
					'sortDirection' => $this->sortDirection,
					'sortBy'        => $this->sortBy,
					'filter'        => '',
				] ),
				'ajax'   => $this->getAjaxUrl( [
					'action'        => 'submissions',
					'sortDirection' => $this->sortDirection,
					'sortBy'        => $this->sortBy,
					'filter'        => '',
				] ),
				'active' => false,
			],
		];
		$categories    = $this->getCategories();

		foreach ( $categories as $categoryId => $category ):
			$filterByCategorySlug                   = "category:{$categoryId}";
			$filterByItems[ $filterByCategorySlug ] = [
				'label'  => $category,
				'url'    => $this->getUrl( [
					'action'        => 'submissions',
					'sortDirection' => $this->sortDirection,
					'sortBy'        => $this->sortBy,
					'filterBy'      => 'category',
					'filter'        => $categoryId,
				] ),
				'ajax'   => $this->getAjaxUrl( [
					'action'        => 'submissions',
					'sortDirection' => $this->sortDirection,
					'sortBy'        => $this->sortBy,
					'filterBy'      => 'category',
					'filter'        => $categoryId,
				] ),
				'active' => $this->filterBy === 'category' && $this->filter == $categoryId,
			];
		endforeach;


		/**
		 * Filters the contest filter by items.
		 *
		 * @param array $items Contest sort-by items.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return array
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/filter-by', $filterByItems, $this );
	}

	/**
	 * Get current page.
	 *
	 * @return int
	 */
	public function getCurrentPage() {
		return $this->currentPage;
	}

	/**
	 * Set current page.
	 *
	 * @param $page
	 */
	public function setCurrentPage( $page ) {
		$this->currentPage = absint( $page ) ?: 1;
	}

	/**
	 * Set action.
	 *
	 * @param string $action
	 */
	public function setAction( $action ) {
		$this->action = (string) $action;
	}

	/**
	 * Get prefix.
	 *
	 * @param string $append
	 *
	 * @return string
	 * @since 1.0.0
	 */
	public function getPrefix( $append = '' ) {
		return TotalContest()->env( 'prefix' ) . "{$this->id}_{$append}";
	}

	/**
	 * Get current screen.
	 *
	 * @return string Current screen.
	 * @since 1.0.0
	 */
	public function getScreen() {
		return $this->screen;
	}

	/**
	 * Set current screen.
	 *
	 * @param $screen string Screen name.
	 *
	 * @return $this
	 * @since 1.0.0
	 */
	public function setScreen( $screen ) {
		$this->screen = (string) $screen;

		return $this;
	}

	/**
	 * Get content pages
	 *
	 * @return array
	 * @since 2.0.0
	 */
	public function getCustomPages() {
		$pages = array_reduce(
			(array) $this->getSettingsItem( 'pages.other', [] ),
			function ( $pages, $item ) {
				$pages[ $item['id'] ] = $item;

				return $pages;
			}, [] );

		/**
		 * Filters the contest custom pages.
		 *
		 * @param array $items Contest custom pages.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return array
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/custom-pages', $pages, $this );
	}

	/**
	 * Get current content page.
	 *
	 * @param null $id
	 *
	 * @return array|null
	 * @since 1.0.0
	 */
	public function getCustomPage( $id = null ) {
		if ( ! $id ):
			$id = $this->customPage;
		endif;

		$pages = (array) $this->getCustomPages();
		foreach ( $pages as $page ):
			if ( $id === $page['id'] ):
				return $page;
			endif;
		endforeach;

		return null;
	}

	/**
	 * Get current content page Id.
	 *
	 * @return string|null
	 * @since 1.0.0
	 */
	public function getCustomPageId() {
		return $this->customPage;
	}

	/**
	 * Set current content Id.
	 *
	 * @param $customPage
	 *
	 * @return $this
	 * @since 1.0.0
	 */
	public function setCustomPageId( $customPage ) {
		$this->customPage = (string) $customPage;

		return $this;
	}

	/**
	 * Get menu visibility.
	 *
	 * @return string Current screen.
	 * @since 1.0.0
	 */
	public function getMenuVisibility() {
		return $this->menu;
	}

	/**
	 * Set menu visibility.
	 *
	 * @param $visible
	 *
	 * @return $this
	 * @since 1.0.0
	 */
	public function setMenuVisibility( $visible ) {
		$this->menu = (boolean) $visible;

		return $this;
	}

	/**
	 * Set menu item visibility.
	 *
	 * @param $slug
	 *
	 * @return $this
	 * @since    1.1.0
	 */
	public function setMenuItemVisibility( $slug ) {
		$this->menuItemsVisibility[ $slug ] = true;

		return $this;
	}

	/**
	 * Get menu item visibility.
	 *
	 * @return array
	 * @since    1.1.0
	 */
	public function getMenuItemsVisibility() {
		return $this->menuItemsVisibility;
	}

	/**
	 * Set menu item visibility.
	 *
	 * @param $items
	 *
	 * @return $this
	 * @since    1.1.0
	 */
	public function setMenuItemsVisibility( $items ) {
		$this->menuItemsVisibility = (array) $items;

		return $this;
	}

	/**
	 * Get template id.
	 *
	 * @return mixed
	 * @since 2.0.0
	 */
	public function getTemplateId() {
		return $this->getSettingsItem( 'design.template', 'basic-template' );
	}

	/**
	 * Get preset id.
	 *
	 * @return string
	 * @since 2.0.0
	 */
	public function getPresetUid() {
		return $this->getSettingsItem( 'presetUid', md5( $this->getId() ) );
	}

	/**
	 * Get vote scale.
	 *
	 * @return int
	 * @since 2.0.0
	 */
	public function getVoteScale() {
		return (int) $this->getSettingsItem( 'vote.scale', 5 );
	}

	/**
	 * Get vote type.
	 *
	 * @return string
	 * @since 2.0.0
	 */
	public function getVoteType() {
		return $this->getSettingsItem( 'vote.type', 'count' );
	}

	/**
	 * Get vote criteria.
	 *
	 * @return array
	 * @since 2.0.0
	 */
	public function getVoteCriteria() {
		return (array) $this->getSettingsItem( 'vote.criteria', [] );
	}

	/**
	 * Get votes count from log.
	 *
	 * @return int
	 * @since 2.0.0
	 */
	public function getVotesFromLogs() {
		return TotalContest( 'log.repository' )->count( [
			'conditions' => [
				'contest_id' => $this->getId(),
				'action'     => 'vote',
				'status'     => 'accepted'
			]
		] );
	}

	/**
	 * Get contest votes count.
	 *
	 * @return int
	 * @since 1.0.0
	 */
	public function getVotes() {
		return (int) $this->getMetadata( '_tc_votes' );
	}

	/**
	 * Get contest votes formatted number.
	 *
	 * @return string
	 * @since 2.0.0
	 */
	public function getVotesNumber() {
		return number_format( $this->getVotes() );
	}

	/**
	 * Get contest votes with label.
	 * @return string
	 * @since 2.0.0
	 */
	public function getVotesWithLabel() {
		return sprintf( _n( '%s Vote', '%s Votes', $this->getVotes(), 'totalcontest' ), number_format( $this->getVotes() ) );
	}

	/**
	 * Is contest vote is rate.
	 *
	 * @return bool
	 * @since 2.0.0
	 */
	public function isRateVoting() {
		return $this->getVoteType() === 'rate';
	}

	/**
	 * Is contest vote is count.
	 *
	 * @return bool
	 * @since 2.0.0
	 */
	public function isCountVoting() {
		return $this->getVoteType() === 'count';
	}

	/**
	 * Is contest accepting submissions.
	 *
	 * @return bool
	 * @since 1.0.0
	 */
	public function isAcceptingSubmissions() {
		$limited = $this->getLimitations()->check();
		if ( $limited instanceof \WP_Error ):
			$this->error = $limited;

			return false;
		else:
			$restricted = $this->getRestrictions()->check();
			if ( $restricted instanceof \WP_Error ):
				$this->error = $restricted;

				return false;
			endif;
		endif;

		/**
		 * Filters whether the contest is accepting new submissions or not.
		 *
		 * @param bool $acceptSubmission True when new submissions are accepted otherwise false.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return bool
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/accept-submissions', ! is_wp_error( $this->error ), $this );
	}

	/**
	 * Render contest.
	 *
	 * @return string
	 * @since 1.0.0
	 */
	public function render() {
		if ( $this->isPasswordProtected() ):
			return '';
		endif;

		$renderer = TotalContest( 'contests.renderer' );
		$renderer->setContest( $this );
		$renderer->setSubmission( null );

		return $renderer;
	}

	/**
	 * Get contest permalink.
	 *
	 * @return string
	 * @since 2.0.0
	 */
	public function getPermalink() {
		if ( Misc::isRestRequest() ):
			return get_rest_url( null, TotalContest()->env( 'rest-namespace' ) . '/contest/' . $this->getId() . '/' );
		endif;

		return get_permalink( $this->contestPost );
	}

	/**
	 * JSON representation of contest.
	 *
	 * @return array
	 * @since 2.0.0
	 */
	public function jsonSerialize() {
		return $this->toArray();
	}

	/**
	 * @return bool
	 */
	public function isPasswordProtected() {
		return post_password_required( $this->contestPost );
	}

	/**
	 * Get the instance as an array.
	 *
	 * @return array
	 * @since 2.0.0
	 */
	public function toArray() {
		$contestAsArray = [
			'id'        => $this->getId(),
			'permalink' => $this->getPermalink(),
			'title'     => $this->getTitle() ?: 'Contest #' . $this->getId(),
			'menu'      => $this->getMenuItems(),
			'pages'     => $this->getCustomPages(),
			'forms'     => [
				'participate' => $this->getFormFields(),
			],
			'settings'  => [
				'design'  => $this->getSettingsItem( 'design' ),
				'vote'    => $this->isCountVoting() ? [ 'type' => 'count' ] : [
					'type'     => 'rate',
					'scale'    => $this->getVoteScale(),
					'criteria' => $this->getVoteCriteria(),
				],
				'sharing' => $this->getShareAttributes(),
			],
		];

		if ( is_admin() ):
			$contestAsArray['admin'] = [
				'editLink' => $this->getAdminEditLink(),
			];
		endif;

		/**
		 * Filters the array representation of contest.
		 *
		 * @param bool $contestAsArray Contest as array.
		 * @param \TotalContest\Contracts\Contest\Model $contest Contest model object.
		 *
		 * @return bool
		 * @since 2.0.0
		 */
		return apply_filters( 'totalcontest/filters/contest/array', $contestAsArray, $this );
	}

	/**
	 * @return string
	 */
	public function __toString() {
		return (string) $this->render();
	}

	/**
	 * Get landing url.
	 *
	 * @return mixed
	 */
	public function getLandingUrl( $args = [] ) {
		return $this->getUrl( Arrays::parse( [ 'action' => 'landing' ], $args ) );
	}

	/**
	 * Get landing ajax url.
	 *
	 * @param array $args
	 *
	 * @return mixed
	 */
	public function getLandingAjaxUrl( $args = [] ) {
		return $this->getAjaxUrl( Arrays::parse( [ 'action' => 'landing' ], $args ) );
	}

	/**
	 * Get participate url.
	 *
	 * @param array $args
	 *
	 * @return mixed
	 */
	public function getParticipateUrl( $args = [] ) {
		return $this->getUrl( Arrays::parse( [ 'action' => 'participate' ], $args ) );
	}

	/**
	 * Get participate ajax url.
	 *
	 * @param array $args
	 *
	 * @return mixed
	 */
	public function getParticipateAjaxUrl( $args = [] ) {
		return $this->getAjaxUrl( Arrays::parse( [ 'action' => 'participate' ], $args ) );
	}

	/**
	 * Get submissions url.
	 *
	 * @param array $args
	 *
	 * @return mixed
	 */
	public function getSubmissionsUrl( $args = [] ) {
		return $this->getUrl( Arrays::parse( [ 'action' => 'submissions' ], $args ) );
	}

	/**
	 * Get submissions ajax url.
	 *
	 * @param array $args
	 *
	 * @return mixed
	 */
	public function getSubmissionsAjaxUrl( $args = [] ) {
		return $this->getAjaxUrl( Arrays::parse( [ 'action' => 'submissions' ], $args ) );
	}

	/**
	 * Get custom page url.
	 *
	 * @param $pageId
	 *
	 * @return mixed
	 */
	public function getCustomPageUrl( $pageId, $args = [] ) {
		return $this->getUrl( Arrays::parse( [ 'action' => 'content', 'customPage' => $pageId ], $args ) );
	}

	/**
	 * Get custom page ajax url.
	 *
	 * @param $pageId
	 *
	 * @return mixed
	 */
	public function getCustomPageAjaxUrl( $pageId, $args = [] ) {
		return $this->getAjaxUrl( Arrays::parse( [ 'action' => 'content', 'customPage' => $pageId ], $args ) );
	}

	/**
	 * Get log page in WordPress dashboard.
	 * @return string
	 */
	public function getAdminLogLink() {
		return admin_url( "edit.php?post_type=contest&page=log&contest={$this->getId()}" );
	}

	/**
	 * Get submissions page in WordPress dashboard.
	 * @return string
	 */
	public function getAdminSubmissionsLink() {
		return admin_url( "edit.php?post_type=contest_submission&contest={$this->getId()}" );
	}

	/**
	 * Edit link in WordPress dashboard.
	 * @return string
	 */
	public function getAdminEditLink() {
		return get_edit_post_link( $this->getId(), '' );
	}

	/**
	 * Is current screen.
	 *
	 * @param $screen string Screen name.
	 *
	 * @return bool
	 * @since 1.0.0
	 */
	public function isScreen( $screen ) {
		return $this->screen === $screen;
	}

	/**
	 * Is landing screen.
	 *
	 * @return bool
	 * @since 1.0.0
	 */
	public function isLandingScreen() {
		return $this->isScreen( 'contest.landing' );
	}

	/**
	 * Is participate screen.
	 *
	 * @return bool
	 * @since 1.0.0
	 */
	public function isParticipateScreen() {
		return $this->isScreen( 'contest.participate' );
	}

	/**
	 * Is submissions screen.
	 *
	 * @return bool
	 * @since 1.0.0
	 */
	public function isSubmissionsScreen() {
		return $this->isScreen( 'contest.submissions' );
	}

	/**
	 * Is submission screen.
	 *
	 * @return bool
	 * @since 1.0.0
	 */
	public function isSubmissionScreen() {
		return $this->isScreen( 'submission.view' );
	}

	/**
	 * Is custom page screen.
	 *
	 * @param string $pageId
	 *
	 * @return bool
	 * @since 1.0.0
	 */
	public function isCustomPageScreen( $pageId = null ) {
		return $this->isScreen( 'contest.content' ) && ( empty( $pageId ) || $this->isCustomPage( $pageId ) );
	}

	/**
	 * Is content page.
	 *
	 * @param $pageId
	 *
	 * @return bool
	 */
	public function isCustomPage( $pageId ) {
		return $this->customPage && $this->customPage === $pageId;
	}

	/**
	 * Get received votes.
	 *
	 * @return int
	 * @since 2.0.0
	 */
	public function getReceivedVotes() {
		return $this->receivedVotes;
	}

	/**
	 * Increment votes.
	 *
	 * @param int $by
	 *
	 * @return int
	 * @since 2.0.0
	 */
	public function incrementVotes( $by = 1 ) {
		$this->receivedVotes += (int) $by;
		$this->incrementMetadata( '_tc_votes', $by );

		return $this->receivedVotes;
	}


	/**
	 * @return bool
	 */
	public function save() {
		// Remove WP filters
		if ( function_exists( 'wp_remove_targeted_link_rel_filters' ) ) {
			wp_remove_targeted_link_rel_filters();
		}

		return ! is_wp_error(
			wp_update_post( [
				'ID'           => $this->getId(),
				'post_content' => wp_slash( json_encode( $this->attributes, JSON_UNESCAPED_SLASHES ) ),
			] )
		);
	}

	public function getContext() {
		return $this->context ?: get_post_type();
	}

	public function setContext( $context ) {
		$this->context = $context;

		return $this;
	}

	/**
	 * @return string
	 */
	public function getSortBy() {
		return $this->sortBy;
	}

	/**
	 * @return string
	 */
	public function getSortDirection() {
		return $this->sortDirection;
	}
}