Test Failed
Push — master ( 339236...7fe983 )
by Devin
09:29 queued 04:18
created

Give_i18n_Banner::init()   B

Complexity

Conditions 8
Paths 6

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 9
nc 6
nop 0
dl 0
loc 18
rs 7.7777
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Class Give_i18n
5
 */
6
class Give_i18n_Banner {
7
8
	/**
9
	 * Your translation site's URL.
10
	 *
11
	 * @var string
12
	 */
13
	private $glotpress_url;
14
15
	/**
16
	 * Hook where you want to show the promo box.
17
	 *
18
	 * @var string
19
	 */
20
	private $hook;
21
22
	/**
23
	 * Will contain the site's locale.
24
	 *
25
	 * @access private
26
	 * @var string
27
	 */
28
	private $locale;
29
30
	/**
31
	 * Will contain the locale's name, obtained from your translation site.
32
	 *
33
	 * @access private
34
	 * @var string
35
	 */
36
	private $locale_name;
37
38
	/**
39
	 * Will contain the percentage translated for the plugin translation project in the locale.
40
	 *
41
	 * @access private
42
	 * @var int
43
	 */
44
	private $percent_translated;
45
46
47
	/**
48
	 * Indicates whether there's a translation available at all.
49
	 *
50
	 * @access private
51
	 * @var bool
52
	 */
53
	private $translation_exists;
54
55
	/**
56
	 * Indicates whether the translation's loaded.
57
	 *
58
	 * @access private
59
	 * @var bool
60
	 */
61
	private $translation_loaded;
62
63
	/**
64
	 * Give_i18n constructor.
65
	 *
66
	 * @param $args
67
	 */
68
	public function __construct( $args ) {
69
70
		// Only for admins.
71
		if ( ! is_admin() ) {
72
			return;
73
		}
74
75
		foreach ( $args as $key => $arg ) {
76
			$this->$key = $arg;
77
		}
78
79
		add_action( 'admin_init', array( $this, 'init' ) );
80
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
81
82
	}
83
84
	/**
85
	 * Initialize i18n banner.
86
	 */
87
	function init() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
88
89
		// First get user's locale (4.7+).
90
		$this->locale = function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale();
91
92
		// This plugin is en_US native.
93
		if ( 'en_US' === $this->locale ) {
94
			return;
95
		}
96
97
		if (
98
			! $this->hide_promo()
99
			&& ( ! empty( $_GET['post_type'] ) && 'give_forms' === $_GET['post_type'] )
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
100
			&& ( ! empty( $_GET['page'] ) && 'give-settings' === $_GET['page'] )
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
101
		) {
102
			add_action( $this->hook, array( $this, 'promo' ) );
103
		}
104
	}
105
106
107
	/**
108
	 * Check whether the promo should be hidden or not.
109
	 *
110
	 * @access private
111
	 *
112
	 * @return bool
113
	 */
114
	private function hide_promo() {
115
		$hide_promo = Give_Cache::get( 'give_i18n_give_promo_hide', true );
116
		if ( ! $hide_promo ) {
117
			if ( filter_input( INPUT_GET, 'remove_i18n_promo', FILTER_VALIDATE_INT ) === 1 ) {
0 ignored issues
show
introduced by
Found "=== 1". Use Yoda Condition checks, you must
Loading history...
118
				// No expiration time, so this would normally not expire, but it wouldn't be copied to other sites etc.
119
				Give_Cache::set( 'give_i18n_give_promo_hide', true, null, true );
120
				$hide_promo = true;
121
			}
122
		}
123
124
		return $hide_promo;
125
	}
126
127
	/**
128
	 * Generates a promo message.
129
	 *
130
	 * @access private
131
	 *
132
	 * @return bool|string $message
133
	 */
