Completed
Pull Request — develop (#1933)
by Aristeides
03:59
created

Kirki_Modules_Telemetry::consent()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 4
nc 4
nop 0
dl 0
loc 9
rs 9.6111
c 0
b 0
f 0
1
<?php
2
/**
3
 * Telemetry implementation for Kirki.
4
 *
5
 * @package     Kirki
6
 * @category    Core
7
 * @author      Aristeides Stathopoulos
8
 * @copyright   Copyright (c) 2017, Aristeides Stathopoulos
9
 * @license     http://opensource.org/licenses/https://opensource.org/licenses/MIT
10
 * @since       3.0.36
11
 */
12
13
// Exit if accessed directly.
14
if ( ! defined( 'ABSPATH' ) ) {
15
	exit;
16
}
17
18
/**
19
 * Telemetry implementation.
20
 */
21
final class Kirki_Modules_Telemetry {
22
23
	/**
24
	 * The object instance.
25
	 *
26
	 * @static
27
	 * @access private
28
	 * @since 3.0.36
29
	 * @var object
30
	 */
31
	private static $instance;
32
33
    /**
34
	 * Constructor.
35
	 *
36
	 * @access protected
37
	 * @since 3.0.36
38
	 */
39
	protected function __construct() {
40
41
		// Early exit if telemetry is disabled.
42
		if ( ! apply_filters( 'kirki_telemetry', true ) ) {
43
			return;
44
		}
45
46
		add_action( 'init', array( $this, 'init' ) );
47
		add_action( 'admin_notices', array( $this, 'admin_notice' ) );
48
	}
49
50
	/**
51
	 * Gets an instance of this object.
52
	 * Prevents duplicate instances which avoid artefacts and improves performance.
53
	 *
54
	 * @static
55
	 * @access public
56
	 * @since 3.0.36
57
	 * @return object
58
	 */
59
	public static function get_instance() {
60
		if ( ! self::$instance ) {
61
			self::$instance = new self();
62
		}
63
		return self::$instance;
64
	}
65
66
	/**
67
	 * Additional actions that run on init.
68
	 *
69
	 * @access public
70
	 * @since 3.0.36
71
	 * @return void
72
	 */
73
	public function init() {
74
		$this->dismiss_notice();
75
		$this->consent();
76
77
		// This is the last thing to run. No impact on performance or anything else.
78
		add_action( 'wp_footer', array( $this, 'maybe_send_data' ), 99999 );
79
	}
80
81
	/**
82
	 * Maybe send data.
83
	 *
84
	 * @access public
85
	 * @since 3.0.36
86
	 * @return void
87
	 */
88
	public function maybe_send_data() {
89
90
		// Check if the user has consented to the data sending.
91
		if ( ! get_option( 'kirki_telemetry_optin' ) ) {
92
			return;
93
		}
94
95
		// Only send data once/month.
96
		$sent = get_site_transient( 'kirki_telemetry_sent' );
97
		if ( ! $sent ) {
98
			$this->send_data();
99
			set_site_transient( 'kirki_telemetry_sent', time(), MONTH_IN_SECONDS );
0 ignored issues
show
Bug introduced by Aristeides Stathopoulos
The constant MONTH_IN_SECONDS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
100
		}
101
	}
102
103
	/**
104
	 * Sends data.
105
	 *
106
	 * @access private
107
	 * @since 3.0.36
108
	 * @return void
109
	 */
110
	private function send_data() {
111
112
		// Ping remote server.
113
		wp_remote_post( 'https://wplemon.com/?action=kirki-stats', [
0 ignored issues
show
Coding Style introduced by Ari
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
Coding Style introduced by Ari
For multi-line function calls, each argument should be on a separate line.

For a function calls that spawns multiple lines, the coding style suggests to split arguments to separate lines like this:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
);
Loading history...
114
			'method'   => 'POST',
115
			'blocking' => false,
116
			'body'     => array_merge(
117
				array(
118
					'action' => 'kirki-stats',
119
				),
120
				$this->get_data()
121
			),
122
		] );
0 ignored issues
show
Coding Style introduced by Ari
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
123
	}
124
125
	/**
126
	 * The admin-notice.
127
	 *
128
	 * @access private
129
	 * @since 3.0.36
130
	 * @return void
131
	 */
132
	public function admin_notice() {
133
134
		// Early exit if the user has dismissed the consent, or if they have opted-in.
135
		if ( get_option( 'kirki_telemetry_no_consent' ) || get_option( 'kirki_telemetry_optin' ) ) {
136
			return;
137
		}
138
		$data = $this->get_data();
139
		?>
140
		<div class="notice notice-info kirki-telemetry">
141
			<h3><strong><?php esc_html_e( 'Help us improve Kirki.', 'kirki' ); ?></strong></h3>
142
			<p style="max-width: 76em;"><?php echo wp_kses_post( __( 'Help us begin a dialogue with theme developers, collaborate and improve both the theme you are using and the Kirki framework by agreeing to send anonymous data. <strong>The data is completely anonymous and we will never collect any identifyable information about you or your website.</strong>', 'kirki' ) ); ?></p>
143
			<table class="data-to-send hidden widefat">
144
				<thead>
145
					<tr>
146
						<th colspan="2"><?php esc_html_e( 'Data that will be sent', 'kirki' ); ?></th>
147
					</tr>
148
				</thead>
149
				<tbody>
150
					<tr>
151
						<td style="min-width: 200px;"><?php esc_html_e( 'PHP Version', 'kirki' ); ?></td>
152
						<td><code><?php echo esc_html( $data['phpVer'] ); ?></code></td>
153
					</tr>
154
					<tr>
155
						<td><?php esc_html_e( 'Theme Name', 'kirki' ); ?></td>
156
						<td><code><?php echo esc_html( $data['themeName'] ); ?></code></td>
157
					</tr>
158
					<tr>
159
						<td><?php esc_html_e( 'Theme Author', 'kirki' ); ?></td>
160
						<td><code><?php echo esc_html( $data['themeAuthor'] ); ?></code></td>
161
					</tr>
162
					<tr>
163
						<td><?php esc_html_e( 'Theme URI', 'kirki' ); ?></td>
164
						<td><code><?php echo esc_html( $data['themeURI'] ); ?></code></td>
165
					</tr>
166
					<tr>
167
						<td><?php esc_html_e( 'Field Types Used', 'kirki' ); ?></td>
168
						<td><code><?php echo esc_html( implode( ',', $data['fieldTypes'] ) ); ?></code></td>
169
					</tr>
170
				</tbody>
171
				<tfoot>
172
					<tr>
173
						<th colspan="2">
174
							<?php
175
							printf(
176
								/* translators: %1$s: URL to the server plugin code. %2$s: URL to the stats page. */
177
								__( 'We believe in complete transparency. You can see the code used on our server <a href="%1$s" rel="nofollow">here</a>, and the results of the statistics we\'re gathering on <a href="%2$s" rel="nofollow">this page</a>.', 'kirki' ),
0 ignored issues
show
introduced by Ari
All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '__'.
Loading history...
178
								'https://github.com/aristath/kirki-telemetry-server',
179
								'https://wplemon.com/kirki-telemetry-statistics/'
180
							);
181
							?>
182
						</th>
183
					</tr>
184
				</tfoot>
185
			</table>
186
			<p class="actions">
187
188
				<a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'kirki-consent-notice', 'telemetry' ) ) ); ?>" class="button button-primary consent"><?php esc_html_e( 'I agree', 'kirki' ); ?></a>
