├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── config.json └── core ├── ConfigRegistry.php ├── Helpers ├── ArrayHelper.php ├── FileHelper.php └── StringHelper.php ├── Licensing └── WHMCS_License.php ├── ObjectCache.php ├── PluginTools.php ├── ScriptObject.php └── ToolKit.php /.gitignore: -------------------------------------------------------------------------------- 1 | # Packages # 2 | ############ 3 | *.7z 4 | *.dmg 5 | *.gz 6 | *.bz2 7 | *.iso 8 | *.jar 9 | *.rar 10 | *.tar 11 | *.zip 12 | *.tgz 13 | *.map 14 | 15 | # Logs and databases # 16 | ###################### 17 | *.log 18 | *.sql 19 | 20 | # OS generated files # 21 | ###################### 22 | **.DS_Store* 23 | ehthumbs.db 24 | Icon? 25 | Thumbs.db 26 | ._* 27 | 28 | # Vim generated files # 29 | ####################### 30 | *.un~ 31 | 32 | # SASS # 33 | ######## 34 | **/.sass-cache 35 | **/.sass-cache/* 36 | **/.map 37 | *.scssc 38 | config.rb 39 | 40 | # Composer # 41 | ############ 42 | vendor/ 43 | !assets/js/vendor/ 44 | wpcs/ 45 | composer.lock 46 | 47 | # Gulp # 48 | ######## 49 | package-lock.json 50 | 51 | # Bower # 52 | ######### 53 | assets/bower_components/* 54 | 55 | # Codekit # 56 | ########### 57 | /codekit-config.json 58 | *.codekit 59 | **.codekit-cache/* 60 | 61 | # NPM # 62 | ####### 63 | node_modules 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 | {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. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Author](https://img.shields.io/badge/author-Daniel%20M.%20Hendricks-blue.svg?colorB=9900cc&style=flat-square)](https://www.danhendricks.com/?utm_source=github.com&utm_medium=campaign&utm_content=button&utm_campaign=dmhendricks%2Fwordpress-toolkit) 2 | [![Latest Release](https://img.shields.io/github/release/dmhendricks/wordpress-toolkit.svg?style=flat-square)](https://github.com/dmhendricks/wordpress-toolkit/releases) 3 | [![GitHub License](https://img.shields.io/badge/license-GPLv2-yellow.svg?style=flat-square)](https://raw.githubusercontent.com/dmhendricks/wordpress-toolkit/master/LICENSE) 4 | [![Total Downloads](https://img.shields.io/packagist/dt/dmhendricks/wordpress-toolkit.svg?style=flat-square)](https://packagist.org/packages/dmhendricks/wordpress-toolkit) 5 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg?style=flat-square)](https://paypal.me/danielhendricks) 6 | [![Flywheel](https://img.shields.io/badge/style-Flywheel-green.svg?style=flat-square&label=get%20hosted&colorB=AE2A21)](https://share.getf.ly/e25g6k?utm_source=github.com&utm_medium=campaign&utm_content=button&utm_campaign=dmhendricks%2Fwordpress-toolkit) 7 | [![Twitter](https://img.shields.io/twitter/url/https/github.com/dmhendricks/wordpress-toolkit.svg?style=social)](https://twitter.com/danielhendricks) 8 | 9 | # WordPress Tool Kit 10 | 11 | A collection of classes that I use in my WordPress projects & plugins. 12 | 13 | ### Contributing 14 | 15 | If you can make the code better or recommend/contribute code that would be useful to include, [please let me know](https://github.com/dmhendricks/wordpress-toolkit/issues). 16 | 17 | ## Features 18 | 19 | * [ConfigRegistry](https://github.com/dmhendricks/wordpress-toolkit/wiki/ConfigRegistry) class - Loads plugin/theme settings from an array or JSON file. 20 | * [Licensing](https://github.com/dmhendricks/wordpress-toolkit/wiki/Licensing) class - Currently only support license code validation via the [Software Licensing](https://www.whmcs.com/software-licensing/?utm_source=github.com&utm_medium=referral&utm_content=link&utm_campaign=dmhendricks%2Fwordpress-toolkit) addon for WHMCS. 21 | * [ObjectCache](https://github.com/dmhendricks/wordpress-toolkit/wiki/ObjectCache) class - A wrapper for setting/fetching values from the WordPress object cache, where available. 22 | * [PluginTools](https://github.com/dmhendricks/wordpress-toolkit/wiki/PluginTools) class - A class for retrieving data and performing various tasks on plugins. 23 | * [ScriptObject](https://github.com/dmhendricks/wordpress-toolkit/wiki/ScriptObject) class - Inject JavaScript variables or CSS into the page head or write/enqueue external files. 24 | 25 | ## Installation 26 | 27 | ### Requirements 28 | 29 | * WordPress 4.7 or higher 30 | * PHP 7.0 or higher 31 | 32 | Compatibility tested with WordPress 5.0, multisite and PHP 7.3. 33 | 34 | ### Install with Composer 35 | 36 | ```bash 37 | composer require dmhendricks/wordpress-toolkit 38 | ``` 39 | 40 | ## Usage 41 | 42 | Please see the [Documentation](https://github.com/dmhendricks/wordpress-toolkit/wiki) page. 43 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dmhendricks/wordpress-toolkit", 3 | "description": "A collection of helper classes and functions for WordPress plugins and themes.", 4 | "license": "GPL-2.0-or-later", 5 | "homepage": "https://github.com/dmhendricks/wordpress-toolkit", 6 | "authors": [ 7 | { 8 | "name": "Daniel M. Hendricks", 9 | "homepage": "https://danhendricks.com", 10 | "role": "Developer" 11 | } 12 | ], 13 | "support": { 14 | "source": "https://github.com/dmhendricks/wordpress-toolkit", 15 | "wiki": "https://github.com/dmhendricks/wordpress-toolkit/wiki", 16 | "issues": "https://github.com/dmhendricks/wordpress-toolkit/issues" 17 | }, 18 | "require": { 19 | "php": ">=5.6.4", 20 | "vlucas/phpdotenv": "^2.5.1" 21 | }, 22 | "autoload": { 23 | "psr-4": { 24 | "WordPress_ToolKit\\": "core/" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "toolkit-version": "0.4.2", 3 | "prefix": "wptk", 4 | "object_cache": { 5 | "group": "wordpress_toolkit_cache_group", 6 | "expire": 86400 7 | }, 8 | "encrypt": { 9 | "method": "AES-128-ECB" 10 | }, 11 | "js_object": "js_object", 12 | "dynamic_scripts_directory": "dynamic" 13 | } 14 | -------------------------------------------------------------------------------- /core/ConfigRegistry.php: -------------------------------------------------------------------------------- 1 | config = $context; 37 | } else if( is_string( $context ) ) { 38 | $this->load( $context ); 39 | } else { 40 | if( $suppress_errors ) { 41 | $this->config = false; 42 | } else { 43 | throw new \Exception( 'Invalid configuration argument.' ); 44 | } 45 | } 46 | 47 | } 48 | 49 | /** 50 | * Magic get method; allows accessing config items via object notation. 51 | * 52 | * @param string $key Unique configuration option key 53 | * @return mixed New ConfigRegistry object or config item value 54 | */ 55 | public function __get( $key ) 56 | { 57 | 58 | $item = $this->get( $key ); 59 | if (is_array( $item )) { 60 | return new static( $item ); 61 | } 62 | return $item; 63 | 64 | } 65 | 66 | /** 67 | * Magic toString method; returns config object as JSON-encoded string 68 | * 69 | * @return mixed New ConfigRegistry object or config item value 70 | */ 71 | public function __toString() 72 | { 73 | return json_encode( $this->config ); 74 | } 75 | 76 | /** 77 | * Load configuration options from a file or directory. 78 | * 79 | * @param string $path Path to configuration file or directory 80 | * @param bool $override Weather or not to override existing options with 81 | * values from the loaded file 82 | * 83 | * @return object This Config object 84 | */ 85 | private function load( $path ) { 86 | 87 | $json = json_decode( trim( file_get_contents( $path ) ), true ); 88 | 89 | $this->config = $json ?: false; 90 | 91 | } 92 | 93 | /** 94 | * Retrieve a configuration option via a provided key. 95 | * 96 | * @param string $key Unique configuration option key 97 | * @param mixed $default Default value to return if option does not exist 98 | * @return mixed Stored config item or $default value 99 | */ 100 | public function get($key = null, $default = null) 101 | { 102 | 103 | if ( !isset( $key ) ) { 104 | return $this->config; 105 | } 106 | $config = $this->config; 107 | foreach( explode('/', $key ) as $k ) { 108 | if ( !isset( $config[$k] ) ) { 109 | return $default; 110 | } 111 | $config = &$config[$k]; 112 | } 113 | return $config; 114 | 115 | } 116 | 117 | /** 118 | * Store a config value with a specified key. 119 | * 120 | * @param string $key Unique configuration option key 121 | * @param mixed $value Config item value 122 | * @return object This ConfigRegistry object 123 | */ 124 | public function set($key, $value) 125 | { 126 | 127 | $config = $this->config; 128 | foreach( explode('/', $key) as $k ) { 129 | $config = &$config[$k]; 130 | } 131 | $config = $value; 132 | return true; 133 | 134 | } 135 | 136 | /** 137 | * Check for the existance of a config item. 138 | * 139 | * @param string $key Unique configuration option key 140 | * @return bool True if item existst, otherwise false 141 | */ 142 | public function has($key) 143 | { 144 | 145 | $config = $this->config; 146 | foreach( explode('/', $key) as $k ) { 147 | if ( !isset( $config[$k] ) ) { 148 | return false; 149 | } 150 | $config = $config[$k]; 151 | } 152 | return true; 153 | 154 | } 155 | 156 | /** 157 | * Merge another ConfigRegistry object into this one. 158 | * 159 | * @param Config $config Instance of ConfigRegistry 160 | * @return object This ConfigRegistry object 161 | */ 162 | public function merge( ConfigRegistry $config ) 163 | { 164 | 165 | $current = $config->get(); 166 | if( $this->config && $current ) { 167 | $this->config = array_merge( $this->config, $current ); 168 | } 169 | return $this; 170 | 171 | } 172 | 173 | /** 174 | * Split a sub-array of configuration options into it's own ConfigRegistry object. 175 | * 176 | * @param string $key Unique configuration option key 177 | * @return Config A new ConfigRegistry object 178 | */ 179 | public function split($key) 180 | { 181 | return new static( $this->get($key) ); 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /core/Helpers/ArrayHelper.php: -------------------------------------------------------------------------------- 1 | $default) { 27 | if ( array_key_exists($name, $atts) ) { 28 | $result[$name] = $atts[$name]; 29 | } else { 30 | $result[$name] = $default; 31 | } 32 | } 33 | 34 | return $result; 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /core/Helpers/FileHelper.php: -------------------------------------------------------------------------------- 1 | get_const( 'DB_HOST' ); // MySQL host name 18 | * echo $this->get_const( 'MY_BOOLEAN_CONST', FILTER_VALIDATE_BOOLEAN ); 19 | * // null if undefined, true if valid boolean, else false 20 | * 21 | * @param string $const The name of constant to retrieve. 22 | * @param const $filter_validate filter_var() filter to apply (optional). 23 | * Valid values: http://php.net/manual/en/filter.filters.validate.php 24 | * @return mixed Value of constant if specified, else null. 25 | * @since 0.1.0 26 | */ 27 | public function get_const( $const, $filter_validate = null ) { 28 | 29 | if( !defined( $const ) ) { 30 | return null; 31 | } else if( $filter_validate ) { 32 | return filter_var( constant( $const ), $filter_validate); 33 | } 34 | return constant( $const ); 35 | 36 | } 37 | 38 | /** 39 | * Encrypts string using WP_ENCRYPT_KEY as salt if defined, else SECURE_AUTH_KEY. 40 | * 41 | * @param string $str String to encrypt 42 | * @return string Encrypted string 43 | * @since 0.1.0 44 | */ 45 | public static function encrypt( $str ) { 46 | $salt = parent::$salt; 47 | return openssl_encrypt( $str, self::$config->get( 'encrypt/method' ), parent::$salt ); 48 | } 49 | 50 | /** 51 | * Decrypts encrypted string 52 | * 53 | * @param string $str String to decrypt 54 | * @return string Decrypted string 55 | * @since 0.1.0 56 | */ 57 | public static function decrypt( $str ) { 58 | return openssl_decrypt( $str, self::$config->get( 'encrypt/method' ), parent::$salt ); 59 | } 60 | 61 | /** 62 | * Checks whether a JSON string has valid syntax 63 | * 64 | * @param string $json The JSON string to test 65 | * @return bool 66 | * @since 0.1.0 67 | */ 68 | public static function is_json( $json ) { 69 | 70 | json_decode( $json ); 71 | return ( json_last_error() == JSON_ERROR_NONE ); 72 | 73 | } 74 | 75 | /** 76 | * Converts hyphens to underscores in a string 77 | * 78 | * @param string $str Input string 79 | * @param string $delimiter Word delimiter (default: '-') 80 | * @return string 81 | * @since 0.4.1 82 | */ 83 | public static function slugify( $str, $delimiter = null ) { 84 | 85 | $str = sanitize_title( $str ); 86 | if( $delimiter ) $str = str_replace( '-', $delimiter, $str ); 87 | return $str; 88 | 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /core/Licensing/WHMCS_License.php: -------------------------------------------------------------------------------- 1 | get_config( 'plugin/path' ); 41 | $verifyfilepath = 'modules/servers/licensing/verify.php'; 42 | $local_keyvalid = false; 43 | 44 | // Process local key, if set 45 | if( $local_key ) { 46 | 47 | $local_key = str_replace( "\n", '', $local_key ); # Remove the line breaks 48 | $localdata = substr( $local_key, 0, strlen( $local_key ) - 32 ); # Extract License Data 49 | $md5hash = substr( $local_key, strlen( $local_key ) - 32 ); # Extract MD5 Hash 50 | 51 | if( $md5hash == md5( $localdata . $this->get_config( 'whmcs/product_key' ) ) ) { 52 | 53 | $localdata = strrev( $localdata ); # Reverse the string 54 | $md5hash = substr( $localdata, 0, 32 ); # Extract MD5 Hash 55 | $localdata = substr( $localdata, 32 ); # Extract License Data 56 | $localdata = base64_decode( $localdata ); 57 | $local_keyresults = unserialize( $localdata ); 58 | $originalcheckdate = $local_keyresults['checkdate']; 59 | 60 | if( $md5hash == md5( $originalcheckdate . $this->get_config( 'whmcs/product_key' ) ) ) { 61 | $localexpiry = date( 'Ymd', mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - $this->get_config( 'whmcs/local_key_expire_days' ), date( 'Y' ) ) ); 62 | 63 | if( $originalcheckdate > $localexpiry ) { 64 | $local_keyvalid = true; 65 | $results = $local_keyresults; 66 | $validdomains = explode( ',', $results['validdomain'] ); 67 | 68 | if( !in_array( $_SERVER['SERVER_NAME'], $validdomains ) ) { 69 | $local_keyvalid = false; 70 | $local_keyresults['status'] = 'Invalid'; 71 | $results = array(); 72 | } 73 | 74 | if( isset( $results['validip'] ) && !in_array( $usersip, explode( ',', $results['validip'] ) ) ) { 75 | $local_keyvalid = false; 76 | $local_keyresults['status'] = 'Invalid'; 77 | $results = array(); 78 | } 79 | 80 | if( isset( $results['validdirectory'] ) && !in_array( $dirpath, explode( ',', $results['validdirectory'] ) ) ) { 81 | $local_keyvalid = false; 82 | $local_keyresults['status'] = 'Invalid'; 83 | $results = array(); 84 | } 85 | } 86 | } 87 | } 88 | } 89 | 90 | // If local key is invalid or expired, recheck 91 | if( !$local_keyvalid ) { 92 | 93 | $responseCode = 0; 94 | $postfields = array( 95 | 'licensekey' => $license_key, 96 | 'domain' => $domain, 97 | 'ip' => $usersip, 98 | 'dir' => $dirpath, 99 | ); 100 | 101 | if( $check_token ) $postfields['check_token'] = $check_token; 102 | $query_string = ''; 103 | foreach ( $postfields as $k => $v ) { 104 | $query_string .= $k.'='.urlencode($v).'&'; 105 | } 106 | 107 | if( function_exists( 'curl_exec' ) ) { 108 | 109 | $ch = curl_init(); 110 | curl_setopt( $ch, CURLOPT_URL, $this->get_config( 'whmcs/url' ) . $verifyfilepath ); 111 | curl_setopt( $ch, CURLOPT_POST, 1 ); 112 | curl_setopt( $ch, CURLOPT_POSTFIELDS, $query_string ); 113 | curl_setopt( $ch, CURLOPT_TIMEOUT, 30 ); 114 | curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); 115 | $data = curl_exec( $ch ); 116 | $responseCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE ); 117 | curl_close( $ch ); 118 | 119 | } else { 120 | 121 | $responseCodePattern = '/^HTTP\/\d+\.\d+\s+(\d+)/'; 122 | $fp = @fsockopen( $this->get_config( 'whmcs/url' ), 80, $errno, $errstr, 5 ); 123 | 124 | if ( $fp ) { 125 | 126 | $newlinefeed = "\r\n"; 127 | $header = 'POST ' . $this->get_config( 'whmcs/url' ) . $verifyfilepath . ' HTTP/1.0' . $newlinefeed; 128 | $header .= 'Host: ' . $this->get_config( 'whmcs/url' ) . $newlinefeed; 129 | $header .= 'Content-type: application/x-www-form-urlencoded' . $newlinefeed; 130 | $header .= 'Content-length: ' . @strlen($query_string) . $newlinefeed; 131 | $header .= 'Connection: close' . $newlinefeed . $newlinefeed; 132 | $header .= $query_string; 133 | $data = $line = ''; 134 | 135 | @stream_set_timeout( $fp, 20 ); 136 | @fputs( $fp, $header ); 137 | $status = @socket_get_status( $fp ); 138 | 139 | while( !@feof( $fp ) && $status ) { 140 | $line = @fgets( $fp, 1024 ); 141 | $patternMatches = array(); 142 | if( !$responseCode && preg_match( $responseCodePattern, trim( $line ), $patternMatches ) ) { 143 | $responseCode = ( empty( $patternMatches[1] ) ) ? 0 : $patternMatches[1]; 144 | } 145 | $data .= $line; 146 | $status = @socket_get_status( $fp ); 147 | } 148 | @fclose ( $fp ); 149 | } 150 | 151 | } 152 | 153 | if( $responseCode != 200 ) { 154 | $localexpiry = date( 'Ymd', mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - ( $this->get_config( 'whmcs/local_key_expire_days' ) + $this->get_config( 'whmcs/allow_check_fail_days' ) ), date( 'Y' ) ) ); 155 | 156 | if( isset( $originalcheckdate ) && $originalcheckdate > $localexpiry ) { 157 | $results = $local_keyresults; 158 | } else { 159 | $results = array(); 160 | $results['status'] = 'Invalid'; 161 | $results['description'] = 'Remote Check Failed'; 162 | return $results; 163 | } 164 | 165 | } else { 166 | 167 | preg_match_all( '/<(.*?)>([^<]+)<\/\\1>/i', $data, $matches ); 168 | $results = array(); 169 | foreach( $matches[1] as $k => $v ) { 170 | $results[$v] = $matches[2][$k]; 171 | } 172 | 173 | } 174 | 175 | if( !is_array( $results ) ) { 176 | // TODO 177 | die( 'Invalid License Server Response' ); 178 | } 179 | 180 | if( isset( $results['md5hash'] ) && $results['md5hash'] ) { 181 | if( $results['md5hash'] != md5( $this->get_config( 'whmcs/product_key' ) . $check_token ) ) { 182 | $results['status'] = 'Invalid'; 183 | $results['description'] = 'MD5 Checksum Verification Failed'; 184 | return $results; 185 | } 186 | } 187 | 188 | if ($results['status'] == 'Active') { 189 | 190 | $results['checkdate'] = $checkdate; 191 | $data_encoded = serialize( $results ); 192 | $data_encoded = base64_encode( $data_encoded ); 193 | $data_encoded = md5( $checkdate . $this->get_config( 'whmcs/product_key' ) ) . $data_encoded; 194 | $data_encoded = strrev( $data_encoded ); 195 | $data_encoded = $data_encoded . md5( $data_encoded . $this->get_config( 'whmcs/product_key' ) ); 196 | $data_encoded = wordwrap( $data_encoded, 80, "\n", true ); 197 | $results['localkey'] = $data_encoded; 198 | 199 | } 200 | 201 | $results['remotecheck'] = true; 202 | 203 | } 204 | 205 | unset( $postfields, $data, $matches, $checkdate, $usersip, $md5hash ); 206 | return $results; 207 | 208 | } 209 | 210 | } 211 | -------------------------------------------------------------------------------- /core/ObjectCache.php: -------------------------------------------------------------------------------- 1 | self::$config->get( 'object_cache/expire' ) ?: DAY_IN_SECONDS, // Expiration time for cache value or group 29 | 'group' => self::$config->get( 'object_cache/group' ) ?: sanitize_title( self::$config->get( 'data/Name' ) ), 30 | 'single' => false, // Store as single key rather than group array 31 | 'network_global' => false // Set to true to store cache value for entire network, rather than per sub-site 32 | ], $args ); 33 | 34 | $result = null; 35 | $result_group = null; 36 | 37 | // Validate arguments 38 | $args['expire'] = intval( $args['expire'] ); 39 | $args['single'] = filter_var( $args['single'], FILTER_VALIDATE_BOOLEAN ); 40 | $args['network_global'] = filter_var( $args['network_global'], FILTER_VALIDATE_BOOLEAN ); 41 | 42 | // Add site ID suffic to cache group if multisite 43 | if( is_multisite() ) $args['group'] .= '_' . get_current_site()->id; 44 | 45 | // Set key variable, appending blog ID if network_global is false 46 | $object_cache_key = $key . ( is_multisite() && !$args['network_global'] && get_current_blog_id() ? '_' . get_current_blog_id() : '' ); 47 | 48 | // Try to get key value from cache 49 | if( $args['single'] ) { 50 | 51 | // Store value in individual key 52 | $result = unserialize( wp_cache_get( $object_cache_key, $args['group'], false, $cache_hit ) ); 53 | 54 | } else { 55 | 56 | // Store value in array of values with group as key 57 | $result_group = wp_cache_get( $args['group'], $args['group'], false, $cache_hit ); 58 | $result_group = $cache_hit ? (array) unserialize( $result_group ) : []; 59 | 60 | if( $cache_hit && isset( $result_group[$object_cache_key] ) ) { 61 | $result = $result_group[$object_cache_key]; 62 | } else { 63 | $cache_hit = false; 64 | } 65 | 66 | } 67 | 68 | // If cache miss, set & return the value from $callback() 69 | if( !$cache_hit ) { 70 | 71 | $result = $callback(); 72 | 73 | // Store cache key value pair 74 | if( $args['single'] ) { 75 | 76 | // If single, store cache value. 77 | wp_cache_set( $object_cache_key, serialize( $result ), $args['group'], $args['expire'] ); 78 | 79 | } else { 80 | 81 | // Store cache value in group array to allow "flushing" of individual group 82 | $result_group[$object_cache_key] = $result; 83 | wp_cache_set( $args['group'], serialize( $result_group ), $args['group'], $args['expire'] ); 84 | 85 | } 86 | 87 | } 88 | 89 | return $result; 90 | 91 | } 92 | 93 | /** 94 | * Flushes the entire object cache 95 | * 96 | * @return bool True on success, false on error 97 | * @since 0.1.0 98 | */ 99 | public function flush() { 100 | 101 | try { 102 | wp_cache_flush(); 103 | } catch ( Exception $e ) { 104 | return false; 105 | } 106 | 107 | return true; 108 | 109 | } 110 | 111 | /** 112 | * Flushes (deletes) the key group from cache. This is a poor man's way of flushing 113 | * a single group rather than entire object cache through wp_cache_flush() 114 | * 115 | * @param string $group The name of the key group to flush (delete) 116 | * @return bool True on success, false on error 117 | * @since 0.4.0 118 | */ 119 | public function flush_group( $cache_group = null ) { 120 | 121 | $cache_group = $cache_group ?: self::$config->get( 'object_cache/group' ); 122 | 123 | try { 124 | wp_cache_delete( $cache_group, $cache_group ); 125 | } catch ( Exception $e ) { 126 | return false; 127 | } 128 | 129 | return true; 130 | 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /core/PluginTools.php: -------------------------------------------------------------------------------- 1 | values = $values; 25 | $this->default_args = array( 26 | 'version' => true, 27 | 'target' => 'wp', 28 | 'css_media' => null, 29 | 'dependencies' => array(), 30 | 'localize' => null, 31 | 'variable_name' => $this->prefix( self::$config->get( 'js_object' ) ?: 'js_object' ), 32 | 'handle' => $this->prefix( 'dynamic_script' ), 33 | 'script_dir' => $this->prefix( self::$config->get( 'dynamic_scripts_directory' ) ?: 'dynamic' ), 34 | 'filename' => null 35 | ); 36 | 37 | } 38 | 39 | /** 40 | * Method to inject values into the page head as CSS 41 | * 42 | * @param array $args Configuration array 43 | * @return bool Success or failure 44 | * @since 0.1.0 45 | */ 46 | public function injectCSS( $args = array() ) { 47 | return $this->save( 'css', $args ); 48 | } 49 | 50 | /** 51 | * Method to inject values into the page head as JavaScript 52 | * 53 | * @param array $args Configuration array 54 | * @return bool Success or failure 55 | * @since 0.1.0 56 | */ 57 | public function injectJS( $args = array() ) { 58 | return $this->save( 'js', $args ); 59 | } 60 | 61 | /** 62 | * Method to enqueue extranal CSS script and optionally update values 63 | * 64 | * @param array $args Configuration array 65 | * @param bool $update Whether or not to update the script before enqueuing 66 | * @return bool Success or failure 67 | * @since 0.1.0 68 | */ 69 | public function enqueueCSS( $args = array(), $update = false ) { 70 | $success = true; 71 | if( $update ) $success = $this->save( 'css', $args, true ); 72 | return $success ? $this->enqueue( 'css', $args ) : $success; 73 | } 74 | 75 | /** 76 | * Method to enqueue extranal JS script and optionally update values 77 | * 78 | * @param array $args Configuration array 79 | * @param bool $update Whether or not to update the script before enqueuing 80 | * @return bool Success or failure 81 | * @since 0.1.0 82 | */ 83 | public function enqueueJS( $args = array(), $update = false ) { 84 | $success = true; 85 | if( $update ) $success = $this->save( 'js', $args, true ); 86 | return $success ? $this->enqueue( 'js', $args ) : $success; 87 | } 88 | 89 | /** 90 | * Method to update/write extranal CSS script with provided values 91 | * 92 | * @param array $args Configuration array 93 | * @return bool Success or failure 94 | * @since 0.1.0 95 | */ 96 | public function writeCSS( $args = array() ) { 97 | return $this->save( 'css', $args, true ); 98 | } 99 | 100 | /** 101 | * Method to update/write extranal JS script with provided values 102 | * 103 | * @param array $args Configuration array 104 | * @return bool Success or failure 105 | * @since 0.1.0 106 | */ 107 | public function writeJS( $args = array() ) { 108 | return $this->save( 'js', $args, true); 109 | } 110 | 111 | /** 112 | * Injects or enqueues JS/CSS data 113 | * 114 | * @param string $type Specifies whether to treat as CSS or JS. Valid values: 115 | * 'js' or 'css' 116 | * @param array $args Configuration associative array 117 | * @param bool $action Array of actions to perform: inject, enqueue, write 118 | * @return bool Success (true) or failure (false) 119 | * @since 0.1.0 120 | */ 121 | private function save( $type, $args, $external = false ) { // , $update = false 122 | $args = ArrayHelper::set_default_atts( $this->default_args, $args); 123 | $type = strtolower( $type ); 124 | $targets = (array) $args['target']; 125 | 126 | // Generate script content 127 | $content = ''; 128 | if( $type == 'js' ) { 129 | 130 | $content = 'var ' . $args['variable_name'] . " = JSON.parse('" . str_replace( "'", "\'", json_encode( $this->values ) ) . "')"; 131 | 132 | } else if ( $type == 'css' ) { 133 | 134 | foreach( $this->values as $key => $css ) { 135 | 136 | $content .= $key . ' { ' . $css . ' }' . ( $external ? "\n" : '' ); 137 | 138 | } 139 | 140 | } 141 | if( !$content ) return false; 142 | 143 | // If we're not writing an external file, simply inject into head 144 | if( !$external ) { 145 | 146 | // Inject JavaScript variables into page head 147 | 148 | foreach( $targets as $target ) { 149 | 150 | if( $type == 'js' ) { 151 | $content .= ';'; 152 | 153 | add_action( $target . '_head', function() use ( &$args, &$content ) { 154 | echo ''; 155 | }); 156 | 157 | } else if ( $type == 'css' ) { 158 | 159 | add_action( $target . '_head', function() use ( &$args, &$content ) { 160 | echo "\n" . '' . "\n"; 161 | }); 162 | 163 | } 164 | 165 | } 166 | 167 | return true; 168 | 169 | } 170 | 171 | // Get upload directory and URL 172 | $upload_path = $this->get_script_upload_location( $args ); 173 | 174 | // Write the script file 175 | $script_output_filename = $upload_path['dir'] . ( $args['filename'] ?: $this->prefix( 'dynamic_script' ) . '.' . $type ); 176 | return file_put_contents( $script_output_filename, $content ); 177 | 178 | } 179 | 180 | private function enqueue( $type, $args = array() ) { 181 | 182 | $upload_path = $this->get_script_upload_location( $args ); 183 | $script_output_filename = $upload_path['dir'] . ( $args['filename'] ?: $this->prefix( 'dynamic_script' ) . '.' . $type ); 184 | $targets = (array) $args['target']; 185 | 186 | if( file_exists( $script_output_filename ) ) { 187 | $script_url = $upload_path['url'] . ( $args['filename'] ?: $this->prefix( 'dynamic_script' ) . '.' . $type ); 188 | 189 | // Set script version 190 | $script_version = get_bloginfo( 'version' ); 191 | if( is_string( $args['version'] ) ) { 192 | 193 | // If $args['version'] is a string, use it a 194 | $script_version = $args['version']; 195 | 196 | } else if( is_bool( $args['version'] ) ) { 197 | 198 | if( $args['version'] ) { 199 | // If $args['version'] is true, get file modification date/time 200 | $script_version = date("ymd-Gis", filemtime( $script_output_filename ) ); 201 | } else { 202 | // If $args['version'] is false, set to null 203 | $script_version = null; 204 | } 205 | 206 | } 207 | 208 | // Enqueue script 209 | foreach( $targets as $target ) { 210 | 211 | add_action( $target . '_enqueue_scripts', function() use ( &$type, &$args, &$content, &$script_url, &$script_version ) { 212 | 213 | if( $type == 'js' ) { 214 | 215 | wp_enqueue_script( $args['handle'], $script_url, $args['dependencies'], $script_version, true ); 216 | if( isset( $args['localize'][0] ) ) wp_localize_script( $args['handle'], key( $args['localize'] ), array( current( $args['localize'] ) ) ); 217 | 218 | } else if ( $type == 'css' ) { 219 | 220 | wp_enqueue_style( $args['handle'], $script_url, $args['dependencies'], $script_version, $args['css_media'] ); 221 | 222 | } 223 | 224 | }); 225 | 226 | } 227 | 228 | } 229 | 230 | 231 | } 232 | 233 | /** 234 | * Get the upload directory and URL for enqueued scripts 235 | * 236 | * @param array $args Configuration associative array 237 | * @return array The absolute path and URL to the script directory 238 | * @since 0.1.0 239 | */ 240 | private function get_script_upload_location( $args = array() ) { 241 | 242 | $result = array( 'dir' => null, 'url' => null ); 243 | 244 | $upload_dir = wp_upload_dir(); 245 | if ( empty( $upload_dir['basedir'] ) ) return $result; 246 | 247 | // Set and create upload folder if it does exist 248 | $result['url'] = $upload_dir['baseurl'] . '/' . trim( $args['script_dir'], '/' ) . '/'; 249 | $result['dir'] = trailingslashit( $upload_dir['basedir'] ) . trailingslashit( $args['script_dir'] ); 250 | if ( !file_exists( $result['dir'] ) ) wp_mkdir_p( $result['dir'] ); 251 | 252 | return $result; 253 | 254 | } 255 | 256 | /** 257 | * Magic method to retrieve values array as string 258 | * @return array Success (true) or failure (false) 259 | * @since 0.1.0 260 | */ 261 | public function __toString() { 262 | return print_r( $this->values, true ); 263 | } 264 | 265 | /** 266 | * Magic method to retrieve specific value 267 | * 268 | * @param string $key Key in $this->values to retrieve 269 | * @return string JSON encoded string of array $this->values 270 | * @since 0.1.0 271 | */ 272 | public function __get( $key ) { 273 | return isset( $this->values[ $key ] ) ? json_encode( $this->values[ $key ] ) : null; 274 | } 275 | 276 | } 277 | -------------------------------------------------------------------------------- /core/ToolKit.php: -------------------------------------------------------------------------------- 1 | merge( new ConfigRegistry( 32 | [ 33 | 'base_dir' => trailingslashit( $base_dir ), 34 | 'wordpress' => [ 35 | 'version' => get_bloginfo('version'), 36 | 'root_dir' => $this->get_wordpress_config_dir(), 37 | 'upload_dir' => trailingslashit( $wp_upload_dir['basedir'] ), 38 | 'upload_url' => $wp_upload_dir['baseurl'] 39 | ] 40 | ] 41 | )); 42 | 43 | // Add theme or plugin properties 44 | if( $args ) $config->merge( new ConfigRegistry( $args ) ); 45 | 46 | // Define toolkit version 47 | if ( !defined( __NAMESPACE__ . '\VERSION' ) ) define( __NAMESPACE__ . '\VERSION', $config->get( 'toolkit-version' ) ); 48 | 49 | // Initialize ObjectCache 50 | self::$cache = new ObjectCache( $config ); 51 | 52 | // Set ecryption salt 53 | if( defined( 'WP_ENCRYPT_KEY' ) ) { 54 | self::$salt = WP_ENCRYPT_KEY; 55 | } else if( $config->get( 'encrypt/salt' ) ) { 56 | self::$salt = $config->get( 'encrypt/salt' ); 57 | } else { 58 | self::$salt = SECURE_AUTH_KEY; 59 | } 60 | 61 | // Load Environmental Variables 62 | $this->load_env_vars( [ $base_dir, $config->get( 'wordpress/root_dir' ) ] ); 63 | 64 | self::$config = $config; 65 | return $config; 66 | 67 | } 68 | 69 | /** 70 | * Append a field prefix as defined in $config 71 | * 72 | * @param string|null $field_name The string/field to prefix 73 | * @param string $before String to add before the prefix 74 | * @param string $after String to add after the prefix 75 | * @return string Prefixed string/field value 76 | * @since 0.1.0 77 | */ 78 | public static function prefix( $field_name = null, $before = '', $after = '_' ) { 79 | 80 | $prefix = $before . self::$config->get( 'prefix' ) . $after; 81 | return $field_name !== null ? $prefix . $field_name : $prefix; 82 | 83 | } 84 | 85 | /** 86 | * Fetch a config value or entire object config 87 | * 88 | * @param string|null $key The configuration key path to return. If null, 89 | * returns all config values. 90 | * @return string|ConfigRegistry Config key path value or ConfigRegistry object 91 | * @since 0.1.4 92 | */ 93 | protected function get_config( $key = null) { 94 | return self::$config->get( $key ); 95 | } 96 | 97 | /** 98 | * Get current plugin properties 99 | * 100 | * @param string $field Return specific field 101 | * @return ConfigRegistry object 102 | * @since 0.2.0 103 | */ 104 | protected function get_current_plugin_meta( $type = ConfigRegistry ) { 105 | if( !self::$config->get( 'base_dir' ) ) return []; 106 | 107 | $plugin_data['slug'] = current( explode( DIRECTORY_SEPARATOR, plugin_basename( self::$config->get( 'base_dir' ) ) ) ); 108 | $plugin_data['path'] = trailingslashit( str_replace( plugin_basename( self::$config->get( 'base_dir' ) ), '', rtrim( self::$config->get( 'base_dir' ), '/' ) ) . $plugin_data['slug'] ); 109 | $plugin_data['url'] = current( explode( $plugin_data['slug'] . '/', plugin_dir_url( self::$config->get( 'base_dir' ) ) ) ) . $plugin_data['slug'] . '/'; 110 | 111 | // Get plugin path/file identifier 112 | foreach( get_plugins() as $key => $plugin ) { 113 | 114 | if( strstr( $key, trailingslashit( $plugin_data['slug'] ) ) ) { 115 | $parts = explode( '/', $key ); 116 | $plugin_data['identifier'] = $key; 117 | $plugin_data['file'] = end( $parts ); 118 | $plugin_data['meta'] = get_plugin_data( $plugin_data['path'] . $plugin_data['file'] ); 119 | } 120 | 121 | } 122 | 123 | if( $type == 'ConfigRegistry' ) { 124 | $plugin_data = new ConfigRegistry( $plugin_data ); 125 | } 126 | 127 | return $plugin_data; 128 | 129 | } 130 | 131 | /** 132 | * Returns the directory location of wp-config.php 133 | * 134 | * @return bool 135 | * @since 0.3.0 136 | */ 137 | private function get_wordpress_config_dir() { 138 | $dir = dirname( __FILE__ ); 139 | do { 140 | if( file_exists( $dir . '/wp-config.php' ) ) { 141 | return $dir; 142 | } 143 | } while( $dir = realpath( trailingslashit( $dir ) . ".." ) ); 144 | return null; 145 | } 146 | 147 | /** 148 | * Load environment variables from various .env, if present. 149 | * 150 | * @param string|array $paths The directories to look within for .env file 151 | * @return bool Returns true if .env found and loaded 152 | * @since 0.3.0 153 | */ 154 | private function load_env_vars( $paths = __DIR__ ) { 155 | 156 | $paths = (array) $paths; 157 | 158 | $result = null; 159 | foreach( $paths as $path ) { 160 | $result = $this->load_env_from_apth( $path ); 161 | } 162 | 163 | return $result; 164 | } 165 | 166 | /** 167 | * Load environment variables from specified .env file. 168 | * 169 | * @param string $path The directory load .env file from 170 | * @return bool 171 | * @since 0.3.0 172 | */ 173 | private function load_env_from_apth( $path ) { 174 | try { 175 | $env = new \Dotenv\Dotenv( $path ); 176 | $env->load(); 177 | } catch ( \Dotenv\Exception\InvalidPathException $e ) { 178 | } catch ( Exception $e ) { } 179 | 180 | $this->set_environment(); 181 | } 182 | 183 | /** 184 | * Returns true if request is via AJAX. 185 | * 186 | * @return bool 187 | * @since 0.2.1 188 | */ 189 | public function is_ajax() { 190 | return defined( 'DOING_AJAX' ) && DOING_AJAX; 191 | } 192 | 193 | /** 194 | * Returns true if environment is anything other than 'development' or 195 | * 'staging'. For example, for determining whether or not to enqueue a 196 | * minified or non-minified script (which can be useful for debugging via 197 | * browser). 198 | * 199 | * @return bool 200 | * @see ToolKit::get_environment() 201 | * @since 0.1.0 202 | */ 203 | public static function is_production() { 204 | return strtolower( self::get_environment() ) == 'production'; 205 | } 206 | 207 | /** 208 | * Sets the environmental variable `ENVIRONMENT` if $env is passed or if 209 | * constant WP_ENV is define. 210 | * 211 | * @param string $env If provided, set's the enviroment to string provided 212 | * @since 0.3.0 213 | */ 214 | public static function set_environment( $env = null ) { 215 | 216 | switch( true ) { 217 | case ( is_string( $env ) ): 218 | putenv( 'ENVIRONMENT=' . $env ); 219 | break; 220 | case ( defined( 'WP_ENV' ) ): 221 | putenv( 'ENVIRONMENT=' . WP_ENV ); 222 | break; 223 | } 224 | 225 | } 226 | 227 | /** 228 | * Gets the current development environmental variable if set via WP_ENV 229 | * constant or .env values. 230 | * 231 | * @param string $env If provided, set's the enviroment to string provided 232 | * @see ToolKit::load_env_vars() 233 | * @see ToolKit::set_environment() 234 | * @since 0.3.0 235 | */ 236 | public static function get_environment() { 237 | return getenv( 'ENVIRONMENT' ) ?: 'production'; 238 | } 239 | 240 | } 241 | --------------------------------------------------------------------------------