Test Failed
Push — master ( 87eb8d...25783a )
by Paul
03:58
created

Schema::getRatingCounts()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 9
ccs 0
cts 9
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules;
4
5
use DateTime;
6
use GeminiLabs\SiteReviews\Database\CountsManager;
7
use GeminiLabs\SiteReviews\Database\OptionManager;
8
use GeminiLabs\SiteReviews\Database\ReviewManager;
9
use GeminiLabs\SiteReviews\Helper;
10
use GeminiLabs\SiteReviews\Modules\Rating;
11
use GeminiLabs\SiteReviews\Modules\Schema\UnknownType;
12
use WP_Post;
13
14
class Schema
15
{
16
	/**
17
	 * @var array
18
	 */
19
	protected $args;
20
21
	/**
22
	 * @var array
23
	 */
24
	protected $ratingCounts;
25
26
	/**
27
	 * @return array
28
	 */
29
	public function build( array $args = [] )
30
	{
31
		$this->args = $args;
32
		$schema = $this->buildSummary( $args );
33
		$reviews = [];
34
		foreach( glsr( ReviewManager::class )->get( $this->args )->results as $review ) {
35
			// Only include critic reviews that have been directly produced by your site, not reviews from third- party sites or syndicated reviews.
36
			// @see https://developers.google.com/search/docs/data-types/review
37
			if( $review->review_type != 'local' )continue;
38
			$reviews[] = $this->buildReview( $review );
39
		}
40
		if( !empty( $reviews )) {
41
			array_walk( $reviews, function( &$review ) {
42
				unset( $review['@context'] );
43
				unset( $review['itemReviewed'] );
44
			});
45
			$schema['review'] = $reviews;
46
		}
47
		return $schema;
48
	}
49
50
	/**
51
	 * @param null|array $args
52
	 * @return array
53
	 */
54
	public function buildSummary( $args = null )
55
	{
56
		if( is_array( $args )) {
57
			$this->args = $args;
58
		}
59
		$buildSummary = glsr( Helper::class )->buildMethodName( $this->getSchemaOptionValue( 'type' ), 'buildSummaryFor' );
60
		$count = array_sum( $this->getRatingCounts() );
61
		$schema = method_exists( $this, $buildSummary )
62
			? $this->$buildSummary()
63
			: $this->buildSummaryForCustom();
64
		if( !empty( $count )) {
65
			$schema->aggregateRating(
66
				$this->getSchemaType( 'AggregateRating' )
67
					->ratingValue( $this->getRatingValue() )
68
					->reviewCount( $count )
69
					->bestRating( Rating::MAX_RATING )
70
					->worstRating( Rating::MIN_RATING )
71
			);
72
		}
73
		$schema = $schema->toArray();
74
		return apply_filters( 'site-reviews/schema/'.$schema['@type'], $schema, $args );
75
	}
76
77
	/**
78
	 * @return void
79
	 */
80
	public function render()
81
	{
82
		if( is_null( glsr()->schemas ))return;
83
		printf( '<script type="application/ld+json">%s</script>', json_encode(
84
			apply_filters( 'site-reviews/schema/all', glsr()->schemas ),
85
			JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
86
		));
87
	}
88
89
	/**
90
	 * @return void
91
	 */
92
	public function store( array $schema )
93
	{
94
		$schemas = glsr()->schemas;
95
		$schemas[] = $schema;
96
		glsr()->schemas = array_map( 'unserialize', array_unique( array_map( 'serialize', $schemas )));
97
	}
98
99
	/**
100
	 * @param object $review
101
	 * @return array
102
	 */
103
	protected function buildReview( $review )
104
	{
105
		$schema = $this->getSchemaType( 'Review' )
106
			->doIf( !in_array( 'title', $this->args['hide'] ), function( $schema ) use( $review ) {
107
				$schema->name( $review->title );
108
			})
109
			->doIf( !in_array( 'excerpt', $this->args['hide'] ), function( $schema ) use( $review ) {
110
				$schema->reviewBody( $review->content );
111
			})
112
			->datePublished(( new DateTime( $review->date )))
113
			->author( $this->getSchemaType( 'Person' )->name( $review->author ))
114
			->itemReviewed( $this->getSchemaType()->name( $this->getSchemaOptionValue( 'name' )));
115
		if( !empty( $review->rating )) {
116
			$schema->reviewRating(
117
				$this->getSchemaType( 'Rating' )
118
					->ratingValue( $review->rating )
119
					->bestRating( Rating::MAX_RATING )
120
					->worstRating( Rating::MIN_RATING )
121
			);
122
		}
123
		return apply_filters( 'site-reviews/schema/review', $schema->toArray(), $review, $this->args );
124
	}
125
126
	/**
127
	 * @param mixed $schema
128
	 * @return mixed
129
	 */
130
	protected function buildSchemaValues( $schema, array $values = [] )
131
	{
132
		foreach( $values as $value ) {
133
			$option = $this->getSchemaOptionValue( $value );
134
			if( empty( $option ))continue;
135
			$schema->$value( $option );
136
		}
137
		return $schema;
138
	}
139
140
	/**
141
	 * @return mixed
142
	 */
143
	protected function buildSummaryForCustom()
144
	{
145
		return $this->buildSchemaValues( $this->getSchemaType(), [
146
			'description', 'image', 'name', 'url',
147
		]);
148
	}
149
150
	/**
151
	 * @return mixed
152
	 */
153
	protected function buildSummaryForLocalBusiness()
154
	{
155
		return $this->buildSchemaValues( $this->buildSummaryForCustom(), [
156
			'address', 'priceRange', 'telephone',
157
		]);
158
	}
159
160
	/**
161
	 * @return mixed
162
	 */
163
	protected function buildSummaryForProduct()
164
	{
165
		$offers = $this->buildSchemaValues( $this->getSchemaType( 'AggregateOffer' ), [
166
			'highPrice', 'lowPrice', 'priceCurrency',
167
		]);
168
		return $this->buildSummaryForCustom()
169
			->offers( $offers )
170
			->setProperty( '@id', $this->getSchemaOptionValue( 'url' ));
171
	}
172
173
	/**
174
	 * @return array
175
	 */
176
	protected function getRatingCounts()
177
	{
178
		if( !isset( $this->ratingCounts )) {
179
			$ratingCounts = glsr( CountsManager::class )->getFlattened([
0 ignored issues
show
Unused Code introduced by
The assignment to $ratingCounts is dead and can be removed.
Loading history...
180
				'min' => $this->args['rating'],
181
				'types' => 'local',
182
			]);
183
		}
184
		return $this->ratingCounts;
185
	}
186
187
	/**
188
	 * @return int|float
189
	 */
190
	protected function getRatingValue()
191
	{
192
		return glsr( Rating::class )->getAverage( $this->getRatingCounts() );
193
	}
194
195
	/**
196
	 * @param string $option
197
	 * @param string $fallback
198
	 * @return string
199
	 */
200
	protected function getSchemaOption( $option, $fallback )
201
	{
202
		$option = strtolower( $option );
203
		if( $schemaOption = trim( (string)get_post_meta( intval( get_the_ID() ), 'schema_'.$option, true ))) {
204
			return $schemaOption;
205
		}
206
		$setting = glsr( OptionManager::class )->get( 'settings.schema.'.$option );
207
		if( is_array( $setting )) {
208
			return $this->getSchemaOptionDefault( $setting, $fallback );
209
		}
210
		return !empty( $setting )
211
			? $setting
212
			: $fallback;
213
	}
214
215
	/**
216
	 * @param string $fallback
217
	 * @return string
218
	 */
219
	protected function getSchemaOptionDefault( array $setting, $fallback )
220
	{
221
		$setting = wp_parse_args( $setting, [
222
			'custom' => '',
223
			'default' => $fallback,
224
		]);
225
		return $setting['default'] != 'custom'
226
			? $setting['default']
227
			: $setting['custom'];
228
	}
229
230
	/**
231
	 * @param string $option
232
	 * @param string $fallback
233
	 * @return void|string
234
	 */
235
	protected function getSchemaOptionValue( $option, $fallback = 'post' )
236
	{
237
		$value = $this->getSchemaOption( $option, $fallback );
238
		if( $value != $fallback ) {
239
			return $value;
240
		}
241
		if( !is_single() && !is_page() )return;
242
		$method = glsr( Helper::class )->buildMethodName( $option, 'getThing' );
243
		if( method_exists( $this, $method )) {
244
			return $this->$method();
245
		}
246
	}
247
248
	/**
249
	 * @param null|string $type
250
	 * @return mixed
251
	 */
252
	protected function getSchemaType( $type = null )
253
	{
254
		if( !is_string( $type )) {
255
			$type = $this->getSchemaOption( 'type', 'LocalBusiness' );
256
		}
257
		$className = glsr( Helper::class )->buildClassName( $type, 'Modules\Schema' );
258
		return class_exists( $className )
259
			? new $className()
260
			: new UnknownType( $type );
261
	}
262
263
	/**
264
	 * @return string
265
	 */
266
	protected function getThingDescription()
267
	{
268
		$post = get_post();
269
		if( !( $post instanceof WP_Post )) {
270
			return '';
271
		}
272
		$text = strip_shortcodes( wp_strip_all_tags( $post->post_excerpt ));
273
		return wp_trim_words( $text, apply_filters( 'excerpt_length', 55 ));
274
	}
275
276
	/**
277
	 * @return string
278
	 */
279
	protected function getThingImage()
280
	{
281
		return (string)get_the_post_thumbnail_url( null, 'large' );
282
	}
283
284
	/**
285
	 * @return string
286
	 */
287
	protected function getThingName()
288
	{
289
		return get_the_title();
290
	}
291
292
	/**
293
	 * @return string
294
	 */
295
	protected function getThingUrl()
296
	{
297
		return (string)get_the_permalink();
298
	}
299
}
300