Favicon Rotator - Version 1.2

Version Description

  • Add: Support for setting Touch icon (iOS, Android, etc.)
Download this release

Release Info

Developer Archetyped
Plugin Icon wp plugin Favicon Rotator
Version 1.2
Comparing to
See all releases

Code changes from version 1.1 to 1.2

css/admin_styles.css CHANGED
@@ -31,6 +31,11 @@
31
  height: 16px;
32
  }
33
 
 
 
 
 
 
34
  .fv_item .remove {
35
  background: url('../images/icon_close.gif') no-repeat;
36
  text-indent: -2000em;
@@ -46,3 +51,13 @@
46
  .fv_item a:hover.remove {
47
  opacity: 1;
48
  }
 
 
 
 
 
 
 
 
 
 
31
  height: 16px;
32
  }
33
 
34
+ #fv_item_wrap_touch .fv_item .icon {
35
+ width: 114px;
36
+ height: 114px;
37
+ }
38
+
39
  .fv_item .remove {
40
  background: url('../images/icon_close.gif') no-repeat;
41
  text-indent: -2000em;
51
  .fv_item a:hover.remove {
52
  opacity: 1;
53
  }
54
+
55
+ .fv_btn {
56
+ font-family: Georgia, "Times New Roman", Times, serif;
57
+ font-weight: normal;
58
+ }
59
+
60
+ .fv_container {
61
+ clear: all;
62
+ overflow: hidden;
63
+ }
css/media.css CHANGED
@@ -1 +1,2 @@
 
1
  .ml-submit { display: none !important; }
1
+ #media-items .fvrt_data,
2
  .ml-submit { display: none !important; }
includes/class.base.php CHANGED
@@ -9,18 +9,6 @@ require_once 'class.utilities.php';
9
  */
10
  class FVRT_Base {
11
 
12
- /**
13
- * Size to use for icon attachment
14
- * @var string
15
- */
16
- var $icon_size = 'favicon';
17
-
18
- /**
19
- * Favicon Dimensions
20
- * @var array
21
- */
22
- var $icon_dimensions = array('w' => '16', 'h' => '16');
23
-
24
  /**
25
  * Prefix for Cornerstone-related data (attributes, DB tables, etc.)
26
  * @var string
9
  */
10
  class FVRT_Base {
11
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * Prefix for Cornerstone-related data (attributes, DB tables, etc.)
14
  * @var string
includes/class.media.php CHANGED
@@ -19,7 +19,13 @@ class FVRT_Media extends FVRT_Base {
19
  * Prefix added upon instantiation
20
  * @var string
21
  */
22
- var $var_type = 'icon';
 
 
 
 
 
 
23
 
24
  /**
25
  * Query var used to set media upload action
@@ -47,6 +53,18 @@ class FVRT_Media extends FVRT_Base {
47
  */
48
  var $upload_url_args;
49
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  /**
51
  * Legacy Constructor
52
  */
@@ -69,7 +87,14 @@ class FVRT_Media extends FVRT_Base {
69
  add_action('admin_print_styles-media-upload-popup', $this->m('upload_styles'));
70
 
71
  //Register handler for custom media requests
72
- add_action('media_upload_' . $this->add_prefix('icon'), $this->m('upload_icon'));
 
 
 
 
 
 
 
73
 
74
  //Display custom UI in media item box
75
  add_filter('attachment_fields_to_edit', $this->m('attachment_fields_to_edit'), 11, 2);
@@ -78,7 +103,10 @@ class FVRT_Media extends FVRT_Base {
78
  add_filter('intermediate_image_sizes', $this->m('add_intermediate_image_size'));
79
 
80
  //Modify tabs in upload popup for fields
81
- add_filter('media_upload_tabs', $this->m('field_upload_tabs'));
 
 
 
82
 
83
  //Restrict file types in upload file dialog
84
  add_filter('upload_file_glob', $this->m('upload_file_types'));
@@ -91,13 +119,12 @@ class FVRT_Media extends FVRT_Base {
91
  * @return array Updated sizes
92
  */
93
  function add_intermediate_image_size($sizes) {
94
- $img = array('width' => 0, 'height' => 0, 'crop' => true);
95
- if ( $this->is_custom_media() ) {
96
- $img['width'] = $this->icon_dimensions['w'];
97
- $img['height'] = $this->icon_dimensions['h'];
 
98
  }
99
- add_image_size($this->icon_size, $img['width'], $img['height'], $img['crop']);
100
- $sizes[] = $this->icon_size;
101
  return $sizes;
102
  }
103
 
@@ -113,7 +140,6 @@ class FVRT_Media extends FVRT_Base {
113
  }
114
  }
115
 
116
-
117
  /**
118
  * Sets acceptable file types for uploading
119
  * Also sets File dialog description (hacky but works)
@@ -122,45 +148,109 @@ class FVRT_Media extends FVRT_Base {
122
  */
123
  function upload_file_types($types) {
124
  if ( $this->is_custom_media() ) {
125
- $filetypes = '*.' . implode(';*.', array('png', 'gif', 'jpg', 'ico'));
126
- $types = esc_js($filetypes) . '",file_types_description: "' . esc_js(__('Favicon files'));
 
127
  }
128
  return $types;
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
131
  /**
132
- * Modifies media upload URL to work with plugin attachments
133
  * @param string $url Full admin URL
134
- * @param string $path Path part of URL
135
  * @return string Modified media upload URL
136
  */
137
- function media_upload_url($url) {
138
- if ( strpos($url, 'media-upload.php') === 0 ) {
139
- $url = add_query_arg(array($this->var_action => 1, 'type' => $this->var_type, 'tab' => 'type'), $url);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
141
  return $url;
142
  }
143
 
144
  /**
145
  * Retrieve source data for icon media
 
146
  * @param int $icon_id Attachment ID
147
  * @return array Image data (src, width, height)
148
  */
149
- function get_icon_src($icon_id) {
150
- $this->update_attachment_metadata($icon_id);
151
- $icon = ( wp_attachment_is_image($icon_id) ) ? wp_get_attachment_image_src($icon_id, $this->icon_size) : wp_get_attachment_url($icon_id);
152
- if ( is_string($icon) )
 
 
 
 
 
 
 
 
153
  $icon = array($icon, 0, 0);
 
154
  return $icon;
155
  }
156
 
157
  /**
158
- * Updates image thumbnail if necessary
159
  * @param int $id Attachment ID
160
  */
161
- function update_attachment_metadata($id) {
162
- //Generate favicon image file (if necessary)
163
- if ( ( $meta = wp_get_attachment_metadata($id) ) && !isset($meta['sizes'][$this->icon_size]) && wp_attachment_is_image($id) ) {
 
 
 
 
 
 
 
 
 
164
  //Full metadata update
165
  if ( function_exists('wp_generate_attachment_metadata') ) {
166
  $data = wp_generate_attachment_metadata($id, get_attached_file($id));
@@ -172,27 +262,31 @@ class FVRT_Media extends FVRT_Base {
172
  /**
173
  * Handles upload/selecting of an icon
174
  */
175
- function upload_icon() {
176
  $errors = array();
177
  $id = 0;
178
-
179
  //Process media selection
180
  if ( isset($_POST[$this->var_setmedia]) ) {
181
  /* Send image data to main post edit form and close popup */
182
  //Get Attachment ID
183
- $field_var = $this->add_prefix('field');
184
  $args = new stdClass();
185
  $args->id = array_shift( array_keys($_POST[$this->var_setmedia]) );
186
  //Make sure post is valid
187
  if ( wp_attachment_is_image($args->id) ) {
 
 
188
  //Build object of properties to send to parent page
189
  $icon = $this->get_icon_src($args->id);
190
  if ( !empty($icon) ) {
191
  $args->url = $icon[0];
192
  $meta = wp_get_attachment_metadata($args->id);
193
  $args->name = basename( ( isset($meta['file']) && !empty($meta['file']) ) ? $meta['file'] : wp_get_attachment_url($args->id) );
 
 
 
194
  }
195
  }
 
196
  //Build JS Arguments string
197
  $arg_string = array();
198
  foreach ( (array)$args as $key => $val ) {
@@ -239,6 +333,58 @@ class FVRT_Media extends FVRT_Base {
239
  wp_enqueue_style($this->add_prefix('media'), $this->util->get_file_url('css/media.css'));
240
  }
241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  /**
243
  * Modifies array of form fields to display on Attachment edit form
244
  * Array items are in the form:
@@ -252,34 +398,43 @@ class FVRT_Media extends FVRT_Base {
252
  * @param object $attachment Attachment post object
253
  */
254
  function attachment_fields_to_edit($form_fields, $attachment) {
255
-
256
  if ( $this->is_custom_media() ) {
257
  $post =& get_post($attachment);
258
  //Clear all form fields
259
  $form_fields = array();
260
-
261
- //Add "Set as Image" button (if valid attachment type)
262
- if ( isset($post->post_type) && strpos($post->post_mime_type, 'image/') === 0 ) {
263
- $set_as = __('Add icon');
264
- $field = array(
265
- 'input' => 'html',
266
- 'html' => '<input type="submit" class="button" value="' . $set_as . '" name="' . $this->var_setmedia . '[' . $post->ID . ']" />'
267
- );
268
- //Add field ID value as hidden field (if set)
269
- if ( isset($_REQUEST[$this->var_type]) ) {
270
- $field = array(
271
- 'input' => 'hidden',
272
- 'value' => $_REQUEST[$this->var_type]
273
- );
274
- $form_fields[$this->var_type] = $field;
 
 
275
  }
276
- } else {
 
 
 
 
 
 
 
 
277
  $field = array(
278
- 'input' => 'hidden',
279
- 'value' => ''
280
  );
 
281
  }
282
- $form_fields['buttons'] = $field;
283
  }
284
  return $form_fields;
285
  }
@@ -295,22 +450,104 @@ class FVRT_Media extends FVRT_Base {
295
  }
296
 
297
  /**
298
- * Checks whether current media upload/selection request is initiated by the plugin
 
299
  */
300
- function is_custom_media() {
301
- $ret = false;
302
- $action = $this->var_action;
303
- if ( isset($_REQUEST[$action]) || ( isset($_REQUEST['type']) && $_REQUEST['type'] == $this->var_type ) )
304
- $ret = true;
305
- else {
306
- $qs = array();
307
- $ref = parse_url(wp_get_referer());
308
- if ( isset($ref['query']) )
309
- parse_str($ref['query'], $qs);
310
- if (array_key_exists($action, $qs))
311
- $ret = true;
 
 
 
 
312
  }
313
- return $ret;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
  }
315
 
316
  /**
@@ -319,19 +556,8 @@ class FVRT_Media extends FVRT_Base {
319
  * @return string Upload URI
320
  */
321
  function get_upload_iframe_src($type = 'media', $args = null) {
322
- //Build filter tag and callback method
323
- $tag = $type . '_upload_iframe_src';
324
- $callback =& $this->m('media_upload_url');
325
- //Load arguments into instance
326
- $this->load_upload_args($args);
327
- //Add filter
328
- add_filter($tag, $callback);
329
  //Build Upload URI
330
- $ret = get_upload_iframe_src($type);
331
- //Remove filter
332
- remove_filter($tag, $callback);
333
- //Clear arguments from instance
334
- $this->unload_upload_args();
335
  //Return URI
336
  return $ret;
337
  }
@@ -351,7 +577,7 @@ class FVRT_Media extends FVRT_Base {
351
  * @uses load_upload_args()
352
  */
353
  function unload_upload_args() {
354
- $this->load_upload_args(null);
355
  }
356
 
357
  /*-** Field-Specific **-*/
@@ -363,9 +589,11 @@ class FVRT_Media extends FVRT_Base {
363
  * @see media_upload_tabs() for full $default_tabs array
364
  * @return array Modified tabs array
365
  */
366
- function field_upload_tabs($default_tabs) {
367
- if ( $this->is_custom_media() )
368
  unset($default_tabs['type_url']);
 
 
369
  return $default_tabs;
370
  }
371
 
@@ -577,7 +805,7 @@ class FVRT_Media extends FVRT_Base {
577
  $attribs = '';
578
  $attr_format = '%s="%s"';
579
  foreach ($attributes as $attr => $val) {
580
- $attribs .= sprintf($attr_format, $attr, attribute_escape($val));
581
  }
582
  $attributes = $attribs;
583
  }
@@ -586,5 +814,92 @@ class FVRT_Media extends FVRT_Base {
586
  }
587
  return $ret;
588
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  }
590
  ?>
19
  * Prefix added upon instantiation
20
  * @var string
21
  */
22
+ var $var_type = 'media';
23
+
24
+ /**
25
+ * Query data identifier
26
+ * @var string
27
+ */
28
+ var $var_query_data = 'data';
29
 
30
  /**
31
  * Query var used to set media upload action
53
  */
54
  var $upload_url_args;
55
 
56
+ /**
57
+ * Intermediate media types
58
+ * @var array
59
+ */
60
+ var $types = array();
61
+
62
+ /**
63
+ * Name of type for current request
64
+ * @var string
65
+ */
66
+ var $type_current = null;
67
+
68
  /**
69
  * Legacy Constructor
70
  */
87
  add_action('admin_print_styles-media-upload-popup', $this->m('upload_styles'));
88
 
89
  //Register handler for custom media requests
90
+ add_action('media_upload_' . $this->var_type, $this->m('upload_media'));
91
+
92
+ //Limit mime types for custom requests
93
+ add_filter('post_mime_types', $this->m('post_mime_types'));
94
+
95
+ add_filter('media_upload_mime_type_links', $this->m('media_upload_mime_type_links'));
96
+
97
+ add_filter('parse_query', $this->m('set_query_mime_types'));
98
 
99
  //Display custom UI in media item box
100
  add_filter('attachment_fields_to_edit', $this->m('attachment_fields_to_edit'), 11, 2);
103
  add_filter('intermediate_image_sizes', $this->m('add_intermediate_image_size'));
104
 
105
  //Modify tabs in upload popup for fields
106
+ add_filter('media_upload_tabs', $this->m('upload_tabs'));
107
+
108
+ //Modifies media upload query vars so that request is routed through plugin
109
+ add_filter('media_upload_form_url', $this->m('upload_url'), 10, 2);
110
 
111
  //Restrict file types in upload file dialog
112
  add_filter('upload_file_glob', $this->m('upload_file_types'));
119
  * @return array Updated sizes
120
  */
121
  function add_intermediate_image_size($sizes) {
122
+ $p = $this->get_request_props();
123
+ if ( !!$p && $p->width && $p->height ) {
124
+ $crop = true;
125
+ add_image_size($p->type_name, $p->width, $p->height, $crop);
126
+ $sizes[] = $p->type_name;
127
  }
 
 
128
  return $sizes;
129
  }
130
 
140
  }
141
  }
142
 
 
143
  /**
144
  * Sets acceptable file types for uploading
145
  * Also sets File dialog description (hacky but works)
148
  */
149
  function upload_file_types($types) {
150
  if ( $this->is_custom_media() ) {
151
+ $p = $this->get_request_props();
152
+ $filetypes = '*.' . implode(';*.', $p->file_type);
153
+ $types = esc_js($filetypes) . '",file_types_description: "' . esc_js(__($p->file_desc));
154
  }
155
  return $types;
156
  }
157
 
158
+ function set_query_mime_types(&$q) {
159
+ $var = 'post_mime_type';
160
+ if ( $this->is_custom_media() && 'attachment' == $q->query_vars['post_type'] && empty($q->query_vars[$var]) ) {
161
+ $qv =& $q->query_vars;
162
+ $p = $this->get_request_props();
163
+ //Set GET variable when single mime type specified (for future queries)
164
+ if ( !!$p && isset($p->file_mime) && is_array($p->file_mime) )
165
+ $qv[$var] = $p->file_mime;
166
+ }
167
+ }
168
+
169
  /**
170
+ * Modifies media upload URL to work with plugin
171
  * @param string $url Full admin URL
172
+ * @param string $type Media type
173
  * @return string Modified media upload URL
174
  */
175
+ function upload_url($url, $type = null) {
176
+ $args = ( is_array($type) ) ? $type : array();
177
+ $custom = ( ( is_string($type) && 0 === strpos($type, $this->add_prefix('')) ) || !empty($args) ) ? true : $this->is_custom_media($url);
178
+ $p = parse_url($url);
179
+ $p = basename( ( isset($p['path']) ) ? $p['path'] : $url );
180
+ if ( strpos($p, 'media-upload.php') === 0 && $custom ) {
181
+ $defaults = array(
182
+ 'type' => $this->var_type,
183
+ 'tab' => 'type'
184
+ );
185
+ $u = ( is_string($type) ) ? null : $url;
186
+ //Parse URL
187
+ $q = wp_parse_args($args, $this->get_request_args($u));
188
+ //Check for tab variable
189
+ if ( isset($q['tab']) && 'type' != $q['tab'] ) {
190
+ //Replace tab value
191
+ $defaults[$this->add_prefix('tab')] = $q['tab'];
192
+ }
193
+ //Move Thickbox query args to end of URL
194
+ $tb = array();
195
+ foreach ( $q as $key => $val ) {
196
+ if ( 0 === strpos($key, 'TB_') ) {
197
+ //Add arg to temp array
198
+ $tb[$key] = $val;
199
+ //Remove from query array
200
+ $defaults[$key] = false;
201
+ }
202
+ }
203
+ unset($q);
204
+
205
+ //Build URL query
206
+ $args = ( is_array($type) ) ? wp_parse_args($type, $defaults) : $defaults;
207
+ $url = add_query_arg($args, $url);
208
+ //Add thickbox args back to URL
209
+ if ( count($tb) )
210
+ $url = add_query_arg($tb, $url);
211
  }
212
  return $url;
213
  }
214
 
215
  /**
216
  * Retrieve source data for icon media
217
+ * Updates metadata (intermediate sizes, etc.) if necessary
218
  * @param int $icon_id Attachment ID
219
  * @return array Image data (src, width, height)
220
  */
221
+ function get_icon_src($icon_id, $type = null) {
222
+ //Add intermediate size (if necessary)
223
+ $type = $this->set_type_current($type);
224
+ $this->update_attachment_metadata($icon_id, $type);
225
+ if ( !$type ) {
226
+ $p = $this->get_request_props();
227
+ $type = $p->type_name;
228
+ } else {
229
+ $type = $type->type_name;
230
+ }
231
+ $icon = ( wp_attachment_is_image($icon_id) && is_string($type) ) ? wp_get_attachment_image_src($icon_id, $type) : wp_get_attachment_url($icon_id);
232
+ if ( !is_array($icon) )
233
  $icon = array($icon, 0, 0);
234
+ $this->clear_type_current();
235
  return $icon;
236
  }
237
 
238
  /**
239
+ * Updates image intermediate size if necessary
240
  * @param int $id Attachment ID
241
  */
242
+ function update_attachment_metadata($id, $type = null) {
243
+ $type = $this->get_type($type);
244
+ if ( !$type ) {
245
+ $p = $this->get_request_props();
246
+ if ( !$p )
247
+ return false;
248
+ $type = $p->type_name;
249
+ } else {
250
+ $type = $type->type_name;
251
+ }
252
+ //Generate intermediate size (if necessary)
253
+ if ( wp_attachment_is_image($id) && ( $meta = wp_get_attachment_metadata($id) ) && !isset($meta['sizes'][$type]) ) {
254
  //Full metadata update
255
  if ( function_exists('wp_generate_attachment_metadata') ) {
256
  $data = wp_generate_attachment_metadata($id, get_attached_file($id));
262
  /**
263
  * Handles upload/selecting of an icon
264
  */
265
+ function upload_media() {
266
  $errors = array();
267
  $id = 0;
 
268
  //Process media selection
269
  if ( isset($_POST[$this->var_setmedia]) ) {
270
  /* Send image data to main post edit form and close popup */
271
  //Get Attachment ID
 
272
  $args = new stdClass();
273
  $args->id = array_shift( array_keys($_POST[$this->var_setmedia]) );
274
  //Make sure post is valid
275
  if ( wp_attachment_is_image($args->id) ) {
276
+ $p = $this->get_request_props();
277
+
278
  //Build object of properties to send to parent page
279
  $icon = $this->get_icon_src($args->id);
280
  if ( !empty($icon) ) {
281
  $args->url = $icon[0];
282
  $meta = wp_get_attachment_metadata($args->id);
283
  $args->name = basename( ( isset($meta['file']) && !empty($meta['file']) ) ? $meta['file'] : wp_get_attachment_url($args->id) );
284
+ if ( isset($p->type_name) ) {
285
+ $args->type_name = $p->type_name;
286
+ }
287
  }
288
  }
289
+
290
  //Build JS Arguments string
291
  $arg_string = array();
292
  foreach ( (array)$args as $key => $val ) {
333
  wp_enqueue_style($this->add_prefix('media'), $this->util->get_file_url('css/media.css'));
334
  }
335
 
336
+ /**
337
+ * Filter mime types for custom requests
338
+ * @see `post_mime_types` hook to filter mime types
339
+ * @see get_post_mime_types()
340
+ * @uses $_GET to set post_mime_type variable (if necessary)
341
+ * @param array $post_mime_types Default post mime types
342
+ * @return array Filtered mime types
343
+ */
344
+ function post_mime_types($post_mime_types) {
345
+ global $wp_query;
346
+ if ( $this->is_custom_media() && ( $p = $this->get_request_props() ) && isset($p->file_mime) ) {
347
+ //Save original mime types
348
+ $mime_types = $post_mime_types;
349
+ //Add additional mime types
350
+ $mime_types_extra = array(
351
+ 'image/png' => array(__('PNG Images'), __('Manage PNG Images'), _n_noop('PNG Image <span class="count">(%s)</span>', 'PNG Images <span class="count">(%s)</span>')),
352
+ 'image/gif' => array(__('GIF Images'), __('Manage GIF Images'), _n_noop('GIF Image <span class="count">(%s)</span>', 'GIF Images <span class="count">(%s)</span>')),
353
+ 'image/jpeg' => array(__('JPG Images'), __('Manage JPG Images'), _n_noop('JPG Image <span class="count">(%s)</span>', 'JPG Images <span class="count">(%s)</span>')),
354
+ 'image/x-icon' => array(__('ICO Images'), __('Manage ICO Images'), _n_noop('ICO Image <span class="count">(%s)</span>', 'ICO Images <span class="count">(%s)</span>'))
355
+ );
356
+ $mime_types = wp_parse_args($mime_types_extra, $mime_types);
357
+ //Clear mime types array
358
+ $post_mime_types = array();
359
+ foreach ( $p->file_mime as $mime ) {
360
+ if ( isset($mime_types[$mime]) )
361
+ $post_mime_types[$mime] = $mime_types[$mime];
362
+ }
363
+ //Set GET variable when single mime type specified (for future queries)
364
+ $var = 'post_mime_type';
365
+ if ( empty($_GET[$var]) && !!$p && isset($p->file_mime) && is_array($p->file_mime) && count($p->file_mime) == 1 )
366
+ $_GET[$var] = $p->file_mime;
367
+
368
+ }
369
+ return $post_mime_types;
370
+ }
371
+
372
+ /**
373
+ * Filter mime type links for custom requests
374
+ * @see `media_upload_mime_type_links` hook to filter mime types
375
+ * @see media_upload_library_form()
376
+ * @param array $type_links Default mime type links
377
+ * @return array Filtered mime type links
378
+ */
379
+ function media_upload_mime_type_links($type_links) {
380
+ global $wp_query;
381
+ if ( $this->is_custom_media() && ( $p = $this->get_request_props() ) && isset($p->file_mime) && count($p->file_mime) == 1 ) {
382
+ //Remove ALL media type link for requests that specify a SINGLE mime type
383
+ array_shift($type_links);
384
+ }
385
+ return $type_links;
386
+ }
387
+
388
  /**
389
  * Modifies array of form fields to display on Attachment edit form
390
  * Array items are in the form:
398
  * @param object $attachment Attachment post object
399
  */
400
  function attachment_fields_to_edit($form_fields, $attachment) {
 
401
  if ( $this->is_custom_media() ) {
402
  $post =& get_post($attachment);
403
  //Clear all form fields
404
  $form_fields = array();
405
+ if ( isset($post->post_mime_type) && 0 === strpos($post->post_mime_type, 'image/') && ( $q = $this->get_request_props() ) && false !== $q ) {
406
+ $html = array();
407
+ $type = 'hidden';
408
+ $name_base = $this->var_query_data . '[' . $post->ID . '][%1$s]';
409
+ $name_base_sub = $name_base . '[%2$s]';
410
+ //Create fields for all custom parameters
411
+ foreach ( (array)$q as $prop => $val ) {
412
+ //Build multiple fields for array values
413
+ if ( is_array($val) ) {
414
+ foreach ( $val as $akey => $aval ) {
415
+ $name = sprintf($name_base_sub, $prop, $akey);
416
+ $html[] = $this->util->build_input_element($type, $name, $aval);
417
+ }
418
+ } else {
419
+ $name = sprintf($name_base, $prop);
420
+ $html[] = $this->util->build_input_element($type, $name, $val);
421
+ }
422
  }
423
+ //Add custom fields
424
+ if ( !empty($html) ) {
425
+ $form_fields[$this->var_query_data] = array('input' => 'html', 'html' => implode('', $html));
426
+ }
427
+
428
+ //Add "Set as Image" button (if valid attachment type)
429
+ $set_as = __( ( isset($q->lbl_set) ) ? $q->lbl_set : 'Set Media' );
430
+ $field_name = sprintf('%1$s[%2$s]', $this->var_setmedia, $post->ID);
431
+ $field_html = $this->util->build_input_element('submit', $field_name, $set_as, array('class' => 'button'));
432
  $field = array(
433
+ 'input' => 'html',
434
+ 'html' => $field_html
435
  );
436
+ $form_fields['buttons'] = $field;
437
  }
 
438
  }
439
  return $form_fields;
440
  }
450
  }
451
 
452
  /**
453
+ * Retrieve raw parameters for current media selection/upload request
454
+ * @return array Parameters
455
  */
456
+ function get_request_args($url = null) {
457
+ $q = array();
458
+ $u = null;
459
+ if ( is_string($url) && !empty($url) )
460
+ $u = $url;
461
+ //Use referrer for async uploads
462
+ elseif ( 'async-upload' == basename($_SERVER['SCRIPT_NAME'], '.php') )
463
+ $u = wp_get_referer();
464
+
465
+ if ( !is_null($u) ) {
466
+ //Parse referrer
467
+ $u = parse_url($u);
468
+ if ( isset($u['query']) )
469
+ parse_str($u['query'], $q);
470
+ } else {
471
+ $q = $_REQUEST;
472
  }
473
+ return $q;
474
+ }
475
+
476
+ /**
477
+ * Retrieve properties of current media request
478
+ * Retrieves current type as fallback
479
+ * @param string (optional) $url URL to parse
480
+ * @return object|bool Properties object (FALSE if no properties exist)
481
+ */
482
+ function get_request_props($url = null) {
483
+ $p = array();
484
+ $q = $this->get_request_args($url);
485
+ $c = array();
486
+ //Get form post data (if set)
487
+ if ( isset($q[$this->var_setmedia]) && isset($q[$this->var_query_data]) ) {
488
+ $id = array_shift(array_keys($q[$this->var_setmedia]));
489
+ //Save form data
490
+ if ( isset($q[$this->var_query_data][$id]) ) {
491
+ $c = $q[$this->var_query_data][$id];
492
+ //Remove from args array
493
+ unset($q[$this->var_query_data]);
494
+ }
495
+ }
496
+ $prefix = $this->add_prefix('');
497
+ foreach ( $q as $arg => $val ) {
498
+ //Process all custom query args
499
+ if ( 0 !== strpos($arg, $prefix) )
500
+ continue;
501
+ $arg = substr($arg, strlen($prefix));
502
+ $p[$arg] = $val;
503
+ }
504
+ //Add form data
505
+ if ( !empty($c) )
506
+ $p = array_merge($p, $c);
507
+
508
+ //Retrieve curren type as callback
509
+ if ( empty($p) ) {
510
+ $p = $this->get_type_current();
511
+ if ( !!$p )
512
+ $p = get_object_vars($p);
513
+ }
514
+
515
+ //Finalize
516
+ if ( !empty($p) ) {
517
+ //Remap properties
518
+ $remap = array(
519
+ 'media' => 'type_name'
520
+ );
521
+ foreach ( $remap as $from => $to ) {
522
+ if ( !isset($p[$from]) )
523
+ continue;
524
+ $p[$to] = $p[$from];
525
+ unset($p[$from]);
526
+ }
527
+
528
+ //Add default properties
529
+ $p = (object) wp_parse_args($p, array(
530
+ 'type_name' => 'media',
531
+ 'width' => 0,
532
+ 'height' => 0
533
+ ));
534
+ } else {
535
+ $p = false;
536
+ }
537
+
538
+ return $p;
539
+ }
540
+
541
+ /**
542
+ * Checks whether media upload/selection request is initiated by the plugin
543
+ * Checks current request by default
544
+ * @param string $url (optional) URL to check
545
+ * @return bool TRUE if URL is custom media
546
+ */
547
+ function is_custom_media($url = null) {
548
+ $type = $this->var_type;
549
+ $q = $this->get_request_args($url);
550
+ return ( isset($q['type']) && $type == $q['type'] ) ? true : false;
551
  }
552
 
553
  /**
556
  * @return string Upload URI
557
  */
558
  function get_upload_iframe_src($type = 'media', $args = null) {
 
 
 
 
 
 
 
559
  //Build Upload URI
560
+ $ret = $this->upload_url(get_upload_iframe_src($type), $args);
 
 
 
 
561
  //Return URI
562
  return $ret;
563
  }
577
  * @uses load_upload_args()
578
  */
579
  function unload_upload_args() {
580
+ $this->load_upload_args(null);
581
  }
582
 
583
  /*-** Field-Specific **-*/
589
  * @see media_upload_tabs() for full $default_tabs array
590
  * @return array Modified tabs array
591
  */
592
+ function upload_tabs($default_tabs) {
593
+ if ( $this->is_custom_media() ) {
594
  unset($default_tabs['type_url']);
595
+ $p = $this->get_request_props();
596
+ }
597
  return $default_tabs;
598
  }
599
 
805
  $attribs = '';
806
  $attr_format = '%s="%s"';
807
  foreach ($attributes as $attr => $val) {
808
+ $attribs .= sprintf($attr_format, $attr, esc_attr($val));
809
  }
810
  $attributes = $attribs;
811
  }
814
  }
815
  return $ret;
816
  }
817
+
818
+ /* Media Types */
819
+
820
+ /**
821
+ * Add media type to collection
822
+ * Saves properties as object
823
+ * @param string $name Type Name
824
+ * @param array|object $props Type Properties
825
+ * @return object Type properties
826
+ */
827
+ function register_type($name, $props = null) {
828
+ $defaults = array(
829
+ 'lbl_title' => '',
830
+ 'lbl_set' => 'Set Media',
831
+ 'file_mime' => array('image/png', 'image/gif', 'image/jpeg'),
832
+ 'file_type' => array('png', 'gif', 'jpg'),
833
+ 'file_desc' => 'Icon Files',
834
+ 'width' => 0,
835
+ 'height' => 0
836
+ );
837
+
838
+ $props = wp_parse_args($props, $defaults);
839
+ $props['type_name'] = $name;
840
+ $this->types[$name] = (object) $props;
841
+ return $this->types[$name];
842
+ }
843
+
844
+ /**
845
+ * Retrieve all registered media types
846
+ * @return array Media types (as a reference)
847
+ */
848
+ function &get_types() {
849
+ return $this->types;
850
+ }
851
+
852
+ /**
853
+ * Retrieve media type
854
+ * @param object|bool $type Type properties (FALSE if type not registered)
855
+ */
856
+ function get_type($type) {
857
+ //Normalize
858
+ if ( is_object($type) )
859
+ $type = get_object_vars($type);
860
+ if ( is_array($type) && isset($type['name']) )
861
+ $type = $type['name'];
862
+ if ( !is_string($type) )
863
+ $type = strval($type);
864
+
865
+ $types =& $this->get_types();
866
+ //Fetch type
867
+ if ( isset($types[$type]) )
868
+ return $types[$type];
869
+ //Return FALSE if type does not exist
870
+ return false;
871
+ }
872
+
873
+ /**
874
+ * Set type for current request
875
+ * @param mixed $type Type to set
876
+ * @return object Current type (normalized)
877
+ */
878
+ function set_type_current($type) {
879
+ $type = $this->get_type($type);
880
+ if ( !$type )
881
+ $this->clear_type_current();
882
+ else {
883
+ $this->type_current = $type->type_name;
884
+ }
885
+ return $type;
886
+ }
887
+
888
+ /**
889
+ * Retrieve current type
890
+ * @return object|bool Current type (FALSE if no type set)
891
+ */
892
+ function get_type_current() {
893
+ return $this->get_type($this->type_current);
894
+ }
895
+
896
+ /**
897
+ * Clear type from current request
898
+ */
899
+ function clear_type_current() {
900
+ $this->type_current = null;
901
+ }
902
+
903
+
904
  }
905
  ?>
includes/class.utilities.php CHANGED
@@ -480,6 +480,21 @@ class FVRT_Utilities {
480
  return $this->build_html_element(array('tag' => 'script', 'attributes' => $attributes));
481
  }
482
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
483
  /**
484
  * Generate HTML element based on values
485
  * @param $args Element arguments
480
  return $this->build_html_element(array('tag' => 'script', 'attributes' => $attributes));
481
  }
482
 
483
+ /**
484
+ * Generate input element
485
+ * @param string $type (optional) Input type
486
+ * @param string $name (optional) Input name
487
+ * @param mixed $value (optional) Input value
488
+ * @param array $attributes (optional) Additional attributes
489
+ */
490
+ function build_input_element($type = 'text', $name = '', $value = '', $attributes = array()) {
491
+ //Build attributes
492
+ $attributes = wp_parse_args($attributes, array('type' => $type, 'name' => $name, 'value' => $value));
493
+ //Build element
494
+ $el = array('tag' => 'input', 'wrap' => false, 'attributes' => $attributes);
495
+ return $this->build_html_element($el);
496
+ }
497
+
498
  /**
499
  * Generate HTML element based on values
500
  * @param $args Element arguments
js/admin.js CHANGED
@@ -15,41 +15,52 @@ if ( !Array.indexOf ) {
15
  }
16
  }
17
 
18
- if ( typeof(fvrt) == 'undefined' || typeof(fvrt) != 'object' )
19
  fvrt = {};
20
  (function($) {
21
  /**
22
  * Initialization routines
23
  */
24
- fvrt['init'] = function() {
25
  this.setupActions();
26
  };
27
 
28
- fvrt['sel'] = {
29
- no_icons: '#fv_no_icons',
30
- list: '#fv_list',
 
31
  item: '.fv_item',
32
  image: '.icon',
33
  details: '.details',
34
  name: '.name',
35
- itemTemplate: '#fv_item_temp',
36
  remove: '.remove',
37
- field: '#fv_ids'
38
  };
39
 
40
  /**
41
  * Setup event actions for icon elements
42
  */
43
- fvrt['setupActions'] = function() {
44
  //Get remove links on page
45
  var t = this;
46
- $(this.buildSelector('list', 'item', 'remove')).live('click', function() {
47
  t.removeItem(this);
48
  return false;
49
  });
50
  };
51
 
52
- fvrt['buildSelector'] = function() {
 
 
 
 
 
 
 
 
 
 
 
53
  var sel = [];
54
  for ( var i = 0; i < arguments.length; i++ ) {
55
  if ( arguments[i] in this.sel ) {
@@ -63,17 +74,17 @@ if ( typeof(fvrt) == 'undefined' || typeof(fvrt) != 'object' )
63
  * Retrieve IDs hidden field
64
  * @return object IDs field
65
  */
66
- fvrt['getField'] = function() {
67
- return $(this.sel.field);
68
  };
69
 
70
  /**
71
  * Gets IDs of icons
72
  * @return array Icon IDs
73
  */
74
- fvrt['getIds'] = function() {
75
  var ids = [];
76
- var idVal = $(this.getField()).val();
77
  if ( idVal.toString().length > 0 ) {
78
  ids = idVal.split(',');
79
  }
@@ -85,52 +96,101 @@ if ( typeof(fvrt) == 'undefined' || typeof(fvrt) != 'object' )
85
  * @param int itemId Icon ID
86
  * @return bool TRUE if icon is already added
87
  */
88
- fvrt['hasId'] = function(itemId) {
89
- return ( this.getIds().indexOf(itemId) != -1 ) ? true : false;
90
  };
91
 
92
  /**
93
  * Sets list of Icon IDs
94
  * @param array Icon IDs
95
  */
96
- fvrt['setIds'] = function(ids) {
97
- $(this.getField()).val(ids.join(','));
98
  };
99
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  /**
101
  * Add ID to IDs field
102
  * @param int itemId Attachment ID to add
103
  */
104
- fvrt['addId'] = function(itemId) {
105
- if ( !this.hasId(itemId) ) {
106
- var vals = this.getIds();
107
- vals.push(itemId);
108
- this.setIds(vals);
 
 
 
 
 
 
 
109
  }
110
  };
111
 
112
  /**
113
  * Remove ID from IDs field
114
  * @param int itemId Icon ID to remove
 
115
  */
116
- fvrt['removeId'] = function(itemId) {
117
- var vals = this.getIds();
118
  var idx = vals.indexOf(itemId);
119
  if ( idx != -1 )
120
  vals.splice(idx, 1);
121
- this.setIds(vals);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  };
123
 
124
  /**
125
  * Get Icon ID of specified item
126
  * @param {Object} el Node element
 
127
  */
128
- fvrt['getItemId'] = function(el) {
129
- var id = '';
130
- var parts = el.id.split('_');
131
- if ( parts.length )
132
- id = parts[parts.length - 1];
133
- return id;
 
 
 
 
 
134
  };
135
 
136
  /**
@@ -140,22 +200,31 @@ if ( typeof(fvrt) == 'undefined' || typeof(fvrt) != 'object' )
140
  * name: File name
141
  * url: Attachment URL
142
  */
143
- fvrt['addItem'] = function(args) {
144
- if (typeof args == 'object' && args.id && args.name && args.url && !this.hasId(args.id)) {
 
 
 
 
145
  //Build new item
146
- var item = $(this.sel.itemTemplate).clone();
147
- $(item).attr('id', 'fv_item_' + args.id);
148
- $(item).find(this.sel.image).attr('src', args.url);
149
- $(item).find(this.sel.name).text(args.name);
150
- $(item).find(this.sel.remove).attr('id', 'fv_id_' + args.id);
 
 
 
 
 
 
151
 
152
  //Add element to container
153
- $(item).appendTo(this.sel.list)
154
 
155
  //Add element ID to list
156
- this.addId(args.id);
157
-
158
- this.setMessageVisibility();
159
  }
160
  };
161
 
@@ -163,22 +232,29 @@ if ( typeof(fvrt) == 'undefined' || typeof(fvrt) != 'object' )
163
  * Remove item from list
164
  * @param {Object} el Node to remove
165
  */
166
- fvrt['removeItem'] = function(el) {
167
  //Get ID of item
168
  var id = this.getItemId(el);
 
 
169
  //Remove item
170
- $(el).parents('.fv_item').remove();
171
  //Remove ID from field
172
- this.removeId(id);
173
 
174
- this.setMessageVisibility();
175
  };
176
 
177
- fvrt['setMessageVisibility'] = function() {
178
- if (this.getIds().length)
179
- $(this.sel.no_icons).hide();
 
 
 
 
 
180
  else {
181
- $(this.sel.no_icons).show();
182
  }
183
  };
184
 
15
  }
16
  }
17
 
18
+ if ( typeof(fvrt) != 'object' )
19
  fvrt = {};
20
  (function($) {
21
  /**
22
  * Initialization routines
23
  */
24
+ fvrt.init = function() {
25
  this.setupActions();
26
  };
27
 
28
+ fvrt.sel = {
29
+ msg_empty: '#fv_msg_empty',
30
+ item_wrap: '#fv_item_wrap',
31
+ item_temp: '#fv_item_temp',
32
  item: '.fv_item',
33
  image: '.icon',
34
  details: '.details',
35
  name: '.name',
 
36
  remove: '.remove',
37
+ field: '#fv_id',
38
  };
39
 
40
  /**
41
  * Setup event actions for icon elements
42
  */
43
+ fvrt.setupActions = function() {
44
  //Get remove links on page
45
  var t = this;
46
+ $(this.buildSelector('item', 'remove')).live('click', function() {
47
  t.removeItem(this);
48
  return false;
49
  });
50
  };
51
 
52
+ /**
53
+ * Build selector string from variable number of parameters
54
+ */
55
+ fvrt.getSelector = function() {
56
+ var sep = '_', args = [];
57
+ for ( var i = 0; i < arguments.length; i++ ) {
58
+ args.push(arguments[i]);
59
+ }
60
+ return args.join(sep);
61
+ };
62
+
63
+ fvrt.buildSelector = function() {
64
  var sel = [];
65
  for ( var i = 0; i < arguments.length; i++ ) {
66
  if ( arguments[i] in this.sel ) {
74
  * Retrieve IDs hidden field
75
  * @return object IDs field
76
  */
77
+ fvrt.getField = function(itype) {
78
+ return $(this.getSelector(this.sel.field, itype));
79
  };
80
 
81
  /**
82
  * Gets IDs of icons
83
  * @return array Icon IDs
84
  */
85
+ fvrt.getIds = function(itype) {
86
  var ids = [];
87
+ var idVal = $(this.getField(itype)).val();
88
  if ( idVal.toString().length > 0 ) {
89
  ids = idVal.split(',');
90
  }
96
  * @param int itemId Icon ID
97
  * @return bool TRUE if icon is already added
98
  */
99
+ fvrt.hasId = function(img) {
100
+ return ( this.getIds(img.type).indexOf(img.id) != -1 ) ? true : false;
101
  };
102
 
103
  /**
104
  * Sets list of Icon IDs
105
  * @param array Icon IDs
106
  */
107
+ fvrt.setIds = function(ids, itype) {
108
+ $(this.getField(itype)).val(ids.join(','));
109
  };
110
 
111
+ /**
112
+ * Determine if icon type can support mutliple icons
113
+ * @param string itype Icon type
114
+ * @return bool TRUE if type supports multiple icons
115
+ */
116
+ fvrt.isMulti = function(itype) {
117
+ //Get wrapper
118
+ var w = (this.getSelector(this.sel.item_wrap, itype));
119
+ //Check for class
120
+ return $(w).hasClass('multi');
121
+ }
122
+
123
  /**
124
  * Add ID to IDs field
125
  * @param int itemId Attachment ID to add
126
  */
127
+ fvrt.addId = function(img) {
128
+ if ( !this.hasId(img) ) {
129
+ var vals;
130
+ //Append ID to field if multiple images are supported
131
+ if (this.isMulti(img.type)) {
132
+ vals = this.getIds(img.type);
133
+ vals.push(img.id);
134
+ } else {
135
+ //Set single ID if only one image supported
136
+ vals = [img.id];
137
+ }
138
+ this.setIds(vals, img.type);
139
  }
140
  };
141
 
142
  /**
143
  * Remove ID from IDs field
144
  * @param int itemId Icon ID to remove
145
+ * @param string itype Icon type
146
  */
147
+ fvrt.removeId = function(itemId, itype) {
148
+ var vals = this.getIds(itype);
149
  var idx = vals.indexOf(itemId);
150
  if ( idx != -1 )
151
  vals.splice(idx, 1);
152
+ this.setIds(vals, itype);
153
+ };
154
+
155
+ /**
156
+ * Split element ID segments into array
157
+ * @param {Object} el Node element
158
+ * @return array ID segements
159
+ */
160
+ fvrt.getItemIdParts = function(el) {
161
+ return $(el).attr('id').split('_');
162
+ };
163
+
164
+ /**
165
+ * Retrieve specific segment of ID
166
+ * @uses fvrt.getItemIdParts to get all parts
167
+ * @param {Object} el Node element
168
+ * @param int part Index of segment
169
+ * @return string Specific segment (empty string if segment is higher than number of parts)
170
+ */
171
+ fvrt.getItemIdPart = function(el, part) {
172
+ var parts = this.getItemIdParts(el);
173
+ if ( part < 0 )
174
+ part = parts.length + part;
175
+ return ( part >= 0 && part < parts.length ) ? parts[part] : '';
176
  };
177
 
178
  /**
179
  * Get Icon ID of specified item
180
  * @param {Object} el Node element
181
+ * @return string Icon ID
182
  */
183
+ fvrt.getItemId = function(el) {
184
+ return this.getItemIdPart(el, -1);
185
+ };
186
+
187
+ /**
188
+ * Get Icon Type of specified item
189
+ * @param {Object} el Node element
190
+ * @return string Icon type
191
+ */
192
+ fvrt.getItemType = function(el) {
193
+ return this.getItemIdPart(el, -2);
194
  };
195
 
196
  /**
200
  * name: File name
201
  * url: Attachment URL
202
  */
203
+ fvrt.addItem = function(img) {
204
+ if ( typeof img != 'object' )
205
+ return false;
206
+ if ( img.type_name )
207
+ img.type = img.type_name;
208
+ if ( img.id && img.name && img.url && img.type && !this.hasId(img)) {
209
  //Build new item
210
+ var id_base = img.type + '_' + img.id,
211
+ item = $(this.getSelector(this.sel.item_temp, img.type)).clone(),
212
+ item_wrap = this.getSelector(this.sel.item_wrap, img.type);
213
+ $(item).attr('id', 'fv_item_' + id_base);
214
+ $(item).find(this.sel.image).attr('src', img.url);
215
+ $(item).find(this.sel.name).text(img.name);
216
+ $(item).find(this.sel.remove).attr('id', 'fv_id_' + id_base);
217
+
218
+ //Remove item(s) from container if multiple icons are not supported
219
+ if ( !this.isMulti(img.type) )
220
+ $(item_wrap).empty();
221
 
222
  //Add element to container
223
+ $(item).appendTo(item_wrap);
224
 
225
  //Add element ID to list
226
+ this.addId(img);
227
+ this.setMessageVisibility(img.type);
 
228
  }
229
  };
230
 
232
  * Remove item from list
233
  * @param {Object} el Node to remove
234
  */
235
+ fvrt.removeItem = function(el) {
236
  //Get ID of item
237
  var id = this.getItemId(el);
238
+ var itype = this.getItemType(el);
239
+
240
  //Remove item
241
+ $(el).parents(this.sel.item).remove();
242
  //Remove ID from field
243
+ this.removeId(id, itype);
244
 
245
+ this.setMessageVisibility(itype);
246
  };
247
 
248
+ /**
249
+ * Hide/Show message based on number of items in container
250
+ * @param {Object} itype Icon type
251
+ */
252
+ fvrt.setMessageVisibility = function(itype) {
253
+ var msg = this.getSelector(this.sel.msg_empty, itype);
254
+ if (this.getIds(itype).length)
255
+ $(msg).hide();
256
  else {
257
+ $(msg).show();
258
  }
259
  };
260
 
main.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Favicon Rotator
4
  Plugin URI: http://archetyped.com/tools/favicon-rotator/
5
  Description: Easily set site favicon and even rotate through multiple icons
6
- Version: 1.1.2
7
  Author: Archetyped
8
  Author URI: http://archetyped.com
9
  */
3
  Plugin Name: Favicon Rotator
4
  Plugin URI: http://archetyped.com/tools/favicon-rotator/
5
  Description: Easily set site favicon and even rotate through multiple icons
6
+ Version: 1.2.1
7
  Author: Archetyped
8
  Author URI: http://archetyped.com
9
  */
model.php CHANGED
@@ -33,6 +33,54 @@ class FaviconRotator extends FVRT_Base {
33
  */
34
  var $opt_icons = 'icons';
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  /**
37
  * Save action
38
  * @var string
@@ -68,8 +116,14 @@ class FaviconRotator extends FVRT_Base {
68
  }
69
 
70
  function register_hooks() {
 
 
 
 
71
  /*-** Admin **-*/
72
 
 
 
73
  //Menu
74
  add_action('admin_menu', $this->m('admin_menu'));
75
  //Plugins page
@@ -78,7 +132,7 @@ class FaviconRotator extends FVRT_Base {
78
  /*-** Main **-*/
79
 
80
  //Template
81
- add_action('wp_head', $this->m('display_icon'));
82
 
83
  //Instance setup
84
  $this->media->register_hooks();
@@ -116,113 +170,255 @@ class FaviconRotator extends FVRT_Base {
116
  }
117
 
118
  /*-** Media **-*/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
  /**
121
  * Retrieve Post IDs of favicons
122
- * @return array Icon IDs
 
123
  */
124
- function get_icon_ids() {
125
- //Get array of post IDs for icons
126
  $icons = $this->get_options($this->opt_icons);
 
 
 
 
 
 
 
 
 
127
  return $icons;
128
  }
129
 
130
- function get_icon_ids_list() {
131
- return implode(',', $this->get_icon_ids());
 
 
 
 
 
132
  }
133
 
134
  /**
135
  * Retrieve icons saved in options menu
136
  * @return array Media attachment objects
137
  */
138
- function get_icons() {
139
  $icons = array();
140
  //Get icon ids
141
- $ids = $this->get_icon_ids();
142
  //Retrieve attachment objects
143
  if ( !empty($ids) ) {
144
- $icons = get_posts(array('post_type' => 'attachment', 'include' => $ids));
145
- }
146
-
147
- //Fix icon option if invalid icons were passed
148
- if ( count($icons) != count($ids) ) {
149
- $ids = array();
150
- foreach ( $icons as $icon ) {
151
- $ids[] = $icon->ID;
152
  }
153
- //Save to DB
154
- $this->save_icons($ids);
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  }
156
- return $icons;
 
157
  }
158
 
159
  /**
160
  * Save list of selected icons to DB
161
  * @param array $ids (optional) Array of icon IDs
 
162
  */
163
- function save_icons($ids = null) {
164
  //Check if valid icon IDs are passed to function
165
- if ( !is_null($ids) ) {
166
- if ( !is_array($ids) ) {
167
- $ids = ( is_int($ids) ) ? array($ids) : null;
168
  }
169
  }
170
 
171
  //Get icon IDs from form submission
172
- if ( is_null($ids) && isset($_POST['fv_ids']) && check_admin_referer($this->action_save) ) {
173
- $ids = explode(',', $_POST['fv_ids']);
 
 
 
 
 
 
 
174
  }
 
175
  //Save to DB
176
- if ( is_array($ids) ) {
 
 
 
 
 
 
 
 
177
  //Validate values
178
- $changed = false;
179
- foreach ( $ids as $key => $id ) {
180
- if ( !intval($id) ) {
181
- unset($ids[$key]);
182
- $changed = true;
 
 
 
 
 
183
  }
184
  }
185
- if ( $changed )
186
- $ids = array_values($ids);
187
- $this->set_option($this->opt_icons, $ids);
 
 
 
 
 
 
 
 
 
188
  }
 
189
  }
190
 
191
  /**
192
- * Build favicon element for output in template
193
  */
194
- function display_icon() {
195
  //Get icons
196
- $icons = $icons_orig = $this->get_icon_ids();
197
  $icon = null;
198
- //Retrieve icon data
199
  while ( is_null($icon) && count($icons) > 0 ) {
200
- //Select one from random
201
  $idx = ( count($icons) > 1 ) ? array_rand($icons) : 0;
202
  $icon_id = $icons[$idx];
203
- $icon = $this->media->get_icon_src($icon_id);
204
- if ( !$icon || ( is_string($icon) && 'ico' != substr($icon, strrpos($icon, '.') + 1) ) ) {
205
- //Reset variable to NULL
 
206
  $icon = null;
207
- //Remove icon from list (no longer valid)
208
  unset($icons[$idx]);
209
- array_values($icons);
210
  }
211
- //Load image src (for image attachments)
212
- if ( is_array($icon) )
213
- $icon = $icon[0];
214
  }
215
 
216
  //Display icon
217
  if ( !is_null($icon) ) {
218
- ?>
219
- <link rel="shortcut icon" href="<?php echo esc_attr($icon); ?>" />
220
- <?php
221
  }
222
 
223
  //Update icons array (if necessary)
224
- if ( $icons !== $icons_orig )
225
- $this->save_icons($icons);
226
  }
227
 
228
  /*-** Admin **-*/
@@ -263,7 +459,6 @@ class FaviconRotator extends FVRT_Base {
263
  add_action("admin_head-$p", $this->m('admin_help'));
264
  }
265
 
266
-
267
  /**
268
  * Defines content for admin page
269
  */
@@ -274,50 +469,66 @@ class FaviconRotator extends FVRT_Base {
274
  //Get saved icons
275
  if ( isset($_POST['fv_submit']) )
276
  $this->save_icons();
277
- $icons = $this->get_icons();
 
 
 
 
 
 
 
 
 
278
  ?>
279
-
280
  <div class="wrap">
281
  <?php screen_icon(); ?>
282
- <h2><?php _e('Favicon Rotator'); ?> <a href="<?php echo $this->media->get_upload_iframe_src('image'); ?>" class="button add-new-h2 thickbox" title="<?php esc_attr_e('Add Icon'); ?>"><?php echo esc_html_x('Add new', 'file')?></a></h2>
283
- <div id="fv_list_container">
284
- <p id="fv_no_icons"<?php if ( $icons ) echo ' style="display: none;"'?>>No favicons set</p>
285
- <ul id="fv_list">
286
- <?php foreach ( $icons as $icon ) : //List icons
287
- $icon_src = wp_get_attachment_image_src($icon->ID, $this->icon_size);
288
- $icon_src = $icon_src[0];
289
- $src = wp_get_attachment_image_src($icon->ID, 'full');
290
- $src = $src[0];
291
- ?>
292
- <li class="fv_item">
293
- <div>
294
- <img class="icon" src="<?php echo $icon_src; ?>" />
295
- <div class="details">
296
- <div class="name"><?php echo basename($src); ?></div>
297
- <div class="options">
298
- <a href="#" id="fv_id_<?php echo esc_attr($icon->ID); ?>" class="remove">Remove</a>
 
 
 
 
 
 
 
 
 
299
  </div>
300
  </div>
301
- </div>
302
- </li>
303
- <?php endforeach; //End icon listing ?>
304
- </ul>
305
- <div style="display: none">
306
- <li id="fv_item_temp" class="fv_item">
307
- <div>
308
- <img class="icon" src="" />
309
- <div class="details">
310
- <div class="name"></div>
311
- <div class="options">
312
- <a href="#" class="remove">Remove</a>
313
  </div>
314
  </div>
315
- </div>
316
- </li>
317
  </div>
318
- </div>
319
- <form method="post" action="<?php echo esc_attr($_SERVER['REQUEST_URI']); ?>">
320
- <input type="hidden" id="fv_ids" name="fv_ids" value="<?php echo esc_attr($this->get_icon_ids_list()); ?>" />
321
  <?php wp_nonce_field($this->action_save); ?>
322
  <p class="submit"><input type="submit" class="button-primary" name="fv_submit" value="<?php esc_attr_e( 'Save Changes' ); ?>" /></p>
323
  </form>
33
  */
34
  var $opt_icons = 'icons';
35
 
36
+ /**
37
+ * Icon types
38
+ * @var array
39
+ */
40
+ var $icon_types = array(
41
+ 'favicon' => array(
42
+ 'lbl_title' => 'Browser Icon',
43
+ 'lbl_set' => 'Add Browser Icon'
44
+ ),
45
+ 'touch' => array(
46
+ 'limit' => 1,
47
+ 'lbl_title' => 'Touch Icon',
48
+ 'lbl_add' => 'Set Icon',
49
+ 'lbl_set' => 'Set Touch Icon',
50
+ 'lbl_empty' => 'No touch icon set',
51
+ 'display' => '<link rel="apple-touch-icon-precomposed" href="%1$s" />',
52
+ 'file_mime' => array('image/png'),
53
+ 'file_type' => array('png'),
54
+ 'file_desc' => 'Touch Icon Files',
55
+ 'width' => 114,
56
+ 'height' => 114
57
+ )
58
+ );
59
+
60
+ /**
61
+ * Default properties for an icon type
62
+ * @var array
63
+ */
64
+ var $icon_type_default_properties = array(
65
+ 'limit' => null,
66
+ 'lbl_title' => '',
67
+ 'lbl_add' => 'Add Icon',
68
+ 'lbl_set' => 'Add Icon',
69
+ 'lbl_empty' => 'No icons set',
70
+ 'display' => '<link rel="shortcut icon" href="%1$s" />',
71
+ 'file_mime' => array('image/png', 'image/gif', 'image/jpeg', 'image/x-icon'),
72
+ 'file_type' => array('png', 'gif', 'jpg', 'ico'),
73
+ 'file_desc' => 'Icon Files',
74
+ 'width' => 16,
75
+ 'height' => 16
76
+ );
77
+
78
+ /**
79
+ * Default icon type
80
+ * @var string
81
+ */
82
+ var $icon_type_default = 'favicon';
83
+
84
  /**
85
  * Save action
86
  * @var string
116
  }
117
 
118
  function register_hooks() {
119
+ /*-** General **-*/
120
+
121
+ add_action('init', $this->m('register_icon_types'));
122
+
123
  /*-** Admin **-*/
124
 
125
+ add_action('admin_print_scripts-media-upload-popup', $this->m('admin_scripts'));
126
+
127
  //Menu
128
  add_action('admin_menu', $this->m('admin_menu'));
129
  //Plugins page
132
  /*-** Main **-*/
133
 
134
  //Template
135
+ add_action('wp_head', $this->m('display_icons'));
136
 
137
  //Instance setup
138
  $this->media->register_hooks();
170
  }
171
 
172
  /*-** Media **-*/
173
+
174
+ /**
175
+ * Register icon types with Media instance
176
+ * @see register_hooks() Hook to method added
177
+ * @return array Registered types
178
+ */
179
+ function register_icon_types() {
180
+ $types = $this->icon_types;
181
+ //Register types
182
+ foreach ( $types as $type => $props ) {
183
+ $types[$type] = $this->media->register_type($type, array_merge($this->icon_type_default_properties, $props));
184
+ }
185
+ return $types;
186
+ }
187
+
188
+ /**
189
+ * Retrieve icon types
190
+ * @return array Icon types (as object of properties)
191
+ */
192
+ function get_icon_types() {
193
+ static $types = null;
194
+ if ( is_null($types) ) {
195
+ $types = $this->register_icon_types();
196
+ }
197
+ return $types;
198
+ }
199
+
200
+ /**
201
+ * Retrieve icon type names
202
+ * @return array Icon type names
203
+ */
204
+ function get_icon_type_names() {
205
+ static $names = null;
206
+ if ( is_null($names) )
207
+ $names = array_keys($this->get_icon_types());
208
+ return $names;
209
+ }
210
+
211
+ /**
212
+ * Retrieve icon type properties
213
+ * @param string $type Icon type
214
+ * @return object|bool Type properties (FALSE if type not registered)
215
+ */
216
+ function get_icon_type($type) {
217
+ $ret = null;
218
+ $types = $this->get_icon_types();
219
+ if ( isset($types[$type]) ) {
220
+ $ret = $types[$type];
221
+ } else {
222
+ $ret = (object) $this->icon_type_default_properties;
223
+ $ret->type_name = $type;
224
+ }
225
+ return $ret;
226
+ }
227
+
228
+ /**
229
+ * Normalize icons array to contain valid icon groups
230
+ * @param array $icons Raw Icons array
231
+ * @return array Normalized icons
232
+ */
233
+ function normalize_icons($icons) {
234
+ static $groups_default = null;
235
+ $save = false;
236
+ //Build default groups array
237
+ if ( is_null($groups_default) ) {
238
+ $groups_default = $dval = array();
239
+ foreach ( $this->get_icon_type_names() as $type ) {
240
+ $groups_default[$type] = $dval;
241
+ }
242
+ }
243
+ //Make sure icons array is valid (icons grouped by type)
244
+ if ( is_array($icons) && !empty($icons) ) {
245
+ $icons_temp = array_values($icons);
246
+ //Put icons into default group if necessary
247
+ if ( !is_array($icons_temp[0]) ) {
248
+ $icons = array($this->icon_type_default => $icons_temp);
249
+ $save = true;
250
+ }
251
+ } elseif ( !is_array($icons) ) {
252
+ $icons = array();
253
+ }
254
+ //Merge and return icons with defaults
255
+ $icons = array_merge($groups_default, $icons);
256
+ if ( $save )
257
+ $this->save_icons($icons);
258
+ return $icons;
259
+ }
260
 
261
  /**
262
  * Retrieve Post IDs of favicons
263
+ * @param string $type Icon type to retrieve
264
+ * @return array Icon IDs grouped by icon type
265
  */
266
+ function get_icon_ids($type = null) {
267
+ //Get array of attachment IDs for icons (grouped by type)
268
  $icons = $this->get_options($this->opt_icons);
269
+
270
+ //Normalize icons array
271
+ $icons = $this->normalize_icons($icons);
272
+
273
+ //Get specific icon type
274
+ if ( is_string($type) && !empty($type) ) {
275
+ $icons = ( isset($icons[$type]) ) ? $icons[$type] : array();
276
+ }
277
+
278
  return $icons;
279
  }
280
 
281
+ /**
282
+ * Retrieve list of icons as string
283
+ * @param string $type Icon type
284
+ * @return string Icon list
285
+ */
286
+ function get_icon_ids_list($type) {
287
+ return implode(',', $this->get_icon_ids($type));
288
  }
289
 
290
  /**
291
  * Retrieve icons saved in options menu
292
  * @return array Media attachment objects
293
  */
294
+ function get_icons($type = null) {
295
  $icons = array();
296
  //Get icon ids
297
+ $ids = $this->get_icon_ids($type);
298
  //Retrieve attachment objects
299
  if ( !empty($ids) ) {
300
+ //Wrap IDs in assoc array if valid type is specified
301
+ $type_valid = false;
302
+ if ( is_string($type) && !empty($type) ) {
303
+ $ids = array($type => $ids);
304
+ $type_valid = true;
 
 
 
305
  }
306
+ foreach ( $ids as $type_key => $type_ids ) {
307
+ $icons[$type_key] = ( !empty($type_ids) ) ? get_posts(array('post_type' => 'attachment', 'include' => $type_ids)) : array();
308
+ //Fix icon option if invalid icons were passed
309
+ if ( count($icons[$type_key]) != count($type_ids) ) {
310
+ $ids_temp = array();
311
+ foreach ( $icons[$type_key] as $icon ) {
312
+ $ids_temp[] = $icon->ID;
313
+ }
314
+ //Save to DB
315
+ $this->save_icons($ids_temp, $type_key);
316
+ }
317
+ }
318
+ //Break specified type out of assoc array
319
+ if ( $type_valid )
320
+ $icons = $icons[$type];
321
  }
322
+
323
+ return $icons;
324
  }
325
 
326
  /**
327
  * Save list of selected icons to DB
328
  * @param array $ids (optional) Array of icon IDs
329
+ * @param string $type (optional) Icon type being saved
330
  */
331
+ function save_icons($icons = null, $type = null) {
332
  //Check if valid icon IDs are passed to function
333
+ if ( !is_null($icons) ) {
334
+ if ( !is_array($icons) ) {
335
+ $icons = ( is_int($icons) ) ? array($icons) : null;
336
  }
337
  }
338
 
339
  //Get icon IDs from form submission
340
+ if ( is_null($icons) && check_admin_referer($this->action_save) ) {
341
+ $icons = array();
342
+ $field_base = 'fv_id_';
343
+ foreach ( $this->get_icon_type_names() as $itype ) {
344
+ $field = $field_base . $itype;
345
+ if ( isset($_POST[$field]) ) {
346
+ $icons[$itype] = explode(',', $_POST[$field]);
347
+ }
348
+ }
349
  }
350
+
351
  //Save to DB
352
+ if ( is_array($icons) ) {
353
+ //Build full icons array: Combine saved icons and current icons
354
+ if ( !is_null($type) ) {
355
+ $icons_temp = $icons;
356
+ $icons = array($type => $icons_temp);
357
+ unset($icons_temp);
358
+ //Merge saved icons with new icon values
359
+ $icons = wp_parse_args($icons, $this->get_icon_ids());
360
+ }
361
  //Validate values
362
+ foreach ( $icons as $itype => $type_ids ) {
363
+ $changed = false;
364
+ foreach ( $type_ids as $idx => $id ) {
365
+ if ( !intval($id) ) {
366
+ unset($icons[$itype][$idx]);
367
+ $changed = true;
368
+ }
369
+ }
370
+ if ( $changed ) {
371
+ $icons[$itype] = array_values($icons[$itype]);
372
  }
373
  }
374
+ //Save icons to DB
375
+ $this->set_option($this->opt_icons, $icons);
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Output markup for all icons
381
+ */
382
+ function display_icons() {
383
+ echo "<!-- Favicon Rotator -->\r\n";
384
+ foreach ( $this->get_icon_type_names() as $type ) {
385
+ $this->display_icon($type);
386
  }
387
+ echo "<!-- End Favicon Rotator -->\r\n";
388
  }
389
 
390
  /**
391
+ * Output markup for specified icon type
392
  */
393
+ function display_icon($type) {
394
  //Get icons
395
+ $icons = $icons_orig = $this->get_icon_ids($type);
396
  $icon = null;
397
+ //Loop through retrieved icons until valid icon is returned
398
  while ( is_null($icon) && count($icons) > 0 ) {
399
+ //Select random icon
400
  $idx = ( count($icons) > 1 ) ? array_rand($icons) : 0;
401
  $icon_id = $icons[$idx];
402
+ $icon = array_shift($this->media->get_icon_src($icon_id, $type));
403
+ //Validate icon
404
+ if ( !is_string($icon) || empty($icon) ) {
405
+ //Reset variable to NULL (will loop to next icon)
406
  $icon = null;
407
+ //Remove invalid icon from list
408
  unset($icons[$idx]);
409
+ $icons = array_values($icons);
410
  }
 
 
 
411
  }
412
 
413
  //Display icon
414
  if ( !is_null($icon) ) {
415
+ $t = $this->get_icon_type($type);
416
+ echo sprintf($t->display, $icon) . "\r\n";
 
417
  }
418
 
419
  //Update icons array (if necessary)
420
+ if ( count($icons) !== count($icons_orig) )
421
+ $this->save_icons($icons, $type);
422
  }
423
 
424
  /*-** Admin **-*/
459
  add_action("admin_head-$p", $this->m('admin_help'));
460
  }
461
 
 
462
  /**
463
  * Defines content for admin page
464
  */
469
  //Get saved icons
470
  if ( isset($_POST['fv_submit']) )
471
  $this->save_icons();
472
+ $class = "button thickbox fv_btn";
473
+ //Setup query arguments
474
+ $filter = array('limit', 'lbl_title', 'lbl_add', 'lbl_empty', 'display');
475
+ $upload_args_base = array_diff(array_keys($this->icon_type_default_properties), $filter);
476
+ $upload_args_base[] = 'type_name';
477
+ $upload_args_map = array();
478
+ foreach ( $upload_args_base as $key ) {
479
+ $upload_args_map[$this->add_prefix($key)] = $key;
480
+ }
481
+
482
  ?>
 
483
  <div class="wrap">
484
  <?php screen_icon(); ?>
485
+ <h2><?php _e('Favicon Rotator'); ?></h2>
486
+ <form method="post" action="<?php echo esc_attr($_SERVER['REQUEST_URI']); ?>">
487
+ <?php foreach ( $this->get_icon_types() as $tname => $t ) : /* Output UI for icon types */
488
+ $icons = $this->get_icons($t->type_name);
489
+ $upload_args = array();
490
+ foreach ( $upload_args_map as $param => $prop ) {
491
+ if ( isset($t->$prop) )
492
+ $upload_args[$param] = $t->$prop;
493
+ }
494
+ ?>
495
+ <h3><?php _e($t->lbl_title); ?> <a href="<?php echo $this->media->get_upload_iframe_src('image', $upload_args); ?>" class="<?php echo esc_attr($class); ?>" title="<?php esc_attr_e($t->lbl_add); ?>"><?php echo esc_html_x($t->lbl_add, 'file')?></a></h3>
496
+ <div class="fv_container">
497
+ <p id="fv_msg_empty_<?php echo $t->type_name; ?>"<?php if ( $icons ) echo ' style="display: none;"'?>><?php _e($t->lbl_empty); ?></p>
498
+ <ul id="fv_item_wrap_<?php echo $t->type_name; ?>" class="fv_item_wrap <?php echo ( is_null($t->limit) ) ? 'multi' : 'single'; ?>">
499
+ <?php foreach ( $icons as $icon ) : //List icons
500
+ $icon_src = array_shift($this->media->get_icon_src($icon->ID, $t->type_name));
501
+ $src = array_shift(wp_get_attachment_image_src($icon->ID, 'full'));
502
+ ?>
503
+ <li class="fv_item">
504
+ <div>
505
+ <img class="icon" src="<?php echo $icon_src; ?>" />
506
+ <div class="details">
507
+ <div class="name"><?php echo basename($src); ?></div>
508
+ <div class="options">
509
+ <a href="#" id="<?php echo esc_attr('fv_id_' . $t->type_name . '_' . $icon->ID); ?>" class="remove">Remove</a>
510
+ </div>
511
  </div>
512
  </div>
513
+ </li>
514
+ <?php endforeach; //End icon listing ?>
515
+ </ul>
516
+ <div style="display: none">
517
+ <li id="fv_item_temp_<?php echo $t->type_name; ?>" class="fv_item">
518
+ <div>
519
+ <img class="icon" src="" />
520
+ <div class="details">
521
+ <div class="name"></div>
522
+ <div class="options">
523
+ <a href="#" class="remove">Remove</a>
524
+ </div>
525
  </div>
526
  </div>
527
+ </li>
528
+ </div>
529
  </div>
530
+ <input type="hidden" id="fv_id_<?php echo $t->type_name; ?>" name="fv_id_<?php echo $t->type_name; ?>" value="<?php echo esc_attr($this->get_icon_ids_list($t->type_name)); ?>" />
531
+ <?php endforeach; /* END UI for icon types */ ?>
 
532
  <?php wp_nonce_field($this->action_save); ?>
533
  <p class="submit"><input type="submit" class="button-primary" name="fv_submit" value="<?php esc_attr_e( 'Save Changes' ); ?>" /></p>
534
  </form>
readme.txt CHANGED
@@ -1,8 +1,9 @@
1
  === Favicon Rotator ===
2
- Contributors: archetyped
3
- Tags: favicon,icon,template,theme,customization,simple,media
4
- Requires at least: 3.0
5
- Tested up to: 3.0.1
 
6
  Stable tag: trunk
7
 
8
  Easily set site favicon and even rotate through multiple icons
@@ -12,19 +13,26 @@ Easily set site favicon and even rotate through multiple icons
12
  Favicon Rotator makes it easy to customize the favicon for your site. Just add a favicon via the administration page and it will be displayed whenever someone visits your site.
13
 
14
  #### Highlights
 
15
  * Simply point and click to add a favicon to your site
16
- * Support for **multiple icons**, from which a **randomly selected** favicon from the rotation will be displayed.
17
- * Automatic icon generation for large images (smaller files and faster loading)
18
 
 
 
19
 
20
- [More Information on Favicons](http://wikipedia.org/wiki/Favicon)
 
 
 
 
 
 
 
21
 
22
  == Installation ==
23
 
24
- 1. Activate the plugin through the 'Plugins' menu in WordPress
25
- 1. Go to **Theme > Favicon** admin page to add images to use for the favicon
26
- 1. Verify that your theme uses the `wp_head()` template tag (this is where the necessary code will be added to your theme output)
27
- 1. Plugin will automatically add a favicon from the rotation to your theme when a visitor loads your site
28
 
29
  == Upgrade Notice ==
30
 
@@ -32,7 +40,7 @@ No upgrade notices
32
 
33
  == Frequently Asked Questions ==
34
 
35
- Go to http://archetyped.com/tools/favicon-rotator/ for any questions or comments
36
 
37
  == Screenshots ==
38
 
@@ -40,13 +48,24 @@ Go to http://archetyped.com/tools/favicon-rotator/ for any questions or comments
40
  1. Favicon submenu in Appearance menu
41
 
42
  == Changelog ==
 
 
 
 
 
 
 
 
43
  = 1.1.2 =
44
  * Updated: Utilities code (internal)
 
45
  = 1.1 =
46
  * Added: Generate icon file from uploaded images
47
  * Added: Settings link from plugins page
48
  * Optimized: File path resolution
 
49
  = 1.0.1 =
50
  * Fix: Various bugs
 
51
  = 1.0 =
52
  * Initial release
1
  === Favicon Rotator ===
2
+ Contributors: Archetyped
3
+ Donate link: http://archetyped.com/tools/favicon-rotator/#donate
4
+ Tags: favicon,icon,template,theme,customization,simple,media,touch,ios,android
5
+ Requires at least: 3.1.3
6
+ Tested up to: 3.3
7
  Stable tag: trunk
8
 
9
  Easily set site favicon and even rotate through multiple icons
13
  Favicon Rotator makes it easy to customize the favicon for your site. Just add a favicon via the administration page and it will be displayed whenever someone visits your site.
14
 
15
  #### Highlights
16
+ * **New: Set icon for Touch devices (Android, iPhone, iPad, iPod Touch, etc.)**
17
  * Simply point and click to add a favicon to your site
18
+ * Supports adding **multiple icons**, from which a **randomly selected** favicon will be displayed.
19
+ * Automatic icon conversion for large images (smaller files and faster loading)
20
 
21
+ #### Usage
22
+ 1. Go to **Theme > Favicon** admin page to add/upload image(s) to use for the favicon
23
 
24
+ **That's it! The favicon will be displayed in visitors' browsers when they visit your site**
25
+
26
+ **Notes**
27
+
28
+ * Verify that your theme uses the `wp_head()` template tag
29
+ * If you add multiple icons, then a randomly selected icon will be displayed each time the site is loaded
30
+
31
+ [More Information on Favicon Rotator's Official Page](http://archetyped.com/tools/favicon-rotator/)
32
 
33
  == Installation ==
34
 
35
+ 1. Install and activate via admin dashboard
 
 
 
36
 
37
  == Upgrade Notice ==
38
 
40
 
41
  == Frequently Asked Questions ==
42
 
43
+ [Please post questions/feedback Favicon Rotator's Official page](http://archetyped.com/tools/favicon-rotator/)
44
 
45
  == Screenshots ==
46
 
48
  1. Favicon submenu in Appearance menu
49
 
50
  == Changelog ==
51
+
52
+ = 1.2.1 =
53
+ * Add: WP 3.3 Support
54
+ * Update: Remove references to deprecated functions
55
+
56
+ = 1.2 =
57
+ * Add: Support for setting Touch icon (iOS, Android, etc.)
58
+
59
  = 1.1.2 =
60
  * Updated: Utilities code (internal)
61
+
62
  = 1.1 =
63
  * Added: Generate icon file from uploaded images
64
  * Added: Settings link from plugins page
65
  * Optimized: File path resolution
66
+
67
  = 1.0.1 =
68
  * Fix: Various bugs
69
+
70
  = 1.0 =
71
  * Initial release
screenshot-1.png ADDED
Binary file
screenshot-2.png ADDED
Binary file