189
				<a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'kirki-hide-notice', 'telemetry' ) ) ); ?>" class="button button-secondary dismiss"><?php esc_html_e( 'No thanks', 'kirki' ); ?></a>
190
				<a class="button button-link details details-show"><?php esc_html_e( 'Show me the data', 'kirki' ); ?></a>
191
				<a class="button button-link details details-hide hidden"><?php esc_html_e( 'Collapse data', 'kirki' ); ?></a>
192
			</p>
193
			<script>
194
			jQuery( '.kirki-telemetry a.consent' ).on( 'click', function() {
195
196
			});
197
			jQuery( '.kirki-telemetry a.dismiss' ).on( 'click', function() {
198
199
			});
200
			jQuery( '.kirki-telemetry a.details' ).on( 'click', function() {
201
				jQuery( '.kirki-telemetry .data-to-send' ).toggleClass( 'hidden' );
202
				jQuery( '.kirki-telemetry a.details-show' ).toggleClass( 'hidden' );
203
				jQuery( '.kirki-telemetry a.details-hide' ).toggleClass( 'hidden' );
204
			});
205
			</script>
206
		</div>
207
		<?php
208
	}
209
210
	/**
211
	 * Builds and returns the data or uses cached if data already exists.
212
	 *
213
	 * @access private
214
	 * @since 3.0.36
215
	 * @return array
216
	 */
