Completed
Pull Request — trunk (#578)
by Juliette
14:17 queued 06:50
created

CMB2_Utils::array_insert()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2
Metric Value
dl 0
loc 5
rs 9.4285
ccs 0
cts 0
cp 0
cc 1
eloc 4
nc 1
nop 3
crap 2
1
<?php
2
/**
3
 * CMB2 Utilities
4
 *
5
 * @since  1.1.0
6
 *
7
 * @category  WordPress_Plugin
8
 * @package   CMB2
9
 * @author    WebDevStudios
10
 * @license   GPL-2.0+
11
 * @link      http://webdevstudios.com
12
 */
13
class CMB2_Utils {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
14
15
	/**
16
	 * The url which is used to load local resources.
17
	 * @var   string
18
	 * @since 2.0.0
19
	 */
20
	protected $url = '';
21
22 1
	/**
23 1
	 * Utility method that attempts to get an attachment's ID by it's url
24
	 * @since  1.0.0
25 1
	 * @param  string  $img_url Attachment url
26
	 * @return int|false            Attachment ID or false
27 1
	 */
28 1
	public function image_id_from_url( $img_url ) {
29 1
		$attachment_id = 0;
30 1
		$dir = wp_upload_dir();
31
32
		// Is URL in uploads directory?
33 1
		if ( false === strpos( $img_url, $dir['baseurl'] . '/' ) ) {
34
			return false;
35
		}
36 1
37 1
		$file = basename( $img_url );
38
39
		$query_args = array(
40
			'post_type'   => 'attachment',
41
			'post_status' => 'inherit',
42
			'fields'      => 'ids',
43
			'meta_query'  => array(
44
				array(
45
					'value'   => $file,
46
					'compare' => 'LIKE',
47
					'key'     => '_wp_attachment_metadata',
48
				),
49
			)
50 2
		);
51 2
52 1
		$query = new WP_Query( $query_args );
53 1
54 1
		if ( $query->have_posts() ) {
55
56
			foreach ( $query->posts as $post_id ) {
57
				$meta = wp_get_attachment_metadata( $post_id );
58
				$original_file       = basename( $meta['file'] );
59
				$cropped_image_files = isset( $meta['sizes'] ) ? wp_list_pluck( $meta['sizes'], 'file' ) : array();
60
				if ( $original_file === $file || in_array( $file, $cropped_image_files ) ) {
61
					$attachment_id = $post_id;
62
					break;
63 1
				}
64
			}
65
66
		}
67
68
		return 0 === $attachment_id ? false : $attachment_id;
69
	}
70
71
	/**
72
	 * Utility method that returns time string offset by timezone
73
	 * @since  1.0.0
74
	 * @param  string $tzstring Time string
75
	 * @return string           Offset time string
76
	 */
77 2
	public function timezone_offset( $tzstring ) {
78 2
		$tz_offset = 0;
79 2
80
		if ( ! empty( $tzstring ) && is_string( $tzstring ) ) {
81 2
			if ( 'UTC' === substr( $tzstring, 0, 3 ) ) {
82 2
				$tzstring = str_replace( array( ':15', ':30', ':45' ), array( '.25', '.5', '.75' ), $tzstring );
83 2
				return intval( floatval( substr( $tzstring, 3 ) ) * HOUR_IN_SECONDS );
84 2
			}
85
86
			try {
87
				$date_time_zone_selected = new DateTimeZone( $tzstring );
88
				$tz_offset = timezone_offset_get( $date_time_zone_selected, date_create() );
89 2
			} catch ( Exception $e ) {
90
				$this->log_if_debug( __METHOD__, __LINE__, $e->getMessage() );
91 2
			}
92
93
		}
94
95
		return $tz_offset;
96
	}
97
98
	/**
99
	 * Utility method that returns a timezone string representing the default timezone for the site.
100 5
	 *
101 5
	 * Roughly copied from WordPress, as get_option('timezone_string') will return
102
	 * an empty string if no value has been set on the options page.
103
	 * A timezone string is required by the wp_timezone_choice() used by the
104
	 * select_timezone field.
105 5
	 *
106 5
	 * @since  1.0.0
107 5
	 * @return string Timezone string
108
	 */
109
	public function timezone_string() {
110
		$current_offset = get_option( 'gmt_offset' );
111
		$tzstring       = get_option( 'timezone_string' );
112
113
		if ( empty( $tzstring ) ) { // Create a UTC+- zone if no timezone string exists
114
			if ( 0 == $current_offset ) {
115
				$tzstring = 'UTC+0';
116 5
			} elseif ( $current_offset < 0 ) {
117 5
				$tzstring = 'UTC' . $current_offset;
118 5
			} else {
119 5
				$tzstring = 'UTC+' . $current_offset;
120 5
			}
121
		}
122
123
		return $tzstring;
124
	}
125
126
	/**
127
	 * Returns a timestamp, first checking if value already is a timestamp.
128
	 * @since  2.0.0
129
	 * @param  string|int $string Possible timestamp string
130 2
	 * @return int   	            Time stamp
131 2
	 */
132 1
	public function make_valid_time_stamp( $string ) {
133
		if ( ! $string ) {
134
			return 0;
135 1
		}
136
137
		return $this->is_valid_time_stamp( $string )
138
			? (int) $string :
139
			strtotime( (string) $string );
140
	}
141
142 1
	/**
143 1
	 * Determine if a value is a valid timestamp
144 1
	 * @since  2.0.0
145 1
	 * @param  mixed  $timestamp Value to check
146 1
	 * @return boolean           Whether value is a valid timestamp
147
	 */
148
	public function is_valid_time_stamp( $timestamp ) {
149
		return (string) (int) $timestamp === (string) $timestamp
150
			&& $timestamp <= PHP_INT_MAX
151
			&& $timestamp >= ~PHP_INT_MAX;
152
	}
153
154 1
	/**
155
	 * Checks if a value is 'empty'. Still accepts 0.
156 1
	 * @since  2.0.0
157
	 * @param  mixed $value Value to check
158
	 * @return bool         True or false
159
	 */
160 1
	public function isempty( $value ) {
161
		return null === $value || '' === $value || false === $value;
162
	}
163
164
	/**
165
	 * Insert a single array item inside another array at a set position
166
	 * @since  2.0.2
167
	 * @param  array &$array   Array to modify. Is passed by reference, and no return is needed.
168
	 * @param  array $new      New array to insert
169
	 * @param  int   $position Position in the main array to insert the new array
170
	 */
171
	public function array_insert( &$array, $new, $position ) {
172
		$before = array_slice( $array, 0, $position - 1 );
173
		$after  = array_diff_key( $array, $before );
174
		$array  = array_merge( $before, $new, $after );
175
	}
176
177
	/**
178
	 * Defines the url which is used to load local resources.
179
	 * This may need to be filtered for local Window installations.
180
	 * If resources do not load, please check the wiki for details.
181
	 * @since  1.0.1
182
	 * @return string URL to CMB2 resources
183
	 */
184
	public function url( $path = '' ) {
185
		if ( $this->url ) {
186
			return $this->url . $path;
187
		}
188
189
		if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) ) {
190
			// Windows
191
			$content_dir = str_replace( '/', DIRECTORY_SEPARATOR, WP_CONTENT_DIR );
192
			$content_url = str_replace( $content_dir, WP_CONTENT_URL, cmb2_dir() );
193
			$cmb2_url = str_replace( DIRECTORY_SEPARATOR, '/', $content_url );
194
195
		} else {
196
			$cmb2_url = str_replace(
197
				array( WP_CONTENT_DIR, WP_PLUGIN_DIR ),
198
				array( WP_CONTENT_URL, WP_PLUGIN_URL ),
199
				cmb2_dir()
200
			);
201
		}
202
203
		/**
204
		 * Filter the CMB location url
205
		 *
206
		 * @param string $cmb2_url Currently registered url
207
		 */
208
		$this->url = trailingslashit( apply_filters( 'cmb2_meta_box_url', set_url_scheme( $cmb2_url ), CMB2_VERSION ) );
209
210
		return $this->url . $path;
211
	}
