Completed
Pull Request — develop (#1143)
by Naveen
04:18 queued 01:05
created

Wordlift_Jsonld_Service::get()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 0
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
1
<?php
2
/**
3
 * Define the Wordlift_Jsonld_Service class to support JSON-LD.
4
 *
5
 * @since   3.8.0
6
 * @package Wordlift
7
 */
8
9
/**
10
 * This class exports an entity using JSON-LD.
11
 *
12
 * @since 3.8.0
13
 */
14
class Wordlift_Jsonld_Service {
15
16
	/**
17
	 * A {@link Wordlift_Entity_Service} instance.
18
	 *
19
	 * @since  3.8.0
20
	 * @access private
21
	 * @var Wordlift_Entity_Service $entity_service A {@link Wordlift_Entity_Service} instance.
22
	 */
23
	private $entity_service;
24
25
	/**
26
	 * A {@link Wordlift_Post_Converter} instance.
27
	 *
28
	 * @since  3.8.0
29
	 * @access private
30
	 * @var \Wordlift_Post_Converter A {@link Wordlift_Post_Converter} instance.
31
	 */
32
	private $converter;
33
34
35
	/**
36
	 * A {@link Wordlift_Website_Jsonld_Converter} instance.
37
	 *
38
	 * @since  3.14.0
39
	 * @access private
40
	 * @var \Wordlift_Website_Jsonld_Converter A {@link Wordlift_Website_Jsonld_Converter} instance.
41
	 */
42
	private $website_converter;
43
44
	/**
45
	 * The singleton instance for the JSON-LD service.
46
	 *
47
	 * @since 3.15.1
48
	 *
49
	 * @var \Wordlift_Jsonld_Service $instance The singleton instance for the JSON-LD service.
50
	 */
51
	private static $instance;
52
53
	/**
54
	 * Create a JSON-LD service.
55
	 *
56
	 * @param \Wordlift_Entity_Service $entity_service A {@link Wordlift_Entity_Service} instance.
57
	 * @param \Wordlift_Post_Converter $converter A {@link Wordlift_Uri_To_Jsonld_Converter} instance.
58
	 * @param \Wordlift_Website_Jsonld_Converter $website_converter A {@link Wordlift_Website_Jsonld_Converter} instance.
59
	 *
60
	 * @since 3.8.0
61
	 *
62
	 */
63
	public function __construct( $entity_service, $converter, $website_converter ) {
64
65
		$this->entity_service    = $entity_service;
66
		$this->converter         = $converter;
67
		$this->website_converter = $website_converter;
68
69
		self::$instance = $this;
70
71
	}
72
73
	/**
74
	 * Get the singleton instance for the JSON-LD service.
75
	 *
76
	 * @return \Wordlift_Jsonld_Service The singleton instance for the JSON-LD service.
77
	 * @since 3.15.1
78
	 *
79
	 */
80
	public static function get_instance() {
81
82
		return self::$instance;
83
	}
84
85
	/**
86
	 * Process calls to the AJAX 'wl_jsonld' endpoint.
87
	 *
88
	 * @since 3.8.0
89
	 */
90
	public function get() {
91
		// Clear the buffer to be sure someone doesn't mess with our response.
92
		//
93
		// See https://github.com/insideout10/wordlift-plugin/issues/406.
94
		// See https://codex.wordpress.org/AJAX_in_Plugins.
95
		@ob_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
96
97
		// Get the parameter from the request.
98
		$is_homepage = isset( $_REQUEST['homepage'] );
99
		$post_id     = isset( $_REQUEST['id'] ) && is_numeric( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : null;
100
101
		// Send the generated JSON-LD.
102
		$this->send_jsonld( $this->get_jsonld( $is_homepage, $post_id ) );
103
104
	}
105
106
	/**
107
	 * A close of WP's own `wp_send_json` function which uses `application/ld+json` as content type.
108
	 *
109
	 * @param mixed $response Variable (usually an array or object) to encode as JSON,
110
	 *                           then print and die.
111
	 * @param int $status_code The HTTP status code to output.
112
	 *
113
	 * @since 3.18.5
114
	 *
115
	 */
116
	private function send_jsonld( $response, $status_code = null ) {
0 ignored issues
show
Unused Code introduced by
The parameter $status_code is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
117
		@header( 'Content-Type: application/ld+json; charset=' . get_option( 'blog_charset' ) );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
118
		echo wp_json_encode( $response );
119
		if ( apply_filters( 'wp_doing_ajax', defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
120
			wp_die();
121
		} else {
122
			die;
123
		}
124
	}
125
126
	/**
127
	 * Get the JSON-LD.
128
	 *
129
	 * @param bool $is_homepage Whether the JSON-LD for the homepage is being requested.
130
	 * @param int|null $post_id The JSON-LD for the specified {@link WP_Post} id.
131
	 *
132
	 * @return array A JSON-LD structure.
133
	 * @since 3.15.1
134
	 *
135
	 */
136
	public function get_jsonld( $is_homepage = false, $post_id = null ) {
137
138
		// Tell NewRelic to ignore us, otherwise NewRelic customers might receive
139
		// e-mails with a low apdex score.
140
		//
141
		// See https://github.com/insideout10/wordlift-plugin/issues/521
142
		Wordlift_NewRelic_Adapter::ignore_apdex();
143
144
		// Switch to Website converter if is home page.
145
		if ( $is_homepage ) {
146
			/**
147
			 * Filter: 'wordlift_disable_website_json_ld' - Allow disabling of the json+ld output.
148
			 *
149
			 * @since  3.14.0
150
			 * @api    bool $display_search Whether or not to display json+ld search on the frontend.
151
			 */
152
			if ( apply_filters( 'wordlift_disable_website_json_ld', false ) ) {
153
				return array();
154
			}
155
156
			// Set a reference to the website_converter.
157
			$website_converter = $this->website_converter;
158
159
			// Send JSON-LD.
160
			return $website_converter->create_schema();
161
		}
162
163
		// If no id has been provided return an empty array.
164
		if ( ! isset( $post_id ) ) {
165
			return array();
166
		}
167
168
		// An array of references which is captured when converting an URI to a
169
		// json which we gather to further expand our json-ld.
170
		$references       = array();
171
		$references_infos = array();
172
173
		// Set a reference to the entity_to_jsonld_converter to use in the closures.
174
		$entity_to_jsonld_converter = $this->converter;
175
176
		// Convert each URI to a JSON-LD array, while gathering referenced entities.
177
		// in the references array.
178
		$jsonld = array_merge(
179
			array( $entity_to_jsonld_converter->convert( $post_id, $references, $references_infos ) ),
180
			// Convert each URI in the references array to JSON-LD. We don't output
181
			// entities already output above (hence the array_diff).
182
			array_filter( array_map( function ( $item ) use ( $entity_to_jsonld_converter, &$references_infos ) {
183
184
				// "2nd level properties" may not output here, e.g. a post
185
				// mentioning an event, located in a place: the place is referenced
186
				// via the `@id` but no other properties are loaded.
187
				$ignored = array();
188
189
				return $entity_to_jsonld_converter->convert( $item, $ignored, $references_infos );
190
			}, array_unique( $references ) ) ) );
191
192
		$required_references = array_filter( $references_infos, function ( $item ) use ( $references ) {
193
			return isset( $item['reference'] ) &&
194
			       // Check that the reference is required
195
			       $item['reference']->get_required() &&
196
			       // Check that the reference isn't being output already.
197
			       ! in_array( $item['reference']->get_id(), $references );
198
		} );
199
200
		$jsonld = array_merge( $jsonld, array_filter( array_map( function ( $item ) use ( $references, $entity_to_jsonld_converter ) {
201
202
			if ( ! isset( $item['reference'] ) ) {
203
				return null;
204
			}
205
206
			$post_id = $item['reference']->get_id();
207
			if ( in_array( $post_id, $references ) ) {
208
				return null;
209
			}
210
211
			$references[] = $post_id;
212
213
			return $entity_to_jsonld_converter->convert( $post_id, $references );
214
		}, $required_references ) ) );
215
216
		/**
217
		 * Filter name: wl_after_get_jsonld
218
		 * @return array
219
		 * @since 3.27.2
220
		 * @var $jsonld array The final jsonld before outputting to page.
221
		 * @var $post_id int The post id for which the jsonld is generated.
222
		 *
223
		 */
224
		$jsonld = apply_filters( 'wl_after_get_jsonld', $jsonld, $post_id );
225
226
		return $jsonld;
227
	}
228
229
	/**
230
	 * Write the JSON-LD in the head.
231
	 *
232
	 * This function isn't actually used, but may be used to quickly enable writing the JSON-LD synchronously to the
233
	 * document head, using the `wp_head` hook.
234
	 *
235
	 * @since 3.18.5
236
	 */
237
	public
238
	function wp_head() {
239
240
		// Determine whether this is the home page or whether we're displaying a single post.
241
		$is_homepage = is_home() || is_front_page();
242
		$post_id     = is_singular() ? get_the_ID() : null;
243
244
		$jsonld = json_encode( $this->get_jsonld( $is_homepage, $post_id ) );
245
		?>
246
        <script type="application/ld+json"><?php echo $jsonld; ?></script><?php
247
	}
248
249
}
250