217
	private function get_data() {
218
		// Get the theme.
219
		$theme = wp_get_theme();
220
221
		// Format the PHP version.
222
		$php_version = phpversion( 'tidy' );
223
		if ( ! $php_version ) {
224
			$php_version = array_merge( explode( '.', phpversion() ), array( 0, 0 ) );
225
			$php_version = "{$php_version[0]}.{$php_version[1]}";
226
		}
227
228
		// Build data and return the array.
229
		return array(
230
			'phpVer'      => $php_version,
231
			'themeName'   => $theme->get( 'Name' ),
232
			'themeAuthor' => $theme->get( 'Author' ),
233
			'themeURI'    => $theme->get( 'ThemeURI' ),
234
			'fieldTypes'  => $this->get_field_types(),
235
		);
236
	}
237
238
	/**
239
	 * Get the field-types used.
240
	 *
241
	 * @access private
242
	 * @since 3.0.36
243
	 * @return array
244
	 */
245
	public function get_field_types() {
246
		$types = array();
247
		foreach ( Kirki::$fields as $field ) {
248
			if ( isset( $field['type'] ) ) {
249
				$types[] = $field['type'];
250
			}
251
		}
252
		return $types;
253
	}
254
255
	/**
256
	 * Dismisses the notice.
257
	 *
258
	 * @access private
259
	 * @since 3.0.36
260
	 * @return void
261
	 */
262
	private function dismiss_notice() {
263
264
		// Check if this is the request we want.
265
		if ( isset( $_GET['_wpnonce'] ) && isset( $_GET['kirki-hide-notice'] ) ) {
266
			if ( 'telemetry' === sanitize_text_field( wp_unslash( $_GET['kirki-hide-notice'] ) ) ) {
0 ignored issues
show
introduced by Aristeides Stathopoulos
Processing form data without nonce verification.
Loading history...
267
				// Check the wp-nonce.
268
				if ( wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) ) ) {
269
					// All good, we can save the option to dismiss this notice.
270
					update_option( 'kirki_telemetry_no_consent', true );
271
				}
272
			}
273
		}
274
	}
275
276
	/**
277
	 * Dismisses the notice.
278
	 *
279
	 * @access private
280
	 * @since 3.0.36
281
	 * @return void
282
	 */
283
	private function consent() {
284
285
		// Check if this is the request we want.
286
		if ( isset( $_GET['_wpnonce'] ) && isset( $_GET['kirki-consent-notice'] ) ) {
287
			if ( 'telemetry' === sanitize_text_field( wp_unslash( $_GET['kirki-consent-notice'] ) ) ) {
0 ignored issues
show
introduced by Aristeides Stathopoulos
Processing form data without nonce verification.
Loading history...
288
				// Check the wp-nonce.
289
				if ( wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) ) ) {
290
					// All good, we can save the option to dismiss this notice.
291
					update_option( 'kirki_telemetry_optin', true );
292
				}
293
			}
294
		}
295
	}
296
}
297