212
213
	/**
214
	 * Get timestamp from text date
215
	 * @since  2.2.0
216
	 * @param  string $value       Date value
217
	 * @param  string $date_format Expected date format
218
	 * @return mixed               Unix timestamp representing the date.
219
	 */
220
	public function get_timestamp_from_value( $value, $date_format ) {
221
		$date_object = date_create_from_format( $date_format, $value );
222
		return $date_object ? $date_object->setTime( 0, 0, 0 )->getTimeStamp() : strtotime( $value );
223
	}
224
225
	/**
226
	 * Takes a php date() format string and returns a string formatted to suit for the date/time pickers
227
	 * It will work with only with the following subset ot date() options:
228
	 *
229
	 *  d, j, z, m, n, y, and Y.
230
	 *
231
	 * A slight effort is made to deal with escaped characters.
232
	 *
233
	 * Other options are ignored, because they would either bring compatibility problems between PHP and JS, or
234
	 * bring even more translation troubles.
235
	 *
236
	 * @since 2.2.0
237
	 * @param string $format php date format
238
	 * @return string reformatted string
239
	 */
240
	public function php_to_js_dateformat( $format ) {
241
242
		// order is relevant here, since the replacement will be done sequentially.
243
		$supported_options = array(
244
			'd' => 'dd',  // Day, leading 0
245
			'j' => 'd',   // Day, no 0
246
			'z' => 'o',   // Day of the year, no leading zeroes,
247
			// 'D' => 'D',   // Day name short, not sure how it'll work with translations
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
248
			// 'l' => 'DD',  // Day name full, idem before
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
249
			'm' => 'mm',  // Month of the year, leading 0
250
			'n' => 'm',   // Month of the year, no leading 0
251
			// 'M' => 'M',   // Month, Short name
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
252
			// 'F' => 'MM',  // Month, full name,
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
253
			'y' => 'y',   // Year, two digit
254
			'Y' => 'yy',  // Year, full
255
			'H' => 'HH',  // Hour with leading 0 (24 hour)
256
			'G' => 'H',   // Hour with no leading 0 (24 hour)
257
			'h' => 'hh',  // Hour with leading 0 (12 hour)
258
			'g' => 'h',   // Hour with no leading 0 (12 hour),
259
			'i' => 'mm',  // Minute with leading 0,
260
			's' => 'ss',  // Second with leading 0,
261
			'a' => 'tt',  // am/pm
262
			'A' => 'TT'   // AM/PM
263
		);
264
265
		foreach ( $supported_options as $php => $js ) {
266
			// replaces every instance of a supported option, but skips escaped characters
267
			$format = preg_replace( "~(?<!\\\\)$php~", $js, $format );
268
		}
269
270
		$format = preg_replace_callback( '~(?:\\\.)+~', array( $this, 'wrap_escaped_chars' ), $format );
271
272
		return $format;
273
	}
274
275
	/**
276
	 * Helper function for CMB_Utils->php_to_js_dateformat, because php 5.2 was retarded.
277
	 * @since  2.2.0
278
	 * @param  $value Value to wrap/escape
279
	 * @return string Modified value
280
	 */
281
	public function wrap_escaped_chars( $value ) {
282
		return "&#39;" . str_replace( '\\', '', $value[0] ) . "&#39;";
283
	}
284
285
	/**
286
	 * Send to debug.log if WP_DEBUG is defined and true
287
	 *
288
	 * @since  2.2.0
289
	 *
290
	 * @param  string  $function Function name
291
	 * @param  int     $line     Line number
292
	 * @param  mixed   $msg      Message to output
293
	 * @param  mixed   $debug    Variable to print_r
294
	 */
295
	public function log_if_debug( $function, $line, $msg, $debug = null ) {
296
		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
297
			error_log( "In $function, $line:" . print_r( $msg, true ) . ( $debug ? print_r( $debug, true ) : '' ) );
298
		}
299
	}
300
301
}
302