Completed
Push — master ( c336cf...9cad87 )
by David
30:41
created

Wordlift_Jsonld_Service   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 195
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 0
loc 195
rs 10
c 0
b 0
f 0
wmc 15
lcom 1
cbo 3

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A get_instance() 0 4 1
A get() 0 15 3
A send_jsonld() 0 9 3
A get_jsonld() 0 54 4
A wp_head() 0 10 3
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
	 * @since 3.8.0
57
	 *
58
	 * @param \Wordlift_Entity_Service $entity_service A {@link Wordlift_Entity_Service} instance.
59
	 * @param \Wordlift_Post_Converter $converter A {@link Wordlift_Uri_To_Jsonld_Converter} instance.
60
	 * @param \Wordlift_Website_Jsonld_Converter $website_converter A {@link Wordlift_Website_Jsonld_Converter} instance.
61
	 */
62
	public function __construct( $entity_service, $converter, $website_converter ) {
63
64
		$this->entity_service    = $entity_service;
65
		$this->converter         = $converter;
66
		$this->website_converter = $website_converter;
67
68
		self::$instance = $this;
69
70
	}
71
72
	/**
73
	 * Get the singleton instance for the JSON-LD service.
74
	 *
75
	 * @since 3.15.1
76
	 *
77
	 * @return \Wordlift_Jsonld_Service The singleton instance for the JSON-LD service.
78
	 */
79
	public static function get_instance() {
80
81
		return self::$instance;
82
	}
83
84
	/**
85
	 * Process calls to the AJAX 'wl_jsonld' endpoint.
86
	 *
87
	 * @since 3.8.0
88
	 */
89
	public function get() {
0 ignored issues
show
Coding Style introduced by
get uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
90
		// Clear the buffer to be sure someone doesn't mess with our response.
91
		//
92
		// See https://github.com/insideout10/wordlift-plugin/issues/406.
93
		// See https://codex.wordpress.org/AJAX_in_Plugins.
94
		@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...
95
96
		// Get the parameter from the request.
97
		$is_homepage = isset( $_REQUEST['homepage'] );
98
		$post_id     = isset( $_REQUEST['id'] ) && is_numeric( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : null;
99
100
		// Send the generated JSON-LD.
101
		$this->send_jsonld( $this->get_jsonld( $is_homepage, $post_id ) );
102
103
	}
104
105
	/**
106
	 * A close of WP's own `wp_send_json` function which uses `application/ld+json` as content type.
107
	 *
108
	 * @since 3.18.5
109
	 *
110
	 * @param mixed $response Variable (usually an array or object) to encode as JSON,
111
	 *                           then print and die.
112
	 * @param int $status_code The HTTP status code to output.
113
	 */
114
	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...
115
		@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...
116
		echo wp_json_encode( $response );
117
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
118
			wp_die();
119
		} else {
120
			die;
0 ignored issues
show
Coding Style Compatibility introduced by
The method send_jsonld() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
121
		}
122
	}
123
124
	/**
125
	 * Get the JSON-LD.
126
	 *
127
	 * @since 3.15.1
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
	 */
134
	public function get_jsonld( $is_homepage = false, $post_id = null ) {
135
136
		// Tell NewRelic to ignore us, otherwise NewRelic customers might receive
137
		// e-mails with a low apdex score.
138
		//
139
		// See https://github.com/insideout10/wordlift-plugin/issues/521
140
		Wordlift_NewRelic_Adapter::ignore_apdex();
141
142
		// Switch to Website converter if is home page.
143
		if ( $is_homepage ) {
144
			/**
145
			 * Filter: 'wordlift_disable_website_json_ld' - Allow disabling of the json+ld output.
146
			 *
147
			 * @since  3.14.0
148
			 * @api    bool $display_search Whether or not to display json+ld search on the frontend.
149
			 */
150
			if ( ! apply_filters( 'wordlift_disable_website_json_ld', false ) ) {
151
				// Set a reference to the website_converter.
152
				$website_converter = $this->website_converter;
153
154
				// Send JSON-LD.
155
				return $website_converter->create_schema();
156
			}
157
		}
158
159
		// If no id has been provided return an empty array.
160
		if ( ! isset( $post_id ) ) {
161
			return array();
162
		}
163
164
		// An array of references which is captured when converting an URI to a
165
		// json which we gather to further expand our json-ld.
166
		$references = array();
167
168
		// Set a reference to the entity_to_jsonld_converter to use in the closures.
169
		$entity_to_jsonld_converter = $this->converter;
170
171
		// Convert each URI to a JSON-LD array, while gathering referenced entities.
172
		// in the references array.
173
		$jsonld = array_merge(
174
			array( $entity_to_jsonld_converter->convert( $post_id, $references ) ),
175
			// Convert each URI in the references array to JSON-LD. We don't output
176
			// entities already output above (hence the array_diff).
177
			array_filter( array_map( function ( $item ) use ( $entity_to_jsonld_converter, $references ) {
178
179
				// "2nd level properties" may not output here, e.g. a post
180
				// mentioning an event, located in a place: the place is referenced
181
				// via the `@id` but no other properties are loaded.
182
				return $entity_to_jsonld_converter->convert( $item, $references );
183
			}, $references ) ) );
184
185
		// Finally send the JSON-LD.
186
		return $jsonld;
187
	}
188
189
	/**
190
	 * Write the JSON-LD in the head.
191
	 *
192
	 * This function isn't actually used, but may be used to quickly enable writing the JSON-LD synchronously to the
193
	 * document head, using the `wp_head` hook.
194
	 *
195
	 * @since 3.18.5
196
	 */
197
	public function wp_head() {
198
199
		// Determine whether this is the home page or whether we're displaying a single post.
200
		$is_homepage = is_home() || is_front_page();
201
		$post_id     = is_singular() ? get_the_ID() : null;
202
203
		$jsonld = json_encode( $this->get_jsonld( $is_homepage, $post_id ) );
204
		?>
205
        <script type="application/ld+json"><?php echo $jsonld; ?></script><?php
206
	}
207
208
}
209