Passed
Push — master ( 6f6d9e...e32a3c )
by Paul
04:05
created

Schema::getSchemaOption()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 4
nop 2
dl 0
loc 13
ccs 0
cts 13
cp 0
crap 20
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules;
4
5
use DateTime;
6
use GeminiLabs\SiteReviews\Database;
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 $reviewCounts;
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->getReviewCounts() );
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 int|float
175
	 */
176
	protected function getRatingValue()
177
	{
178
		return glsr( Rating::class )->getAverage( $this->getReviewCounts() );
179
	}
180
181
	/**
182
	 * @return array
183
	 */
184
	protected function getReviewCounts()
185
	{
186
		if( !isset( $this->reviewCounts )) {
187
			$this->reviewCounts = glsr( Database::class )->getReviewCounts([
188
				'min' => $this->args['rating'],
189
			]);
190
		}
191
		return $this->reviewCounts;
192
	}
193
194
	/**
195
	 * @param string $option
196
	 * @param string $fallback
197
	 * @return string
198
	 */
199
	protected function getSchemaOption( $option, $fallback )
200
	{
201
		$option = strtolower( $option );
202
		if( $schemaOption = trim( (string)get_post_meta( intval( get_the_ID() ), 'schema_'.$option, true ))) {
203
			return $schemaOption;
204
		}
205
		$setting = glsr( OptionManager::class )->get( 'settings.schema.'.$option );
206
		if( is_array( $setting )) {
207
			return $this->getSchemaOptionDefault( $setting, $fallback );
208
		}
209
		return !empty( $setting )
210
			? $setting
211
			: $fallback;
212
	}
213
214
	/**
215
	 * @param string $fallback
216
	 * @return string
217
	 */
218
	protected function getSchemaOptionDefault( array $setting, $fallback )
219
	{
220
		$setting = wp_parse_args( $setting, [
221
			'custom' => '',
222
			'default' => $fallback,
223
		]);
224
		return $setting['default'] != 'custom'
225
			? $setting['default']
226
			: $setting['custom'];
227
	}
228
229
	/**
230
	 * @param string $option
231
	 * @param string $fallback
232
	 * @return void|string
233
	 */
234
	protected function getSchemaOptionValue( $option, $fallback = 'post' )
235
	{
236
		$value = $this->getSchemaOption( $option, $fallback );
237
		if( $value != $fallback ) {
238
			return $value;
239
		}
240
		if( !is_single() && !is_page() )return;
241
		$method = glsr( Helper::class )->buildMethodName( $option, 'getThing' );
242
		if( method_exists( $this, $method )) {
243
			return $this->$method();
244
		}
245
	}
246
247
	/**
248
	 * @param null|string $type
249
	 * @return mixed
250
	 */
251
	protected function getSchemaType( $type = null )
252
	{
253
		if( !is_string( $type )) {
254
			$type = $this->getSchemaOption( 'type', 'LocalBusiness' );
255
		}
256
		$className = glsr( Helper::class )->buildClassName( $type, 'Modules\Schema' );
257
		return class_exists( $className )
258
			? new $className()
259
			: new UnknownType( $type );
260
	}
261
262
	/**
263
	 * @return string
264
	 */
265
	protected function getThingDescription()
266
	{
267
		$post = get_post();
268
		if( !( $post instanceof WP_Post )) {
269
			return '';
270
		}
271
		$text = strip_shortcodes( wp_strip_all_tags( $post->post_excerpt ));
272
		return wp_trim_words( $text, apply_filters( 'excerpt_length', 55 ));
273
	}
274
275
	/**
276
	 * @return string
277
	 */
278
	protected function getThingImage()
279
	{
280
		return (string)get_the_post_thumbnail_url( null, 'large' );
281
	}
282
283
	/**
284
	 * @return string
285
	 */
286
	protected function getThingName()
287
	{
288
		return get_the_title();
289
	}
290
291
	/**
292
	 * @return string
293
	 */
294
	protected function getThingUrl()
295
	{
296
		return (string)get_the_permalink();
297
	}
298
}
299