File: /storage/v6964/gopalak/public_html/wp-content/plugins/totalcontest-lite/src/Submission/Model.php
<?php
namespace TotalContest\Submission;
use DateInterval;
use TotalContest\Contracts\Submission\Model as ModelContract;
use TotalContestVendors\TotalCore\Contracts\Form\Field;
use TotalContestVendors\TotalCore\Contracts\Form\Form;
use TotalContestVendors\TotalCore\Contracts\Helpers\DateTime;
use TotalContestVendors\TotalCore\Helpers\Arrays;
use TotalContestVendors\TotalCore\Helpers\Misc;
use TotalContestVendors\TotalCore\Helpers\Strings;
use TotalContestVendors\TotalCore\Traits\Cookies;
use TotalContestVendors\TotalCore\Traits\Metadata;
/**
* Submission model
*
* @package TotalContest\Submission
*/
class Model implements ModelContract {
use Metadata, Cookies;
/**
* Submission ID.
*
* @var int|null
* @since 2.0.0
*/
protected $id = null;
/**
* Submission attributes.
*
* @var array|null
* @since 2.0.0
*/
protected $attributes = null;
/**
* Submission date.
*
* @var DateTime
* @since 2.0.0
*/
protected $date = null;
/**
* Contest seo attributes.
*
* @var array|null
* @since 2.0.0
*/
protected $seo = null;
/**
* Received votes.
*
* @var int
* @since 2.0.0
*/
protected $receivedVotes = 0;
/**
* Received views.
*
* @var int
* @since 2.0.0
*/
protected $receivedViews = 0;
/**
* Submission WordPress post.
*
* @var array|null|\WP_Post
* @since 2.0.0
*/
protected $submissionPost = null;
/**
* Submission contest.
*
* @var \TotalContest\Contest\Model
* @since 2.0.0
*/
protected $contest = null;
/**
* Submission vote form.
*
* @var Form $form
* @since 2.0.0
*/
protected $form = null;
/**
* Submission current screen
*
* @var string
* @since 2.0.0
*/
protected $screen = 'submission.view';
/**
* Submission current action
*
* @var string
* @since 2.0.0
*/
protected $action = 'view';
/**
* Limitations
*
* @var \TotalContestVendors\TotalCore\Contracts\Limitations\Bag
* @since 2.0.0
*/
protected $limitations;
/**
* Restrictions
*
* @var \TotalContestVendors\TotalCore\Contracts\Restrictions\Bag
* @since 2.0.0
*/
protected $restrictions;
/**
* Error.
*
* @var null|\WP_Error
* @since 2.0.0
*/
protected $error;
/**
* Model constructor.
*
* @param array $attributes
* @param \TotalContest\Contest\Model $contest
*
* @since 2.0.0
*/
public function __construct( $attributes, $contest ) {
$this->id = $attributes['id'];
$this->submissionPost = $attributes['post'];
$this->date = TotalContest( 'datetime', [ $this->submissionPost->post_date, wp_timezone() ] );
$this->contest = $contest;
// Parse attributes JSON.
$this->attributes = wp_unslash( (array) json_decode( $this->submissionPost->post_content, true ) );
$this->attributes['fields'] = is_string( $this->attributes['fields'] ) ? unserialize( base64_decode( $this->attributes['fields'] ) ) : $this->attributes['fields'];
$this->attributes['contents'] = is_string( $this->attributes['contents'] ) ? unserialize( base64_decode( $this->attributes['contents'] ) ) : $this->attributes['contents'];
/**
* Filters the submission attributes.
*
* @param array $attributes Submission model attributes.
* @param \TotalContest\Submission\Model $submission Submission model object.
* @param \TotalContest\Contest\Model $contest Contest model object.
*
* @return array
* @since 2.0.0
*/
$this->attributes = apply_filters( 'totalcontest/filters/submission/attributes',
$this->attributes,
$this,
$contest );
// Limitations
$this->limitations = new \TotalContestVendors\TotalCore\Limitations\Bag();
$periodArgs = $contest->getSettingsItem( 'vote.limitations.period' );
if ( ! empty( $periodArgs['enabled'] ) ):
$periodArgs['context'] = 'vote';
$this->limitations->add( 'period', new \TotalContest\Limitations\Period( $periodArgs ) );
endif;
$membershipArgs = $contest->getSettingsItem( 'vote.limitations.membership' );
if ( ! empty( $membershipArgs['enabled'] ) ):
$membershipArgs['context'] = 'vote';
$this->limitations->add( 'membership', new \TotalContest\Limitations\Membership( $membershipArgs ) );
endif;
$quotaArgs = $contest->getSettingsItem( 'vote.limitations.quota' );
if ( ! empty( $quotaArgs['enabled'] ) ):
$quotaArgs['context'] = 'vote';
$quotaArgs['currentValue'] = $this->getVotes();
$this->limitations->add( 'quota', new \TotalContest\Limitations\Quota( $quotaArgs ) );
endif;
/**
* Fires after limitations setup.
*
* @param \TotalContest\Submission\Model $contest Submission model object.
*
* @since 2.0.0
*/
do_action( 'totalcontest/actions/submission/limitations', $this, $contest, $this->limitations );
$this->restrictions = new \TotalContestVendors\TotalCore\Restrictions\Bag();
$frequencyArgs = $contest->getSettingsItem( 'vote.frequency', [ 'timeout' => 3600 ] );
$frequencyArgs['contest'] = $contest;
$frequencyArgs['submission'] = $this;
$frequencyArgs['action'] = 'vote';
$frequencyArgs['fullCheck'] = TotalContest()->option( 'performance.fullChecks.enabled' );
$frequencyArgs['categoryAware'] = $contest->hasCategoryField();
$frequencyArgs['preventSelfVote'] = $contest->getSettingsItem( 'vote.frequency.preventSelfVote', false );
$frequencyArgs['message'] = esc_html__( 'You cannot vote again.', '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\Submission\Model $submission Submission model object.
* @param array $frequencyArgs Frequency arguments.
*
* @since 2.0.0
*/
do_action( 'totalcontest/actions/submission/restrictions', $this, $frequencyArgs );
/**
* Fires after submission model setup is completed.
*
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @since 2.0.0
*/
do_action( 'totalcontest/actions/submission/setup', $this );
}
/**
* Get submissions votes count.
*
* @return int
* @since 2.0.0
*/
public function getVotes() {
return absint( $this->getMetadata( '_tc_votes' ) );
}
/**
* Get submission votes formatted number.
*
* @return string
* @since 2.0.0
*/
public function getVotesNumber() {
return number_format( $this->getVotes() );
}
/**
* Get submission 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() ) );
}
/**
* Get contest id.
*
* @return int
* @since 2.0.0
*/
public function getId() {
return (int) $this->id;
}
/**
* Get contest date diff.
*
* @return DateInterval
* @since 2.0.0
*/
public function getDateDiff() {
$now = TotalContest( 'datetime', [ 'now', wp_timezone() ] );
return $now->diff( $this->getDate(), true );
}
/**
* Get contest date diff.
*
* @return string
* @since 2.0.0
*/
public function getDateDiffForHuman() {
$diff = $this->getDateDiff();
if ( $diff->y > 0 ):
return $diff->format( _n( '%y Year', '%y Years', $diff->y, 'totalcontest' ) );
elseif ( $diff->m > 0 ):
return $diff->format( _n( '%m Month', '%m Months', $diff->m, 'totalcontest' ) );
elseif ( $diff->d > 0 ):
return $diff->format( _n( '%d Day', '%d Days', $diff->d, 'totalcontest' ) );
elseif ( $diff->h > 0 ):
return $diff->format( _n( '%h Hour', '%h Hours', $diff->h, 'totalcontest' ) );
elseif ( $diff->i > 0 ):
return $diff->format( _n( '%i Minute', '%i Minutes', $diff->i, 'totalcontest' ) );
else:
return $diff->format( _n( '%s Second', '%s Seconds', $diff->s, 'totalcontest' ) );
endif;
}
/**
* Get submission content.
*
* @return string
* @since 2.0.0
*/
public function getContent() {
if ( $this->contest->isUsingBlocks() ) {
$content = '';
foreach ( $this->getBlocks() as $block ):
$block['source'] = empty( $block['source'] ) ? '' : $block['source'];
$content .= '<div class="totalcontest-submission-content-block totalcontest-submission-content-block-type-' . esc_attr( $block['type'] ) . ' ' . esc_attr( $block['class'] ) . '">';
if ( $block['type'] === 'text' ):
$content .= "<p>{$block['html']}</p>";
elseif ( $block['type'] === 'title' ):
$content .= "<h3>{$block['html']}</h3>";
elseif ( $block['type'] === 'subtitle' ):
$content .= "<p>{$block['html']}</p>";
elseif ( $block['type'] === 'image' ):
if ( strtolower( $block['source'] ) === 'custom' ) :
$content .= '<img style="max-width: 100%" src="' . esc_attr( $block['html'] ) . '" />';
else:
$content .= $block['html'];
endif;
elseif ( $block['type'] === 'embed' ):
$content .= $block['html'];
else:
$content .= $block['html'];
endif;
$content .= '</div>';
endforeach;
} else {
$content = Strings::template(
$this->contest->getSettingsItem( 'contest.submissions.content' ),
$this->getBindings()
);
}
$content = do_shortcode( $GLOBALS['wp_embed']->run_shortcode( $content ) );
/**
* Filters the submission content.
*
* @param mixed $content Content.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return mixed
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/content', $content, $this );
}
/**
* Get submission attributes.
*
* @return array|null
* @since 2.0.0
*/
public function getAttributes() {
return $this->attributes;
}
/**
* Get attributes section or item.
*
* @param mixed $attribute Attribute name or dot notation representation
* @param null $default Default value to return when setAttribute is missing
*
* @return array|mixed|null
* @since 2.0.0
*/
public function getAttribute( $attribute, $default = null ) {
/**
* Filters the submission attribute.
*
* @param mixed $value Attribute value.
* @param array $attributes Attributes.
* @param string $default Default value.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return mixed
* @since 2.0.0
*/
return apply_filters( "totalcontest/filters/submission/attribute/{$attribute}",
Arrays::getDotNotation( $this->attributes, $attribute, $default ),
$this->attributes,
$default,
$this );
}
/**
* Get field content.
*
* @param $field
* @param null $default
*
* @return array|mixed|null
*/
public function getFieldContent( $field, $default = null ) {
if ( $this->getAttribute( "contents.$field.type" ) === 'attachment' ):
$value = $this->getAttribute( "contents.$field.attachment.url" );
endif;
if ( empty( $value ) ):
$value = $this->getAttribute( "fields.$field", $default );
endif;
if ( $field === 'category' && is_numeric( $value ) ):
return get_term( $value )->name;
endif;
if ( is_array( $value ) ):
return implode( ', ', $value );
endif;
return $value;
}
/**
* Get field.
*
* @param $field
* @param null $default
*
* @return array|mixed|null
*/
public function getField( $field, $default = null ) {
$value = $this->getAttribute( "fields.$field", $default );
if ( $field === 'category' && is_numeric( $value ) ):
return get_term( $value )->name;
endif;
return $value;
}
/**
* Get fields.
*
* @return array
* @since 2.0.0
*/
public function getFields() {
return (array) $this->getAttribute( 'fields', [] );
}
/**
* Get visible fields.
*
* @return array
* @since 2.0.0
*/
public function getVisibleFields() {
$fields = array_diff_key( $this->getFields(),
[
'action' => true,
'contestId' => true,
'category' => true,
] );
$formFields = $this->getContest()
->getFormFieldsDefinitions();
foreach ( $formFields as $field ):
if ( ! empty( $fields[ $field['name'] ] ) && in_array( $field['type'], [ 'image', 'video', 'audio' ] ) ):
$fields[ $field['name'] ] = wp_get_attachment_url( $fields[ $field['name'] ] );
endif;
if ( ! empty( $fields["{$field['name']}_url"] ) ):
$fields[ $field['name'] ] = $fields["{$field['name']}_url"];
endif;
if ( isset( $fields["{$field['name']}_url"] ) ):
unset( $fields["{$field['name']}_url"] );
endif;
endforeach;
return $fields;
}
/**
* Get bindings.
*
* @return array
* @since 1.1.0
*/
public function getBindings() {
$date = $this->getDate()
->toArray();
$contents = $this->getAttribute( 'contents', [] );
foreach ( $contents as $fieldId => $content ) {
if ( $content['type'] === 'attachment' && ! empty( $content['attachment']['id'] ) ) {
$metadata = maybe_unserialize( wp_get_attachment_metadata( $content['attachment']['id'] ) );
$contents[ $fieldId ]['sizes'] = [];
foreach ( maybe_unserialize( $metadata['sizes'] ?? [] ) as $size => $details ) {
$details['url'] = wp_get_attachment_image_url( $content['attachment']['id'],
$size );
$contents[ $fieldId ]['sizes'][ $size ] = $details;
}
}
}
$bindings = [
'id' => $this->getId(),
'contest' => $this->getContest()
->getTitle(),
'title' => $this->getTitle() ?: esc_html__( 'Submission #', 'totalcontest' ) . $this->getId(),
'sitename' => get_bloginfo( 'name' ),
'user' => $this->getAuthor()
->to_array(),
'fields' => $this->getAttribute( 'fields', [] ),
'contents' => $contents,
'date' => $date['date'],
'time' => $date['time'],
'datetime' => $date['datetime'],
'dateArray' => $date,
'category' => ( $this->getCategory() ?: new \WP_Term( new \stdClass() ) )->to_array(),
'views' => $this->getViews(),
'viewsWithLabel' => $this->getViewsWithLabel(),
'votes' => $this->getVotes(),
'votesWithLabel' => $this->getVotesWithLabel(),
'percentage' => $this->getPercentage(),
'percentageWithLabel' => $this->getPercentageWithLabel(),
'rate' => $this->getRateNumber(),
'rateWithLabel' => $this->getRateWithLabel(),
];
/**
* Filters the bindings.
*
* @param array $bindings Bindings.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return array
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/bindings', $bindings, $this );
}
/**
* @return \WP_Post
*/
public function getSubmissionPost() {
return $this->submissionPost;
}
/**
* Get contest.
*
* @return null|string|\TotalContest\Contest\Model
* @since 2.0.0
*/
public function getContest() {
return $this->contest;
}
/**
* Get submission title.
*
* @return string
* @since 2.0.0
*/
public function getTitle() {
return wp_kses_post( Strings::template( $this->contest->getSettingsItem( 'contest.submissions.title' ),
apply_filters(
'totalcontest/filters/submission/bindings',
[
'id' => $this->getId(),
'contest' => $this->getContest()
->getTitle(),
'title' => $this->submissionPost->post_title,
'sitename' => get_bloginfo( 'name' ),
'user' => $this->getAuthor()
->to_array(),
'fields' => $this->getAttribute( 'fields', [] ),
'date' => $this->getDate()
->toArray(),
'category' => ( $this->getCategory() ?: new \WP_Term( new \stdClass() ) )->to_array(),
'views' => $this->getViews(),
'votes' => $this->getVotes(),
'votesWithLabel' => $this->getVotesWithLabel(),
'rate' => $this->getRate(),
'rateWithLabel' => $this->getRateWithLabel(),
],
$this
),
$this->submissionPost->post_title ) );
}
/**
* Get contest date.
*
* @return DateTime
* @since 2.0.0
*/
public function getDate() {
return $this->date;
}
/**
* Get submission views count.
*
* @return int
* @since 2.0.0
*/
public function getViews() {
return (int) $this->getMetadata( '_tc_views' );
}
/**
* Get submission views formatted number.
*
* @return string
* @since 2.0.0
*/
public function getViewsNumber() {
return number_format( $this->getViews() );
}
/**
* Get submission views with label.
*
* @return string
* @since 2.0.0
*/
public function getViewsWithLabel() {
return sprintf( _n( '%s View', '%s Views', $this->getViews(), 'totalcontest' ),
number_format( $this->getViews() ) );
}
/**
* Get percentage of votes.
*
* @return float
*/
public function getPercentage() {
if ( $this->contest->getVotes() === 0 ) {
return 0;
}
return round( ( $this->getVotes() / $this->contest->getVotes() * 100 ), 2 );
}
/**
* Get percentage of votes with label.
*
* @return string
*/
public function getPercentageWithLabel() {
if ( $this->contest->getVotes() === 0 ) {
return '0%';
}
return round( ( $this->getVotes() / $this->contest->getVotes() * 100 ), 2 ) . '%';
}
/**
* Get rate.
*
* @return float
* @since 2.0.0
*/
public function getRate() {
return (float) $this->getMetadata( '_tc_rate' );
}
/**
* Get submission rate formatted number.
*
* @return string
* @since 2.0.0
*/
public function getRateNumber() {
return number_format( $this->getRate(), 1 );
}
/**
* Get submission rate with label.
*
* @return string
* @since 2.0.0
*/
public function getRateWithLabel() {
$scale = $this->getContest()
->getVoteScale();
return sprintf( esc_html__( '%s of %s', 'totalcontest' ), $this->getRateNumber(), $scale );
}
/**
* Get submission permalink.
*
* @return false|string
* @since 2.0.0
*/
public function getPermalink( $args = [] ) {
if ( Misc::isRestRequest() ):
return get_rest_url( null, TotalContest()->env( 'rest-namespace' ) . '/submission/' . $this->getId() );
endif;
return $this->getUrl();
}
/**
* Edit link in WordPress dashboard.
*
* @return string
*/
public function getAdminEditLink() {
return get_edit_post_link( $this->getId(), '' );
}
/**
* Get thumbnail url.
*
* @return string
* @since 2.0.0
*/
public function getThumbnailUrl() {
$contest = $this->getContest();
$source = $contest->getSettingsItem( 'contest.submissions.preview.source' );
$noPreview = $contest->getSettingsItem( 'contest.submissions.preview.default' ) ?: TotalContest()->env( 'url' ) . 'assets/dist/images/no-preview.png';
if ( empty( $noPreview ) ):
$noPreview = wp_get_attachment_url( get_post_thumbnail_id( $this->submissionPost ) );
endif;
$thumbnail = $this->getAttribute( "contents.{$source}.thumbnail.url" ) ?: wp_get_attachment_url( get_post_thumbnail_id( $this->getAttribute( "contents.{$source}.thumbnail.id" ) ) ) ?: $noPreview;
/**
* Filters the submission thumbnail.
*
* @param string $thumbnail Submission thumbnail.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return string
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/thumbnail', $thumbnail, $this );
}
/**
* Get preview
*/
public function getPreview() {
$source = $this->getContest()
->getSettingsItem( 'contest.submissions.preview.source' );
$preview = (string) $this->getAttribute( "contents.{$source}.preview" );
$preview = do_shortcode( $preview );
if ( empty( $preview ) ):
$preview = sprintf( '[totalcontest-image src="%s"]', $this->getThumbnailUrl() );
$preview = do_shortcode( $preview );
endif;
/**
* Filters the submission preview.
*
* @param string $thumbnail Submission preview.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return string
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/preview', $preview, $this );
}
/**
* Get category term object.
*
* @return \WP_Term|null
*/
public function getCategory() {
$category = get_term( $this->getAttribute( 'fields.category' ) );
$terms = wp_get_post_terms( $this->submissionPost->ID, 'submission_category' );
if ( ! empty( $terms[0] ) ) {
$category = $terms[0];
}
$category = $category instanceof \WP_Error || ! $category ? null : $category;
/**
* Filters the submission category.
*
* @param \WP_Term|null $category Submission category term.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return string
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/category', $category, $this );
}
/**
* Get category name.
*
* @return string|null
*/
public function getCategoryName() {
$category = $this->getCategory();
return $category ? $category->name : null;
}
/**
* Get submission type.
*
* @return string
* @since 2.0.0
*/
public function getType() {
return $this->getAttribute( 'type', $this->contest->getSettingsItem( 'contest.participate.type' ) );
}
/**
* Get meta information.
*
* @return string
* @since 2.0.0
*/
public function getSubtitle() {
return wp_kses_post( Strings::template( $this->contest->getSettingsItem( 'contest.submissions.subtitle' ),
$this->getBindings() ) );
}
/**
* Get seo attributes.
*
* @return array
* @since 2.0.0
*/
public function getSeoAttributes() {
if ( $this->seo === null ):
$bindings = $this->getBindings();
$this->seo = [
'title' => Strings::template( $this->getContest()
->getSettingsItem( 'seo.submission.title' ),
$bindings ) ?: $this->getTitle(),
'description' => Strings::template( $this->getContest()
->getSettingsItem( 'seo.submission.description' ),
$bindings ) ?: $this->getSubtitle(),
];
$this->seo = array_map( 'wp_strip_all_tags', $this->seo );
endif;
/**
* Filters the submission seo attributes.
*
* @param array $seo SEO attributes.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return array
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/seo', $this->seo, $this );
}
/**
* Get ratings.
*
* @return array
* @since 2.0.0
*/
public function getRatings() {
$scale = $this->getContest()
->getVoteScale();
$criteria = $this->getContest()
->getVoteCriteria();
foreach ( $criteria as $criterionIndex => $criterion ):
$criteria[ $criterionIndex ]['value'] = number_format( (float) $this->getMetadata( "_tc_{$criterionIndex}:{$scale}_rate" ),
1 );
endforeach;
/**
* Filters the submission ratings.
*
* @param array $criteria Submission ratings.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return string
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/ratings', $criteria, $this );
}
/**
* Get detailed ratings.
*
* @return array
* @since 2.0.0
*/
public function getDetailedRatings() {
$scale = $this->getContest()
->getVoteScale();
$criteria = $this->getContest()
->getVoteCriteria();
foreach ( $criteria as $criterionIndex => $criterion ):
$criterionVotes = (int) $this->getMetadata( "_tc_{$criterionIndex}:{$scale}_votes" );
$criterionCumulative = (int) $this->getMetadata( "_tc_{$criterionIndex}:{$scale}_cumulative" );
$criterionRate = (float) $criterionCumulative / ( $criterionVotes === 0 ? 1 : $criterionVotes );
$criteria[ $criterionIndex ]['scale'] = $scale;
$criteria[ $criterionIndex ]['votes'] = $criterionVotes;
$criteria[ $criterionIndex ]['cumulative'] = $criterionCumulative;
$criteria[ $criterionIndex ]['rate'] = $criterionRate;
endforeach;
/**
* Filters the submission ratings.
*
* @param array $criteria Submission ratings.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return string
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/detailed-ratings', $criteria, $this );
}
/**
* Is submission embeddable.
*/
public function isEmbeddable() {
return strpos( $this->submissionPost->post_content, '[embed]' ) !== false;
}
/**
* Is submission approved.
*
* @return bool
* @since 2.0.0
*/
public function isApproved() {
$approved = $this->submissionPost->post_status === 'publish';
/**
* Filters the submission approval state.
*
* @param bool $approved True when approved otherwise false.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return bool
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/approved', $approved, $this );
}
/**
* Is submission accepting votes.
*
* @return bool
* @since 2.0.0
*/
public function isAcceptingVotes() {
$limited = $this->getLimitations()
->check();
if ( $limited instanceof \WP_Error ):
$this->error = $limited;
else:
$restricted = $this->getRestrictions()
->check();
if ( $restricted instanceof \WP_Error ):
$this->error = $restricted;
endif;
endif;
if ( $this->isWinner() ):
$this->error = new \WP_Error( 'winner', esc_html__( 'You cannot vote for winners.', 'totalcontest' ) );
endif;
/**
* Filters whether the submission is accepting new votes or not.
*
* @param bool $acceptVotes True when new votes are accepted otherwise false.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return bool
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/accept-vote', ! is_wp_error( $this->error ), $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;
}
/**
* Is a winning submission.
*
* @return bool
* @since 2.0.0
*/
public function isWinner() {
return (bool) $this->getAttribute( 'designation.winner', false );
}
/**
* 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 );
}
/**
* Get error message.
*
* @return mixed|null|string
*/
public function getErrorMessage() {
return $this->error instanceof \WP_Error ? $this->error->get_error_message() : null;
}
/**
* @return bool
*/
public function hasError() {
return ! empty( $this->error );
}
/**
* Whether the current user owns the submission.
*
* @return bool
* @since 2.0.0
*/
public function isOwner() {
$viaUser = get_current_user_id() === (int) $this->submissionPost->post_author;
$viaCookie = $this->getAttribute( 'token' ) === $this->getCookie( $this->getContest()
->getPrefix( "token_{$this->getId()}" ) );
/**
* Filters whether the submission is owned by the current user or not.
*
* @param bool $owned True when is owned by current user otherwise false.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return bool
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/owner', $viaUser || $viaCookie, $this );
}
/**
* Get submission's author.
*
* @return \WP_User
* @since 1.2.0
*/
public function getAuthor() {
return new \WP_User( $this->submissionPost->post_author );
}
/**
* Get vote form.
*
* @return Form Form object
* @since 2.0.0
*/
public function getForm() {
return $this->form;
}
/**
* Set vote form.
*
* @param Form $form
*
* @return Form Form object
* @since 2.0.0
*/
public function setForm( Form $form ) {
return $this->form = $form;
}
/**
* 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 submission form fields.
*
* @param array $fields Submission custom fields.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return array
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/fields', $fields, $this );
}
/**
* Get submission URL with arguments.
*
* @param array $args
*
* @return string
* @since 2.0.0
*/
public function getUrl( $args = [] ) {
$args['action'] = 'submission';
$args['submissionId'] = $this->getId();
return $this->getContest()
->getUrl( $args );
}
/**
* Get AJAX url.
*
* @param array $args
*
* @return string
*/
public function getAjaxUrl( $args = [] ) {
$args['action'] = 'submission';
$args['submissionId'] = $this->getId();
return $this->getContest()
->getAjaxUrl( $args );
}
/**
* Get prefix.
*
* @param string $append
*
* @return string
* @since 2.0.0
*/
public function getPrefix( $append = '' ) {
return $this->getContest()
->getPrefix( "{$this->getId()}_{$append}" );
}
/**
* Get current screen.
*
* @return string Current screen.
* @since 2.0.0
*/
public function getScreen() {
return $this->screen;
}
/**
* Set current screen.
*
* @param $screen string Screen name.
*
* @return $this
* @since 2.0.0
*/
public function setScreen( $screen ) {
$this->screen = esc_html( (string) $screen );
return $this;
}
/**
* Get share attributes.
*
* @return array
* @since 2.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\Contest\Model $contest Contest model object.
*
* @return array
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/share',
array_intersect_key( $websitesUrls, $websites ),
$this );
}
/**
* Get template instance.
*
* @return mixed
* @since 1.4.0
*/
public function getTemplateId() {
return $this->getContest()
->getTemplateId();
}
/**
* @param $expressions
*
* @return string
* @since 2.1.0
*/
protected function compileExpressions( $expressions ) {
$template = '';
foreach ( $expressions as $expression ):
if ( $expression['type'] === 'val' ):
$template .= $expression['source'];
else:
$template .= "{{{$expression['source']}||''}}";
endif;
endforeach;
return $template;
}
/**
* @return mixed
* @since 2.1.0
*/
public function getBlocks() {
$blocks = $this->contest->getBlocksDefinitions();
foreach ( $blocks as &$block ):
$block['class'] = '';
if ( $block['type'] === 'text' || $block['type'] === 'title' || $block['type'] === 'subtitle' ):
$block['html'] = Strings::template( $this->compileExpressions( $block['expressions'] ),
$this->getBindings(),
'' );
elseif ( $block['type'] === 'image' ):
if ( $block['source'] === '' ):
$preview = sprintf( '[totalcontest-image src="%s"]',
TotalContest()->env( 'url' ) . 'assets/dist/images/no-preview.png' );
$block['html'] = do_shortcode( $preview );
elseif ( $block['source'] === 'custom' ):
$block['html'] = $block['custom'];
else:
$block['fallback'] = empty( $block['fallback'] ) ? null : (string) $block['fallback'];
$source = str_replace( 'thumbnail.url', 'thumbnail.id', $block['source'] ?: '' );
$preview = '';
if ( ! $this->getAttribute( $source ) ) {
$source = $block['source'] ?: '';
}
if ( ! empty( $source ) && strstr( $source, 'thumbnail.id' ) !== false ) {
$preview = sprintf( '[totalcontest-image id="%s" size="thumbnail"]',
$this->getAttribute( $source ) );
}
if ( empty( $preview ) ) {
$preview = sprintf( '[totalcontest-image src="%s"]',
$this->getAttribute( $source ) ?: $block['fallback'] );
}
$preview = do_shortcode( $preview );
if ( empty( $preview ) ):
$preview = sprintf( '[totalcontest-image src="%s"]', $block['fallback'] );
$preview = do_shortcode( $preview );
endif;
$block['html'] = $preview;
endif;
elseif ( $block['type'] === 'embed' ):
$block['html'] = $GLOBALS['wp_embed']->run_shortcode( $this->getAttribute( $block['source'] ) );
if ( ! empty( $block['aspectRatio'] ) ):
$block['class'] = "has-aspect-ratio aspect-ratio-{$block['aspectRatio']}";
endif;
elseif ( $block['type'] === 'raw' ):
$html = Strings::template( $this->compileExpressions( $block['expressions'] ),
$this->getBindings(),
'' );
$block['html'] = wp_specialchars_decode( wp_kses( $html, 'data' ) );
$block['html'] = do_shortcode( $block['html'] );
endif;
endforeach;
return $blocks;
}
/**
* Render submission.
*
* @return string
* @since 2.0.0
*/
public function render() {
$contest = $this->getContest();
$contest = $contest->setScreen( 'submission.view' );
$renderer = $contest->render();
if ( $renderer ):
$renderer->setSubmission( $this );
endif;
return (string) $renderer;
}
/**
* JSON representation of submission.
*
* @return array
* @since 2.0.0
*/
#[\ReturnTypeWillChange]
public function jsonSerialize() {
return $this->toArray();
}
/**
* Get the instance as an array.
*
* @return array
* @since 2.0.0
*/
public function toArray() {
$bindings = $this->getBindings();
$submissionBindings = [];
$submissionBindings['category'] = $bindings['category'];
$submissionBindings['contents'] = $bindings['contents'];
$submissionBindings['fields'] = $bindings['fields'];
$submissionBindings['views'] = $bindings['views'];
$submissionBindings['viewsWithLabel'] = $bindings['viewsWithLabel'];
$submissionBindings['votes'] = $bindings['votes'];
$submissionBindings['votesWithLabel'] = $bindings['votesWithLabel'];
$submissionBindings['percentage'] = $bindings['percentage'];
$submissionBindings['percentageWithLabel'] = $bindings['percentageWithLabel'];
$submissionBindings['rate'] = $bindings['rate'];
$submissionBindings['rateWithLabel'] = $bindings['rateWithLabel'];
$submissionBindings['date'] = $bindings['date'];
$submissionBindings['time'] = $bindings['time'];
$submissionBindings['datetime'] = $bindings['datetime'];
$submissionAsArray = [
'id' => $this->getId(),
'permalink' => $this->getPermalink(),
'title' => $this->getTitle(),
'subtitle' => $this->getSubtitle(),
'datetime' => $this->getDate()
->toArray(),
'author' => $this->getAuthor()->display_name,
'votes' => [
'count' => $this->getVotes(),
'rate' => $this->getRate(),
'scale' => $this->getContest()
->getVoteScale(),
'type' => $this->getContest()
->getVoteType(),
'criteria' => $this->getDetailedRatings(),
],
'approved' => $this->isApproved(),
'winner' => $this->isWinner(),
'owner' => $this->isOwner(),
'category' => $this->getCategoryName(),
'content' => $this->getContent(),
'preview' => $this->getPreview(),
'thumbnail' => $this->getThumbnailUrl(),
'actions' => [
'vote' => $this->isAcceptingVotes(),
],
'forms' => [
'vote' => $this->getFormFields(),
],
'bindings' => $submissionBindings,
];
$noPreview = $this->getContest()
->getSettingsItem( 'contest.submissions.preview.default' ) ?: TotalContest()->env( 'url' ) . 'assets/dist/images/no-preview.png';
$previewSource = $this->getContest()
->getSettingsItem( 'contest.submissions.preview.source' );
$attachmentId = (string) $this->getAttribute( "contents.{$previewSource}.attachment.id" );
if ( ! empty( $attachmentId ) ) {
$metadata = maybe_unserialize( wp_get_attachment_metadata( $attachmentId ) );
$sizes = maybe_unserialize( $metadata['sizes'] ?? [] );
foreach ( $sizes as $size => $details ) {
$submissionAsArray[ 'preview_url_' . $size ] = wp_get_attachment_image_url( $attachmentId,
$size ) ?: $noPreview;
$submissionAsArray[ 'preview_metadata_' . $size ] = $details;
}
$submissionAsArray['preview_url_original'] = wp_get_attachment_url( $attachmentId ) ?: $noPreview;
}
if ( is_admin() ):
$submissionAsArray['admin'] = [
'editLink' => $this->getAdminEditLink(),
];
endif;
/**
* Filters the array representation of submission.
*
* @param bool $submissionAsArray Submission as array.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return bool
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submission/array', $submissionAsArray, $this );
}
/**
* @return string
*/
public function __toString() {
return (string) $this->render();
}
/**
* Get received votes.
*
* @return int
* @since 2.0.0
*/
public function getReceivedVotes() {
return $this->receivedVotes;
}
/**
* Get received views.
*
* @return int
* @since 2.0.0
*/
public function getReceivedViews() {
return $this->receivedViews;
}
/**
* 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 );
$this->contest->incrementVotes( $by );
return $this->receivedVotes;
}
/**
* Increment views.
*
* @param int $by
*
* @return int
* @since 2.0.0
*/
public function incrementViews( $by = 1 ) {
$this->receivedViews += (int) $by;
$this->incrementMetadata( '_tc_views', $by );
return $this->receivedViews;
}
/**
* Get contest current action.
*
* @return mixed
* @since 2.0.0
*/
public function getAction() {
return $this->action;
}
/**
* Set contest current action.
*
* @param $action
*
* @return void
* @since 2.0.0
*/
public function setAction( $action ) {
$this->action = esc_html( $action );
}
/**
* @return bool
*/
public function save() {
// Remove WP filters
if ( version_compare( $GLOBALS['wp_version'],
'6.7.0',
'<' ) && 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 | JSON_UNESCAPED_UNICODE ) ),
] ) );
}
/**
* Increment rate.
*
* @param array $values
*
* @return array
* @since 2.0.0
*/
public function incrementRatings( $values = [] ) {
$contest = $this->getContest();
$ratings = [];
if ( $contest->isRateVoting() ):
// Rating
$scale = $contest->getVoteScale();
$criteria = $contest->getVoteCriteria();
$criteriaCumulative = 0;
// Bail if values count does not match criteria count
if ( count( $values ) !== count( $criteria ) ):
return $ratings;
endif;
// Iterate over criteria
foreach ( $criteria as $criterionIndex => $criterion ):
$value = isset( $values[ $criterionIndex ] ) ? absint( $values[ $criterionIndex ] ) : 0;
$value = $value > $scale ? $scale : $value;
$criterionVotes = (int) $this->incrementMetadata( "_tc_{$criterionIndex}:{$scale}_votes" );
$criterionCumulative = $this->incrementMetadata( "_tc_{$criterionIndex}:{$scale}_cumulative", $value );
$criterionRate = (float) ( $criterionCumulative / $criterionVotes );
$this->updateMetadata( "_tc_{$criterionIndex}:{$scale}_rate", $criterionRate );
$criteriaCumulative += $criterionRate;
$ratings[] = $criterionRate;
endforeach;
$rate = $criteriaCumulative / count( $criteria );
$this->updateMetadata( '_tc_rate', (float) $rate );
endif;
return $ratings;
}
/**
* @return bool
*/
public function hasVoted() {
/**
* Filters whether current user has voted before.
*
* @param bool $hasVoted Whether current user has voted or not.
* @param \TotalContest\Submission\Model $submission Submission model object.
*
* @return array
* @since 2.0.0
*/
return apply_filters( 'totalcontest/filters/submissions/has-voted',
is_wp_error( $this->getRestrictions()
->check() ) || $this->getRestrictions()
->isApplied(),
$this );
}
}