Test Failed
Push — master ( 59b255...755753 )
by Paul
04:04
created

SiteReviews::getExcerptSplit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 7
ccs 0
cts 2
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules\Html\Partials;
4
5
use GeminiLabs\SiteReviews\Database;
6
use GeminiLabs\SiteReviews\Database\OptionManager;
7
use GeminiLabs\SiteReviews\Helper;
8
use GeminiLabs\SiteReviews\Modules\Date;
9
use GeminiLabs\SiteReviews\Modules\Html;
10
use GeminiLabs\SiteReviews\Modules\Html\Builder;
11
use GeminiLabs\SiteReviews\Modules\Html\Partial;
12
use GeminiLabs\SiteReviews\Modules\Html\Review;
13
use GeminiLabs\SiteReviews\Modules\Html\Template;
14
use GeminiLabs\SiteReviews\Modules\Rating;
15
use GeminiLabs\SiteReviews\Modules\Schema;
16
use IntlRuleBasedBreakIterator;
17
use WP_Post;
18
19
class SiteReviews
20
{
21
	/**
22
	 * @var array
23
	 */
24
	protected $args;
25
26
	/**
27
	 * @var int
28
	 */
29
	protected $current;
30
31
	/**
32
	 * @var array
33
	 */
34
	protected $options;
35
36
	/**
37
	 * @var object
38
	 */
39
	protected $reviews;
40
41
	/**
42
	 * @return void|string
43
	 */
44
	public function build( array $args = [] )
45
	{
46
		$this->args = $args;
47
		$this->options = glsr( Helper::class )->flattenArray( glsr( OptionManager::class )->all() );
48
		$this->reviews = glsr( Database::class )->getReviews( $args );
49
		$this->generateSchema();
50
		$navigation = wp_validate_boolean( $this->args['pagination'] )
51
			? glsr( Partial::class )->build( 'pagination', ['total' => $this->reviews->max_num_pages] )
52
			: '';
53
		return glsr( Template::class )->build( 'templates/reviews', [
54
			'context' => [
55
				'class' => $this->getClass(),
56
				'id' => $this->args['id'],
57
				'navigation' => $navigation,
58
			],
59
			'reviews' => $this->buildReviews(),
60
		]);
61
	}
62
63
	/**
64
	 * @return array
65
	 */
66
	public function buildReviews()
67
	{
68
		$reviews = [];
69
		foreach( $this->reviews->results as $index => $review ) {
70
			$this->current = $index;
71
			$reviews[] = $this->buildReview( $review );
72
		}
73
		return $reviews;
74
	}
75
76
	/**
77
	 * @param object $review
78
	 * @return object
79
	 */
80
	protected function buildReview( $review )
81
	{
82
		$review = apply_filters( 'site-reviews/review/build/before', (array)$review );
83
		$reviewValues = [];
84
		foreach( $review as $key => $value ) {
85
			$method = glsr( Helper::class )->buildMethodName( $key, 'buildOption' );
86
			if( !method_exists( $this, $method ))continue;
87
			$reviewValues[$key] = $this->$method( $key, $value );
88
		}
89
		$reviewValues = apply_filters( 'site-reviews/review/build/after', $reviewValues );
90
		return new Review( $reviewValues );
91
	}
92
93
	/**
94
	 * @param string $key
95
	 * @param string $value
96
	 * @return void|string
97
	 */
98
	protected function buildOptionAssignedTo( $key, $value )
99
	{
100
		if( $this->isHiddenOrEmpty( $key, 'settings.reviews.assigned_links.enabled' ))return;
101
		$post = get_post( intval( $value ));
102
		if( !( $post instanceof WP_Post ))return;
103
		$permalink = glsr( Builder::class )->a( get_the_title( $post->ID ), [
104
			'href' => get_the_permalink( $post->ID ),
105
		]);
106
		$assignedTo = sprintf( __( 'Review of %s', 'site-reviews' ), $permalink );
107
		return $this->wrap( $key, '<span>'.$assignedTo.'</span>' );
108
	}
109
110
	/**
111
	 * @param string $key
112
	 * @param string $value
113
	 * @return void|string
114
	 */
115
	protected function buildOptionAuthor( $key, $value )
116
	{
117
		if( $this->isHidden( $key ))return;
118
		$prefix = !$this->isOptionEnabled( 'settings.reviews.avatars.enabled' )
119
			? apply_filters( 'site-reviews/review/author/prefix', '&mdash;' )
120
			: '';
121
		return $this->wrap( $key, $prefix.'<span>'.$value.'</span>' );
122
	}
123
124
	/**
125
	 * @param string $key
126
	 * @param string $value
127
	 * @return void|string
128
	 */
129
	protected function buildOptionAvatar( $key, $value )
130
	{
131
		if( $this->isHidden( $key, 'settings.reviews.avatars.enabled' ))return;
132
		$size = $this->getOption( 'settings.reviews.avatars.size', 40 );
133
		return $this->wrap( $key, glsr( Builder::class )->img([
134
			'src' => $this->generateAvatar( $value ),
135
			'height' => $size,
136
			'width' => $size,
137
		]));
138
	}
139
140
	/**
141
	 * @param string $key
142
	 * @param string $value
143
	 * @return void|string
144
	 */
145
	protected function buildOptionContent( $key, $value )
146
	{
147
		$text = $this->normalizeText( $value );
148
		if( $this->isHiddenOrEmpty( $key, $text ))return;
149
		return $this->wrap( $key, '<p>'.$text.'</p>' );
150
	}
151
152
	/**
153
	 * @param string $key
154
	 * @param string $value
155
	 * @return void|string
156
	 */
157
	protected function buildOptionDate( $key, $value )
158
	{
159
		if( $this->isHidden( $key ))return;
160
		$dateFormat = $this->getOption( 'settings.reviews.date.format', 'default' );
161
		if( $dateFormat == 'relative' ) {
162
			$date = glsr( Date::class )->relative( $value );
163
		}
164
		else {
165
			$format = $dateFormat == 'custom'
166
				? $this->getOption( 'settings.reviews.date.custom', 'M j, Y' )
167
				: (string)get_option( 'date_format' );
168
			$date = date_i18n( $format, strtotime( $value ));
169
		}
170
		return $this->wrap( $key, '<span>'.$date.'</span>' );
171
	}
172
173
	/**
174
	 * @param string $key
175
	 * @param string $value
176
	 * @return void|string
177
	 */
178
	protected function buildOptionRating( $key, $value )
179
	{
180
		if( $this->isHiddenOrEmpty( $key, $value ))return;
181
		$rating = glsr( Html::class )->buildPartial( 'star-rating', [
182
			'rating' => $value,
183
		]);
184
		return $this->wrap( $key, $rating );
185
	}
186
187
	/**
188
	 * @param string $key
189
	 * @param string $value
190
	 * @return void|string
191
	 */
192
	protected function buildOptionResponse( $key, $value )
193
	{
194
		if( $this->isHiddenOrEmpty( $key, $value ))return;
195
		$title = sprintf( __( 'Response from %s', 'site-reviews' ), get_bloginfo( 'name' ));
196
		$text = $this->normalizeText( $value );
197
		$text = '<p><strong>'.$title.'</strong></p><p>'.$text.'</p>';
198
		return $this->wrap( $key,
199
			glsr( Builder::class )->div( $text, ['class' => 'glsr-review-response-inner'] ).
200
			glsr( Builder::class )->div( ['class' => 'glsr-review-response-background'] )
201
		);
202
	}
203
204
	/**
205
	 * @param string $key
206
	 * @param string $value
207
	 * @return void|string
208
	 */
209
	protected function buildOptionTitle( $key, $value )
210
	{
211
		if( $this->isHidden( $key ))return;
212
		if( empty( $value )) {
213
			$value = __( 'No Title', 'site-reviews' );
214
		}
215
		return $this->wrap( $key, '<h3>'.$value.'</h3>' );
216
	}
217
218
	/**
219
	 * @param string $avatarUrl
220
	 * @return string
221
	 */
222
	protected function generateAvatar( $avatarUrl )
223
	{
224
		$review = $this->reviews->results[$this->current];
225
		if( !$this->isOptionEnabled( 'settings.reviews.avatars.regenerate' )
226
			|| $review->review_type != 'local' ) {
227
			return $avatarUrl;
228
		}
229
		$authorIdOrEmail = get_the_author_meta( 'ID', $review->user_id );
230
		if( empty( $authorIdOrEmail )) {
231
			$authorIdOrEmail = $review->email;
232
		}
233
		return (string)get_avatar_url( $authorIdOrEmail );
234
	}
235
236
	/**
237
	 * @return void
238
	 */
239
	protected function generateSchema()
240
	{
241
		if( !wp_validate_boolean( $this->args['schema'] ))return;
242
		glsr( Schema::class )->store(
243
			glsr( Schema::class )->build( $this->args )
244
		);
245
	}
246
247
	/**
248
	 * @return string
249
	 */
250
	protected function getClass()
251
	{
252
		$style = apply_filters( 'site-reviews/reviews/style', 'glsr-style' );
253
		$pagination = $this->args['pagination'] == 'ajax'
254
			? 'glsr-ajax-pagination'
255
			: '';
256
		return trim( 'glsr-reviews '.$style.' '.$pagination.' '.$this->args['class'] );
257
	}
258
259
	/**
260
	 * @param string $text
261
	 * @return string
262
	 */
263
	protected function getExcerpt( $text )
264
	{
265
		$limit = intval( $this->getOption( 'settings.reviews.excerpt.length', 55 ));
266
		$split = extension_loaded( 'intl' )
267
			? $this->getExcerptIntlSplit( $text, $limit )
268
			: $this->getExcerptSplit( $text, $limit );
269
		$hiddenText = substr( $text, $split );
270
		if( !empty( $hiddenText )) {
271
			$showMore = glsr( Builder::class )->span( $hiddenText, [
272
				'class' => 'glsr-hidden glsr-hidden-text',
273
				'data-show-less' => __( 'Show less', 'site-reviews' ),
274
				'data-show-more' => __( 'Show more', 'site-reviews' ),
275
			]);
276
			$text = ltrim( substr( $text, 0, $split )).$showMore;
277
		}
278
		return nl2br( $text );
279
	}
280
281
	/**
282
	 * @param string $text
283
	 * @param int $limit
284
	 * @return int
285
	 */
286
	protected function getExcerptIntlSplit( $text, $limit )
287
	{
288
		$words = IntlRuleBasedBreakIterator::createWordInstance( '' );
289
		$words->setText( $text );
290
		$count = 0;
291
		foreach( $words as $offset ){
292
			if( $words->getRuleStatus() === IntlRuleBasedBreakIterator::WORD_NONE )continue;
293
			$count++;
294
			if( $count != $limit )continue;
295
			return $offset;
296
		}
297
		return strlen( $text );
298
	}
299
300
	/**
301
	 * @param string $text
302
	 * @param int $limit
303
	 * @return int
304
	 */
305
	protected function getExcerptSplit( $text, $limit )
306
	{
307
		if( str_word_count( $text, 0 ) > $limit ) {
308
			$words = array_keys( str_word_count( $text, 2 ));
309
			return $words[$limit];
310
		}
311
		return strlen( $text );
312
	}
313
314
	/**
315
	 * @param string $path
316
	 * @param mixed $fallback
317
	 * @return mixed
318
	 */
319
	protected function getOption( $path, $fallback = '' )
320
	{
321
		if( array_key_exists( $path, $this->options )) {
322
			return $this->options[$path];
323
		}
324
		return $fallback;
325
	}
326
327
	/**
328
	 * @param string $key
329
	 * @param string $path
330
	 * @return bool
331
	 */
332
	protected function isHidden( $key, $path = '' )
333
	{
334
		$isOptionEnabled = !empty( $path )
335
			? $this->isOptionEnabled( $path )
336
			: true;
337
		return in_array( $key, $this->args['hide'] ) || !$isOptionEnabled;
338
	}
339
340
	/**
341
	 * @param string $key
342
	 * @param string $value
343
	 * @return bool
344
	 */
345
	protected function isHiddenOrEmpty( $key, $value )
346
	{
347
		return $this->isHidden( $key ) || empty( $value );
348
	}
349
350
	/**
351
	 * @param string $path
352
	 * @return bool
353
	 */
354
	protected function isOptionEnabled( $path )
355
	{
356
		return $this->getOption( $path ) == 'yes';
357
	}
358
359
	/**
360
	 * @param string $text
361
	 * @return string
362
	 */
363
	protected function normalizeText( $text )
364
	{
365
		$text = wp_kses( $text, wp_kses_allowed_html() );
366
		$text = convert_smilies( wptexturize( strip_shortcodes( $text )));
367
		$text = str_replace( ']]>', ']]&gt;', $text );
368
		$text = preg_replace( '/(\R){2,}/', '$1', $text );
369
		return $this->isOptionEnabled( 'settings.reviews.excerpt.enabled' )
370
			? $this->getExcerpt( $text )
371
			: $text;
372
	}
373
374
	/**
375
	 * @param string $key
376
	 * @param string $value
377
	 * @return string
378
	 */
379
	protected function wrap( $key, $value )
380
	{
381
		return glsr( Builder::class )->div( $value, [
382
			'class' => 'glsr-review-'.$key,
383
		]);
384
	}
385
}
386