Favicon by RealFaviconGenerator - Version 1.0.0

Version Description

Download this release

Release Info

Developer phbernard
Plugin Icon 128x128 Favicon by RealFaviconGenerator
Version 1.0.0
Comparing to
See all releases

Version 1.0.0

LICENSE.txt ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+
11
+ The licenses for most software are designed to take away your
12
+ freedom to share and change it. By contrast, the GNU General Public
13
+ License is intended to guarantee your freedom to share and change free
14
+ software--to make sure the software is free for all its users. This
15
+ General Public License applies to most of the Free Software
16
+ Foundation's software and to any other program whose authors commit to
17
+ using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
+ your programs, too.
20
+
21
+ When we speak of free software, we are referring to freedom, not
22
+ price. Our General Public Licenses are designed to make sure that you
23
+ have the freedom to distribute copies of free software (and charge for
24
+ this service if you wish), that you receive source code or can get it
25
+ if you want it, that you can change the software or use pieces of it
26
+ in new free programs; and that you know you can do these things.
27
+
28
+ To protect your rights, we need to make restrictions that forbid
29
+ anyone to deny you these rights or to ask you to surrender the rights.
30
+ These restrictions translate to certain responsibilities for you if you
31
+ distribute copies of the software, or if you modify it.
32
+
33
+ For example, if you distribute copies of such a program, whether
34
+ gratis or for a fee, you must give the recipients all the rights that
35
+ you have. You must make sure that they, too, receive or can get the
36
+ source code. And you must show them these terms so they know their
37
+ rights.
38
+
39
+ We protect your rights with two steps: (1) copyright the software, and
40
+ (2) offer you this license which gives you legal permission to copy,
41
+ distribute and/or modify the software.
42
+
43
+ Also, for each author's protection and ours, we want to make certain
44
+ that everyone understands that there is no warranty for this free
45
+ software. If the software is modified by someone else and passed on, we
46
+ want its recipients to know that what they have is not the original, so
47
+ that any problems introduced by others will not reflect on the original
48
+ authors' reputations.
49
+
50
+ Finally, any free program is threatened constantly by software
51
+ patents. We wish to avoid the danger that redistributors of a free
52
+ program will individually obtain patent licenses, in effect making the
53
+ program proprietary. To prevent this, we have made it clear that any
54
+ patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+ 0. This License applies to any program or other work which contains
63
+ a notice placed by the copyright holder saying it may be distributed
64
+ under the terms of this General Public License. The "Program", below,
65
+ refers to any such program or work, and a "work based on the Program"
66
+ means either the Program or any derivative work under copyright law:
67
+ that is to say, a work containing the Program or a portion of it,
68
+ either verbatim or with modifications and/or translated into another
69
+ language. (Hereinafter, translation is included without limitation in
70
+ the term "modification".) Each licensee is addressed as "you".
71
+
72
+ Activities other than copying, distribution and modification are not
73
+ covered by this License; they are outside its scope. The act of
74
+ running the Program is not restricted, and the output from the Program
75
+ is covered only if its contents constitute a work based on the
76
+ Program (independent of having been made by running the Program).
77
+ Whether that is true depends on what the Program does.
78
+
79
+ 1. You may copy and distribute verbatim copies of the Program's
80
+ source code as you receive it, in any medium, provided that you
81
+ conspicuously and appropriately publish on each copy an appropriate
82
+ copyright notice and disclaimer of warranty; keep intact all the
83
+ notices that refer to this License and to the absence of any warranty;
84
+ and give any other recipients of the Program a copy of this License
85
+ along with the Program.
86
+
87
+ You may charge a fee for the physical act of transferring a copy, and
88
+ you may at your option offer warranty protection in exchange for a fee.
89
+
90
+ 2. You may modify your copy or copies of the Program or any portion
91
+ of it, thus forming a work based on the Program, and copy and
92
+ distribute such modifications or work under the terms of Section 1
93
+ above, provided that you also meet all of these conditions:
94
+
95
+ a) You must cause the modified files to carry prominent notices
96
+ stating that you changed the files and the date of any change.
97
+
98
+ b) You must cause any work that you distribute or publish, that in
99
+ whole or in part contains or is derived from the Program or any
100
+ part thereof, to be licensed as a whole at no charge to all third
101
+ parties under the terms of this License.
102
+
103
+ c) If the modified program normally reads commands interactively
104
+ when run, you must cause it, when started running for such
105
+ interactive use in the most ordinary way, to print or display an
106
+ announcement including an appropriate copyright notice and a
107
+ notice that there is no warranty (or else, saying that you provide
108
+ a warranty) and that users may redistribute the program under
109
+ these conditions, and telling the user how to view a copy of this
110
+ License. (Exception: if the Program itself is interactive but
111
+ does not normally print such an announcement, your work based on
112
+ the Program is not required to print an announcement.)
113
+
114
+ These requirements apply to the modified work as a whole. If
115
+ identifiable sections of that work are not derived from the Program,
116
+ and can be reasonably considered independent and separate works in
117
+ themselves, then this License, and its terms, do not apply to those
118
+ sections when you distribute them as separate works. But when you
119
+ distribute the same sections as part of a whole which is a work based
120
+ on the Program, the distribution of the whole must be on the terms of
121
+ this License, whose permissions for other licensees extend to the
122
+ entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+ <one line to give the program's name and a brief idea of what it does.>
294
+ Copyright (C) <year> <name of author>
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+ Also add information on how to contact you by electronic and paper mail.
311
+
312
+ If the program is interactive, make it output a short notice like this
313
+ when it starts in an interactive mode:
314
+
315
+ Gnomovision version 69, Copyright (C) year name of author
316
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+ This is free software, and you are welcome to redistribute it
318
+ under certain conditions; type `show c' for details.
319
+
320
+ The hypothetical commands `show w' and `show c' should show the appropriate
321
+ parts of the General Public License. Of course, the commands you use may
322
+ be called something other than `show w' and `show c'; they could even be
323
+ mouse-clicks or menu items--whatever suits your program.
324
+
325
+ You should also get your employer (if you work as a programmer) or your
326
+ school, if any, to sign a "copyright disclaimer" for the program, if
327
+ necessary. Here is a sample; alter the names:
328
+
329
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+ <signature of Ty Coon>, 1 April 1989
333
+ Ty Coon, President of Vice
334
+
335
+ This General Public License does not permit incorporating your program into
336
+ proprietary programs. If your program is a subroutine library, you may
337
+ consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
+ Public License instead of this License.
README.txt ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Favicon by RealFaviconGenerator ===
2
+ Contributors: phbernard
3
+ Tags: favicon, apple-touch-icon, realfavicongenerator
4
+ Requires at least: 3.5
5
+ Tested up to: 3.9
6
+ Stable tag: 1.0.0
7
+ License: GPLv2
8
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
+
10
+ Create and install your favicon for all platforms: PC/Mac of course, but also iPhone/iPad, Android devices, Windows 8 tablets, etc.
11
+
12
+ In a few clicks, you generate all the pictures you need to get the best results on all devices, from an old Android phone to a shiny Retina iPad. In addition, you can easily enforce the various platforms guidelines, such as an opaque background for the Apple touch icon or a saturated icon for Windows Metro UI tile. Better your odds at being bookmarked by providing the best experience to your visitors.
13
+
14
+ == Description ==
15
+
16
+ Favicon is not just a single `favicon.ico` file dropped in the middle of your site. Nowadays, with so many different platforms and devices, you need a bunch of pictures to get the job done.
17
+
18
+ iOS devices use a high resolution Apple touch icon to illustrate bookmarks and home screen shortcuts. A first generation iPhone needs a 57x57 picture, whereas a brand new iPad with Retina screen looks for a 152x152 picture. Android Chrome also use this pictures if it finds them. Windows 8 takes another route with a dedicated set of icons and HTML declarations.
19
+
20
+ Favicon is not only a matter of pictures with different resolutions. The various platforms coms with different UI guidelines. For example, the classic desktop favicons often use transparency. But iOS requires opaque icons. And Windows 8 has its own recommendations.
21
+
22
+ Save hours of research and image edition with RealFaviconGenerator and its companion plugin. In a matter of seconds, you setup a favicon compatible with:
23
+
24
+ - Windows (IE, Chrome, Firefox, Opera, Safari)
25
+ - Mac (Safari, Chrome, Firefox, Opera, Camino)
26
+ - iOS (Safari, Chrome, Coast)
27
+ - Android (Chrome, Firefox)
28
+ - Surface (IE)
29
+ - ANd more
30
+
31
+ We take compatibility very seriously. See http://realfavicongenerator.net/favicon_compatibility for the full list.
32
+
33
+ == Installation ==
34
+
35
+ = Using The WordPress Dashboard =
36
+
37
+ 1. Navigate to the 'Add New' in the plugins dashboard
38
+ 2. Search for 'Favicon by RealFaviconGenerator'
39
+ 3. Click 'Install Now'
40
+ 4. Activate the plugin on the Plugin dashboard
41
+ 5. Navigate to the 'Favicon' entry in the Settings menu
42
+ 6. Select a master picture from the Media Library (optional)
43
+ 7. Click the 'Generate Favicon' button and follow the instructions.
44
+
45
+ = Using FTP =
46
+
47
+ 1. Download `favicon-by-realfavicongenerator.zip`
48
+ 2. Extract the `favicon-by-realfavicongenerator` directory to your computer
49
+ 3. Upload the `favicon-by-realfavicongenerator` directory to the `/wp-content/plugins/` directory
50
+ 4. Activate the plugin on the Plugin dashboard
51
+ 5. Navigate to the 'Favicon' entry in the Settings menu
52
+ 6. Select a master picture from the Media Library (optional)
53
+ 7. Click the 'Generate Favicon' button and follow the instructions.
54
+
55
+ == Screenshots ==
56
+
57
+ 1. Initial favicon setup screen. You are invited to setup your favicon.
58
+ 2. Select a master picture from the Media Library (optional)
59
+ 3. Once you hit the Generate Favicon button, you are redirected to <a href="http://realfavicongenerator.net/">RealFaviconGenerator</a>,
60
+ where you can design your favicon: adding a background to your iOS picture, using a saturated version of your master picture for Windows 8...
61
+ 4. When you are done with the favicon editor, you are redirected to the WordPress Dashboard. The favicon is installed automatically.
62
+ This screen presents you a preview of the favicon you various platforms, so you know how your blog looks like on various platforms.
63
+
64
+ == Changelog ==
65
+
66
+ = 1.0 =
67
+ Initial version.
admin/assets/css/admin.css ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ /* Copyright 2014 RealFaviconGenerator */
2
+
3
+ .wrap img {
4
+ border: 2px solid #aaa;
5
+ }
admin/class-favicon-by-realfavicongenerator-admin.php ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Copyright 2014 RealFaviconGenerator
3
+
4
+ require_once plugin_dir_path( __FILE__ ) . '../public/class-favicon-by-realfavicongenerator-common.php';
5
+ require_once plugin_dir_path( __FILE__ ) . 'class-favicon-by-realfavicongenerator-api-response.php';
6
+
7
+ class Favicon_By_RealFaviconGenerator_Admin extends Favicon_By_RealFaviconGenerator_Common {
8
+
9
+ protected static $instance = null;
10
+
11
+ private function __construct() {
12
+ add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
13
+
14
+ add_action( 'admin_head', array( $this, 'add_favicon_markups' ) );
15
+
16
+ // Except for the headers, everything is accessible only to the admin
17
+ if ( ! is_super_admin() ) {
18
+ return;
19
+ }
20
+
21
+ add_action( 'admin_menu',
22
+ array( $this, 'create_favicon_settings_menu' ) );
23
+
24
+ add_action('wp_ajax_' . Favicon_By_RealFaviconGenerator_Common::PLUGIN_PREFIX . '_install_new_favicon',
25
+ array( $this, 'install_new_favicon' ) );
26
+ add_action('wp_ajax_nopriv_' . Favicon_By_RealFaviconGenerator_Common::PLUGIN_PREFIX . '_install_new_favicon',
27
+ array( $this, 'install_new_favicon' ) );
28
+ }
29
+
30
+ /**
31
+ * Return an instance of this class.
32
+ *
33
+ * @since 1.0
34
+ *
35
+ * @return object A single instance of this class.
36
+ */
37
+ public static function get_instance() {
38
+
39
+ // If the single instance hasn't been set, set it now.
40
+ if ( null == self::$instance ) {
41
+ self::$instance = new self;
42
+ }
43
+
44
+ return self::$instance;
45
+ }
46
+
47
+ public function create_favicon_settings_menu() {
48
+ add_options_page( __( 'Favicon Settings', Favicon_By_RealFaviconGenerator_Common::PLUGIN_SLUG ),
49
+ __( 'Favicon', Favicon_By_RealFaviconGenerator_Common::PLUGIN_SLUG ), 'manage_options', __FILE__ . 'favicon_settings_menu',
50
+ array( $this, 'create_favicon_settings_page' ) );
51
+ }
52
+
53
+ public function create_favicon_settings_page() {
54
+ $result = NULL;
55
+
56
+ // Prepare settings page
57
+
58
+ $pic_path = NULL;
59
+ if ( ! $this->can_access_pics_with_url_rewrite() ) {
60
+ // Not in root. Send the path to RFG for correct HTML code generation
61
+ $pic_path = $this->get_full_picture_path();
62
+ }
63
+
64
+ $favicon_configured = $this->is_favicon_configured();
65
+
66
+ $preview_url = $this->is_preview_available() ? $this->get_preview_url() : NULL;
67
+
68
+ if ( isset( $_REQUEST['json_result'] ) ) {
69
+ // New favicon to install:
70
+ // Parameters will be processed with an Ajax call
71
+
72
+ // Encode the parameters to avoid special characters issues in JS
73
+ // (see settings.php).
74
+ // Note that this is *not* related to the classic encod/decode that occurs
75
+ // when doing classic Ajax invocation, this is another "extra" encoding.
76
+ $new_favicon_params = urlencode( stripslashes_deep( $_REQUEST['json_result'] ) );
77
+ $ajax_url = admin_url( 'admin-ajax.php', isset( $_SERVER['HTTPS'] ) ? 'https://' : 'http://' );
78
+ }
79
+ else {
80
+ // No new favicon, simply display the settings page
81
+ $new_favicon_params = NULL;
82
+ }
83
+
84
+ // External files
85
+ wp_enqueue_script( 'jquery' );
86
+ wp_enqueue_script( 'jquery-ui' );
87
+ wp_enqueue_media();
88
+ wp_enqueue_style( 'fbrfg_admin_style', plugins_url( 'assets/css/admin.css', __FILE__ ) );
89
+
90
+ // Template time!
91
+ include_once( plugin_dir_path(__FILE__) . 'views/settings.php' );
92
+ }
93
+
94
+ public function install_new_favicon() {
95
+ header("Content-type: application/json");
96
+
97
+ try {
98
+ // URL is explicitely decoded to compensate the extra encoding performed while generating the settings page
99
+ $result = urldecode( stripslashes_deep( $_REQUEST['json_result'] ) );
100
+
101
+ $response = new Favicon_By_RealFaviconGenerator_Api_Response( $result );
102
+ update_option( Favicon_By_RealFaviconGenerator_Common::OPTION_HTML_CODE, $response->getHtmlCode() );
103
+
104
+ $zip_path = Favicon_By_RealFaviconGenerator_Common::get_tmp_dir();
105
+ if ( ! file_exists( $zip_path ) ) {
106
+ mkdir( $zip_path, 0777, true );
107
+ }
108
+ $response->downloadAndUnpack( $zip_path );
109
+
110
+ $this->store_pictures( $response );
111
+
112
+ $this->store_preview( $response->getPreviewPath() );
113
+
114
+ Favicon_By_RealFaviconGenerator_Common::remove_directory( $zip_path );
115
+
116
+ $this->set_favicon_configured();
117
+ ?>
118
+ {
119
+ "status": "success",
120
+ "preview_url": <?php echo json_encode( $this->get_preview_url() ) ?>
121
+ }
122
+ <?php
123
+ }
124
+ catch(Exception $e) {
125
+ ?>
126
+ {
127
+ "status": "error",
128
+ "message": <?php echo json_encode( $e->getMessage() ) ?>
129
+ }
130
+ <?php
131
+ }
132
+
133
+ die();
134
+ }
135
+
136
+ public function get_picture_dir() {
137
+ return Favicon_By_RealFaviconGenerator_Common::get_files_dir();
138
+ }
139
+
140
+ /**
141
+ * Returns http//somesite.com/blog/wp-content/upload/fbrfg/
142
+ */
143
+ public function get_picture_url() {
144
+ return Favicon_By_RealFaviconGenerator_Common::get_files_url();
145
+ }
146
+
147
+ /**
148
+ * Returns /blog/wp-content/upload/fbrfg/
149
+ */
150
+ public function get_full_picture_path() {
151
+ return parse_url( $this->get_picture_url(), PHP_URL_PATH );
152
+ }
153
+
154
+ /**
155
+ * Returns wp-content/upload/fbrfg/
156
+ */
157
+ public function get_picture_path() {
158
+ return substr( $this->get_picture_url(), strlen( home_url() ) );
159
+ }
160
+
161
+ public function get_preview_path( $preview_file_name = NULL ) {
162
+ if ( ! $preview_file_name ) {
163
+ $preview_file_name = $this->get_preview_file_name();
164
+ }
165
+ return $this->get_picture_dir() . 'preview' . DIRECTORY_SEPARATOR . $preview_file_name;
166
+ }
167
+
168
+ public function get_preview_url( $preview_file_name = NULL ) {
169
+ if ( ! $preview_file_name ) {
170
+ $preview_file_name = $this->get_preview_file_name();
171
+ }
172
+ return $this->get_picture_url() . '/preview/' . $preview_file_name;
173
+ }
174
+
175
+ public function store_preview( $preview_path ) {
176
+ // Remove previous preview, if any
177
+ $previous_preview = $this->get_preview_file_name();
178
+ if ( $previous_preview != NULL && ( file_exists( $this->get_preview_path( $previous_preview ) ) ) ) {
179
+ unlink( $this->get_preview_path( $previous_preview ) );
180
+ }
181
+
182
+ if ( $preview_path == NULL ) {
183
+ // "Unregister" previous preview, if any
184
+ $this->set_preview_file_name( NULL );
185
+ return NULL;
186
+ }
187
+ else {
188
+ $preview_file_name = 'preview_' . md5( 'RFB stuff here ' . rand() . microtime() ) . '.png';
189
+ }
190
+
191
+ if ( ! file_exists( dirname( $this->get_preview_path( $preview_file_name ) ) ) ) {
192
+ mkdir( dirname( $this->get_preview_path( $preview_file_name ) ) );
193
+ }
194
+
195
+ rename( $preview_path, $this->get_preview_path( $preview_file_name ) );
196
+
197
+ $this->set_preview_file_name( $preview_file_name );
198
+ }
199
+
200
+ public function store_pictures( $rfg_response ) {
201
+ $working_dir = $this->get_picture_dir();
202
+
203
+ // Move pictures to production directory
204
+ $files = glob( $working_dir . '*' );
205
+ foreach( $files as $file ) {
206
+ if ( is_file( $file ) ) {
207
+ unlink( $file );
208
+ }
209
+ }
210
+ $files = glob( $rfg_response->getProductionPackagePath() . DIRECTORY_SEPARATOR . '*' );
211
+ foreach( $files as $file ) {
212
+ if ( is_file( $file ) ) {
213
+ rename( $file, $working_dir . basename( $file ) );
214
+ }
215
+ }
216
+
217
+ if ( $rfg_response->isFilesInRoot() ) {
218
+ $this->rewrite_pictures_url( $working_dir );
219
+ flush_rewrite_rules();
220
+ }
221
+ }
222
+
223
+ public function rewrite_pictures_url( $pic_dir ) {
224
+ foreach ( scandir($pic_dir) as $file ) {
225
+ if ( ! is_dir( $pic_dir . DIRECTORY_SEPARATOR . $file ) ) {
226
+ add_rewrite_rule( str_replace( '.', '\.', $file ),
227
+ trim( $this->get_picture_path(), '/') . '/' . $file );
228
+ }
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Indicate if it is possible to create URLs such as /favicon.ico
234
+ */
235
+ public function can_access_pics_with_url_rewrite() {
236
+ global $wp_rewrite;
237
+
238
+ // If blog is in root AND rexriting is available (http://wordpress.stackexchange.com/questions/142273/checking-that-the-rewrite-api-is-available),
239
+ // we can produce URLs such as /favicon.ico
240
+ return ( $this->wp_in_root() && $wp_rewrite->using_permalinks() );
241
+ }
242
+
243
+ /**
244
+ * Indicate if WP is installed in the root of the web site (eg. http://mysite.com) or not (eg. http://mysite.com/blog).
245
+ */
246
+ public function wp_in_root() {
247
+ $path = parse_url( home_url(), PHP_URL_PATH );
248
+ return ( ($path == NULL) || (strlen( $path ) == 0) );
249
+ }
250
+ }
251
+ ?>
admin/class-favicon-by-realfavicongenerator-api-response.php ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Copyright 2014 RealFaviconGenerator
3
+
4
+ define( 'RFG_PACKAGE_URL', 'package_url' );
5
+ define( 'RFG_COMPRESSION', 'compression' );
6
+ define( 'RFG_HTML_CODE', 'html_code' );
7
+ define( 'RFG_FILES_IN_ROOT', 'files_in_root' );
8
+ define( 'RFG_FILES_PATH', 'files_path' );
9
+ define( 'RFG_PREVIEW_PICTURE_URL', 'preview_picture_url' );
10
+ define( 'RFG_CUSTOM_PARAMETER', 'custom_parameter' );
11
+
12
+ define( 'RFG_FAVICON_PRODUCTION_PACKAGE_PATH', 'favicon_production_package_path' );
13
+ define( 'RFG_FAVICON_COMPRESSED_PACKAGE_PATH', 'favicon_compressed_package_path' );
14
+ define( 'RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH', 'favicon_uncompressed_package_path' );
15
+ define( 'RFG_PREVIEW_PATH', 'preview_path' );
16
+
17
+ class Favicon_By_RealFaviconGenerator_Api_Response {
18
+
19
+ private $params = array();
20
+
21
+ public function Favicon_By_RealFaviconGenerator_Api_Response( $json ) {
22
+ if ( $json == NULL ) {
23
+ throw new InvalidArgumentException( "No response from RealFaviconGenerator" );
24
+ }
25
+
26
+ $response = json_decode( $json, true );
27
+
28
+ if ( $response == NULL ) {
29
+ throw new InvalidArgumentException( "JSON could not be parsed" );
30
+ }
31
+
32
+ $response = $this->getParam( $response, 'favicon_generation_result' );
33
+ $result = $this->getParam( $response, 'result' );
34
+ $status = $this->getParam( $result, 'status' );
35
+
36
+ if ( $status != 'success' ) {
37
+ $msg = $this->getParam( $result, 'error_message', false );
38
+ $msg = $msg != NULL ? $msg : 'An error occured';
39
+ throw new InvalidArgumentException( $msg );
40
+ }
41
+
42
+ $favicon = $this->getParam( $response, 'favicon' );
43
+ $this->params[RFG_PACKAGE_URL] = $this->getParam( $favicon, 'package_url' );
44
+ $this->params[RFG_COMPRESSION] = $this->getParam( $favicon, 'compression' ) == 'true';
45
+ $this->params[RFG_HTML_CODE] = $this->getParam( $favicon, 'html_code' );
46
+
47
+ $filesLoc = $this->getParam( $response, 'files_location' );
48
+ $this->params[RFG_FILES_IN_ROOT] = $this->getParam( $filesLoc, 'type' ) == 'root';
49
+ $this->params[RFG_FILES_PATH] = $this->params[RFG_FILES_IN_ROOT] ? '/' : $this->getParam( $filesLoc, 'path' );
50
+
51
+ $this->params[RFG_PREVIEW_PICTURE_URL] = $this->getParam( $response, 'preview_picture_url', false );
52
+
53
+ $this->params[RFG_CUSTOM_PARAMETER] = $this->getParam( $response, 'custom_parameter', false );
54
+ }
55
+
56
+ /**
57
+ * For example: <code>"http://realfavicongenerator.net/files/1234f5d2s34f3ds2/package.zip"</code>
58
+ */
59
+ public function getPackageUrl() {
60
+ return $this->params[RFG_PACKAGE_URL];
61
+ }
62
+
63
+ /**
64
+ * For example: <code>"&lt;link ..."</code>
65
+ */
66
+ public function getHtmlCode() {
67
+ return $this->params[RFG_HTML_CODE];
68
+ }
69
+
70
+ /**
71
+ * <code>true</code> if the user chose to compress the pictures, <code>false</code> otherwise.
72
+ */
73
+ public function isCompressed() {
74
+ return $this->params[RFG_COMPRESSION];
75
+ }
76
+
77
+ /**
78
+ * <code>true</code> if the favicon files are to be stored in the root directory of the target web site, <code>false</code> otherwise.
79
+ */
80
+ public function isFilesInRoot() {
81
+ return $this->params[RFG_FILES_IN_ROOT];
82
+ }
83
+
84
+ /**
85
+ * Indicate where the favicon files should be stored in the target web site. For example: <code>"/"</code>, <code>"/path/to/icons"</code>.
86
+ */
87
+ public function getFilesLocation() {
88
+ return $this->params[RFG_FILES_PATH];
89
+ }
90
+
91
+ /**
92
+ * For example: <code>"http://realfavicongenerator.net/files/1234f5d2s34f3ds2/preview.png"</code>
93
+ */
94
+ public function getPreviewUrl() {
95
+ return $this->params[RFG_PREVIEW_PICTURE_URL];
96
+ }
97
+
98
+ /**
99
+ * Return the customer parameter, as it was transmitted during the invocation of the API.
100
+ */
101
+ public function getCustomParameter() {
102
+ return $this->params[RFG_CUSTOM_PARAMETER];
103
+ }
104
+
105
+ private function getParam( $params, $paramName, $throwIfNotFound = true ) {
106
+ if ( isset( $params[$paramName] ) ) {
107
+ return $params[$paramName];
108
+ }
109
+ else if ( $throwIfNotFound ) {
110
+ throw new InvalidArgumentException( "Cannot find parameter " . $paramName );
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Download and extract the files referenced by the response sent back by RealFaviconGenerator.
116
+ *
117
+ * Warning: as this method does HTTP accesses, calling it can take a few seconds. Better invoke it
118
+ * in an Ajax call, to not slow down the user experience.
119
+ */
120
+ public function downloadAndUnpack( $outputDirectory = NULL ) {
121
+ if ( $outputDirectory == NULL ) {
122
+ $outputDirectory = sys_get_temp_dir();
123
+ }
124
+
125
+ if ( $this->getPackageUrl() != NULL ) {
126
+ $packagePath = $outputDirectory . DIRECTORY_SEPARATOR . 'favicon_package.zip';
127
+ $this->downloadFile( $packagePath, $this->getPackageUrl() );
128
+
129
+ $zip = new ZipArchive();
130
+ $r = $zip->open( $packagePath );
131
+ if ($r === TRUE) {
132
+ $extractedPath = $outputDirectory . DIRECTORY_SEPARATOR . 'favicon_package';
133
+ if ( ! file_exists( $extractedPath ) ) {
134
+ mkdir( $extractedPath );
135
+ }
136
+
137
+ $zip->extractTo( $extractedPath );
138
+ $zip->close();
139
+
140
+ if ( $this->isCompressed() ) {
141
+ // As of today, when the user chooses the compress the picture,
142
+ // the package is provided in two flavors, in two distinct directories.
143
+ // Later, only the compressed version will be provided. Thus, the following code
144
+ // handles both scenarios.
145
+ if ( is_dir( $extractedPath . DIRECTORY_SEPARATOR . 'compressed' ) ) {
146
+ $this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH] = $extractedPath . DIRECTORY_SEPARATOR . 'compressed';
147
+ } else {
148
+ $this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH] = $extractedPath;
149
+ }
150
+
151
+ if ( is_dir( $extractedPath . DIRECTORY_SEPARATOR . 'uncompressed' ) ) {
152
+ $this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH] = $extractedPath . DIRECTORY_SEPARATOR . 'uncompressed';
153
+ } else {
154
+ $this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH] = $extractedPath;
155
+ }
156
+
157
+ $this->params[RFG_FAVICON_PRODUCTION_PACKAGE_PATH] = $this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH];
158
+ }
159
+ else {
160
+ $this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH] = NULL;
161
+ $this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH] = $extractedPath;
162
+ $this->params[RFG_FAVICON_PRODUCTION_PACKAGE_PATH] = $this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH];
163
+ }
164
+ }
165
+ else {
166
+ throw new InvalidArgumentException( 'Cannot open package. Invalid Zip file?!' );
167
+ }
168
+ }
169
+
170
+ if ( $this->getPreviewUrl() != NULL ) {
171
+ $previewPath = $outputDirectory . DIRECTORY_SEPARATOR . 'favicon_preview.png';
172
+ $this->downloadFile( $previewPath, $this->getPreviewUrl() );
173
+ $this->params[RFG_PREVIEW_PATH] = $previewPath;
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Directory where the compressed files are stored. Method <code>downloadAndUnpack</code> must be called first in order to populate this field.
179
+ * Can be <code>NULL</code>.
180
+ */
181
+ public function getCompressedPackagePath() {
182
+ return $this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH];
183
+ }
184
+
185
+ /**
186
+ * Directory where the uncompressed files are stored. Method <code>downloadAndUnpack</code> must be called first in order to populate this field.
187
+ * Can be <code>NULL</code>.
188
+ */
189
+ public function getUncompressedPackagePath() {
190
+ return $this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH];
191
+ }
192
+
193
+ /**
194
+ * Directory where the production favicon files are stored.
195
+ * These are the files to deployed to the targeted web site. When the user asked for compression,
196
+ * this is the path to the compressed folder. Else, this is the path to the regular files folder.
197
+ * Method <code>downloadAndUnpack</code> must be called first in order to populate this field.
198
+ */
199
+ public function getProductionPackagePath() {
200
+ return $this->params[RFG_FAVICON_PRODUCTION_PACKAGE_PATH];
201
+ }
202
+
203
+ /**
204
+ * Path to the preview picture.
205
+ */
206
+ public function getPreviewPath() {
207
+ return $this->params[RFG_PREVIEW_PATH];
208
+ }
209
+
210
+ private function downloadFile( $localPath, $url ) {
211
+ $content = file_get_contents( $url );
212
+ if ( $content === FALSE ) {
213
+ throw new InvalidArgumentException( "Cannot download file at " . $url );
214
+ }
215
+ $ret = file_put_contents( $localPath, $content );
216
+ if ( $ret === FALSE ) {
217
+ throw new InvalidArgumentException( "Cannot store content of " . $url . " to " . $localPath );
218
+ }
219
+ }
220
+
221
+ }
222
+ ?>
admin/views/settings.php ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Copyright 2014 RealFaviconGenerator
3
+ ?>
4
+
5
+ <div class="wrap">
6
+
7
+ <h2><?php echo esc_html( get_admin_page_title() ); ?></h2>
8
+
9
+ <?php if ( $new_favicon_params ) { ?>
10
+ <div id="install_in_progress_message" class="updated">
11
+ <p><?php _e( 'Favicon installation in progress. Please wait...', FBRFG_PLUGIN_SLUG ) ?></p>
12
+ </div>
13
+
14
+ <div id="install_completed_message" class="updated" style="display:none">
15
+ <p>Favicon installed!</p>
16
+ </div>
17
+ <div id="install_error_message" class="error" style="display:none"><p></p></div>
18
+
19
+ <div id="install_completed_container" style="display:none">
20
+ <h3><?php _e( 'Current favicon', FBRFG_PLUGIN_SLUG ) ?></h3>
21
+ <p><?php _e( 'The favicon is up and ready.', FBRFG_PLUGIN_SLUG ) ?></p>
22
+ <img id="preview_image">
23
+ </div>
24
+ <?php } else { ?>
25
+ <h3><?php _e( 'Current favicon', FBRFG_PLUGIN_SLUG ) ?></h3>
26
+
27
+ <?php if ( $favicon_configured) { ?>
28
+ <p><?php _e( 'The favicon is up and ready.', FBRFG_PLUGIN_SLUG ) ?></p>
29
+ <?php } else { ?>
30
+ <p><?php _e( 'No favicon has been configured yet.', FBRFG_PLUGIN_SLUG ) ?></p>
31
+ <?php } ?>
32
+
33
+ <?php if ( $favicon_configured ) {
34
+ if ( $preview_url ) { ?>
35
+
36
+ <img src="<?php echo $preview_url ?>">
37
+
38
+ <?php }
39
+ }
40
+ } ?>
41
+
42
+ <div id="favicon_form_container" <?php echo $new_favicon_params ? 'style="display:none"' : '' ?>>
43
+ <h3><?php _e( 'Favicon generation', FBRFG_PLUGIN_SLUG ) ?></h3>
44
+ <?php if ( $favicon_configured || $new_favicon_params ) { ?>
45
+ <p><?php _e( 'You can replace the existing favicon.', FBRFG_PLUGIN_SLUG ) ?></p>
46
+ <?php } ?>
47
+ <form role="form" method="post" action="http://realfavicongenerator.net/api/favicon_generator" id="favicon_form">
48
+ <input type="hidden" name="json_params" id="json_params"/>
49
+ <table class="form-table"><tbody>
50
+ <tr>
51
+ <th scope="row">
52
+ <label for="master_picture_url"><?php _e( 'Master picture URL', FBRFG_PLUGIN_SLUG ) ?></label>
53
+ </th>
54
+ <td>
55
+ <input id="master_picture_url" name="master_picture_url" size="55">
56
+ <button id="upload_image_button" value="<?php _e( 'Select from the Media Library', FBRFG_PLUGIN_SLUG ) ?>">
57
+ <?php _e( 'Select from the Media Library', FBRFG_PLUGIN_SLUG ) ?>
58
+ </button>
59
+ <p class="description">
60
+ <?php _e( 'Submit a square picture, at least 70x70 (recommended: 260x260 or more)', FBRFG_PLUGIN_SLUG ) ?>
61
+ <br>
62
+ <?php _e( 'If the picture is on your hard drive, you can leave this field blank and upload the picture from RealFaviconGenerator.', FBRFG_PLUGIN_SLUG ) ?>
63
+ </p>
64
+ </td>
65
+ </tr>
66
+ </tbody></table>
67
+
68
+ <p class="submit">
69
+ <input type="submit" name="Generate favicon" id="generate_favicon_button" class="button-primary"
70
+ value="<?php _e( 'Generate favicon', FBRFG_PLUGIN_SLUG ) ?>">
71
+ </p>
72
+ </form>
73
+ </div>
74
+ </div>
75
+
76
+ <script type="text/javascript">
77
+ var picData = null;
78
+
79
+ // See http://stackoverflow.com/questions/934012/get-image-data-in-javascript
80
+ // Credits: Matthew Crumley
81
+ function getBase64Image(img) {
82
+ var canvas = document.createElement("canvas");
83
+ canvas.width = img.width;
84
+ canvas.height = img.height;
85
+
86
+ var ctx = canvas.getContext("2d");
87
+ ctx.drawImage(img, 0, 0);
88
+
89
+ var dataURL = canvas.toDataURL("image/png");
90
+
91
+ return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
92
+ }
93
+
94
+ function computeJson() {
95
+ var params = { favicon_generation: {
96
+ callback: {},
97
+ master_picture: {},
98
+ files_location: {},
99
+ api_key: "87d5cd739b05c00416c4a19cd14a8bb5632ea563"
100
+ }};
101
+
102
+ if (jQuery('#master_picture_url').val().length <= 0) {
103
+ params.favicon_generation.master_picture.type = "no_picture";
104
+ params.favicon_generation.master_picture.demo = true;
105
+ }
106
+ else {
107
+ params.favicon_generation.master_picture.type = "url";
108
+ params.favicon_generation.master_picture.url = jQuery('#master_picture_url').val();
109
+ }
110
+
111
+ <?php if ( $pic_path == NULL ) { ?>
112
+ params.favicon_generation.files_location.type = 'root';
113
+ <?php } else { ?>
114
+ params.favicon_generation.files_location.type = 'path';
115
+ params.favicon_generation.files_location.path = '<?php echo $pic_path ?>';
116
+ <?php } ?>
117
+
118
+ params.favicon_generation.callback.type = 'url';
119
+ params.favicon_generation.callback.url = "<?php echo admin_url('options-general.php?page=favicon-by-realfavicongenerator/admin/class-favicon-by-realfavicongenerator-admin.phpfavicon_settings_menu') ?>";
120
+
121
+ return params;
122
+ }
123
+
124
+ <?php if ( $new_favicon_params ) { ?>
125
+ var data = {
126
+ action: '<?php echo Favicon_By_RealFaviconGenerator_Common::PLUGIN_PREFIX . '_install_new_favicon' ?>',
127
+ json_result: '<?php echo $new_favicon_params ?>'
128
+ };
129
+ <?php } ?>
130
+
131
+ jQuery(document).ready(function() {
132
+ jQuery('#favicon_form').submit(function(e) {
133
+ jQuery('#json_params').val(JSON.stringify(computeJson()));
134
+ });
135
+
136
+ <?php if ( $new_favicon_params ) { ?>
137
+ jQuery.get('<?php echo $ajax_url ?>', data, function(response) {
138
+ if (response.status == 'success') {
139
+ jQuery('#preview_image').attr('src', response.preview_url);
140
+ jQuery('#install_in_progress_message').fadeOut(function() {
141
+ jQuery('#install_completed_message').fadeIn();
142
+ jQuery('#install_completed_container').fadeIn();
143
+ jQuery('#favicon_form_container').fadeIn();
144
+ });
145
+ }
146
+ else {
147
+ var msg = "An error occured";
148
+ if (response.message != null) {
149
+ msg += ": " + response.message;
150
+ }
151
+ jQuery('#install_error_message p').html(msg);
152
+ jQuery('#install_in_progress_message').fadeOut(function() {
153
+ jQuery('#install_error_message').fadeIn();
154
+ });
155
+ }
156
+ });
157
+ <?php } ?>
158
+
159
+ var fileFrame;
160
+
161
+ jQuery('#upload_image_button').live('click', function(event) {
162
+ event.preventDefault();
163
+
164
+ if (fileFrame) {
165
+ fileFrame.open();
166
+ return;
167
+ }
168
+
169
+ // Create the media frame.
170
+ fileFrame = wp.media.frames.file_frame = wp.media({
171
+ title: jQuery(this).data('uploader_title'),
172
+ button: {
173
+ text: jQuery(this).data('uploader_button_text'),
174
+ },
175
+ multiple: false
176
+ });
177
+
178
+ fileFrame.on('select', function() {
179
+ attachment = fileFrame.state().get('selection').first().toJSON();
180
+ jQuery('#master_picture_url').val(attachment.url);
181
+ });
182
+
183
+ fileFrame.open();
184
+ });
185
+
186
+ });
187
+ </script>
assets/screenshot-1.png ADDED
Binary file
assets/screenshot-2.png ADDED
Binary file
assets/screenshot-3.png ADDED
Binary file
assets/screenshot-4.png ADDED
Binary file
favicon-by-realfavicongenerator.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Favicon by RealFaviconGenerator.
4
+ *
5
+ * @package favicon-by-realfavicongenerator
6
+ * @author Philippe Bernard <philippe@realfavicongenerator.net>
7
+ * @license GPLv2
8
+ * @link http://www.gnu.org/licenses/gpl-2.0.html
9
+ * @copyright 2014 RealFaviconGenerator
10
+ *
11
+ * @wordpress-plugin
12
+ * Plugin Name: Favicon by RealFaviconGenerator
13
+ * Plugin URI: http://realfavicongenerator.net/extensions/wordpress
14
+ * Description: Create and install your favicon for all platforms: PC/Mac of course, but also iPhone/iPad, Android devices, Windows 8 tablets, etc.
15
+ * Version: 1.0
16
+ * Author: Philippe Bernard
17
+ * Author URI: http://realfavicongenerator.net/
18
+ * License: GPLv2
19
+ * License URI: http://www.gnu.org/licenses/gpl-2.0.html
20
+ */
21
+
22
+ // If this file is called directly, abort.
23
+ if ( ! defined( 'WPINC' ) ) {
24
+ die;
25
+ }
26
+
27
+ /*----------------------------------------------------------------------------*
28
+ * Public-Facing Functionality
29
+ *----------------------------------------------------------------------------*/
30
+
31
+ require_once( plugin_dir_path( __FILE__ ) . 'public/class-favicon-by-realfavicongenerator.php' );
32
+
33
+ register_activation_hook( __FILE__, array( 'Favicon_By_RealFaviconGenerator', 'activate' ) );
34
+ register_deactivation_hook( __FILE__, array( 'Favicon_By_RealFaviconGenerator', 'deactivate' ) );
35
+
36
+ add_action( 'plugins_loaded', array( 'Favicon_By_RealFaviconGenerator', 'get_instance' ) );
37
+
38
+ /*----------------------------------------------------------------------------*
39
+ * Dashboard and Administrative Functionality
40
+ *----------------------------------------------------------------------------*/
41
+
42
+ if ( is_admin() ) {
43
+
44
+ require_once( plugin_dir_path( __FILE__ ) . 'admin/class-favicon-by-realfavicongenerator-admin.php' );
45
+ add_action( 'plugins_loaded', array( 'Favicon_By_RealFaviconGenerator_Admin', 'get_instance' ) );
46
+
47
+ }
languages/favicon-by-realfavicongenerator-fr_FR.mo ADDED
Binary file
languages/favicon-by-realfavicongenerator-fr_FR.po ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2014 Favicon by RealFaviconGenerator
2
+ # This file is distributed under the same license as the Favicon by RealFaviconGenerator package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: Favicon by RealFaviconGenerator 1.0\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/tag/favicon-by-"
7
+ "realfavicongenerator\n"
8
+ "POT-Creation-Date: 2014-04-30 15:30:56+00:00\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "PO-Revision-Date: 2014-05-02 10:32+0100\n"
13
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
+ "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "Language: fr_FR\n"
16
+ "X-Generator: Poedit 1.6.5\n"
17
+
18
+ #: admin/class-favicon-by-realfavicongenerator-admin.php:64
19
+ msgid "Favicon Settings"
20
+ msgstr "Réglages du favicon"
21
+
22
+ #: admin/class-favicon-by-realfavicongenerator-admin.php:64
23
+ msgid "Favicon"
24
+ msgstr "Favicon"
25
+
26
+ #: admin/views/settings.php:22
27
+ msgid "Favicon installation in progress. Please wait..."
28
+ msgstr "Installation du favicon en cours. Veuillez patienter..."
29
+
30
+ #: admin/views/settings.php:26 admin/views/settings.php:31
31
+ msgid "Current favicon"
32
+ msgstr "Favicon actuel"
33
+
34
+ #: admin/views/settings.php:27 admin/views/settings.php:34
35
+ msgid "The favicon is up and ready."
36
+ msgstr "Le favicon est installé."
37
+
38
+ #: admin/views/settings.php:36
39
+ msgid "No favicon has been configured yet."
40
+ msgstr "Aucun favicon n'a été configuré pour le moment."
41
+
42
+ #: admin/views/settings.php:49
43
+ msgid "Favicon generation"
44
+ msgstr "Génération du favicon"
45
+
46
+ #: admin/views/settings.php:51
47
+ msgid "You can replace the existing favicon."
48
+ msgstr "Vous pouvez remplacer le favicon existant."
49
+
50
+ #: admin/views/settings.php:58
51
+ msgid "Master picture URL"
52
+ msgstr "URL de l'image de base"
53
+
54
+ #: admin/views/settings.php:62 admin/views/settings.php:63
55
+ msgid "Select from the Media Library"
56
+ msgstr "Sélectionner dans la Bibliothèque de médias"
57
+
58
+ #: admin/views/settings.php:66
59
+ msgid "Submit a square picture, at least 70x70 (recommended: 260x260 or more)"
60
+ msgstr ""
61
+ "Utilisez une image carrée en 70x70 minimum (recommandé: 260x260 ou plus)"
62
+
63
+ #: admin/views/settings.php:68
64
+ msgid ""
65
+ "If the picture is on your hard drive, you can leave this field blank and "
66
+ "upload the picture from RealFaviconGenerator."
67
+ msgstr ""
68
+ "Si l'image est sur votre disque dur, vous pouvez laisser ce champ vide et "
69
+ "envoyer une image depuis l'interface de RealFaviconGenerator"
70
+
71
+ #: admin/views/settings.php:75
72
+ msgid "Generate favicon"
73
+ msgstr "Générer le favicon"
74
+
75
+ #. Plugin Name of the plugin/theme
76
+ msgid "Favicon by RealFaviconGenerator"
77
+ msgstr "Favicon par RealFaviconGenerator"
78
+
79
+ #. Description of the plugin/theme
80
+ msgid ""
81
+ "Create and install your favicon for all platforms: PC/Mac of course, but "
82
+ "also iPhone/iPad, Android devices, Windows 8 tablets, etc."
83
+ msgstr ""
84
+ "Créez et installez votre favicon pour toutes les plateformes : PC/Mac "
85
+ "évidemment, mais aussi iPhone/iPad, appareils Android, tablettes Windows 8, "
86
+ "etc."
87
+
88
+ #. Author of the plugin/theme
89
+ msgid "Philippe Bernard"
90
+ msgstr "Philippe Bernard"
public/class-favicon-by-realfavicongenerator-common.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Copyright 2014 RealFaviconGenerator
3
+
4
+ class Favicon_By_RealFaviconGenerator_Common {
5
+
6
+ const PLUGIN_PREFIX = 'fbrfg';
7
+
8
+ const OPTION_FAVICON_CONFIGURED = 'fbrfg_favicon_configured';
9
+ const OPTION_PREVIEW_FILE_NAME = 'fbrfg_preview_file_name';
10
+ const OPTION_HTML_CODE = 'fbrfg_html_code';
11
+
12
+ public static function get_options_list() {
13
+ return array(
14
+ Favicon_By_RealFaviconGenerator_Common::OPTION_FAVICON_CONFIGURED,
15
+ Favicon_By_RealFaviconGenerator_Common::OPTION_PREVIEW_FILE_NAME,
16
+ Favicon_By_RealFaviconGenerator_Common::OPTION_HTML_CODE );
17
+ }
18
+
19
+ const PLUGIN_SLUG = 'favicon-by-realfavicongenerator';
20
+
21
+ /**
22
+ * Indicate if a favicon was configured.
23
+ */
24
+ public function is_favicon_configured() {
25
+ $opt = get_option( Favicon_By_RealFaviconGenerator_Common::OPTION_FAVICON_CONFIGURED );
26
+ return ( $opt == 1 );
27
+ }
28
+
29
+ public function set_favicon_configured( $configured = true ) {
30
+ update_option( Favicon_By_RealFaviconGenerator_Common::OPTION_FAVICON_CONFIGURED,
31
+ $configured ? 1 : 0 );
32
+ }
33
+
34
+ public function is_preview_available() {
35
+ $opt = get_option( Favicon_By_RealFaviconGenerator_Common::OPTION_PREVIEW_FILE_NAME );
36
+ return ( ( $opt != NULL ) && ( $opt != false ) );
37
+ }
38
+
39
+ public function get_preview_file_name() {
40
+ return get_option( Favicon_By_RealFaviconGenerator_Common::OPTION_PREVIEW_FILE_NAME );
41
+ }
42
+
43
+ public function set_preview_file_name($preview_file_name) {
44
+ update_option( Favicon_By_RealFaviconGenerator_Common::OPTION_PREVIEW_FILE_NAME,
45
+ $preview_file_name);
46
+ }
47
+
48
+ public function add_favicon_markups() {
49
+ $code = get_option( Favicon_By_RealFaviconGenerator_Common::OPTION_HTML_CODE );
50
+ if ( $code ) {
51
+ echo $code;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Returns /www/wordpress/wp-content/uploaded/fbrfg
57
+ */
58
+ public static function get_files_dir() {
59
+ $up_dir = wp_upload_dir();
60
+ return $up_dir['basedir'] . DIRECTORY_SEPARATOR . Favicon_By_RealFaviconGenerator_Common::PLUGIN_PREFIX . DIRECTORY_SEPARATOR;
61
+ }
62
+
63
+ /**
64
+ * Returns http//somesite.com/blog/wp-content/upload/fbrfg/
65
+ */
66
+ public static function get_files_url() {
67
+ $up_dir = wp_upload_dir();
68
+ return $up_dir['baseurl'] . DIRECTORY_SEPARATOR . Favicon_By_RealFaviconGenerator_Common::PLUGIN_PREFIX . DIRECTORY_SEPARATOR;
69
+ }
70
+
71
+ public static function get_tmp_dir() {
72
+ return Favicon_By_RealFaviconGenerator_Common::get_files_dir() . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
73
+ }
74
+
75
+ public static function remove_directory($directory) {
76
+ foreach( scandir( $directory ) as $v ) {
77
+ if ( is_dir( $directory . DIRECTORY_SEPARATOR . $v ) ) {
78
+ if ( $v != '.' && $v != '..' ) {
79
+ Favicon_By_RealFaviconGenerator_Common::remove_directory( $directory . DIRECTORY_SEPARATOR . $v );
80
+ }
81
+ }
82
+ else {
83
+ unlink( $directory . DIRECTORY_SEPARATOR . $v );
84
+ }
85
+ }
86
+ rmdir( $directory );
87
+ }
88
+
89
+
90
+ /**
91
+ * Load the plugin text domain for translation.
92
+ */
93
+ public function load_plugin_textdomain() {
94
+
95
+ $domain = Favicon_By_RealFaviconGenerator_Common::PLUGIN_SLUG;
96
+ $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
97
+
98
+ load_textdomain( $domain, trailingslashit( WP_LANG_DIR ) . $domain . '/' . $domain . '-' . $locale . '.mo' );
99
+ load_plugin_textdomain( $domain, FALSE, basename( plugin_dir_path( dirname( __FILE__ ) ) ) . '/languages/' );
100
+
101
+ }
102
+
103
+ }
104
+
105
+ // Shortcut
106
+ const FBRFG_PLUGIN_SLUG = Favicon_By_RealFaviconGenerator_Common::PLUGIN_SLUG;
public/class-favicon-by-realfavicongenerator.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Copyright 2014 RealFaviconGenerator
3
+
4
+ require_once plugin_dir_path( __FILE__ ) . '../public/class-favicon-by-realfavicongenerator-common.php';
5
+
6
+ class Favicon_By_RealFaviconGenerator extends Favicon_By_RealFaviconGenerator_Common {
7
+
8
+ protected static $instance = null;
9
+
10
+ private function __construct() {
11
+ add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
12
+ add_action( 'wp_head', array( $this, 'add_favicon_markups' ) );
13
+ }
14
+
15
+ public static function get_instance() {
16
+
17
+ // If the single instance hasn't been set, set it now.
18
+ if ( null == self::$instance ) {
19
+ self::$instance = new self;
20
+ }
21
+
22
+ return self::$instance;
23
+ }
24
+
25
+
26
+ public static function activate( $network_wide ) {
27
+
28
+ if ( function_exists( 'is_multisite' ) && is_multisite() ) {
29
+
30
+ if ( $network_wide ) {
31
+
32
+ // Get all blog ids
33
+ $blog_ids = self::get_blog_ids();
34
+
35
+ foreach ( $blog_ids as $blog_id ) {
36
+
37
+ switch_to_blog( $blog_id );
38
+ self::single_activate();
39
+ }
40
+
41
+ restore_current_blog();
42
+
43
+ } else {
44
+ self::single_activate();
45
+ }
46
+
47
+ } else {
48
+ self::single_activate();
49
+ }
50
+
51
+ }
52
+
53
+ public static function deactivate( $network_wide ) {
54
+
55
+ if ( function_exists( 'is_multisite' ) && is_multisite() ) {
56
+
57
+ if ( $network_wide ) {
58
+
59
+ // Get all blog ids
60
+ $blog_ids = self::get_blog_ids();
61
+
62
+ foreach ( $blog_ids as $blog_id ) {
63
+
64
+ switch_to_blog( $blog_id );
65
+ self::single_deactivate();
66
+
67
+ }
68
+
69
+ restore_current_blog();
70
+
71
+ } else {
72
+ self::single_deactivate();
73
+ }
74
+
75
+ } else {
76
+ self::single_deactivate();
77
+ }
78
+
79
+ }
80
+
81
+ private static function single_activate() {
82
+ // Nothing to do
83
+ }
84
+
85
+ private static function single_deactivate() {
86
+ // Nothing to do
87
+ }
88
+
89
+ }
uninstall.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Copyright 2014 RealFaviconGenerator
3
+
4
+ // If uninstall not called from WordPress, then exit
5
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
6
+ exit;
7
+ }
8
+
9
+ require_once plugin_dir_path( __FILE__ ) . 'public/class-favicon-by-realfavicongenerator-common.php';
10
+
11
+ function fbrfg_clean_site_instance() {
12
+ // Remove options
13
+ foreach( Favicon_By_RealFaviconGenerator_Common::get_options_list() as $opt ) {
14
+ delete_option( $opt );
15
+ }
16
+
17
+ // Remove files
18
+ Favicon_By_RealFaviconGenerator_Common::remove_directory( Favicon_By_RealFaviconGenerator_Common::get_files_dir() );
19
+ }
20
+
21
+ if ( is_multisite() ) {
22
+ global $wpdb;
23
+ $blogs = $wpdb->get_results( "SELECT blog_id FROM {$wpdb->blogs}", ARRAY_A );
24
+ fbrfg_clean_site_instance();
25
+
26
+ if ( $blogs ) {
27
+ foreach( $blogs as $blog ) {
28
+ switch_to_blog( $blog['blog_id'] );
29
+ fbrfg_clean_site_instance();
30
+ restore_current_blog();
31
+ }
32
+ }
33
+ } else {
34
+ fbrfg_clean_site_instance();
35
+ }