Blocksy Companion - Version 1.0.1

Version Description

  • Remove gz files from build
  • Instagram widget text & defaults changes
Download this release

Release Info

Developer creativethemeshq
Plugin Icon wp plugin Blocksy Companion
Version 1.0.1
Comparing to
See all releases

Version 1.0.1

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., <http://fsf.org/>
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 origina
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
+ {description}
294
+ Copyright (C) {year} {fullname}
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
blocksy-companion.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Plugin Name: Blocksy Companion
5
+ Description: This plugin is the companion for the Blocksy theme, it runs and adds its enhacements only if the Blocksy theme is installed and active.
6
+ Version: 1.0.1
7
+ Author: CreativeThemes
8
+ Author URI: https://creativethemes.com
9
+ Text Domain: blc
10
+ Domain Path: /languages/
11
+ Network: true
12
+ License: GPLv2 or later
13
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
14
+ */
15
+
16
+ if ( ! defined( 'ABSPATH' ) ) {
17
+ exit; // Exit if accessed directly.
18
+ }
19
+ define( 'BLOCKSY__FILE__', __FILE__ );
20
+ define( 'BLOCKSY_PLUGIN_BASE', plugin_basename( BLOCKSY__FILE__ ) );
21
+ define( 'BLOCKSY_PATH', plugin_dir_path( BLOCKSY__FILE__ ) );
22
+ define( 'BLOCKSY_URL', plugin_dir_url( BLOCKSY__FILE__ ) );
23
+
24
+ add_action( 'plugins_loaded', 'blc_load_plugin_textdomain' );
25
+
26
+ if ( ! version_compare( PHP_VERSION, '7.0', '>=' ) ) {
27
+ add_action( 'admin_notices', 'blc_fail_php_version' );
28
+ } elseif ( ! version_compare( get_bloginfo( 'version' ), '5.0', '>=' ) ) {
29
+ add_action( 'admin_notices', 'blc_fail_wp_version' );
30
+ } else {
31
+ require( BLOCKSY_PATH . 'plugin.php' );
32
+ }
33
+
34
+
35
+ /**
36
+ * Load Blocksy textdomain.
37
+ *
38
+ * Load gettext translate for Blocksy text domain.
39
+ */
40
+ function blc_load_plugin_textdomain() {
41
+ load_plugin_textdomain('blc', false, plugin_basename( dirname( __FILE__ ) ) . '/languages');
42
+ }
43
+
44
+ /**
45
+ * Blocksy admin notice for minimum PHP version.
46
+ *
47
+ * Warning when the site doesn't have the minimum required PHP version.
48
+ */
49
+ function blc_fail_php_version() {
50
+ /* translators: %s: PHP version */
51
+ $message = sprintf( esc_html__( 'Blocksy requires PHP version %s+, plugin is currently NOT RUNNING.', 'blc' ), '7.0' );
52
+ $html_message = sprintf( '<div class="error">%s</div>', wpautop( $message ) );
53
+ echo wp_kses_post( $html_message );
54
+ }
55
+
56
+ /**
57
+ * Blocksy admin notice for minimum WordPress version.
58
+ *
59
+ * Warning when the site doesn't have the minimum required WordPress version.
60
+ */
61
+ function blc_fail_wp_version() {
62
+ /* translators: %s: WordPress version */
63
+ $message = sprintf( esc_html__( 'Blocksy requires WordPress version %s+. Because you are using an earlier version, the plugin is currently NOT RUNNING.', 'blc' ), '5.0' );
64
+ $html_message = sprintf( '<div class="error">%s</div>', wpautop( $message ) );
65
+ echo wp_kses_post( $html_message );
66
+ }
67
+
framework/autoload.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Blocksy;
4
+
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit; // Exit if accessed directly.
7
+ }
8
+
9
+ /**
10
+ * Blocksy autoloader.
11
+ */
12
+ class Autoloader {
13
+
14
+ /**
15
+ * Classes map.
16
+ *
17
+ * Maps Elementor classes to file names.
18
+ *
19
+ * @static
20
+ *
21
+ * @var array Classes used by blocksy.
22
+ */
23
+ private static $classes_map = [
24
+ 'ExtensionsManager' => 'framework/extensions-manager.php',
25
+ 'ExtensionsManagerApi' => 'framework/extensions-manager-api.php',
26
+ 'Dashboard' => 'framework/dashboard.php',
27
+ 'ThemeIntegration' => 'framework/theme-integration.php'
28
+ ];
29
+
30
+ /**
31
+ * Run autoloader.
32
+ *
33
+ * Register a function as `__autoload()` implementation.
34
+ *
35
+ * @static
36
+ */
37
+ public static function run() {
38
+ spl_autoload_register( [ __CLASS__, 'autoload' ] );
39
+ }
40
+
41
+ /**
42
+ * Load class.
43
+ *
44
+ * For a given class name, require the class file.
45
+ *
46
+ * @static
47
+ *
48
+ * @param string $relative_class_name Class name.
49
+ */
50
+ private static function load_class( $relative_class_name ) {
51
+ if ( isset( self::$classes_map[ $relative_class_name ] ) ) {
52
+ $filename = BLOCKSY_PATH . '/' . self::$classes_map[ $relative_class_name ];
53
+ } else {
54
+ $filename = strtolower(
55
+ preg_replace(
56
+ [ '/([a-z])([A-Z])/', '/_/', '/\\\/' ],
57
+ [ '$1-$2', '-', DIRECTORY_SEPARATOR ],
58
+ $relative_class_name
59
+ )
60
+ );
61
+
62
+ $filename = BLOCKSY_PATH . $filename . '.php';
63
+ }
64
+
65
+ if ( is_readable( $filename ) ) {
66
+ require $filename;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Autoload.
72
+ *
73
+ * For a given class, check if it exist and load it.
74
+ *
75
+ * @static
76
+ *
77
+ * @param string $class Class name.
78
+ */
79
+ private static function autoload( $class ) {
80
+ if ( 0 !== strpos( $class, __NAMESPACE__ . '\\' ) ) {
81
+ return;
82
+ }
83
+
84
+ $relative_class_name = preg_replace( '/^' . __NAMESPACE__ . '\\\/', '', $class );
85
+
86
+ $final_class_name = __NAMESPACE__ . '\\' . $relative_class_name;
87
+
88
+ if ( ! class_exists( $final_class_name ) ) {
89
+ self::load_class( $relative_class_name );
90
+ }
91
+ }
92
+ }
framework/dashboard.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Blocksy;
4
+
5
+ class Dashboard {
6
+ public function __construct() {
7
+ add_action(
8
+ 'admin_enqueue_scripts',
9
+ [ $this, 'enqueue_static' ]
10
+ );
11
+ }
12
+
13
+ public function enqueue_static() {
14
+ if (! function_exists('blocksy_is_dashboard_page')) return;
15
+ if (! blocksy_is_dashboard_page()) return;
16
+
17
+ $data = get_plugin_data(BLOCKSY__FILE__);
18
+
19
+ wp_enqueue_script(
20
+ 'blocksy-dashboard-scripts',
21
+ BLOCKSY_URL . 'static/bundle/dashboard.js',
22
+ ['wp-i18n', 'ct-dashboard-scripts'],
23
+ $data['Version'],
24
+ true
25
+ );
26
+
27
+ wp_enqueue_style(
28
+ 'blocksy-dashboard-styles',
29
+ BLOCKSY_URL . 'static/bundle/dashboard.css',
30
+ [],
31
+ $data['Version']
32
+ );
33
+ }
34
+ }
framework/extensions-manager-api.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Blocksy;
4
+
5
+ class ExtensionsManagerApi {
6
+ public function __construct() {
7
+ $this->attach_ajax_actions();
8
+ }
9
+
10
+ protected $ajax_actions = [
11
+ 'blocksy_extensions_status',
12
+
13
+ 'blocksy_extension_activate',
14
+ 'blocksy_extension_deactivate',
15
+ ];
16
+
17
+ public function blocksy_extensions_status() {
18
+ $this->check_capability( 'edit_plugins' );
19
+
20
+ $manager = new ExtensionsManager();
21
+ wp_send_json_success($manager->get_extensions());
22
+ }
23
+
24
+ public function blocksy_extension_activate() {
25
+ $this->check_capability( 'edit_plugins' );
26
+ $manager = new ExtensionsManager();
27
+
28
+ $manager->activate_extension($this->get_extension_from_request());
29
+
30
+ wp_send_json_success();
31
+ }
32
+
33
+ public function blocksy_extension_deactivate() {
34
+ $this->check_capability( 'edit_plugins' );
35
+ $manager = new ExtensionsManager();
36
+
37
+ $manager->deactivate_extension($this->get_extension_from_request());
38
+
39
+ wp_send_json_success();
40
+ }
41
+
42
+ public function check_capability( $cap = 'install_plugins' ) {
43
+ $manager = new ExtensionsManager();
44
+
45
+ if ( ! $manager->can( $cap ) ) {
46
+ wp_send_json_error();
47
+ }
48
+
49
+ return true;
50
+ }
51
+
52
+ public function get_extension_from_request() {
53
+ if ( ! isset( $_POST['ext'] ) ) {
54
+ wp_send_json_error();
55
+ }
56
+
57
+ return addslashes( $_POST['ext'] );
58
+ }
59
+
60
+ public function attach_ajax_actions() {
61
+ foreach ( $this->ajax_actions as $action ) {
62
+ add_action(
63
+ 'wp_ajax_' . $action,
64
+ [ $this, $action ]
65
+ );
66
+ }
67
+ }
68
+ }
69
+
framework/extensions-manager.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Blocksy;
4
+
5
+ class ExtensionsManager {
6
+ /**
7
+ * Collection of all the activated extensions.
8
+ *
9
+ * @var array The array of all the extension objects.
10
+ */
11
+ private $extensions = [];
12
+
13
+ private function get_option_name() {
14
+ return 'blocksy_active_extensions';
15
+ }
16
+
17
+ /**
18
+ * Collect all available extensions and activate the ones that have to be so.
19
+ */
20
+ public function __construct() {
21
+ $this->read_installed_extensions();
22
+
23
+ foreach ($this->get_activated_extensions() as $single_id) {
24
+ $this->boot_activated_extension_for($single_id);
25
+ }
26
+
27
+ // print_r($this->extensions);
28
+
29
+ // $this->activate_extension('simple');
30
+ // $this->deactivate_extension('simple');
31
+ }
32
+
33
+ public function get_extensions() {
34
+ return $this->extensions;
35
+ }
36
+
37
+ public function can( $capability = 'install_plugins' ) {
38
+ if ( is_multisite() ) {
39
+ // Only network admin can change files that affects the entire network.
40
+ $can = current_user_can_for_blog( get_current_blog_id(), $capability );
41
+ } else {
42
+ $can = current_user_can( $capability );
43
+ }
44
+
45
+ if ( $can ) {
46
+ // Also you can use this method to get the capability.
47
+ $can = $capability;
48
+ }
49
+
50
+ return $can;
51
+ }
52
+
53
+ public function activate_extension($id) {
54
+ if (! isset($this->extensions[$id])) {
55
+ return;
56
+ }
57
+
58
+ $activated = $this->get_activated_extensions();
59
+ $activated[] = strtolower($id);
60
+
61
+ update_option($this->get_option_name(), array_unique($activated));
62
+ }
63
+
64
+ public function deactivate_extension($id) {
65
+ if (! isset($this->extensions[$id])) {
66
+ return;
67
+ }
68
+
69
+ update_option($this->get_option_name(), array_diff(
70
+ $this->get_activated_extensions(),
71
+ [ $id ]
72
+ ));
73
+ }
74
+
75
+ private function read_installed_extensions() {
76
+ $paths_to_look_for_extensions = [
77
+ BLOCKSY_PATH . 'framework/extensions'
78
+ ];
79
+
80
+ foreach ($paths_to_look_for_extensions as $single_path) {
81
+ $all_extensions = glob($single_path . '/*', GLOB_ONLYDIR);
82
+
83
+ foreach ($all_extensions as $single_extension) {
84
+ $this->register_extension_for($single_extension);
85
+ }
86
+ }
87
+ }
88
+
89
+ private function register_extension_for($path) {
90
+ $id = str_replace('_', '-', basename($path));
91
+
92
+ if (isset($this->extensions[$id])) return;
93
+
94
+ $this->extensions[$id] = [
95
+ 'path' => $path,
96
+ '__object' => null,
97
+ 'config' => $this->read_config_for($path)
98
+ ];
99
+ }
100
+
101
+ private function boot_activated_extension_for($id) {
102
+ if (! isset($this->extensions[$id])) return false;
103
+ if (isset($this->extensions[$id]['__object'])) return;
104
+
105
+ $class_name = explode( '-', $id );
106
+ $class_name = array_map( 'ucfirst', $class_name );
107
+ $class_name = 'BlocksyExtension' . implode( '', $class_name );
108
+
109
+ $path = $this->extensions[$id]['path'];
110
+
111
+ require_once($path . '/extension.php');
112
+
113
+ $this->extensions[$id]['__object'] = new $class_name();
114
+ }
115
+
116
+ private function read_config_for( $file_path ) {
117
+ $_extract_variables = [ 'config' => [] ];
118
+
119
+ if (is_readable($file_path . '/config.php')) {
120
+ require $file_path . '/config.php';
121
+
122
+ foreach ( $_extract_variables as $variable_name => $default_value ) {
123
+ if ( isset( $$variable_name ) ) {
124
+ $_extract_variables[ $variable_name ] = $$variable_name;
125
+ }
126
+ }
127
+ }
128
+
129
+ $name = explode( '-', basename($file_path) );
130
+ $name = array_map( 'ucfirst', $name );
131
+ $name = implode( ' ', $name );
132
+
133
+ $_extract_variables['config'] = array_merge(
134
+ [
135
+ 'name' => $name,
136
+ 'description' => ''
137
+ ],
138
+ $_extract_variables['config']
139
+ );
140
+
141
+ return $_extract_variables['config'];
142
+ }
143
+
144
+ private function get_activated_extensions() {
145
+ return get_option($this->get_option_name(), []);
146
+ }
147
+ }
148
+
framework/extensions/instagram/config.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $config = [
4
+ 'description' => __('Instagram Widget', 'blc')
5
+ ];
6
+
7
+
framework/extensions/instagram/ct-instagram/helpers.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ add_action( 'wp_ajax_blocksy_widget_instagram', 'blocksy_widget_instagram_generate_html' );
4
+ add_action( 'wp_ajax_nopriv_blocksy_widget_instagram', 'blocksy_widget_instagram_generate_html' );
5
+
6
+ function blocksy_widget_instagram_generate_html() {
7
+ $instagram_photos = blocksy_get_instagram_photos(
8
+ sanitize_text_field( $_GET['username'] ),
9
+ intval( sanitize_text_field( $_GET['limit'] ) )
10
+ );
11
+
12
+ ?>
13
+ <?php foreach ( $instagram_photos as $photo ) { ?>
14
+ <li
15
+ <?php
16
+ if ( $photo['is_video'] ) {
17
+ echo ' class="ct-is-video"';}
18
+ ?>
19
+ >
20
+ <?php
21
+ echo blocksy_simple_image(
22
+ $photo['img'],
23
+ [
24
+ 'tag_name' => 'a',
25
+ 'html_atts' => [
26
+ 'target' => '_blank',
27
+ 'href' => 'https://instagram.com/p/' . $photo['code'],
28
+ ],
29
+ 'img_atts' => [
30
+ 'alt' => esc_attr( $photo['description'] ),
31
+ 'title' => esc_attr( $photo['description'] ),
32
+ ],
33
+ ]
34
+ )
35
+ ?>
36
+ </li>
37
+ <?php } ?>
38
+
39
+ <?php
40
+
41
+ wp_die();
42
+ }
43
+
44
+ function blocksy_get_instagram_photos( $username, $items = 10 ) {
45
+ $transient_name = 'blocksy_widget_instagram_' . md5(
46
+ json_encode(
47
+ [ $username, $items ]
48
+ )
49
+ );
50
+
51
+ if ( $maybe_transient_data = get_transient( $transient_name ) ) {
52
+ return $maybe_transient_data;
53
+ }
54
+
55
+ $username = trim( $username );
56
+
57
+ if ( ! $username ) {
58
+ return false;
59
+ }
60
+ // Instagram page source.
61
+ $source = wp_remote_get( 'http://instagram.com/' . $username );
62
+
63
+ $instagram_photos = [];
64
+
65
+ $remote_response = true;
66
+
67
+ if ( is_wp_error( $source ) ) {
68
+ $remote_response = null;
69
+ }
70
+
71
+ if ( 200 !== wp_remote_retrieve_response_code( $source ) ) {
72
+ $remote_response = null;
73
+ }
74
+
75
+ if ( ! $remote_response ) {
76
+ return $instagram_photos;
77
+ }
78
+
79
+ // Get json info about the user.
80
+ preg_match( '|window._sharedData = {(.+?)};</script>|', $source['body'], $matches );
81
+
82
+ if ( ! isset( $matches[1] ) ) {
83
+ return null;
84
+ }
85
+
86
+ $json_data = "{{$matches[1]}}";
87
+ $json_data = json_decode( $json_data, true );
88
+
89
+ if ( ! $json_data ) {
90
+ return new WP_Error( 'bad_json', __( 'Instagram has returned invalid data.', 'blocksy' ) );
91
+ }
92
+
93
+ // Get instagram images.
94
+ if ( isset( $json_data['entry_data']['ProfilePage'][0]['graphql']['user']['edge_owner_to_timeline_media']['edges'] ) ) {
95
+ $images = $json_data['entry_data']['ProfilePage'][0]['graphql']['user']['edge_owner_to_timeline_media']['edges'];
96
+ } else {
97
+ return $instagram_photos;
98
+ }
99
+
100
+ if ( count( $images ) ) {
101
+ foreach ( $images as $image ) {
102
+ if ( count( $instagram_photos ) >= $items ) {
103
+ break;
104
+ }
105
+
106
+ $image = $image['node'];
107
+
108
+ if ( ! isset( $image['edge_media_to_caption'] ) ) {
109
+ $image['edge_media_to_caption'] = array(
110
+ 'edges' => array(
111
+ array(
112
+ 'node' => array(
113
+ 'text' => '',
114
+ ),
115
+ ),
116
+ ),
117
+ );
118
+ }
119
+
120
+ if ( empty( $iamge['edge_media_to_caption']['edges'] ) ) {
121
+ $image['edge_media_to_caption'] = array(
122
+ 'edges' => array(
123
+ array(
124
+ 'node' => array(
125
+ 'text' => '',
126
+ ),
127
+ ),
128
+ ),
129
+ );
130
+ }
131
+
132
+ $instagram_photos[] = array(
133
+ 'code' => $image['shortcode'],
134
+ 'img' => $image['thumbnail_src'],
135
+ 'likes' => $image['edge_liked_by']['count'],
136
+ 'description' => $image['edge_media_to_caption']['edges'][0]['node']['text'],
137
+ 'is_video' => $image['is_video'],
138
+ );
139
+ }
140
+ }
141
+
142
+ set_transient( $transient_name, $instagram_photos, 7 * 24 * HOUR_IN_SECONDS );
143
+
144
+ return $instagram_photos;
145
+ }
146
+
147
+
framework/extensions/instagram/ct-instagram/options.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $options = [
4
+ 'title' => [
5
+ 'type' => 'text',
6
+ 'value' => 'Instagram',
7
+ 'design' => 'inline',
8
+ ],
9
+
10
+ 'username' => [
11
+ 'type' => 'text',
12
+ 'value' => '',
13
+ 'design' => 'inline',
14
+ ],
15
+
16
+ 'photos_number' => [
17
+ 'type' => 'ct-number',
18
+ 'label' => __( 'Number of Images', 'blocksy' ),
19
+ 'min' => 1,
20
+ 'max' => 12,
21
+ 'value' => 6,
22
+ 'design' => 'inline',
23
+ ],
24
+
25
+ 'instagram_images_per_row' => [
26
+ 'type' => 'ct-number',
27
+ 'label' => __( 'Images per Row', 'blocksy' ),
28
+ 'min' => 1,
29
+ 'max' => 5,
30
+ 'value' => 3,
31
+ 'design' => 'inline',
32
+ ],
33
+ ];
framework/extensions/instagram/ct-instagram/static/bundle/1.723de7579d99d3928bad.js ADDED
@@ -0,0 +1 @@
 
1
+ (window.blocksyInstagramWidgetJsonp=window.blocksyInstagramWidgetJsonp||[]).push([[1],{3:function(t,e,r){"use strict";r.r(e);var a=r(2),i=r.n(a);var n=function(t){return[].concat(function(t){if(Array.isArray(t)){for(var e=0,r=Array(t.length);e<t.length;e++)r[e]=t[e];return r}return Array.from(t)}(t.querySelectorAll(".ct-image-container.ct-lazy"))).map(function(t){t.querySelector("img").setAttribute("src",t.querySelector("img").dataset.original),t.querySelector("img").dataset.originalSet&&t.querySelector("img").setAttribute("srcset",t.querySelector("img").dataset.originalSet),t.classList.remove("ct-lazy"),t.classList.add("ct-lazy-loaded")})};r.d(e,"initInstagramWidget",function(){return l});var l=function(t){if(t.querySelector("ul[data-widget]")){if(window.fetch){var e=JSON.parse(t.querySelector("ul").dataset.widget),r=e.limit,a=e.username;t.querySelector("ul").removeAttribute("data-widget"),fetch(blocksy_ext_instagram_localization.ajax_url+"?action=blocksy_widget_instagram&limit="+r+"&username="+a).then(function(t){return t.text()}).then(function(e){t.querySelector("ul").removeAttribute("class"),t.querySelector("ul").innerHTML=e,i.a.trigger("ct:images:lazyload:update")})}}else n(t.querySelector("ul"))}}}]);
framework/extensions/instagram/ct-instagram/static/bundle/main.css ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ /**
2
+ * - v1.0.1
3
+ *
4
+ * Copyright (c) 2019
5
+ * Licensed GPLv2+
6
+ */
7
+
8
+ .ct-widget.ct-instagram-widget ul{display:grid;grid-column-gap:10px;grid-row-gap:10px}.ct-widget.ct-instagram-widget ul li{margin:0;-webkit-transition:opacity 0.12s cubic-bezier(0.455, 0.03, 0.515, 0.955);transition:opacity 0.12s cubic-bezier(0.455, 0.03, 0.515, 0.955)}.ct-widget.ct-instagram-widget ul li:hover{opacity:0.8}.ct-widget.ct-instagram-widget [data-columns='2']{grid-template-columns:repeat(2, 1fr)}.ct-widget.ct-instagram-widget [data-columns='3']{grid-template-columns:repeat(3, 1fr)}.ct-widget.ct-instagram-widget [data-columns='4']{grid-template-columns:repeat(4, 1fr)}.ct-widget.ct-instagram-widget [data-columns='5']{grid-template-columns:repeat(5, 1fr)}
framework/extensions/instagram/ct-instagram/static/bundle/main.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(e){function t(t){for(var n,o,i=t[0],u=t[1],a=0,l=[];a<i.length;a++)o=i[a],r[o]&&l.push(r[o][0]),r[o]=0;for(n in u)Object.prototype.hasOwnProperty.call(u,n)&&(e[n]=u[n]);for(c&&c(t);l.length;)l.shift()()}var n={},r={0:0};function o(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.e=function(e){var t=[],n=r[e];if(0!==n)if(n)t.push(n[2]);else{var i=new Promise(function(t,o){n=r[e]=[t,o]});t.push(n[2]=i);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,o.nc&&a.setAttribute("nonce",o.nc),a.src=function(e){return o.p+""+e+"."+{1:"723de7579d99d3928bad"}[e]+".js"}(e),u=function(t){a.onerror=a.onload=null,clearTimeout(c);var n=r[e];if(0!==n){if(n){var o=t&&("load"===t.type?"missing":t.type),i=t&&t.target&&t.target.src,u=new Error("Loading chunk "+e+" failed.\n("+o+": "+i+")");u.type=o,u.request=i,n[1](u)}r[e]=void 0}};var c=setTimeout(function(){u({type:"timeout",target:a})},12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(t)},o.m=e,o.c=n,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)o.d(n,r,function(t){return e[t]}.bind(null,r));return n},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o.oe=function(e){throw console.error(e),e};var i=window.blocksyInstagramWidgetJsonp=window.blocksyInstagramWidgetJsonp||[],u=i.push.bind(i);i.push=t,i=i.slice();for(var a=0;a<i.length;a++)t(i[a]);var c=u;o(o.s=0)}([function(e,t,n){"use strict";n.r(t);n(1);console.log("here we are"),document.addEventListener("DOMContentLoaded",function(){[].concat(function(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}(document.querySelectorAll(".ct-instagram-widget"))).map(function(e){return n.e(1).then(n.bind(null,3)).then(function(t){(0,t.initInstagramWidget)(e)})})})},function(e,t,n){n.p=blocksy_ext_instagram_localization.public_url},function(e,t){e.exports=window.ctEvents}]);
framework/extensions/instagram/ct-instagram/static/js/instagram-widget.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctEvents from 'ct-events'
2
+ import { markImagesAsLoaded } from './lazy-load-helpers'
3
+
4
+ export const initInstagramWidget = el => {
5
+ if (!el.querySelector('ul[data-widget]')) {
6
+ markImagesAsLoaded(el.querySelector('ul'))
7
+ return
8
+ }
9
+
10
+ if (!window.fetch) return
11
+
12
+ const { limit, username } = JSON.parse(
13
+ el.querySelector('ul').dataset.widget
14
+ )
15
+
16
+ el.querySelector('ul').removeAttribute('data-widget')
17
+
18
+ fetch(
19
+ `${
20
+ blocksy_ext_instagram_localization.ajax_url
21
+ }?action=blocksy_widget_instagram&limit=${limit}&username=${username}`
22
+ )
23
+ .then(r => r.text())
24
+ .then(text => {
25
+ el.querySelector('ul').removeAttribute('class')
26
+ el.querySelector('ul').innerHTML = text
27
+ ctEvents.trigger('ct:images:lazyload:update')
28
+ })
29
+ }
framework/extensions/instagram/ct-instagram/static/js/lazy-load-helpers.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export const markImagesAsLoaded = el =>
2
+ [...el.querySelectorAll('.ct-image-container.ct-lazy')].map(el => {
3
+ el
4
+ .querySelector('img')
5
+ .setAttribute('src', el.querySelector('img').dataset.original)
6
+
7
+ if (el.querySelector('img').dataset.originalSet) {
8
+ el
9
+ .querySelector('img')
10
+ .setAttribute(
11
+ 'srcset',
12
+ el.querySelector('img').dataset.originalSet
13
+ )
14
+ }
15
+
16
+ el.classList.remove('ct-lazy')
17
+ el.classList.add('ct-lazy-loaded')
18
+ })
framework/extensions/instagram/ct-instagram/static/js/main.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import './public-path'
2
+
3
+ console.log('here we are')
4
+
5
+ document.addEventListener('DOMContentLoaded', () => {
6
+ ;[...document.querySelectorAll('.ct-instagram-widget')].map(el =>
7
+ import('./instagram-widget').then(({ initInstagramWidget }) => {
8
+ initInstagramWidget(el)
9
+ })
10
+ )
11
+ })
framework/extensions/instagram/ct-instagram/static/js/public-path.js ADDED
@@ -0,0 +1 @@
 
1
+ __webpack_public_path__ = blocksy_ext_instagram_localization.public_url
framework/extensions/instagram/ct-instagram/static/sass/main.scss ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .ct-widget.ct-instagram-widget {
2
+ ul {
3
+ display: grid;
4
+ grid-column-gap: 10px;
5
+ grid-row-gap: 10px;
6
+
7
+ li {
8
+ margin: 0;
9
+ transition: opacity 0.12s cubic-bezier(0.455, 0.03, 0.515, 0.955);
10
+
11
+ &:hover {
12
+ opacity: 0.8;
13
+ }
14
+ }
15
+ }
16
+
17
+ [data-columns='2'] {
18
+ grid-template-columns: repeat(2, 1fr);
19
+ }
20
+
21
+ [data-columns='3'] {
22
+ grid-template-columns: repeat(3, 1fr);
23
+ }
24
+
25
+ [data-columns='4'] {
26
+ grid-template-columns: repeat(4, 1fr);
27
+ }
28
+
29
+ [data-columns='5'] {
30
+ grid-template-columns: repeat(5, 1fr);
31
+ }
32
+ }
framework/extensions/instagram/ct-instagram/view.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Instagram Widget
5
+ *
6
+ * @copyright 2017-present Creative Themes
7
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
8
+ */
9
+
10
+ // Widget title
11
+ $title = blocksy_akg( 'title', $atts, '' );
12
+
13
+ if ( empty( $title ) ) {
14
+ $title = 'Instagram';
15
+ }
16
+
17
+ $images_per_row = blocksy_akg( 'instagram_images_per_row', $atts, '2' );
18
+
19
+
20
+ echo $before_widget . $before_title . $title . $after_title;
21
+
22
+ $photos_number = intval( blocksy_default_akg( 'photos_number', $atts, '6' ) );
23
+
24
+ $widget_data = json_encode(
25
+ [
26
+ 'limit' => $photos_number,
27
+ 'username' => blocksy_default_akg( 'username', $atts, 'unknown' ),
28
+ ]
29
+ );
30
+
31
+ ?>
32
+
33
+ <?php if ( false && ! empty( $instagram_photos ) ) { ?>
34
+ <ul data-row="<?php echo $images_per_row; ?>">
35
+ </ul>
36
+ <?php } ?>
37
+
38
+ <ul
39
+ class="ct-loading"
40
+ data-widget='<?php echo $widget_data; ?>'
41
+ data-columns="<?php echo $images_per_row; ?>">
42
+
43
+ <?php
44
+ echo str_repeat(
45
+ '<li>' . blocksy_simple_image(
46
+ '#',
47
+ [
48
+ 'tag' => 'a',
49
+ 'html_atts' => [
50
+ 'target' => '_blank',
51
+ 'href' => '#',
52
+ ],
53
+ ]
54
+ ) . '</li>',
55
+ $photos_number
56
+ );
57
+ ?>
58
+ </ul>
59
+
60
+
61
+ <?php echo $after_widget; ?>
62
+
framework/extensions/instagram/ct-instagram/widget.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once dirname( __FILE__ ) . '/helpers.php';
4
+
5
+ class Blocksy_Widget_Ct_Instagram extends Blocksy_Widget_Factory {
6
+ protected function get_config() {
7
+ return [
8
+ 'name' => 'Instagram',
9
+ 'description' => 'Popular/Recent/Most Commented Posts.',
10
+ ];
11
+ }
12
+
13
+ public function get_path() {
14
+ return dirname(__FILE__);
15
+ }
16
+ }
17
+
18
+
19
+
framework/extensions/instagram/extension.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class BlocksyExtensionInstagram {
4
+ public function __construct() {
5
+ add_filter('blocksy_widgets_paths', function ($all_widgets) {
6
+ $all_widgets[] = dirname(__FILE__) . '/ct-instagram';
7
+ return $all_widgets;
8
+ });
9
+
10
+ add_action('wp_enqueue_scripts', function () {
11
+ if (! function_exists('get_plugin_data')){
12
+ require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
13
+ }
14
+
15
+ $data = get_plugin_data(BLOCKSY__FILE__);
16
+
17
+ if (is_admin()) return;
18
+
19
+ wp_enqueue_style(
20
+ 'blocksy-ext-instagram-styles',
21
+ BLOCKSY_URL . 'framework/extensions/instagram/ct-instagram/static/bundle/main.css',
22
+ [],
23
+ $data['Version']
24
+ );
25
+
26
+ wp_enqueue_script(
27
+ 'blocksy-ext-instagram-scripts',
28
+ BLOCKSY_URL . 'framework/extensions/instagram/ct-instagram/static/bundle/main.js',
29
+ [],
30
+ $data['Version'],
31
+ true
32
+ );
33
+
34
+ $data = [
35
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
36
+ 'public_url' => BLOCKSY_URL . 'framework/extensions/instagram/ct-instagram/static/bundle/',
37
+ ];
38
+
39
+ wp_localize_script(
40
+ 'blocksy-ext-instagram-scripts',
41
+ 'blocksy_ext_instagram_localization',
42
+ $data
43
+ );
44
+ });
45
+ }
46
+ }
47
+
48
+
framework/theme-integration.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Blocksy;
4
+
5
+ class ThemeIntegration {
6
+ public function __construct() {
7
+ add_filter(
8
+ 'blocksy_add_menu_page',
9
+ function ($res, $options) {
10
+ add_menu_page(
11
+ $options['title'],
12
+ $options['menu-title'],
13
+ $options['permision'],
14
+ $options['top-level-handle'],
15
+ $options['callback'],
16
+ $options['icon-url'],
17
+ 2
18
+ );
19
+
20
+ return true;
21
+ },
22
+ 10, 2
23
+ );
24
+ }
25
+ }
plugin.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Blocksy;
4
+
5
+ class Plugin {
6
+ /**
7
+ * Blocksy instance.
8
+ *
9
+ * Holds the blocksy plugin instance.
10
+ *
11
+ * @var Plugin
12
+ */
13
+ public static $instance = null;
14
+
15
+ /**
16
+ * Blocksy extensions manager.
17
+ *
18
+ * @var ExtensionsManager
19
+ */
20
+ public $extensions = null;
21
+ public $extensions_api = null;
22
+
23
+ public $dashboard = null;
24
+
25
+ public $theme_integration = null;
26
+
27
+ /**
28
+ * Instance.
29
+ *
30
+ * Ensures only one instance of the plugin class is loaded or can be loaded.
31
+ *
32
+ * @static
33
+ *
34
+ * @return Plugin An instance of the class.
35
+ */
36
+ public static function instance() {
37
+ if ( is_null( self::$instance ) ) {
38
+ self::$instance = new self();
39
+ }
40
+
41
+ return self::$instance;
42
+ }
43
+
44
+ public function init() {
45
+ if (! $this->check_if_blocksy_is_activated()) {
46
+ return;
47
+ }
48
+
49
+ $this->extensions_api = new ExtensionsManagerApi();
50
+ $this->theme_integration = new ThemeIntegration();
51
+ }
52
+
53
+ /**
54
+ * Init components that need early access to the system.
55
+ *
56
+ * @access private
57
+ */
58
+ public function early_init() {
59
+ if (! $this->check_if_blocksy_is_activated()) {
60
+ return;
61
+ }
62
+
63
+ $this->extensions = new ExtensionsManager();
64
+ $this->dashboard = new Dashboard();
65
+ }
66
+
67
+ /**
68
+ * Register autoloader.
69
+ *
70
+ * Blocksy autoloader loads all the classes needed to run the plugin.
71
+ *
72
+ * @access private
73
+ */
74
+ private function register_autoloader() {
75
+ require BLOCKSY_PATH . '/framework/autoload.php';
76
+
77
+ Autoloader::run();
78
+ }
79
+
80
+ /**
81
+ * Plugin constructor.
82
+ *
83
+ * Initializing Blocksy plugin.
84
+ *
85
+ * @access private
86
+ */
87
+ private function __construct() {
88
+ $this->register_autoloader();
89
+ $this->early_init();
90
+
91
+ add_action( 'init', [ $this, 'init' ], 0 );
92
+ }
93
+
94
+ private function check_if_blocksy_is_activated() {
95
+ return wp_get_theme()->get('Name') === 'Blocksy';
96
+ }
97
+ }
98
+
99
+ Plugin::instance();
100
+
readme.txt ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Blocksy Companion ===
2
+ Contributors: creativethemeshq
3
+ Tags: widget, widgets
4
+ Requires at least: 5.0
5
+ Requires PHP: 7.0
6
+ Tested up to: 5.1
7
+ License: GPLv2 or later
8
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
+
10
+ == Description ==
11
+
12
+ Blocksy Companion adds the extensions system to the Blocksy dashboard and introduces the Instagram extension.
13
+
14
+ This plugin runs and adds its enhacements only if the Blocksy theme is installed and active.
15
+
16
+ = Minimum Requirements =
17
+
18
+ * WordPress 5.0 or greater
19
+ * PHP version 7.0 or greater
20
+
21
+ = Installation =
22
+
23
+ 1. Upload `Blocksy-Companion-version_number.zip` to the `/wp-content/plugins/` directory and extract.
24
+ 2. Activate the plugin by going to **Plugins** page in WordPress admin and clicking on **Activate** link.
25
+
26
+ = 1.0.0 =
27
+ * Initial Release
28
+
29
+ = 1.0.1 =
30
+ * Remove `gz` files from build
31
+ * Instagram widget text & defaults changes
static/bundle/dashboard.css ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ /**
2
+ * - v1.0.1
3
+ *
4
+ * Copyright (c) 2019
5
+ * Licensed GPLv2+
6
+ */
7
+
8
+ .ct-extensions-list ul{display:grid;grid-template-columns:repeat(2, 1fr);grid-column-gap:35px;grid-row-gap:35px;margin:0}.ct-extensions-list ul li{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0;border-radius:3px;border:1px solid rgba(226,230,235,0.7);-webkit-box-shadow:0 2px 5px rgba(143,163,184,0.12);box-shadow:0 2px 5px rgba(143,163,184,0.12)}.ct-extension-title{margin:35px 0 15px 0;padding:0 25px}.ct-extension-description{margin-bottom:35px;padding:0 25px}.ct-extension-actions{margin-top:auto;padding:20px 25px;border-top:1px solid rgba(226,230,235,0.7)}
static/bundle/dashboard.js ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ !function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=3)}([function(e,t){e.exports=window.wp.element},function(e,t){e.exports=window.wp.i18n},function(e,t,n){var r;
2
+ /*!
3
+ Copyright (c) 2017 Jed Watson.
4
+ Licensed under the MIT License (MIT), see
5
+ http://jedwatson.github.io/classnames
6
+ */
7
+ /*!
8
+ Copyright (c) 2017 Jed Watson.
9
+ Licensed under the MIT License (MIT), see
10
+ http://jedwatson.github.io/classnames
11
+ */
12
+ !function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var a=typeof r;if("string"===a||"number"===a)e.push(r);else if(Array.isArray(r)&&r.length){var c=o.apply(null,r);c&&e.push(c)}else if("object"===a)for(var i in r)n.call(r,i)&&r[i]&&e.push(i)}}return e.join(" ")}e.exports?(o.default=o,e.exports=o):void 0===(r=function(){return o}.apply(t,[]))||(e.exports=r)}()},function(e,t,n){"use strict";n.r(t);var r=n(0),o=n(1),a=(n(2),function(){return function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,o=!1,a=void 0;try{for(var c,i=e[Symbol.iterator]();!(r=(c=i.next()).done)&&(n.push(c.value),!t||n.length!==t);r=!0);}catch(e){o=!0,a=e}finally{try{!r&&i.return&&i.return()}finally{if(o)throw a}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}());function c(e){return function(){var t=e.apply(this,arguments);return new Promise(function(e,n){return function r(o,a){try{var c=t[o](a),i=c.value}catch(e){return void n(e)}if(!c.done)return Promise.resolve(i).then(function(e){r("next",e)},function(e){r("throw",e)});e(i)}("next")})}}var i=null,u=function(e){var t,n=e.extension,i=e.onExtsSync,u=Object(r.useState)(!1),s=a(u,2),l=s[0],f=s[1],p=(t=c(regeneratorRuntime.mark(function e(t,n){var r;return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return(r=new FormData).append("ext",t),r.append("action",n),f(!0),e.prev=4,e.next=7,fetch(ctDashboardLocalizations.ajax_url,{method:"POST",body:r});case 7:i(),e.next=12;break;case 10:e.prev=10,e.t0=e.catch(4);case 12:return e.next=14,new Promise(function(e){return setTimeout(function(){return e()},1e3)});case 14:f(!1);case 15:case"end":return e.stop()}},e,void 0,[[4,10]])})),function(e,n){return t.apply(this,arguments)});return Object(r.createElement)("li",null,Object(r.createElement)("h4",{className:"ct-extension-title"},n.config.name),n.config.description&&Object(r.createElement)("div",{className:"ct-extension-description"},n.config.description),Object(r.createElement)("div",{className:"ct-extension-actions"},Object(r.createElement)("button",{className:"ct-button","data-button":"white",disabled:l,onClick:function(){return p(n.name,n.__object?"blocksy_extension_deactivate":"blocksy_extension_activate")}},l?Object(o.__)("Loading"):n.__object?Object(o.__)("Deactivate"):Object(o.__)("Activate"))))},s=function(){var e,t=Object(r.useState)(!i),n=a(t,2),s=n[0],l=n[1],f=Object(r.useState)(i||[]),p=a(f,2),b=p[0],d=p[1],v=(e=c(regeneratorRuntime.mark(function e(){var t,n,r,o,a,c=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return c&&l(!0),(t=new FormData).append("action","blocksy_extensions_status"),e.prev=3,e.next=6,fetch(ctDashboardLocalizations.ajax_url,{method:"POST",body:t});case 6:if(200!==(n=e.sent).status){e.next=14;break}return e.next=10,n.json();case 10:r=e.sent,o=r.success,a=r.data,o&&(d(a),i=a);case 14:e.next=18;break;case 16:e.prev=16,e.t0=e.catch(3);case 18:l(!1);case 19:case"end":return e.stop()}},e,void 0,[[3,16]])})),function(){return e.apply(this,arguments)});Object(r.useEffect)(function(){v(!i)},[]);var m=Object.values(b).map(function(e,t){return e.name=Object.keys(b)[t],e});return Object(r.createElement)("div",{className:"ct-extensions-list"},s&&Object(r.createElement)("p",{className:"ct-loading-text"},Object(o.__)("Loading Extensions Status...")),!s&&m.length>0&&Object(r.createElement)("ul",null,m.map(function(e){return Object(r.createElement)(u,{key:e.name,extension:e,onExtsSync:function(){return v()}})})))};ctEvents.on("ct:dashboard:routes",function(e){return e.push({Component:function(){return Object(r.createElement)(s,null)},path:"/extensions"})}),ctEvents.on("ct:dashboard:navigation-links",function(e){return e.push({text:Object(o.__)("Extensions"),path:"/extensions"})})}]);
static/js/dashboard.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { createElement, Component } from '@wordpress/element'
2
+ import * as check from '@wordpress/element'
3
+
4
+ import { __ } from 'ct-i18n'
5
+ import Extensions from './screens/Extensions'
6
+
7
+ ctEvents.on('ct:dashboard:routes', r =>
8
+ r.push({
9
+ Component: () => <Extensions />,
10
+ path: '/extensions'
11
+ })
12
+ )
13
+ ctEvents.on('ct:dashboard:navigation-links', r =>
14
+ r.push({
15
+ text: __('Extensions'),
16
+ path: '/extensions'
17
+ })
18
+ )
static/js/screens/Extensions.js ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ createElement,
3
+ Component,
4
+ useEffect,
5
+ useState
6
+ } from '@wordpress/element'
7
+ import { __ } from 'ct-i18n'
8
+ import classnames from 'classnames'
9
+
10
+ let exts_status_cache = null
11
+
12
+ const Extension = ({ extension, onExtsSync }) => {
13
+ const [isLoading, setIsLoading] = useState(false)
14
+
15
+ const makeAction = async (ext, actionName) => {
16
+ const body = new FormData()
17
+ body.append('ext', ext)
18
+ body.append('action', actionName)
19
+
20
+ setIsLoading(true)
21
+
22
+ try {
23
+ await fetch(ctDashboardLocalizations.ajax_url, {
24
+ method: 'POST',
25
+ body
26
+ })
27
+
28
+ onExtsSync()
29
+ } catch (e) {}
30
+
31
+ await new Promise(r => setTimeout(() => r(), 1000))
32
+
33
+ setIsLoading(false)
34
+ }
35
+
36
+ return (
37
+ <li>
38
+ <h4 className="ct-extension-title">
39
+ {extension.config.name}
40
+ </h4>
41
+
42
+ {extension.config.description && (
43
+ <div className="ct-extension-description">
44
+ {extension.config.description}
45
+ </div>
46
+ )}
47
+
48
+ <div className="ct-extension-actions">
49
+ <button
50
+ className="ct-button"
51
+ data-button="white"
52
+ disabled={isLoading}
53
+ onClick={() =>
54
+ makeAction(
55
+ extension.name,
56
+ extension.__object
57
+ ? 'blocksy_extension_deactivate'
58
+ : 'blocksy_extension_activate'
59
+ )
60
+ }>
61
+ {isLoading
62
+ ? __('Loading')
63
+ : extension.__object ? __('Deactivate') : __('Activate')}
64
+ </button>
65
+ </div>
66
+ </li>
67
+ )
68
+ }
69
+
70
+ const Extensions = () => {
71
+ const [isLoading, setIsLoading] = useState(!exts_status_cache)
72
+ const [exts_status, setExtsStatus] = useState(exts_status_cache || [])
73
+
74
+ const syncExts = async (verbose = false) => {
75
+ if (verbose) {
76
+ setIsLoading(true)
77
+ }
78
+
79
+ const body = new FormData()
80
+ body.append('action', 'blocksy_extensions_status')
81
+
82
+ try {
83
+ const response = await fetch(ctDashboardLocalizations.ajax_url, {
84
+ method: 'POST',
85
+ body
86
+ })
87
+
88
+ if (response.status === 200) {
89
+ const { success, data } = await response.json()
90
+
91
+ if (success) {
92
+ setExtsStatus(data)
93
+ exts_status_cache = data
94
+ }
95
+ }
96
+ } catch (e) {}
97
+
98
+ setIsLoading(false)
99
+ }
100
+
101
+ useEffect(() => {
102
+ syncExts(!exts_status_cache)
103
+ }, [])
104
+
105
+ const exts = Object.values(exts_status).map((ext, index) => {
106
+ ext['name'] = Object.keys(exts_status)[index]
107
+ return ext
108
+ })
109
+
110
+ return (
111
+ <div className="ct-extensions-list">
112
+ {isLoading && (
113
+ <p className="ct-loading-text">
114
+ {__('Loading Extensions Status...')}
115
+ </p>
116
+ )}
117
+
118
+ {!isLoading &&
119
+ exts.length > 0 && (
120
+ <ul>
121
+ {exts.map(ext => (
122
+ <Extension
123
+ key={ext.name}
124
+ extension={ext}
125
+ onExtsSync={() => syncExts()}
126
+ />
127
+ ))}
128
+ </ul>
129
+ )}
130
+ </div>
131
+ )
132
+ }
133
+
134
+ export default Extensions
static/sass/dashboard.scss ADDED
@@ -0,0 +1 @@
 
1
+ @import 'extensions';
static/sass/extensions.scss ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $extension-spacing: 25px;
2
+
3
+ .ct-extensions-list ul {
4
+ display: grid;
5
+ grid-template-columns: repeat(2, 1fr);
6
+ grid-column-gap: 35px;
7
+ grid-row-gap: 35px;
8
+ margin: 0;
9
+
10
+ li {
11
+ display: flex;
12
+ flex-direction: column;
13
+ margin: 0;
14
+ // padding: $extension-spacing 0;
15
+ border-radius: 3px;
16
+ border: 1px solid rgba(226, 230, 235, 0.7);
17
+ box-shadow: 0 2px 5px rgba(143, 163, 184, 0.12);
18
+ }
19
+ }
20
+
21
+ .ct-extension-title {
22
+ margin: 35px 0 15px 0;
23
+ padding: 0 $extension-spacing;
24
+ }
25
+
26
+ .ct-extension-description {
27
+ margin-bottom: 35px;
28
+ padding: 0 $extension-spacing;
29
+ }
30
+
31
+ .ct-extension-actions {
32
+ margin-top: auto;
33
+ padding: 20px $extension-spacing;
34
+ border-top: 1px solid rgba(226, 230, 235, 0.7);
35
+ }