134
	private function promo_message() {
135
		$message = false;
136
137
		// Using a translation less than 90% complete.
138
		if ( $this->translation_exists && $this->translation_loaded && $this->percent_translated < 90 ) {
139
			$message = __( 'As you can see, there is a translation of this plugin in %1$s. This translation is currently %3$d%% complete. We need your help to make it complete and to fix any errors. Please register at %4$s to help %5$s to %1$s!', 'give' );
140
		} elseif ( ! $this->translation_loaded && $this->translation_exists ) {
141
			$message = __( 'You\'re using WordPress in %1$s. While %2$s has been %3$d%% translated to %1$s, it has not been shipped with the plugin yet. You can help! Register at %4$s to help complete the translation to %1$s!', 'give' );
142
		} elseif ( ! $this->translation_exists ) {
143
			$message = __( 'You\'re using WordPress in a language we don\'t support yet. We\'d love for %2$s to be translated in that language too, but unfortunately, it isn\'t right now. You can change that! Register at %4$s to help translate it!', 'give' );
144
		}
145
146
		// Links.
147
		$registration_link = sprintf( '<a href="%1$s" target="_blank">%2$s</a>', 'https://wordpress.org/support/register.php', esc_html__( 'WordPress.org', 'give' ) );
148
		$translations_link = sprintf( '<a href="%1$s" target="_blank">%2$s</a>', 'https://translate.wordpress.org/projects/wp-plugins/give', esc_html__( 'complete the translation', 'give' ) );
149
150
		// Message.
151
		$message = sprintf( $message, $this->locale_name, 'Give', $this->percent_translated, $registration_link, $translations_link );
152
153
		return $message;
154
155
	}
156
157
	/**
158
	 * Outputs a promo box
159
	 */
160
	public function promo() {
161
162
		$this->translation_details();
163
		$message = $this->promo_message();
164
165
		if ( $message ) { ?>
166
167
			<style>
168
				/* Banner specific styles */
169
				div.give-addon-alert.updated {
170
					padding: 10px 20px;
171
					position: relative;
172
					border-color: #66BB6A;
173
					overflow: hidden;
174
				}
175
176
				div.give-addon-alert a {
177
					color: #66BB6A;
178
				}
179
180
				#give-i18n-notice > .give-i18n-icon {
181
					overflow: hidden;
182
				}
183
184
				#give-i18n-notice > .give-i18n-icon .dashicons {
185
					width: 110px;
186
					height: 110px;
187
				}
188
189
				#give-i18n-notice > .give-i18n-icon:focus {
190
					box-shadow: none;
191
				}
192
193
				.give-i18n-notice-content {
194
					margin: 0 30px 0 125px;
195
				}
196
197
				div.give-addon-alert .dismiss {
198
					position: absolute;
199
					right: 20px;
200
					height: 100%;
201
					top: 50%;
202
					margin-top: -10px;
203
					outline: none;
204
					box-shadow: none;
205
					text-decoration: none;
206
					color: #AAA;
207
				}
208
209
				div.give-addon-alert .dismiss:hover {
210
					color: #333;
211
				}
212
213
				/* RTL Styles for banner */
214
				body.rtl .give-i18n-notice-content {
215
					margin: 0 125px 0 30px;
216
				}
217
218
				body.rtl div.give-addon-alert .dismiss {
219
					left: 20px;
220
					right: auto;
221
				}
222
223
			</style>
224
			<div id="give-i18n-notice" class="give-addon-alert updated" style="">
225
226
				<a href="https://wordpress.org/support/register.php" class="alignleft give-i18n-icon" style="margin:0" target="_blank"><span class="dashicons dashicons-translation"
227
				                                                                                                                             style="font-size: 110px; text-decoration: none;"></span></a>
228
229
				<div class="give-i18n-notice-content">
230
					<a href="<?php echo esc_url( add_query_arg( array( 'remove_i18n_promo' => '1' ) ) ); ?>" class="dismiss"><span class="dashicons dashicons-dismiss"></span></a>
