Test Failed
Push — issues/2042 ( e8b6b5 )
by Ravinder
05:59
created

Give_i18n_Banner::init()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 6
nc 6
nop 0
dl 0
loc 14
rs 8.8571
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 ( ! $this->hide_promo() && ( 'give_forms' === $_GET['post_type'] ) && ( '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-validated input variable: $_GET
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
98
			add_action( $this->hook, array( $this, 'promo' ) );
99
		}
100
	}
101
102
103
	/**
104
	 * Check whether the promo should be hidden or not.
105
	 *
106
	 * @access private
107
	 *
108
	 * @return bool
109
	 */
110
	private function hide_promo() {
111
		$hide_promo = Give_Cache::get( 'give_i18n_give_promo_hide', true );
112
		if ( ! $hide_promo ) {
113
			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...
114
				// No expiration time, so this would normally not expire, but it wouldn't be copied to other sites etc.
115
				Give_Cache::set( 'give_i18n_give_promo_hide', true, null, true );
116
				$hide_promo = true;
117
			}
118
		}
119
120
		return $hide_promo;
121
	}
122
123
	/**
124
	 * Generates a promo message.
125
	 *
126
	 * @access private
127
	 *
128
	 * @return bool|string $message
129
	 */
130
	private function promo_message() {
131
		$message = false;
132
133
		// Using a translation less than 90% complete.
134
		if ( $this->translation_exists && $this->translation_loaded && $this->percent_translated < 90 ) {
135
			$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' );
136
		} elseif ( ! $this->translation_loaded && $this->translation_exists ) {
137
			$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' );
138
		} elseif ( ! $this->translation_exists ) {
139
			$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' );
140
		}
141
142
		// Links.
143
		$registration_link = sprintf( '<a href="%1$s" target="_blank">%2$s</a>', 'https://wordpress.org/support/register.php', esc_html__( 'WordPress.org', 'give' ) );
144
		$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' ) );
145
146
		// Message.
147
		$message = sprintf( $message, $this->locale_name, 'Give', $this->percent_translated, $registration_link, $translations_link );
148
149
		return $message;
150
151
	}
152
153
	/**
154
	 * Outputs a promo box
155
	 */
156
	public function promo() {
157
158
		$this->translation_details();
159
		$message = $this->promo_message();
160
161
		if ( $message ) { ?>
162
163
			<style>
164
				/* Banner specific styles */
165
				div.give-addon-alert.updated {
166
					padding: 10px 20px;
167
					position: relative;
168
					border-color: #66BB6A;
169
					overflow: hidden;
170
				}
171
172
				div.give-addon-alert a {
173
					color: #66BB6A;
174
				}
175
176
				#give-i18n-notice > .give-i18n-icon {
177
					overflow: hidden;
178
				}
179
180
				#give-i18n-notice > .give-i18n-icon .dashicons {
181
					width: 110px;
182
					height: 110px;
183
				}
184
185
				#give-i18n-notice > .give-i18n-icon:focus {
186
					box-shadow: none;
187
				}
188
189
				.give-i18n-notice-content {
190
					margin: 0 30px 0 125px;
191
				}
192
193
				div.give-addon-alert .dismiss {
194
					position: absolute;
195
					right: 20px;
196
					height: 100%;
197
					top: 50%;
198
					margin-top: -10px;
199
					outline: none;
200
					box-shadow: none;
201
					text-decoration: none;
202
					color: #AAA;
203
				}
204
205
				div.give-addon-alert .dismiss:hover {
206
					color: #333;
207
				}
208
209
				/* RTL Styles for banner */
210
				body.rtl .give-i18n-notice-content {
211
					margin: 0 125px 0 30px;
212
				}
213
214
				body.rtl div.give-addon-alert .dismiss {
215
					left: 20px;
216
					right: auto;
217
				}
218
219
			</style>
220
			<div id="give-i18n-notice" class="give-addon-alert updated" style="">
221
222
				<a href="https://wordpress.org/support/register.php" class="alignleft give-i18n-icon" style="margin:0" target="_blank"><span class="dashicons dashicons-translation"
223
				                                                                                                                             style="font-size: 110px; text-decoration: none;"></span></a>
224
225
				<div class="give-i18n-notice-content">
226
					<a href="<?php echo esc_url( add_query_arg( array( 'remove_i18n_promo' => '1' ) ) ); ?>" class="dismiss"><span class="dashicons dashicons-dismiss"></span></a>
227
228
					<h2 style="margin: 10px 0;"><?php printf( esc_html__( 'Help Translate Give to %s', 'give' ), $this->locale_name ); ?></h2>
229
					<p><?php echo $message; ?></p>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$message'
Loading history...
230
					<p>
231
						<a href="https://wordpress.org/support/register.php" target="_blank"><?php _e( 'Register now &raquo;', 'give' ); ?></a>
232
					</p>
233
				</div>
234
			</div>
235
			<?php
236
		}
237
	}
238
239
	/**
240
	 * Try to find the transient for the translation set or retrieve them.
241
	 *
242
	 * @access private
243
	 *
244
	 * @return object|null
245
	 */
246
	private function find_or_initialize_translation_details() {
247
248
		$set = Give_Cache::get( "give_i18n_give_{$this->locale}", true );
249
250
		if ( ! $set ) {
251
			$set = $this->retrieve_translation_details();
252
			Give_Cache::set( "give_i18n_give_{$this->locale}", $set, DAY_IN_SECONDS, true );
253
		}
254
255
		return $set;
256
	}
257
258
	/**
259
	 * Try to get translation details from cache, otherwise retrieve them, then parse them.
260
	 *
261
	 * @access private
262
	 */
263
	private function translation_details() {
264
		$set = $this->find_or_initialize_translation_details();
265
266
		$this->translation_exists = ! is_null( $set );
267
		$this->translation_loaded = is_textdomain_loaded( 'give' );
268
269
		$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 264 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...
270
	}
271
272
	/**
273
	 * Retrieve the translation details from Give Translate.
274
	 *
275
	 * @access private
276
	 *
277
	 * @return object|null
278
	 */
279
	private function retrieve_translation_details() {
280
281
		$api_url = trailingslashit( $this->glotpress_url );
282
283
		$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...
284
285
		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...
286
			return null;
287
		}
288
289
		$body = wp_remote_retrieve_body( $resp );
290
		unset( $resp );
291
292
		if ( $body ) {
293
			$body = json_decode( $body );
294
295
			foreach ( $body->translation_sets as $set ) {
296
				if ( ! property_exists( $set, 'wp_locale' ) ) {
297
					continue;
298
				}
299
300
				if ( $this->locale == $set->wp_locale ) {
301
					return $set;
302
				}
303
			}
304
		}
305
306
		return null;
307
	}
308
309
	/**
310
	 * Set the needed private variables based on the results from Give Translate.
311
	 *
312
	 * @param object $set The translation set
313
	 *
314
	 * @access private
315
	 */
316
	private function parse_translation_set( $set ) {
317
		if ( $this->translation_exists && is_object( $set ) ) {
318
			$this->locale_name        = $set->name;
319
			$this->percent_translated = $set->percent_translated;
320
		} else {
321
			$this->locale_name        = '';
322
			$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...
323
		}
324
	}
325
}
326
327
$give_i18n = new Give_i18n_Banner( array(
328
		'hook'          => 'admin_notices',
329
		'glotpress_url' => 'https://translate.wordpress.org/api/projects/wp-plugins/give/stable/',
330
	) );
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...
331