|
1 <?php |
|
2 /** |
|
3 * Widget API: WP_Widget_Media_Image class |
|
4 * |
|
5 * @package WordPress |
|
6 * @subpackage Widgets |
|
7 * @since 4.8.0 |
|
8 */ |
|
9 |
|
10 /** |
|
11 * Core class that implements an image widget. |
|
12 * |
|
13 * @since 4.8.0 |
|
14 * |
|
15 * @see WP_Widget |
|
16 */ |
|
17 class WP_Widget_Media_Image extends WP_Widget_Media { |
|
18 |
|
19 /** |
|
20 * Constructor. |
|
21 * |
|
22 * @since 4.8.0 |
|
23 */ |
|
24 public function __construct() { |
|
25 parent::__construct( 'media_image', __( 'Image' ), array( |
|
26 'description' => __( 'Displays an image.' ), |
|
27 'mime_type' => 'image', |
|
28 ) ); |
|
29 |
|
30 $this->l10n = array_merge( $this->l10n, array( |
|
31 'no_media_selected' => __( 'No image selected' ), |
|
32 'add_media' => _x( 'Add Image', 'label for button in the image widget' ), |
|
33 'replace_media' => _x( 'Replace Image', 'label for button in the image widget; should preferably not be longer than ~13 characters long' ), |
|
34 'edit_media' => _x( 'Edit Image', 'label for button in the image widget; should preferably not be longer than ~13 characters long' ), |
|
35 'missing_attachment' => sprintf( |
|
36 /* translators: %s: URL to media library */ |
|
37 __( 'We can’t find that image. Check your <a href="%s">media library</a> and make sure it wasn’t deleted.' ), |
|
38 esc_url( admin_url( 'upload.php' ) ) |
|
39 ), |
|
40 /* translators: %d: widget count */ |
|
41 'media_library_state_multi' => _n_noop( 'Image Widget (%d)', 'Image Widget (%d)' ), |
|
42 'media_library_state_single' => __( 'Image Widget' ), |
|
43 ) ); |
|
44 } |
|
45 |
|
46 /** |
|
47 * Get schema for properties of a widget instance (item). |
|
48 * |
|
49 * @since 4.8.0 |
|
50 * |
|
51 * @see WP_REST_Controller::get_item_schema() |
|
52 * @see WP_REST_Controller::get_additional_fields() |
|
53 * @link https://core.trac.wordpress.org/ticket/35574 |
|
54 * @return array Schema for properties. |
|
55 */ |
|
56 public function get_instance_schema() { |
|
57 return array_merge( |
|
58 parent::get_instance_schema(), |
|
59 array( |
|
60 'size' => array( |
|
61 'type' => 'string', |
|
62 'enum' => array_merge( get_intermediate_image_sizes(), array( 'full', 'custom' ) ), |
|
63 'default' => 'medium', |
|
64 'description' => __( 'Size' ), |
|
65 ), |
|
66 'width' => array( // Via 'customWidth', only when size=custom; otherwise via 'width'. |
|
67 'type' => 'integer', |
|
68 'minimum' => 0, |
|
69 'default' => 0, |
|
70 'description' => __( 'Width' ), |
|
71 ), |
|
72 'height' => array( // Via 'customHeight', only when size=custom; otherwise via 'height'. |
|
73 'type' => 'integer', |
|
74 'minimum' => 0, |
|
75 'default' => 0, |
|
76 'description' => __( 'Height' ), |
|
77 ), |
|
78 |
|
79 'caption' => array( |
|
80 'type' => 'string', |
|
81 'default' => '', |
|
82 'sanitize_callback' => 'wp_kses_post', |
|
83 'description' => __( 'Caption' ), |
|
84 'should_preview_update' => false, |
|
85 ), |
|
86 'alt' => array( |
|
87 'type' => 'string', |
|
88 'default' => '', |
|
89 'sanitize_callback' => 'sanitize_text_field', |
|
90 'description' => __( 'Alternative Text' ), |
|
91 ), |
|
92 'link_type' => array( |
|
93 'type' => 'string', |
|
94 'enum' => array( 'none', 'file', 'post', 'custom' ), |
|
95 'default' => 'custom', |
|
96 'media_prop' => 'link', |
|
97 'description' => __( 'Link To' ), |
|
98 'should_preview_update' => true, |
|
99 ), |
|
100 'link_url' => array( |
|
101 'type' => 'string', |
|
102 'default' => '', |
|
103 'format' => 'uri', |
|
104 'media_prop' => 'linkUrl', |
|
105 'description' => __( 'URL' ), |
|
106 'should_preview_update' => true, |
|
107 ), |
|
108 'image_classes' => array( |
|
109 'type' => 'string', |
|
110 'default' => '', |
|
111 'sanitize_callback' => array( $this, 'sanitize_token_list' ), |
|
112 'media_prop' => 'extraClasses', |
|
113 'description' => __( 'Image CSS Class' ), |
|
114 'should_preview_update' => false, |
|
115 ), |
|
116 'link_classes' => array( |
|
117 'type' => 'string', |
|
118 'default' => '', |
|
119 'sanitize_callback' => array( $this, 'sanitize_token_list' ), |
|
120 'media_prop' => 'linkClassName', |
|
121 'should_preview_update' => false, |
|
122 'description' => __( 'Link CSS Class' ), |
|
123 ), |
|
124 'link_rel' => array( |
|
125 'type' => 'string', |
|
126 'default' => '', |
|
127 'sanitize_callback' => array( $this, 'sanitize_token_list' ), |
|
128 'media_prop' => 'linkRel', |
|
129 'description' => __( 'Link Rel' ), |
|
130 'should_preview_update' => false, |
|
131 ), |
|
132 'link_target_blank' => array( |
|
133 'type' => 'boolean', |
|
134 'default' => false, |
|
135 'media_prop' => 'linkTargetBlank', |
|
136 'description' => __( 'Open link in a new tab' ), |
|
137 'should_preview_update' => false, |
|
138 ), |
|
139 'image_title' => array( |
|
140 'type' => 'string', |
|
141 'default' => '', |
|
142 'sanitize_callback' => 'sanitize_text_field', |
|
143 'media_prop' => 'title', |
|
144 'description' => __( 'Image Title Attribute' ), |
|
145 'should_preview_update' => false, |
|
146 ), |
|
147 |
|
148 /* |
|
149 * There are two additional properties exposed by the PostImage modal |
|
150 * that don't seem to be relevant, as they may only be derived read-only |
|
151 * values: |
|
152 * - originalUrl |
|
153 * - aspectRatio |
|
154 * - height (redundant when size is not custom) |
|
155 * - width (redundant when size is not custom) |
|
156 */ |
|
157 ) |
|
158 ); |
|
159 } |
|
160 |
|
161 /** |
|
162 * Render the media on the frontend. |
|
163 * |
|
164 * @since 4.8.0 |
|
165 * |
|
166 * @param array $instance Widget instance props. |
|
167 * @return void |
|
168 */ |
|
169 public function render_media( $instance ) { |
|
170 $instance = array_merge( wp_list_pluck( $this->get_instance_schema(), 'default' ), $instance ); |
|
171 $instance = wp_parse_args( $instance, array( |
|
172 'size' => 'thumbnail', |
|
173 ) ); |
|
174 |
|
175 $attachment = null; |
|
176 if ( $this->is_attachment_with_mime_type( $instance['attachment_id'], $this->widget_options['mime_type'] ) ) { |
|
177 $attachment = get_post( $instance['attachment_id'] ); |
|
178 } |
|
179 if ( $attachment ) { |
|
180 $caption = ''; |
|
181 if ( ! isset( $instance['caption'] ) ) { |
|
182 $caption = $attachment->post_excerpt; |
|
183 } elseif ( trim( $instance['caption'] ) ) { |
|
184 $caption = $instance['caption']; |
|
185 } |
|
186 |
|
187 $image_attributes = array( |
|
188 'class' => sprintf( 'image wp-image-%d %s', $attachment->ID, $instance['image_classes'] ), |
|
189 'style' => 'max-width: 100%; height: auto;', |
|
190 ); |
|
191 if ( ! empty( $instance['image_title'] ) ) { |
|
192 $image_attributes['title'] = $instance['image_title']; |
|
193 } |
|
194 |
|
195 if ( $instance['alt'] ) { |
|
196 $image_attributes['alt'] = $instance['alt']; |
|
197 } |
|
198 |
|
199 $size = $instance['size']; |
|
200 if ( 'custom' === $size || ! in_array( $size, array_merge( get_intermediate_image_sizes(), array( 'full' ) ), true ) ) { |
|
201 $size = array( $instance['width'], $instance['height'] ); |
|
202 } |
|
203 $image_attributes['class'] .= sprintf( ' attachment-%1$s size-%1$s', is_array( $size ) ? join( 'x', $size ) : $size ); |
|
204 |
|
205 $image = wp_get_attachment_image( $attachment->ID, $size, false, $image_attributes ); |
|
206 |
|
207 $caption_size = _wp_get_image_size_from_meta( $instance['size'], wp_get_attachment_metadata( $attachment->ID ) ); |
|
208 $width = empty( $caption_size[0] ) ? 0 : $caption_size[0]; |
|
209 |
|
210 } else { |
|
211 if ( empty( $instance['url'] ) ) { |
|
212 return; |
|
213 } |
|
214 |
|
215 $instance['size'] = 'custom'; |
|
216 $caption = $instance['caption']; |
|
217 $width = $instance['width']; |
|
218 $classes = 'image ' . $instance['image_classes']; |
|
219 if ( 0 === $instance['width'] ) { |
|
220 $instance['width'] = ''; |
|
221 } |
|
222 if ( 0 === $instance['height'] ) { |
|
223 $instance['height'] = ''; |
|
224 } |
|
225 |
|
226 $image = sprintf( '<img class="%1$s" src="%2$s" alt="%3$s" width="%4$s" height="%5$s" />', |
|
227 esc_attr( $classes ), |
|
228 esc_url( $instance['url'] ), |
|
229 esc_attr( $instance['alt'] ), |
|
230 esc_attr( $instance['width'] ), |
|
231 esc_attr( $instance['height'] ) |
|
232 ); |
|
233 } // End if(). |
|
234 |
|
235 $url = ''; |
|
236 if ( 'file' === $instance['link_type'] ) { |
|
237 $url = $attachment ? wp_get_attachment_url( $attachment->ID ) : $instance['url']; |
|
238 } elseif ( $attachment && 'post' === $instance['link_type'] ) { |
|
239 $url = get_attachment_link( $attachment->ID ); |
|
240 } elseif ( 'custom' === $instance['link_type'] && ! empty( $instance['link_url'] ) ) { |
|
241 $url = $instance['link_url']; |
|
242 } |
|
243 |
|
244 if ( $url ) { |
|
245 $link = sprintf( '<a href="%s"', esc_url( $url ) ); |
|
246 if ( ! empty( $instance['link_classes'] ) ) { |
|
247 $link .= sprintf( ' class="%s"', esc_attr( $instance['link_classes'] ) ); |
|
248 } |
|
249 if ( ! empty( $instance['link_rel'] ) ) { |
|
250 $link .= sprintf( ' rel="%s"', esc_attr( $instance['link_rel'] ) ); |
|
251 } |
|
252 if ( ! empty( $instance['link_target_blank'] ) ) { |
|
253 $link .= ' target="_blank"'; |
|
254 } |
|
255 $link .= '>'; |
|
256 $link .= $image; |
|
257 $link .= '</a>'; |
|
258 $image = $link; |
|
259 } |
|
260 |
|
261 if ( $caption ) { |
|
262 $image = img_caption_shortcode( array( |
|
263 'width' => $width, |
|
264 'caption' => $caption, |
|
265 ), $image ); |
|
266 } |
|
267 |
|
268 echo $image; |
|
269 } |
|
270 |
|
271 /** |
|
272 * Loads the required media files for the media manager and scripts for media widgets. |
|
273 * |
|
274 * @since 4.8.0 |
|
275 */ |
|
276 public function enqueue_admin_scripts() { |
|
277 parent::enqueue_admin_scripts(); |
|
278 |
|
279 $handle = 'media-image-widget'; |
|
280 wp_enqueue_script( $handle ); |
|
281 |
|
282 $exported_schema = array(); |
|
283 foreach ( $this->get_instance_schema() as $field => $field_schema ) { |
|
284 $exported_schema[ $field ] = wp_array_slice_assoc( $field_schema, array( 'type', 'default', 'enum', 'minimum', 'format', 'media_prop', 'should_preview_update' ) ); |
|
285 } |
|
286 wp_add_inline_script( |
|
287 $handle, |
|
288 sprintf( |
|
289 'wp.mediaWidgets.modelConstructors[ %s ].prototype.schema = %s;', |
|
290 wp_json_encode( $this->id_base ), |
|
291 wp_json_encode( $exported_schema ) |
|
292 ) |
|
293 ); |
|
294 |
|
295 wp_add_inline_script( |
|
296 $handle, |
|
297 sprintf( |
|
298 ' |
|
299 wp.mediaWidgets.controlConstructors[ %1$s ].prototype.mime_type = %2$s; |
|
300 wp.mediaWidgets.controlConstructors[ %1$s ].prototype.l10n = _.extend( {}, wp.mediaWidgets.controlConstructors[ %1$s ].prototype.l10n, %3$s ); |
|
301 ', |
|
302 wp_json_encode( $this->id_base ), |
|
303 wp_json_encode( $this->widget_options['mime_type'] ), |
|
304 wp_json_encode( $this->l10n ) |
|
305 ) |
|
306 ); |
|
307 } |
|
308 |
|
309 /** |
|
310 * Render form template scripts. |
|
311 * |
|
312 * @since 4.8.0 |
|
313 */ |
|
314 public function render_control_template_scripts() { |
|
315 parent::render_control_template_scripts(); |
|
316 |
|
317 ?> |
|
318 <script type="text/html" id="tmpl-wp-media-widget-image-fields"> |
|
319 <# var elementIdPrefix = 'el' + String( Math.random() ) + '_'; #> |
|
320 <# if ( data.url ) { #> |
|
321 <p class="media-widget-image-link"> |
|
322 <label for="{{ elementIdPrefix }}linkUrl"><?php esc_html_e( 'Link to:' ); ?></label> |
|
323 <input id="{{ elementIdPrefix }}linkUrl" type="text" class="widefat link" value="{{ data.link_url }}" placeholder="http://" pattern="((\w+:)?\/\/\w.*|\w+:(?!\/\/$)|\/|\?|#).*"> |
|
324 </p> |
|
325 <# } #> |
|
326 </script> |
|
327 <script type="text/html" id="tmpl-wp-media-widget-image-preview"> |
|
328 <# var describedById = 'describedBy-' + String( Math.random() ); #> |
|
329 <# if ( data.error && 'missing_attachment' === data.error ) { #> |
|
330 <div class="notice notice-error notice-alt notice-missing-attachment"> |
|
331 <p><?php echo $this->l10n['missing_attachment']; ?></p> |
|
332 </div> |
|
333 <# } else if ( data.error ) { #> |
|
334 <div class="notice notice-error notice-alt"> |
|
335 <p><?php _e( 'Unable to preview media due to an unknown error.' ); ?></p> |
|
336 </div> |
|
337 <# } else if ( data.url ) { #> |
|
338 <img class="attachment-thumb" src="{{ data.url }}" draggable="false" alt="{{ data.alt }}" <# if ( ! data.alt && data.currentFilename ) { #> aria-describedby="{{ describedById }}" <# } #> /> |
|
339 <# if ( ! data.alt && data.currentFilename ) { #> |
|
340 <p class="hidden" id="{{ describedById }}"><?php |
|
341 /* translators: placeholder is image filename */ |
|
342 echo sprintf( __( 'Current image: %s' ), '{{ data.currentFilename }}' ); |
|
343 ?></p> |
|
344 <# } #> |
|
345 <# } #> |
|
346 </script> |
|
347 <?php |
|
348 } |
|
349 } |