231
232
					<h2 style="margin: 10px 0;"><?php printf( esc_html__( 'Help Translate Give to %s', 'give' ), $this->locale_name ); ?></h2>
233
					<p><?php echo $message; ?></p>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$message'
Loading history...
234
					<p>
235
						<a href="https://wordpress.org/support/register.php" target="_blank"><?php _e( 'Register now &raquo;', 'give' ); ?></a>
236
					</p>
237
				</div>
238
			</div>
239
			<?php
240
		}
241
	}
242
243
	/**
244
	 * Try to find the transient for the translation set or retrieve them.
245
	 *
246
	 * @access private
247
	 *
248
	 * @return object|null
249
	 */
250
	private function find_or_initialize_translation_details() {
251
252
		$set = Give_Cache::get( "give_i18n_give_{$this->locale}", true );
253
254
		if ( ! $set ) {
255
			$set = $this->retrieve_translation_details();
256
			Give_Cache::set( "give_i18n_give_{$this->locale}", $set, DAY_IN_SECONDS, true );
257
		}
258
259
		return $set;
260
	}
261
262
	/**
263
	 * Try to get translation details from cache, otherwise retrieve them, then parse them.
264
	 *
265
	 * @access private
266
	 */
267
	private function translation_details() {
268
		$set = $this->find_or_initialize_translation_details();
269
270
		$this->translation_exists = ! is_null( $set );
271
		$this->translation_loaded = is_textdomain_loaded( 'give' );
272
273
		$this->parse_translation_set( $set );
0 ignored issues
show
Bug introduced by
It seems like $set defined by $this->find_or_initialize_translation_details() on line 268 can also be of type null; however, Give_i18n_Banner::parse_translation_set() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
274
	}
275
276
	/**
277
	 * Retrieve the translation details from Give Translate.
278
	 *
279
	 * @access private
280
	 *
281
	 * @return object|null
282
	 */
283
	private function retrieve_translation_details() {
284
285
		$api_url = trailingslashit( $this->glotpress_url );
286
287
		$resp = wp_remote_get( $api_url );
0 ignored issues
show
introduced by
wp_remote_get is highly discouraged, please use vip_safe_wp_remote_get() instead.
Loading history...
288
289
		if ( is_wp_error( $resp ) || wp_remote_retrieve_response_code( $resp ) === '404' ) {
0 ignored issues
show
introduced by
Found "=== '". Use Yoda Condition checks, you must
Loading history...
290
			return null;
291
		}
292
293
		$body = wp_remote_retrieve_body( $resp );
294
		unset( $resp );
295
296
		if ( $body ) {
297
			$body = json_decode( $body );
298
299
			foreach ( $body->translation_sets as $set ) {
300
				if ( ! property_exists( $set, 'wp_locale' ) ) {
301
					continue;
302
				}
303
304
				if ( $this->locale == $set->wp_locale ) {
305
					return $set;
306
				}
307
			}
308
		}
309
310
		return null;
311
	}
312
313
	/**
314
	 * Set the needed private variables based on the results from Give Translate.
315
	 *
316
	 * @param object $set The translation set
317
	 *
318
	 * @access private
319
	 */
320
	private function parse_translation_set( $set ) {
321
		if ( $this->translation_exists && is_object( $set ) ) {
322
			$this->locale_name        = $set->name;
323
			$this->percent_translated = $set->percent_translated;
324
		} else {
325
			$this->locale_name        = '';
326
			$this->percent_translated = '';
0 ignored issues
show
Documentation Bug introduced by
The property $percent_translated was declared of type integer, but '' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
327
		}
328
	}
329
}
330
331
$give_i18n = new Give_i18n_Banner( array(
332
		'hook'          => 'admin_notices',
333
		'glotpress_url' => 'https://translate.wordpress.org/api/projects/wp-plugins/give/stable/',
334
	) );
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 0 spaces, but found 4.
Loading history...
335