Anti-spam - Version 6.5.1

Version Description

  • 16.12.2019 =
  • Added: Multisite support.
  • Fixed: Bug with redirection loop in multisite mode.
  • Fixed: Readme. GDPR compatibility is ready. Plugin doesn't send any data to the remote server.
  • Removed: Dashboard widget with annoy ads.
Download this release

Release Info

Developer alexkovalevv
Plugin Icon 128x128 Anti-spam
Version 6.5.1
Comparing to
See all releases

Code changes from version 5.5 to 6.5.1

Files changed (212) hide show
  1. admin/ajax/index.php +2 -0
  2. admin/ajax/logs.php +24 -0
  3. admin/assets/css/settings.css +29 -0
  4. admin/assets/css/settings.css.map +1 -0
  5. admin/assets/css/settings.less +36 -0
  6. admin/assets/img/about-preview.jpg +0 -0
  7. admin/assets/js/settings.js +24 -0
  8. admin/boot.php +100 -0
  9. admin/class-activation.php +73 -0
  10. admin/pages/class-pages-about.php +132 -0
  11. admin/pages/class-pages-license.php +67 -0
  12. admin/pages/class-pages-logs.php +122 -0
  13. admin/pages/class-pages-settings.php +190 -0
  14. anti-spam-functions.php +0 -135
  15. anti-spam-settings.php +0 -89
  16. anti-spam.php +133 -75
  17. {js → assets/js}/anti-spam-5.5.js +5 -0
  18. anti-spam-info.php → includes/__anti-spam-info.php +0 -0
  19. includes/class-anti-spam-plugin.php +140 -0
  20. includes/class-protector.php +220 -0
  21. includes/functions.php +82 -0
  22. includes/logger/assets/css/base.css +20 -0
  23. includes/logger/assets/css/base.css.map +1 -0
  24. includes/logger/assets/css/base.less +21 -0
  25. includes/logger/assets/js/base.js +39 -0
  26. includes/logger/class-logger-export.php +253 -0
  27. includes/logger/class-logger-reader.php +72 -0
  28. includes/logger/class-logger-writter.php +402 -0
  29. index.php +2 -2
  30. libs/factory/bootstrap/assets/css-min/bootstrap.accordion.min.css +11 -0
  31. libs/factory/bootstrap/assets/css-min/bootstrap.blue.min.css +11 -0
  32. libs/factory/bootstrap/assets/css-min/bootstrap.coffee.min.css +11 -0
  33. libs/factory/bootstrap/assets/css-min/bootstrap.core.min.css +25 -0
  34. libs/factory/bootstrap/assets/css-min/bootstrap.datepicker.min.css +17 -0
  35. libs/factory/bootstrap/assets/css-min/bootstrap.ectoplasm.min.css +11 -0
  36. libs/factory/bootstrap/assets/css-min/bootstrap.form-group.min.css +11 -0
  37. libs/factory/bootstrap/assets/css-min/bootstrap.light.min.css +11 -0
  38. libs/factory/bootstrap/assets/css-min/bootstrap.midnight.min.css +11 -0
  39. libs/factory/bootstrap/assets/css-min/bootstrap.ocean.min.css +11 -0
  40. libs/factory/bootstrap/assets/css-min/bootstrap.separator.min.css +11 -0
  41. libs/factory/bootstrap/assets/css-min/bootstrap.sunrise.min.css +11 -0
  42. libs/factory/bootstrap/assets/css-min/control.checkbox.min.css +11 -0
  43. libs/factory/bootstrap/assets/css-min/control.dropdown.min.css +11 -0
  44. libs/factory/bootstrap/assets/css-min/control.multiple-textbox.min.css +11 -0
  45. libs/factory/bootstrap/assets/css-min/holder.more-link.min.css +11 -0
  46. libs/factory/bootstrap/assets/images/loader-sm-f6f6f6.gif +0 -0
  47. libs/factory/bootstrap/assets/images/loader-sm-tr.gif +0 -0
  48. libs/factory/bootstrap/assets/js-min/bootstrap.dropdown.min.js +10 -0
  49. libs/factory/bootstrap/assets/js-min/bootstrap.tooltip.min.js +10 -0
  50. libs/factory/bootstrap/assets/js-min/control.checkbox.min.js +10 -0
  51. libs/factory/bootstrap/assets/js-min/control.dropdown.min.js +10 -0
  52. libs/factory/bootstrap/assets/js-min/control.list.min.js +10 -0
  53. libs/factory/bootstrap/assets/js-min/control.multiple-textbox.min.js +10 -0
  54. libs/factory/bootstrap/boot.php +46 -0
  55. libs/factory/bootstrap/includes/functions.php +236 -0
  56. libs/factory/bootstrap/includes/index.php +2 -0
  57. libs/factory/bootstrap/index.php +2 -0
  58. libs/factory/clearfy/assets/css/clearfy-base.css +181 -0
  59. libs/factory/clearfy/assets/css/clearfy-base.css.map +1 -0
  60. libs/factory/clearfy/assets/css/clearfy-base.less +170 -0
  61. libs/factory/clearfy/assets/css/license-manager.css +663 -0
  62. libs/factory/clearfy/assets/img/loader.gif +0 -0
  63. libs/factory/clearfy/assets/js/globals.js +203 -0
  64. libs/factory/clearfy/assets/js/license-manager.js +92 -0
  65. libs/factory/clearfy/boot.php +49 -0
  66. libs/factory/clearfy/includes/ajax-handlers.php +101 -0
  67. libs/factory/clearfy/includes/class-configurate.php +116 -0
  68. libs/factory/clearfy/includes/class-helpers.php +266 -0
  69. libs/factory/clearfy/includes/index.php +0 -0
  70. libs/factory/clearfy/index.php +0 -0
  71. libs/factory/clearfy/langs/wbcr_factory_clearfy_216-ru_RU.mo +0 -0
  72. libs/factory/clearfy/langs/wbcr_factory_clearfy_216-ru_RU.po +307 -0
  73. libs/factory/clearfy/pages/class-page-license.php +393 -0
  74. libs/factory/clearfy/pages/class-page-more-features.php +170 -0
  75. libs/factory/clearfy/pages/class-pages.php +439 -0
  76. libs/factory/clearfy/pages/index.php +0 -0
  77. libs/factory/core/README.md +3 -0
  78. libs/factory/core/boot.php +62 -0
  79. libs/factory/core/includes/activation/class-factory-activator.php +43 -0
  80. libs/factory/core/includes/activation/class-factory-update.php +39 -0
  81. libs/factory/core/includes/activation/index.php +2 -0
  82. libs/factory/core/includes/assets-managment/class-factory-assets-list.php +126 -0
  83. libs/factory/core/includes/assets-managment/class-factory-script-list.php +166 -0
  84. libs/factory/core/includes/assets-managment/class-factory-style-list.php +86 -0
  85. libs/factory/core/includes/assets-managment/index.php +2 -0
  86. libs/factory/core/includes/class-check-compatibility.php +122 -0
  87. libs/factory/core/includes/class-factory-migrations.php +541 -0
  88. libs/factory/core/includes/class-factory-notices.php +291 -0
  89. libs/factory/core/includes/class-factory-options.php +432 -0
  90. libs/factory/core/includes/class-factory-plugin-abstract.php +688 -0
  91. libs/factory/core/includes/class-factory-plugin-base.php +573 -0
  92. libs/factory/core/includes/class-factory-requests.php +150 -0
  93. libs/factory/core/includes/class-factory-requirements.php +294 -0
  94. libs/factory/core/includes/entities/class-factory-paths.php +33 -0
  95. libs/factory/core/includes/entities/class-factory-support.php +124 -0
  96. libs/factory/core/includes/functions.php +205 -0
  97. libs/factory/core/includes/index.php +2 -0
  98. libs/factory/core/includes/premium/class-factory-license-interface.php +32 -0
  99. libs/factory/core/includes/premium/class-factory-manager.php +90 -0
  100. libs/factory/core/includes/premium/class-factory-provider-abstract.php +234 -0
  101. libs/factory/core/includes/premium/index.php +2 -0
  102. libs/factory/core/includes/updates/class-factory-premium-upgrader.php +792 -0
  103. libs/factory/core/includes/updates/class-factory-upgrader.php +313 -0
  104. libs/factory/core/includes/updates/index.php +2 -0
  105. libs/factory/core/includes/updates/repositories/class-factory-repository-abstract.php +62 -0
  106. libs/factory/core/includes/updates/repositories/class-factory-wordpress.php +72 -0
  107. libs/factory/core/includes/updates/repositories/index.php +0 -0
  108. libs/factory/core/index.php +2 -0
  109. libs/factory/core/langs/index.php +2 -0
  110. libs/factory/core/langs/wbcr_factory_424-ru_RU.mo +0 -0
  111. libs/factory/core/langs/wbcr_factory_424-ru_RU.po +128 -0
  112. libs/factory/forms/assets/css/editor.css +12 -0
  113. libs/factory/forms/assets/standard-controls.js +146 -0
  114. libs/factory/forms/boot.php +273 -0
  115. libs/factory/forms/controls/checkbox.php +177 -0
  116. libs/factory/forms/controls/color-and-opacity.php +88 -0
  117. libs/factory/forms/controls/color.php +62 -0
  118. libs/factory/forms/controls/customs/html.php +45 -0
  119. libs/factory/forms/controls/customs/index.php +2 -0
  120. libs/factory/forms/controls/customs/separator.php +35 -0
  121. libs/factory/forms/controls/datepicker-range.php +106 -0
  122. libs/factory/forms/controls/dropdown-and-colors.php +116 -0
  123. libs/factory/forms/controls/dropdown.php +393 -0
  124. libs/factory/forms/controls/font.php +270 -0
  125. libs/factory/forms/controls/google-font.php +152 -0
  126. libs/factory/forms/controls/gradient.php +103 -0
  127. libs/factory/forms/controls/hidden.php +50 -0
  128. libs/factory/forms/controls/holders/accordion-item.php +63 -0
  129. libs/factory/forms/controls/holders/accordion.php +58 -0
  130. libs/factory/forms/controls/holders/columns.php +99 -0
  131. libs/factory/forms/controls/holders/control-group-item.php +76 -0
  132. libs/factory/forms/controls/holders/control-group.php +97 -0
  133. libs/factory/forms/controls/holders/div.php +67 -0
  134. libs/factory/forms/controls/holders/form-group.php +71 -0
  135. libs/factory/forms/controls/holders/index.php +2 -0
  136. libs/factory/forms/controls/holders/more-link.php +75 -0
  137. libs/factory/forms/controls/holders/tab-item.php +68 -0
  138. libs/factory/forms/controls/holders/tab.php +139 -0
  139. libs/factory/forms/controls/index.php +2 -0
  140. libs/factory/forms/controls/integer.php +160 -0
  141. libs/factory/forms/controls/list.php +230 -0
  142. libs/factory/forms/controls/multiple-textbox.php +120 -0
  143. libs/factory/forms/controls/paddings-editor.php +82 -0
  144. libs/factory/forms/controls/pattern.php +181 -0
  145. libs/factory/forms/controls/radio-colors.php +111 -0
  146. libs/factory/forms/controls/radio.php +85 -0
  147. libs/factory/forms/controls/textarea.php +85 -0
  148. libs/factory/forms/controls/textbox.php +83 -0
  149. libs/factory/forms/controls/url.php +43 -0
  150. libs/factory/forms/controls/wp-editor.php +95 -0
  151. libs/factory/forms/includes/complex-control.class.php +133 -0
  152. libs/factory/forms/includes/control-holder.class.php +173 -0
  153. libs/factory/forms/includes/control.class.php +422 -0
  154. libs/factory/forms/includes/custom-element.class.php +46 -0
  155. libs/factory/forms/includes/form-element.class.php +423 -0
  156. libs/factory/forms/includes/form-layout.class.php +123 -0
  157. libs/factory/forms/includes/form.class.php +690 -0
  158. libs/factory/forms/includes/holder.class.php +170 -0
  159. libs/factory/forms/includes/html-builder.class.php +137 -0
  160. libs/factory/forms/includes/index.php +2 -0
  161. libs/factory/forms/includes/providers/index.php +2 -0
  162. libs/factory/forms/includes/providers/meta-value-provider.class.php +303 -0
  163. libs/factory/forms/includes/providers/options-value-provider.class.php +96 -0
  164. libs/factory/forms/includes/providers/value-provider.interface.php +62 -0
  165. libs/factory/forms/index.php +2 -0
  166. libs/factory/forms/langs/wbcr_factory_forms_422-ru_RU.mo +0 -0
  167. libs/factory/forms/langs/wbcr_factory_forms_422-ru_RU.po +95 -0
  168. libs/factory/forms/layouts/bootstrap-3/bootstrap-3.php +217 -0
  169. libs/factory/forms/layouts/bootstrap-3/index.php +2 -0
  170. libs/factory/forms/layouts/index.php +2 -0
  171. libs/factory/freemius/boot.php +52 -0
  172. libs/factory/freemius/includes/class-freemius-api.php +416 -0
  173. libs/factory/freemius/includes/entities/class-freemius-entity.php +178 -0
  174. libs/factory/freemius/includes/entities/class-freemius-license.php +369 -0
  175. libs/factory/freemius/includes/entities/class-freemius-plugin.php +114 -0
  176. libs/factory/freemius/includes/entities/class-freemius-scope.php +34 -0
  177. libs/factory/freemius/includes/entities/class-freemius-site.php +147 -0
  178. libs/factory/freemius/includes/entities/class-freemius-user.php +80 -0
  179. libs/factory/freemius/includes/entities/index.php +2 -0
  180. libs/factory/freemius/includes/index.php +2 -0
  181. libs/factory/freemius/includes/licensing/class-freemius-provider.php +739 -0
  182. libs/factory/freemius/includes/licensing/index.php +2 -0
  183. libs/factory/freemius/includes/sdk/Exceptions/ArgumentNotExistException.php +9 -0
  184. libs/factory/freemius/includes/sdk/Exceptions/EmptyArgumentException.php +9 -0
  185. libs/factory/freemius/includes/sdk/Exceptions/Exception.php +74 -0
  186. libs/factory/freemius/includes/sdk/Exceptions/InvalidArgumentException.php +8 -0
  187. libs/factory/freemius/includes/sdk/Exceptions/OAuthException.php +12 -0
  188. libs/factory/freemius/includes/sdk/Exceptions/index.php +3 -0
  189. libs/factory/freemius/includes/sdk/FreemiusBase.php +215 -0
  190. libs/factory/freemius/includes/sdk/FreemiusWordPress.php +704 -0
  191. libs/factory/freemius/includes/sdk/LICENSE.txt +340 -0
  192. libs/factory/freemius/includes/sdk/index.php +3 -0
  193. libs/factory/freemius/includes/updates/class-freemius-repository.php +123 -0
  194. libs/factory/freemius/includes/updates/index.php +2 -0
  195. libs/factory/freemius/index.php +2 -0
  196. libs/factory/pages/boot.php +43 -0
  197. libs/factory/pages/includes/admin-page.class.php +562 -0
  198. libs/factory/pages/includes/index.php +2 -0
  199. libs/factory/pages/includes/page.class.php +168 -0
  200. libs/factory/pages/index.php +2 -0
  201. libs/factory/pages/langs/wbcr_factory_pages_424-fr_FR.mo +0 -0
  202. libs/factory/pages/langs/wbcr_factory_pages_424-fr_FR.po +99 -0
  203. libs/factory/pages/langs/wbcr_factory_pages_424-ru_RU.mo +0 -0
  204. libs/factory/pages/langs/wbcr_factory_pages_424-ru_RU.po +98 -0
  205. libs/factory/pages/pages.php +107 -0
  206. libs/factory/pages/templates/assets/css/impressive.page.template.css +508 -0
  207. libs/factory/pages/templates/assets/css/impressive.page.template.css.map +1 -0
  208. libs/factory/pages/templates/assets/css/impressive.page.template.less +604 -0
  209. libs/factory/pages/templates/assets/img/5-stars22.png +0 -0
  210. libs/factory/pages/templates/assets/img/paypal-donate.png +0 -0
  211. libs/factory/pages/templates/assets/img/webcraftic-plugin-icon.png +0 -0
  212. libs/factory/pages/templates/impressive-page.class.php +425 -0
admin/ajax/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
admin/ajax/logs.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Used to clean-up logs.
5
+ */
6
+ add_action( 'wp_ajax_wlogger-logs-cleanup', function () {
7
+ check_admin_referer( 'wlogger_clean_logs', 'nonce' );
8
+
9
+ if ( ! current_user_can( 'manage_options' ) ) {
10
+ wp_die( - 1 );
11
+ }
12
+
13
+ if ( ! \WBCR\Logger\Writter::clean_up() ) {
14
+ wp_send_json_error( [
15
+ 'message' => esc_html__( 'Failed to clean-up logs. Please try again later.', 'robin-image-optimizer' ),
16
+ 'type' => 'danger',
17
+ ] );
18
+ }
19
+
20
+ wp_send_json( [
21
+ 'message' => esc_html__( 'Logs clean-up successfully', 'robin-image-optimizer' ),
22
+ 'type' => 'success',
23
+ ] );
24
+ } );
admin/assets/css/settings.css ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #WBCR .factory-checkbox.wantispam-checkbox-premium-label:after {
2
+ display: inline-block;
3
+ position: relative;
4
+ content: 'PRO';
5
+ background: #ff5722;
6
+ border-radius: 4px;
7
+ color: #fff;
8
+ font-size: 10px;
9
+ line-height: 1;
10
+ font-style: normal;
11
+ padding: 4px 6px;
12
+ margin-left: 4px;
13
+ vertical-align: top;
14
+ top: -8px;
15
+ left: -10px;
16
+ right: auto;
17
+ z-index: 11;
18
+ cursor: pointer;
19
+ }
20
+ #WBCR .factory-checkbox--disabled input,
21
+ #WBCR .factory-checkbox--disabled button {
22
+ pointer-events: none;
23
+ cursor: not-allowed;
24
+ opacity: 0.65;
25
+ filter: alpha(opacity=65);
26
+ -webkit-box-shadow: none;
27
+ box-shadow: none;
28
+ }
29
+ /*# sourceMappingURL=settings.css.map */
admin/assets/css/settings.css.map ADDED
@@ -0,0 +1 @@
 
1
+ {"version":3,"sources":["settings.less"],"names":[],"mappings":"AAEI,KADF,kBACG,iCAAiC;EAChC,qBAAA;EACA,kBAAA;EACA,SAAS,KAAT;EACA,mBAAA;EACA,kBAAA;EACA,WAAA;EACA,eAAA;EACA,cAAA;EACA,kBAAA;EACA,gBAAA;EACA,gBAAA;EACA,mBAAA;EACA,SAAA;EACA,WAAA;EACA,WAAA;EACA,WAAA;EACA,eAAA;;AAGF,KArBF,kBAqBG,UAAW;AACZ,KAtBF,kBAsBG,UAAW;EACV,oBAAA;EACA,mBAAA;EACA,aAAA;EACA,yBAAA;EACA,wBAAA;EACA,gBAAA","file":"settings.css"}
admin/assets/css/settings.less ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #WBCR {
2
+ .factory-checkbox {
3
+ &.wantispam-checkbox-premium-label:after {
4
+ display: inline-block;
5
+ position: relative;
6
+ content: 'PRO';
7
+ background: #ff5722;
8
+ border-radius: 4px;
9
+ color: #fff;
10
+ font-size: 10px;
11
+ line-height: 1;
12
+ font-style: normal;
13
+ padding: 4px 6px;
14
+ margin-left: 4px;
15
+ vertical-align: top;
16
+ top: -8px;
17
+ left: -10px;
18
+ right: auto;
19
+ z-index: 11;
20
+ cursor: pointer;
21
+ }
22
+
23
+ &--disabled input,
24
+ &--disabled button {
25
+ pointer-events: none;
26
+ cursor: not-allowed;
27
+ opacity: 0.65;
28
+ filter: alpha(opacity=65);
29
+ -webkit-box-shadow: none;
30
+ box-shadow: none;
31
+ }
32
+ }
33
+
34
+
35
+ }
36
+
admin/assets/img/about-preview.jpg ADDED
Binary file
admin/assets/js/settings.js ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * General scripts
3
+ *
4
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
5
+ * @copyright (c) 03.12.2019, CreativeMotion
6
+ * @version 1.0
7
+ */
8
+
9
+
10
+ (function($) {
11
+ 'use strict';
12
+
13
+ $.wantispam = {};
14
+
15
+ if( $.wbcr_factory_clearfy_216 ) {
16
+ $.wantispam = $.wbcr_factory_clearfy_216;
17
+ }
18
+
19
+ $('.factory-checkbox--disabled.wantispam-checkbox-premium-label').click(function(e) {
20
+ e.stopPropagation();
21
+ window.location.href = 'https://anti-spam.space/pricing/';
22
+ });
23
+
24
+ })(jQuery);
admin/boot.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Admin boot
4
+ *
5
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
6
+ * @copyright Webcraftic 22.10.2019
7
+ */
8
+
9
+ // Exit if accessed directly
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ /*add_action('wantispam/factory/clearfy/check_license_success', function($action, $license_key){
15
+ if('activate' === $action || 'sync' === $action) {
16
+
17
+ }
18
+ });*/
19
+
20
+ /**
21
+ * Виджет отзывов
22
+ *
23
+ * @param string $page_url
24
+ * @param string $plugin_name
25
+ *
26
+ * @return string
27
+ */
28
+ add_filter( 'wbcr_factory_pages_424_imppage_rating_widget_url', function ( $page_url, $plugin_name ) {
29
+ if ( $plugin_name == \WBCR\Antispam\Plugin::app()->getPluginName() ) {
30
+ return 'https://wordpress.org/support/plugin/anti-spam/reviews/';
31
+ }
32
+
33
+ return $page_url;
34
+ }, 10, 2 );
35
+
36
+ /**
37
+ * Удаляем лишние виджеты из правого сайдбара в интерфейсе плагина
38
+ *
39
+ * - Виджет с премиум рекламой
40
+ * - Виджет с рейтингом
41
+ * - Виджет с маркерами информации
42
+ */
43
+ add_filter( 'wbcr/factory/pages/impressive/widgets', function ( $widgets, $position, $plugin ) {
44
+ if ( \WBCR\Antispam\Plugin::app()->getPluginName() == $plugin->getPluginName() && 'right' == $position ) {
45
+ unset( $widgets['business_suggetion'] );
46
+ unset( $widgets['rating_widget'] );
47
+ unset( $widgets['info_widget'] );
48
+ }
49
+
50
+ return $widgets;
51
+ }, 20, 3 );
52
+
53
+ /**
54
+ * Changes plugin title in plugin interface header
55
+ */
56
+ add_filter( 'wbcr/factory/pages/impressive/plugin_title', function ( $title, $plugin_name ) {
57
+ if ( \WBCR\Antispam\Plugin::app()->getPluginName() == $plugin_name ) {
58
+ return __( 'Anti-spam', 'realforce' );
59
+ }
60
+
61
+ return $title;
62
+ }, 20, 2 );
63
+
64
+ /**
65
+ * Инициализации метабоксов и страницы "о плагине".
66
+ *
67
+ * Этот хук реализует условную логику, при которой пользователь переодически будет
68
+ * видет страницу "О плагине", а конкретно при активации и обновлении плагина.
69
+ */
70
+ add_action( 'admin_init', function () {
71
+ $plugin = \WBCR\Antispam\Plugin::app();
72
+
73
+ // If the user has updated the plugin or activated it for the first time,
74
+ // you need to show the page "What's new?"
75
+ //if ( ! $plugin->isNetworkAdmin() ) {
76
+ $about_page_viewed = $plugin->request->get( 'wantispam_about_page_viewed', null );
77
+
78
+ if ( is_null( $about_page_viewed ) ) {
79
+ if ( wantispam_is_need_show_about_page() ) {
80
+ try {
81
+ $redirect_url = $plugin->getPluginPageUrl( 'about', [ 'wantispam_about_page_viewed' => 1 ] );
82
+
83
+ if ( $redirect_url ) {
84
+ wp_safe_redirect( $redirect_url );
85
+ die();
86
+ }
87
+ } catch( Exception $e ) {
88
+ }
89
+ }
90
+ } else {
91
+ if ( wantispam_is_need_show_about_page() ) {
92
+ if ( $plugin->isNetworkAdmin() ) {
93
+ delete_site_option( $plugin->getOptionName( 'what_is_new_64' ) );
94
+ } else {
95
+ delete_option( $plugin->getOptionName( 'what_is_new_64' ) );
96
+ }
97
+ }
98
+ }
99
+ //}
100
+ } );
admin/class-activation.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Antispam;
4
+
5
+ /**
6
+ * Activator for the Antispam
7
+ *
8
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
9
+ * @copyright (c) 26.10.2019, Webcraftic
10
+ * @see Wbcr_Factory424_Activator
11
+ * @version 1.0
12
+ */
13
+
14
+ // Exit if accessed directly
15
+ if ( ! defined( 'ABSPATH' ) ) {
16
+ exit;
17
+ }
18
+
19
+ class Activation extends \Wbcr_Factory424_Activator {
20
+
21
+ /**
22
+ * Runs activation actions.
23
+ *
24
+ * @since 6.0
25
+ */
26
+ public function activate() {
27
+
28
+ $plugin_version_in_db = $this->get_plugin_version_in_db();
29
+ $current_plugin_version = $this->plugin->getPluginVersion();
30
+
31
+ $tab = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
32
+ $log_message = "Plugin starts activation [START].\r\n";
33
+ $log_message .= "{$tab}-Plugin Version in DB: {$plugin_version_in_db}\r\n";
34
+ $log_message .= "{$tab}-Current Plugin Version: {$current_plugin_version}";
35
+
36
+ \WBCR\Logger\Writter::info( $log_message );
37
+
38
+ if ( $this->plugin->isNetworkAdmin() ) {
39
+ update_site_option( $this->plugin->getOptionName( 'what_is_new_64' ), 1 );
40
+ } else {
41
+ update_option( $this->plugin->getOptionName( 'what_is_new_64' ), 1 );
42
+ }
43
+
44
+ \WBCR\Logger\Writter::info( "Plugin has been activated [END]!" );
45
+ }
46
+
47
+ /**
48
+ * Get previous plugin version
49
+ *
50
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
51
+ * @since 6.0
52
+ * @return number
53
+ */
54
+ public function get_plugin_version_in_db() {
55
+ if ( \WBCR\Antispam\Plugin::app()->isNetworkActive() ) {
56
+ return get_site_option( \WBCR\Antispam\Plugin::app()->getOptionName( 'plugin_version' ), 0 );
57
+ }
58
+
59
+ return get_option( \WBCR\Antispam\Plugin::app()->getOptionName( 'plugin_version' ), 0 );
60
+ }
61
+
62
+
63
+ /**
64
+ * Run deactivation actions.
65
+ *
66
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
67
+ * @since 6.0
68
+ */
69
+ public function deactivate() {
70
+ \WBCR\Logger\Writter::info( "Plugin starts deactivate [START]." );
71
+ \WBCR\Logger\Writter::info( "Plugin has been deactivated [END]!" );
72
+ }
73
+ }
admin/pages/class-pages-about.php ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Antispam\Page;
4
+
5
+ // Exit if accessed directly
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ /**
11
+ * The file contains a short help info.
12
+ *
13
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
14
+ * @copyright (c) 2019 Webraftic Ltd
15
+ * @version 1.0
16
+ */
17
+ class About extends \Wbcr_FactoryClearfy216_PageBase {
18
+
19
+ /**
20
+ * {@inheritdoc}
21
+ */
22
+ public $id = 'about';
23
+
24
+ /**
25
+ * {@inheritdoc}
26
+ */
27
+ public $page_menu_dashicon = 'dashicons-star-filled';
28
+
29
+ /**
30
+ * {@inheritdoc}
31
+ */
32
+ public $type = 'page';
33
+
34
+ /**
35
+ * {@inheritdoc}
36
+ */
37
+ public $show_right_sidebar_in_options = false;
38
+
39
+ /**
40
+ * {@inheritdoc}
41
+ */
42
+ public $page_menu_position = 0;
43
+
44
+
45
+ /**
46
+ * Logs constructor.
47
+ *
48
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
49
+ *
50
+ * @param \Wbcr_Factory424_Plugin $plugin
51
+ */
52
+ public function __construct( \Wbcr_Factory424_Plugin $plugin ) {
53
+ $this->plugin = $plugin;
54
+
55
+ $this->menu_title = __( 'Premium', 'anti-spam' );
56
+ $this->page_menu_short_description = sprintf( __( 'What is new in %s?', 'anti-spam' ), $this->plugin->getPluginVersion() );
57
+
58
+ parent::__construct( $plugin );
59
+ }
60
+
61
+ /**
62
+ * {@inheritdoc}
63
+ */
64
+ public function showPageContent() {
65
+ global $wp_version;
66
+ ?>
67
+ <div class="wrap about-wrap full-width-layout" id="wbcr-inp-about">
68
+ <!-- News Title !-->
69
+ <h1>Meet with <?php echo $this->plugin->getPluginTitle() ?>
70
+ Pro in <?php echo $this->plugin->getPluginVersion() ?></h1>
71
+ <!-- News Subtext !-->
72
+ <div class="about-text">
73
+ Thanks for upgrading! Many new features and improvements are available that you will enjoy.
74
+ </div>
75
+ <!-- Latest News !-->
76
+ <div class="headline">
77
+ <h3 class="headline-title">
78
+ You’ve probably noticed how much our plugin has changed! Now, it’s a
79
+ fully-functional cloud anti-spam
80
+ service: easy to use and without captcha or complex settings.
81
+ </h3>
82
+ <div class="featured-image">
83
+ <img src="<?php echo WANTISPAM_PLUGIN_URL ?>/admin/assets/img/about-preview.jpg" alt="">
84
+ </div>
85
+ <p>&nbsp;</p>
86
+ <p class="introduction">
87
+ A new way of checking comments and registrations for spam. Once you install the plugin, all messages
88
+ pass a three-step verification:
89
+ </p>
90
+ <ul>
91
+ <li>- match with the constantly updated spam base;</li>
92
+ <li>- check by a neural network;</li>
93
+ <li>- filter comments posted on a website before the plugin installation.</li>
94
+ </ul>
95
+ <p>Besides, now you have a handy control panel with various settings and analytics section. The result of
96
+ our work is a great plugin that protects your site from spam much better! Check how it works. If you
97
+ like it, don’t forget to post a review – that motivates us the best!</p>
98
+ </div>
99
+ <div class="feature-section one-col">
100
+ <div class="col">
101
+ <h2>Useful features scheduled for future releases:</h2>
102
+ </div>
103
+ </div>
104
+ <div class="feature-section one-col">
105
+ <div class="col">
106
+ <ul>
107
+ <li>An additional level of checking comments on the base of stop words;</li>
108
+ <li>Additional integrations:
109
+ <p>popular plugins for generating forms; membership plugins, plugins
110
+ that add registration forms; elementor builders, beaver, composer; woocommerce; bbPress; the
111
+ subscription forms protection from popular services (for example, Mailchimp).
112
+ </p>
113
+ </li>
114
+ <li>Block or allow comments from specific countries.</li>
115
+ <li>Allow comments in a certain language only.</li>
116
+ <li>
117
+ Manual sorting of comments mistakenly marked as spam.
118
+ <p>(If a user clicked Spam (that it is not spam), display a pop-up window offering to remove the
119
+ user from the blacklist. In that case, the messages from this user won’t be considered as
120
+ spam anymore. It’s a sort of a training model helping the user to avoid manual operations
121
+ when his client mistakenly ended up being in the blacklist.)</p>
122
+ </li>
123
+ <li>Remove all links from comments.</li>
124
+ <li>Admin notifications to control the correct plugin performance.</li>
125
+ <li>The spam list auto clean after a certain period.</li>
126
+ </ul>
127
+ </div>
128
+ </div>
129
+ <?php
130
+ }
131
+
132
+ }
admin/pages/class-pages-license.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Antispam\Page;
4
+
5
+ // Exit if accessed directly
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ /**
11
+ * Страница лицензирования плагина.
12
+ *
13
+ * Поддерживает режим работы с мультисаймами. Вы можете увидеть эту страницу в панели настройки сети.
14
+ *
15
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
16
+ *
17
+ * @copyright (c) 2018 Webraftic Ltd
18
+ */
19
+ class License extends \Wbcr_FactoryClearfy216_LicensePage {
20
+
21
+ /**
22
+ * {@inheritdoc}
23
+ *
24
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
25
+ * @since 6.0
26
+ * @var string
27
+ */
28
+ public $id = 'license';
29
+
30
+ /**
31
+ * {@inheritdoc}
32
+ *
33
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
34
+ * @since 6.0
35
+ * @var string
36
+ */
37
+ public $page_parent_page;
38
+
39
+ /**
40
+ * WCL_LicensePage constructor.
41
+ *
42
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
43
+ *
44
+ * @param \Wbcr_Factory424_Plugin $plugin
45
+ */
46
+ public function __construct( \Wbcr_Factory424_Plugin $plugin ) {
47
+ $this->menu_title = __( 'License', 'anti-spam' );
48
+ $this->page_menu_short_description = __( 'Product activation', 'anti-spam' );
49
+ $this->plan_name = __( 'Anti-spam PRO', 'anti-spam' );
50
+
51
+ parent::__construct( $plugin );
52
+ }
53
+
54
+ /**
55
+ * {@inheritdoc}
56
+ *
57
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
58
+ * @since 1.6.0
59
+ * @return string
60
+ */
61
+ public function get_plan_description() {
62
+ $description = '<p style="font-size: 16px;">' . __( '<b>Anti-spam PRO</b> is a paid package of components for the popular free WordPress plugin named Anti-spam PRO. You get access to all paid components at one price.', 'clearfy' ) . '</p>';
63
+ $description .= '<p style="font-size: 16px;">' . __( 'Paid license guarantees that you can download and update existing and future paid components of the plugin.', 'clearfy' ) . '</p>';
64
+
65
+ return $description;
66
+ }
67
+ }
admin/pages/class-pages-logs.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Antispam\Page;
4
+
5
+ // Exit if accessed directly
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ /**
11
+ * Страница журнала ошибок
12
+ *
13
+ * Не поддерживает режим работы с мультисаймами.
14
+ *
15
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
16
+ * @copyright (c) 2019 Webraftic Ltd
17
+ * @version 1.0
18
+ */
19
+ class Logs extends \Wbcr_FactoryClearfy216_PageBase {
20
+
21
+ /**
22
+ * {@inheritdoc}
23
+ */
24
+ public $id = 'logs';
25
+
26
+ /**
27
+ * {@inheritdoc}
28
+ */
29
+ public $page_menu_dashicon = 'dashicons-admin-tools';
30
+
31
+ /**
32
+ * {@inheritdoc}
33
+ */
34
+ public $type = 'page';
35
+
36
+ /**
37
+ * Logs constructor.
38
+ *
39
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
40
+ *
41
+ * @param \Wbcr_Factory424_Plugin $plugin
42
+ */
43
+ public function __construct( \Wbcr_Factory424_Plugin $plugin ) {
44
+
45
+ $this->menu_title = __( 'Error Log', 'anti-spam' );
46
+ $this->page_menu_short_description = __( 'Plugin debug report', 'anti-spam' );
47
+
48
+ parent::__construct( $plugin );
49
+ }
50
+
51
+ /**
52
+ * {@inheritdoc}
53
+ *
54
+ * @since 1.0.0
55
+ * @return void
56
+ */
57
+ public function assets( $scripts, $styles ) {
58
+ parent::assets( $scripts, $styles );
59
+
60
+ $this->styles->add( WANTISPAM_PLUGIN_URL . '/includes/logger/assets/css/base.css' );
61
+ $this->scripts->add( WANTISPAM_PLUGIN_URL . '/includes/logger/assets/js/base.js' );
62
+ }
63
+
64
+ /**
65
+ * {@inheritdoc}
66
+ */
67
+ public function showPageContent() {
68
+ require_once( WANTISPAM_PLUGIN_DIR . '/includes/logger/class-logger-reader.php' );
69
+ ?>
70
+ <div class="wbcr-factory-page-group-header">
71
+ <strong><?php _e( 'Error Log', 'anti-spam' ) ?></strong>
72
+ <p>
73
+ <?php _e( 'In this section, you can track image optimization errors. Sending this log to us, will help in solving possible optimization issues.', 'anti-spam' ) ?>
74
+ </p>
75
+ </div>
76
+ <div class="wbcr-factory-page-group-body">
77
+ <div class="btn-group">
78
+ <a href="<?php echo wp_nonce_url( $this->getPageUrl() . 'action=export' ) ?>"
79
+ class="btn btn-default"><?php _e( 'Export Debug Information', 'anti-spam' ) ?></a>
80
+ <a href="#"
81
+ data-working="<?php echo esc_attr__( 'Working...', 'anti-spam' ) ?>"
82
+ data-nonce="<?php echo wp_create_nonce( 'wlogger_clean_logs' ) ?>"
83
+ class="btn btn-default js-wlogger-export-debug-report"><?php echo sprintf( __( 'Clean-up Logs (<span id="js-wlogger-size">%s</span>)', 'anti-spam' ), $this->get_log_size_formatted() ) ?></a>
84
+ </div>
85
+ <div class="wlogger-viewer" id="js-wlogger-viewer">
86
+ <?php echo \WBCR\Logger\Reader::prettify() ?>
87
+ </div>
88
+ </div>
89
+ <?php
90
+ }
91
+
92
+ /**
93
+ * Processing log export action in form of ZIP archive.
94
+ *
95
+ * @since 6.0
96
+ */
97
+ public function exportAction() {
98
+ require_once( WANTISPAM_PLUGIN_DIR . '/includes/logger/class-logger-export.php' );
99
+ $export = new \WBCR\Logger\Export();
100
+
101
+ if ( $export->prepare() ) {
102
+ $export->download( true );
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Get log size formatted.
108
+ *
109
+ * @since 6.0
110
+ * @return false|string
111
+ */
112
+ private function get_log_size_formatted() {
113
+
114
+ try {
115
+ return size_format( \WBCR\Logger\Writter::get_total_size() );
116
+ } catch( \Exception $exception ) {
117
+ \WBCR\Logger\Writter::error( sprintf( 'Failed to get total log size as exception was thrown: %s', $exception->getMessage() ) );
118
+ }
119
+
120
+ return '';
121
+ }
122
+ }
admin/pages/class-pages-settings.php ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Antispam\Page;
4
+
5
+ // Exit if accessed directly
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ /**
11
+ * Страница общих настроек для этого плагина.
12
+ *
13
+ * Не поддерживает режим работы с мультисаймами.
14
+ *
15
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
16
+ * @copyright (c) 2019 Webraftic Ltd
17
+ * @version 1.0
18
+ */
19
+ class Settings extends \Wbcr_FactoryClearfy216_PageBase {
20
+
21
+ /**
22
+ * {@inheritDoc}
23
+ *
24
+ * @since 6.0
25
+ * @var string
26
+ */
27
+ public $id = "settings";
28
+
29
+ /**
30
+ * {@inheritDoc}
31
+ *
32
+ * @since 6.0
33
+ * @var string
34
+ */
35
+ public $page_menu_dashicon = 'dashicons-testimonial';
36
+
37
+ /**
38
+ * {@inheritDoc}
39
+ *
40
+ * @since 6.0
41
+ * @var string
42
+ */
43
+ public $menu_target = 'options-general.php';
44
+
45
+ /**
46
+ * {@inheritDoc}
47
+ *
48
+ * @since 6.0
49
+ * @var bool
50
+ */
51
+ public $show_right_sidebar_in_options = true;
52
+
53
+ /**
54
+ * {@inheritDoc}
55
+ *
56
+ * @since 6.0
57
+ * @var bool
58
+ */
59
+ public $internal = false;
60
+
61
+ /**
62
+ * {@inheritDoc}
63
+ *
64
+ * @since 6.0
65
+ * @var bool
66
+ */
67
+ public $add_link_to_plugin_actions = true;
68
+
69
+ /**
70
+ * WBCR\Page\Settings constructor.
71
+ *
72
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
73
+ *
74
+ * @param \Wbcr_Factory424_Plugin $plugin
75
+ */
76
+ public function __construct( \Wbcr_Factory424_Plugin $plugin ) {
77
+ $this->menu_title = __( 'Anti-spam', 'anti-spam' );
78
+ $this->page_menu_short_description = __( 'All settings', 'anti-spam' );
79
+
80
+ parent::__construct( $plugin );
81
+
82
+ $this->plugin = $plugin;
83
+ }
84
+
85
+
86
+ public function getPageTitle() {
87
+ return __( 'General', 'anti-spam' );
88
+ }
89
+
90
+ /**
91
+ * Enqueue page assets
92
+ *
93
+ * @since 6.2
94
+ * @return void
95
+ * @see Wbcr_FactoryPages424_AdminPage
96
+ *
97
+ */
98
+ public function assets( $scripts, $styles ) {
99
+ parent::assets( $scripts, $styles );
100
+
101
+ $this->styles->add( WANTISPAM_PLUGIN_URL . '/admin/assets/css/settings.css' );
102
+ $this->scripts->add( WANTISPAM_PLUGIN_URL . '/admin/assets/js/settings.js', [
103
+ 'jquery',
104
+ 'wbcr-factory-clearfy-216-global'
105
+ ], 'wantispam-settings' );
106
+ }
107
+
108
+ /**
109
+ * Permalinks options.
110
+ *
111
+ * @since 6.2
112
+ * @return mixed[]
113
+ */
114
+ public function getPageOptions() {
115
+ $is_premium = \WBCR\Antispam\Plugin::app()->premium->is_activate();
116
+
117
+ $options[] = [
118
+ 'type' => 'html',
119
+ 'html' => '<div class="wbcr-factory-page-group-header">' . '<strong>' . __( 'Base options.', 'anti-spam' ) . '</strong>' . '<p>' . __( 'More 1 000 000 spam comments were blocked by Anti-spam plugin so far. Upgrade to Anti-spam Pro for advanced protection.', 'anti-spam' ) . '</p>' . '</div>'
120
+ ];
121
+
122
+ $options[] = [
123
+ 'type' => 'checkbox',
124
+ 'way' => 'buttons',
125
+ 'name' => 'save_spam_comments',
126
+ 'title' => __( 'Save spam comments', 'anti-spam' ),
127
+ 'layout' => [ 'hint-type' => 'icon', 'hint-icon-color' => 'green' ],
128
+ 'hint' => __( 'Save spam comments into spam section. Useful for testing how the plugin works.', 'anti-spam' ),
129
+ 'default' => true
130
+ ];
131
+
132
+ if ( $is_premium ) {
133
+ $options[] = [
134
+ 'type' => 'checkbox',
135
+ 'way' => 'buttons',
136
+ 'name' => 'comment_form_privacy_notice',
137
+ 'title' => __( 'Display a privacy notice under your comment forms.', 'anti-spam' ),
138
+ 'layout' => [ 'hint-type' => 'icon', 'hint-icon-color' => 'green' ],
139
+ 'hint' => __( 'To help your site with transparency under privacy laws like the GDPR, Antispam can display a notice to your users under your comment forms. This feature is disabled by default, however, you can turn it on above.', 'anti-spam' ),
140
+ 'default' => false
141
+ ];
142
+ }
143
+
144
+ $options[] = [
145
+ 'type' => 'html',
146
+ 'html' => '<div class="wbcr-factory-page-group-header">' . '<strong>' . __( 'Modules.', 'anti-spam' ) . '</strong>' . '<p>' . __( 'Additional modules to spam protect.', 'anti-spam' ) . '</p>' . '</div>'
147
+ ];
148
+
149
+ $options[] = [
150
+ 'type' => 'checkbox',
151
+ 'way' => 'buttons',
152
+ 'name' => 'protect_register_form',
153
+ 'title' => __( 'Protect Register Form', 'anti-spam' ),
154
+ 'layout' => [ 'hint-type' => 'icon', 'hint-icon-color' => 'green' ],
155
+ 'hint' => __( 'Registration form can be protected in a matter of minutes with a few new fields and limits imposed.', 'anti-spam' ),
156
+ 'default' => false,
157
+ 'cssClass' => ! $is_premium ? [ 'factory-checkbox--disabled wantispam-checkbox-premium-label' ] : [],
158
+ ];
159
+ $options[] = [
160
+ 'type' => 'checkbox',
161
+ 'way' => 'buttons',
162
+ 'name' => 'protect_comments_form',
163
+ 'title' => __( 'Advanced protection of comment forms', 'anti-spam' ),
164
+ 'layout' => [ 'hint-type' => 'icon', 'hint-icon-color' => 'green' ],
165
+ 'hint' => sprintf( __( 'In order to protect your cooment forms, you need to make it difficult or impossible for an automated tool to fill in or submit the form while keeping it as easy as possible for your customers to fill out the form.', 'anti-spam' ), \WBCR\Antispam\Plugin::app()->getPluginTitle() ),
166
+ 'default' => false,
167
+ 'cssClass' => ! $is_premium ? [ 'factory-checkbox--disabled wantispam-checkbox-premium-label' ] : [],
168
+ ];
169
+ /*$options[] = [
170
+ 'type' => 'checkbox',
171
+ 'way' => 'buttons',
172
+ 'name' => 'protect_contacts_form',
173
+ 'title' => __( 'Protect Contact Forms (Beta)', 'anti-spam' ),
174
+ 'layout' => [ 'hint-type' => 'icon', 'hint-icon-color' => 'red' ],
175
+ 'hint' => __( 'Job Spam-Free for WordPress Contact Forms.', 'anti-spam' ),
176
+ 'default' => false,
177
+ 'cssClass' => ! $is_premium ? [ 'factory-checkbox--disabled wantispam-checkbox-premium-label' ] : [],
178
+ ];*/
179
+
180
+ $form_options = [];
181
+
182
+ $form_options[] = [
183
+ 'type' => 'form-group',
184
+ 'items' => $options,
185
+ //'cssClass' => 'postbox'
186
+ ];
187
+
188
+ return apply_filters( 'wantispam/settings_form/options', $form_options, $this );
189
+ }
190
+ }
anti-spam-functions.php DELETED
@@ -1,135 +0,0 @@
1
- <?php
2
-
3
- if ( ! defined( 'ABSPATH' ) ) { // Avoid direct calls to this file and prevent full path disclosure
4
- exit;
5
- }
6
-
7
- function antispam_default_settings() {
8
- $settings = array(
9
- 'save_spam_comments' => 0
10
- );
11
- return $settings;
12
- }
13
-
14
-
15
- function antispam_get_settings() {
16
- $antispam_settings = (array) get_option('antispam_settings');
17
- $default_settings = antispam_default_settings();
18
- $antispam_settings = array_merge($default_settings, $antispam_settings); // set empty options with default values
19
- return $antispam_settings;
20
- }
21
-
22
-
23
- function antispam_counter_stats() {
24
- $antispam_stats = get_option('antispam_stats', array());
25
- if (array_key_exists('blocked_total', $antispam_stats)){
26
- $antispam_stats['blocked_total']++;
27
- } else {
28
- $antispam_stats['blocked_total'] = 1;
29
- }
30
- update_option('antispam_stats', $antispam_stats);
31
- }
32
-
33
-
34
- function antispam_check_for_spam() {
35
- $spam_flag = false;
36
-
37
- $antspm_q = '';
38
- if (isset($_POST['antspm-q'])) {
39
- $antspm_q = trim($_POST['antspm-q']);
40
- }
41
-
42
- $antspm_d = '';
43
- if (isset($_POST['antspm-d'])) {
44
- $antspm_d = trim($_POST['antspm-d']);
45
- }
46
-
47
- $antspm_e = '';
48
- if (isset($_POST['antspm-e-email-url-website'])) {
49
- $antspm_e = trim($_POST['antspm-e-email-url-website']);
50
- }
51
-
52
- if ( $antspm_q != date('Y') ) { // year-answer is wrong - it is spam
53
- if ( $antspm_d != date('Y') ) { // extra js-only check: there is no js added input - it is spam
54
- $spam_flag = true;
55
- }
56
- }
57
-
58
- if ( ! empty($antspm_e)) { // trap field is not empty - it is spam
59
- $spam_flag = true;
60
- }
61
-
62
- return $spam_flag;
63
- }
64
-
65
-
66
- function antispam_store_comment($commentdata) {
67
- global $wpdb;
68
-
69
- if ( isset( $commentdata['user_ID'] ) ) {
70
- $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
71
- }
72
-
73
- $prefiltered_user_id = ( isset( $commentdata['user_id'] ) ) ? (int) $commentdata['user_id'] : 0;
74
-
75
- $commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
76
- if ( isset( $commentdata['user_ID'] ) && $prefiltered_user_id !== (int) $commentdata['user_ID'] ) {
77
- $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
78
- } elseif ( isset( $commentdata['user_id'] ) ) {
79
- $commentdata['user_id'] = (int) $commentdata['user_id'];
80
- }
81
-
82
- $commentdata['comment_parent'] = isset($commentdata['comment_parent']) ? absint($commentdata['comment_parent']) : 0;
83
- $parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status($commentdata['comment_parent']) : '';
84
- $commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;
85
-
86
- if ( ! isset( $commentdata['comment_author_IP'] ) ) {
87
- $commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
88
- }
89
- $commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '', $commentdata['comment_author_IP'] );
90
-
91
- if ( ! isset( $commentdata['comment_agent'] ) ) {
92
- $commentdata['comment_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT']: '';
93
- }
94
- $commentdata['comment_agent'] = substr( $commentdata['comment_agent'], 0, 254 );
95
-
96
- if ( empty( $commentdata['comment_date'] ) ) {
97
- $commentdata['comment_date'] = current_time('mysql');
98
- }
99
-
100
- if ( empty( $commentdata['comment_date_gmt'] ) ) {
101
- $commentdata['comment_date_gmt'] = current_time( 'mysql', 1 );
102
- }
103
-
104
- $commentdata = wp_filter_comment($commentdata);
105
-
106
- $commentdata['comment_approved'] = wp_allow_comment( $commentdata, $avoid_die );
107
- if ( is_wp_error( $commentdata['comment_approved'] ) ) {
108
- return $commentdata['comment_approved'];
109
- }
110
-
111
- $comment_ID = wp_insert_comment($commentdata);
112
- if ( ! $comment_ID ) {
113
- $fields = array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' );
114
-
115
- foreach ( $fields as $field ) {
116
- if ( isset( $commentdata[ $field ] ) ) {
117
- $commentdata[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->comments, $field, $commentdata[ $field ] );
118
- }
119
- }
120
-
121
- $commentdata = wp_filter_comment( $commentdata );
122
-
123
- $commentdata['comment_approved'] = wp_allow_comment( $commentdata, $avoid_die );
124
- if ( is_wp_error( $commentdata['comment_approved'] ) ) {
125
- return $commentdata['comment_approved'];
126
- }
127
-
128
- $comment_ID = wp_insert_comment( $commentdata );
129
- if ( ! $comment_ID ) {
130
- return false;
131
- }
132
- }
133
-
134
- wp_set_comment_status( $comment_ID, 'spam' );
135
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
anti-spam-settings.php DELETED
@@ -1,89 +0,0 @@
1
- <?php
2
- /*
3
- Anti-spam settings code
4
- used WordPress Settings API - http://codex.wordpress.org/Settings_API
5
- */
6
-
7
- if ( ! defined( 'ABSPATH' ) ) { // Avoid direct calls to this file and prevent full path disclosure
8
- exit;
9
- }
10
-
11
-
12
- function antispam_menu() { // add menu item
13
- add_options_page('Anti-spam', 'Anti-spam', 'manage_options', 'anti-spam', 'antispam_settings');
14
- }
15
- add_action('admin_menu', 'antispam_menu');
16
-
17
-
18
- function antispam_admin_init() {
19
- register_setting('antispam_settings_group', 'antispam_settings', 'antispam_settings_validate');
20
-
21
- add_settings_section('antispam_settings_automatic_section', '', 'antispam_section_callback', 'antispam_automatic_page');
22
-
23
- add_settings_field('save_spam_comments', 'Save spam comments', 'antispam_field_save_spam_comments_callback', 'antispam_automatic_page', 'antispam_settings_automatic_section');
24
-
25
- }
26
- add_action('admin_init', 'antispam_admin_init');
27
-
28
-
29
- function antispam_settings_init() { // set default settings
30
- global $antispam_settings;
31
- $antispam_settings = antispam_get_settings();
32
- update_option('antispam_settings', $antispam_settings);
33
- }
34
- add_action('admin_init', 'antispam_settings_init');
35
-
36
-
37
- function antispam_settings_validate($input) {
38
- $default_settings = antispam_get_settings();
39
-
40
- // checkbox
41
- $output['save_spam_comments'] = $input['save_spam_comments'];
42
-
43
- return $output;
44
- }
45
-
46
-
47
- function antispam_section_callback() { // Anti-spam settings description
48
- echo '';
49
- }
50
-
51
-
52
- function antispam_field_save_spam_comments_callback() {
53
- $settings = antispam_get_settings();
54
- echo '<label><input type="checkbox" name="antispam_settings[save_spam_comments]" '.checked(1, $settings['save_spam_comments'], false).' value="1" />';
55
- echo ' Save spam comments into spam section</label>';
56
- echo '<p class="description">Useful for testing how the plugin works. <a href="'. admin_url( 'edit-comments.php?comment_status=spam' ) . '">View spam section</a>.</p>';
57
- }
58
-
59
-
60
- function antispam_settings() {
61
- $antispam_stats = get_option('antispam_stats', array());
62
- $blocked_total = $antispam_stats['blocked_total'];
63
- if (empty($blocked_total)) {
64
- $blocked_total = 0;
65
- }
66
- ?>
67
- <div class="wrap">
68
-
69
- <h2><span class="dashicons dashicons-admin-generic"></span> Anti-spam</h2>
70
-
71
- <div class="antispam-panel-info">
72
- <p style="margin: 0;">
73
- <span class="dashicons dashicons-chart-bar"></span>
74
- <strong><?php echo $blocked_total; ?></strong> spam comments were blocked by <a href="https://wordpress.org/plugins/anti-spam/" target="_blank">Anti-spam</a> plugin so far.
75
- Upgrade to <strong><a href="http://codecanyon.net/item/antispam-pro/6491169?ref=webvitalii" target="_blank">Anti-spam Pro</a></strong> for advanced protection.
76
- </p>
77
- </div>
78
-
79
- <form method="post" action="options.php">
80
- <?php settings_fields('antispam_settings_group'); ?>
81
- <div class="antispam-group-automatic">
82
- <?php do_settings_sections('antispam_automatic_page'); ?>
83
- </div>
84
- <?php submit_button(); ?>
85
- </form>
86
-
87
- </div>
88
- <?php
89
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
anti-spam.php CHANGED
@@ -1,94 +1,152 @@
1
  <?php
2
  /*
3
- Plugin Name: Anti-spam
4
  Plugin URI: http://wordpress.org/plugins/anti-spam/
5
  Description: No spam in comments. No captcha.
6
- Version: 5.5
7
- Author: webvitaly
8
  Text Domain: anti-spam
9
- Author URI: http://web-profile.net/wordpress/plugins/
10
  License: GPLv3
11
  */
12
 
13
- if ( ! defined( 'ABSPATH' ) ) { // Avoid direct calls to this file and prevent full path disclosure
 
14
  exit;
15
  }
16
 
17
- define('ANTISPAM_PLUGIN_VERSION', '5.5');
 
 
 
 
 
 
 
 
 
 
 
18
 
19
- include('anti-spam-functions.php');
20
- include('anti-spam-settings.php');
21
- include('anti-spam-info.php');
 
 
 
 
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
- function antispam_enqueue_script() {
25
- global $withcomments; // WP flag to show comments on all pages
26
- if ((is_singular() || $withcomments) && comments_open()) { // load script only for pages with comments form
27
- wp_enqueue_script('anti-spam-script', plugins_url('/js/anti-spam-5.5.js', __FILE__), null, null, true);
28
- }
29
- }
30
- add_action('wp_enqueue_scripts', 'antispam_enqueue_script');
31
-
32
-
33
- function antispam_form_part() {
34
- $rn = "\r\n"; // .chr(13).chr(10)
35
-
36
- if ( ! is_user_logged_in()) { // add anti-spam fields only for not logged in users
37
- echo $rn.'<!-- Anti-spam plugin v.'.ANTISPAM_PLUGIN_VERSION.' wordpress.org/plugins/anti-spam/ -->'.$rn;
38
- echo ' <p class="antispam-group antispam-group-q" style="clear: both;">
39
- <label>Current ye@r <span class="required">*</span></label>
40
- <input type="hidden" name="antspm-a" class="antispam-control antispam-control-a" value="'.date('Y').'" />
41
- <input type="text" name="antspm-q" class="antispam-control antispam-control-q" value="'.ANTISPAM_PLUGIN_VERSION.'" autocomplete="off" />
42
- </p>'.$rn; // question (hidden with js)
43
- echo ' <p class="antispam-group antispam-group-e" style="display: none;">
44
- <label>Leave this field empty</label>
45
- <input type="text" name="antspm-e-email-url-website" class="antispam-control antispam-control-e" value="" autocomplete="off" />
46
- </p>'.$rn; // empty field (hidden with css); trap for spammers because many bots will try to put email or url here
47
- }
48
- }
49
- add_action('comment_form', 'antispam_form_part'); // add anti-spam inputs to the comment form
50
-
51
-
52
- function antispam_check_comment($commentdata) {
53
- $antispam_settings = antispam_get_settings();
54
-
55
- extract($commentdata);
56
-
57
- if ( ! is_user_logged_in() && $comment_type != 'pingback' && $comment_type != 'trackback') { // logged in user is not a spammer
58
- if( antispam_check_for_spam() ) {
59
- if( $antispam_settings['save_spam_comments'] ) {
60
- antispam_store_comment($commentdata);
61
- }
62
- antispam_counter_stats();
63
- wp_die('Comment is a spam.'); // die - do not send comment and show error message
64
- }
65
- }
66
-
67
- if ($comment_type == 'trackback') {
68
- if( $antispam_settings['save_spam_comments'] ) {
69
- antispam_store_comment($commentdata);
70
- }
71
- antispam_counter_stats();
72
- wp_die('Trackbacks are disabled.'); // die - do not send trackback and show error message
73
- }
74
-
75
- return $commentdata; // if comment does not looks like spam
76
- }
77
 
78
- if ( ! is_admin()) { // without this check it is not possible to add comment in admin section
79
- add_filter('preprocess_comment', 'antispam_check_comment', 1);
 
 
 
 
80
  }
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
- function antispam_plugin_meta($links, $file) { // add some links to plugin meta row
84
- if ( $file == plugin_basename( __FILE__ ) ) {
85
- $row_meta = array(
86
- 'support' => '<a href="http://web-profile.net/wordpress/plugins/anti-spam/" target="_blank">' . __( 'Anti-spam', 'anti-spam' ) . '</a>',
87
- 'donate' => '<a href="http://web-profile.net/donate/" target="_blank">' . __( 'Donate', 'anti-spam' ) . '</a>',
88
- 'upgrage' => '<a href="http://codecanyon.net/item/antispam-pro/6491169?ref=webvitalii" target="_blank">' . __( 'Anti-spam Pro', 'anti-spam' ) . '</a>'
89
- );
90
- $links = array_merge( $links, $row_meta );
91
- }
92
- return (array) $links;
93
  }
94
- add_filter('plugin_row_meta', 'antispam_plugin_meta', 10, 2);
1
  <?php
2
  /*
3
+ Plugin Name: Anti-Spam
4
  Plugin URI: http://wordpress.org/plugins/anti-spam/
5
  Description: No spam in comments. No captcha.
6
+ Version: 6.5.1
7
+ Author: CreativeMotion
8
  Text Domain: anti-spam
9
+ Author URI: https://cm-wp.com/
10
  License: GPLv3
11
  */
12
 
13
+ // Exit if accessed directly
14
+ if ( ! defined( 'ABSPATH' ) ) {
15
  exit;
16
  }
17
 
18
+ /**
19
+ * Developers who contributions in the development plugin:
20
+ *
21
+ * Alexander Kovalev
22
+ * ---------------------------------------------------------------------------------
23
+ * Full plugin development.
24
+ *
25
+ * Email: alex.kovalevv@gmail.com
26
+ * Personal card: https://alexkovalevv.github.io
27
+ * Personal repo: https://github.com/alexkovalevv
28
+ * ---------------------------------------------------------------------------------
29
+ */
30
 
31
+ /**
32
+ * -----------------------------------------------------------------------------
33
+ * CHECK REQUIREMENTS
34
+ * Check compatibility with php and wp version of the user's site. As well as checking
35
+ * compatibility with other plugins from Webcraftic.
36
+ * -----------------------------------------------------------------------------
37
+ */
38
 
39
+ require_once( dirname( __FILE__ ) . '/libs/factory/core/includes/class-factory-requirements.php' );
40
+
41
+ // @formatter:off
42
+ $cm_antspam_plugin_info = array(
43
+ 'prefix' => 'wantispam_',
44
+ 'plugin_name' => 'wantispam',
45
+ 'plugin_title' => __( 'Anti-Spam', 'anti-spam' ),
46
+
47
+ // PLUGIN SUPPORT
48
+ 'support_details' => array(
49
+ 'url' => 'https://anti-spam.space',
50
+ 'pages_map' => array(
51
+ 'support' => 'support', // {site}/support
52
+ 'docs' => 'docs' // {site}/docs
53
+ )
54
+ ),
55
+
56
+ // PLUGIN PREMIUM SETTINGS
57
+ 'has_premium' => true,
58
+ 'license_settings' => array(
59
+ 'provider' => 'freemius',
60
+ 'slug' => 'antispam-premium',
61
+ 'plugin_id' => '5079',
62
+ 'public_key' => 'pk_98a99846a14067246257d4f43c04a',
63
+ 'price' => 15,
64
+ 'has_updates' => true,
65
+ 'updates_settings' => array(
66
+ 'maybe_rollback' => true,
67
+ 'rollback_settings' => array(
68
+ 'prev_stable_version' => '0.0.0'
69
+ )
70
+ )
71
+ ),
72
+
73
+ // PLUGIN ADVERTS
74
+ 'render_adverts' => true,
75
+ 'adverts_settings' => array(
76
+ 'dashboard_widget' => true, // show dashboard widget (default: false)
77
+ 'right_sidebar' => true, // show adverts sidebar (default: false)
78
+ 'notice' => true, // show notice message (default: false)
79
+ ),
80
+
81
+ // FRAMEWORK MODULES
82
+ 'load_factory_modules' => array(
83
+ array( 'libs/factory/bootstrap', 'factory_bootstrap_425', 'admin' ),
84
+ array( 'libs/factory/forms', 'factory_forms_422', 'admin' ),
85
+ array( 'libs/factory/pages', 'factory_pages_424', 'admin' ),
86
+ array( 'libs/factory/clearfy', 'factory_clearfy_216', 'all' ),
87
+ array( 'libs/factory/freemius', 'factory_freemius_112', 'all')
88
+ )
89
+ );
90
+
91
+ $cm_antspam_compatibility = new Wbcr_Factory424_Requirements( __FILE__, array_merge( $cm_antspam_plugin_info, array(
92
+ 'plugin_already_activate' => defined( 'WANTISPAM_PLUGIN_ACTIVE' ),
93
+ 'required_php_version' => '5.4',
94
+ 'required_wp_version' => '4.2.0',
95
+ 'required_clearfy_check_component' => false
96
+ ) ) );
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
+ /**
100
+ * If the plugin is compatible, then it will continue its work, otherwise it will be stopped,
101
+ * and the user will throw a warning.
102
+ */
103
+ if ( ! $cm_antspam_compatibility->check() ) {
104
+ return;
105
  }
106
 
107
+ /**
108
+ * -----------------------------------------------------------------------------
109
+ * CONSTANTS
110
+ * Install frequently used constants and constants for debugging, which will be
111
+ * removed after compiling the plugin.
112
+ * -----------------------------------------------------------------------------
113
+ */
114
+
115
+ // This plugin is activated
116
+ define( 'WANTISPAM_PLUGIN_ACTIVE', true );
117
+ define( 'WANTISPAM_PLUGIN_VERSION', $cm_antspam_compatibility->get_plugin_version() );
118
+ define( 'WANTISPAM_PLUGIN_DIR', dirname( __FILE__ ) );
119
+ define( 'WANTISPAM_PLUGIN_BASE', plugin_basename( __FILE__ ) );
120
+ define( 'WANTISPAM_PLUGIN_URL', plugins_url( null, __FILE__ ) );
121
+
122
+
123
+
124
+
125
+ /**
126
+ * -----------------------------------------------------------------------------
127
+ * PLUGIN INIT
128
+ * -----------------------------------------------------------------------------
129
+ */
130
+
131
+ require_once( WANTISPAM_PLUGIN_DIR . '/libs/factory/core/boot.php' );
132
+ require_once( WANTISPAM_PLUGIN_DIR . '/includes/functions.php' );
133
+ require_once( WANTISPAM_PLUGIN_DIR . '/includes/class-anti-spam-plugin.php' );
134
+
135
+ try {
136
+ new \WBCR\Antispam\Plugin( __FILE__, array_merge( $cm_antspam_plugin_info, array(
137
+ 'plugin_version' => WANTISPAM_PLUGIN_VERSION,
138
+ 'plugin_text_domain' => $cm_antspam_compatibility->get_text_domain(),
139
+ ) ) );
140
+ } catch( Exception $e ) {
141
+ // Plugin wasn't initialized due to an error
142
+ define( 'WANTISPAM_PLUGIN_THROW_ERROR', true );
143
+
144
+ $cm_antspam_plugin_error_func = function () use ( $e ) {
145
+ $error = sprintf( "The %s plugin has stopped. <b>Error:</b> %s Code: %s", 'CreativeMotion Antispam', $e->getMessage(), $e->getCode() );
146
+ echo '<div class="notice notice-error"><p>' . $error . '</p></div>';
147
+ };
148
 
149
+ add_action( 'admin_notices', $cm_antspam_plugin_error_func );
150
+ add_action( 'network_admin_notices', $cm_antspam_plugin_error_func );
 
 
 
 
 
 
 
 
151
  }
152
+ // @formatter:on
{js → assets/js}/anti-spam-5.5.js RENAMED
@@ -15,6 +15,11 @@ wordpress.org/plugins/anti-spam/
15
  current_year = new Date().getFullYear(),
16
  dynamic_control;
17
 
 
 
 
 
 
18
  elements = document.querySelectorAll('.antispam-group');
19
  len = elements.length;
20
  for (i = 0; i < len; i++) { // hide inputs from users
15
  current_year = new Date().getFullYear(),
16
  dynamic_control;
17
 
18
+ elements = document.querySelectorAll('.antispam-control-j');
19
+ for (i = 0; i < elements.length; i++) {
20
+ elements[i].value = 'on';
21
+ }
22
+
23
  elements = document.querySelectorAll('.antispam-group');
24
  len = elements.length;
25
  for (i = 0; i < len; i++) { // hide inputs from users
anti-spam-info.php → includes/__anti-spam-info.php RENAMED
File without changes
includes/class-anti-spam-plugin.php ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Antispam;
4
+
5
+ // Exit if accessed directly
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ /**
11
+ * Transliteration core class
12
+ *
13
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
14
+ * @copyright (c) 20.10.2019, Webcraftic
15
+ */
16
+ class Plugin extends \Wbcr_Factory424_Plugin {
17
+
18
+ /**
19
+ * Number of comments that will be sent for verification
20
+ *
21
+ * @since 6.2
22
+ */
23
+ const COUNT_TO_CHECK = 30;
24
+
25
+ /**
26
+ * @see self::app()
27
+ * @var \Wbcr_Factory424_Plugin
28
+ */
29
+ private static $app;
30
+
31
+ /**
32
+ * @since 6.0
33
+ * @var array
34
+ */
35
+ private $plugin_data;
36
+
37
+ /**
38
+ * Конструктор
39
+ *
40
+ * Применяет конструктор родительского класса и записывает экземпляр текущего класса в свойство $app.
41
+ * Подробнее о свойстве $app см. self::app()
42
+ *
43
+ * @since 6.0
44
+ *
45
+ * @param string $plugin_path
46
+ * @param array $data
47
+ *
48
+ * @throws \Exception
49
+ */
50
+ public function __construct( $plugin_path, $data ) {
51
+ parent::__construct( $plugin_path, $data );
52
+
53
+ self::$app = $this;
54
+ $this->plugin_data = $data;
55
+
56
+ $this->global_scripts();
57
+
58
+ if ( is_admin() ) {
59
+ $this->admin_scripts();
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Статический метод для быстрого доступа к интерфейсу плагина.
65
+ *
66
+ * Позволяет разработчику глобально получить доступ к экземпляру класса плагина в любом месте
67
+ * плагина, но при этом разработчик не может вносить изменения в основной класс плагина.
68
+ *
69
+ * Используется для получения настроек плагина, информации о плагине, для доступа к вспомогательным
70
+ * классам.
71
+ *
72
+ * @since 6.0
73
+ * @return \Wbcr_Factory424_Plugin|\WBCR\Antispam\Plugin
74
+ */
75
+ public static function app() {
76
+ return self::$app;
77
+ }
78
+
79
+ /**
80
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
81
+ * @since 6.0
82
+ */
83
+ protected function init_activation() {
84
+ include_once( WANTISPAM_PLUGIN_DIR . '/admin/class-activation.php' );
85
+ self::app()->registerActivation( "\WBCR\Antispam\Activation" );
86
+ }
87
+
88
+ /**
89
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
90
+ * @since 6.0
91
+ * @throws \Exception
92
+ */
93
+ private function register_pages() {
94
+ if ( ! defined( 'WANTISPAMP_PLUGIN_ACTIVE' ) ) {
95
+ self::app()->registerPage( '\WBCR\Antispam\Page\Settings', WANTISPAM_PLUGIN_DIR . '/admin/pages/class-pages-settings.php' );
96
+ }
97
+
98
+ self::app()->registerPage( '\WBCR\Antispam\Page\License', WANTISPAM_PLUGIN_DIR . '/admin/pages/class-pages-license.php' );
99
+ self::app()->registerPage( '\WBCR\Antispam\Page\Logs', WANTISPAM_PLUGIN_DIR . '/admin/pages/class-pages-logs.php' );
100
+ self::app()->registerPage( '\WBCR\Antispam\Page\About', WANTISPAM_PLUGIN_DIR . '/admin/pages/class-pages-about.php' );
101
+ }
102
+
103
+ /**
104
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
105
+ * @since 6.0
106
+ * @throws \Exception
107
+ */
108
+ private function admin_scripts() {
109
+ require_once( WANTISPAM_PLUGIN_DIR . '/admin/boot.php' );
110
+
111
+ $this->init_activation();
112
+
113
+ add_action( 'plugins_loaded', function () {
114
+ $this->register_pages();
115
+ }, 30 );
116
+
117
+ if ( ! wp_doing_ajax() || ! isset( $_REQUEST['action'] ) ) {
118
+ return;
119
+ }
120
+
121
+ switch ( $_REQUEST['action'] ) {
122
+
123
+ case 'wlogger-logs-cleanup':
124
+ require_once( WANTISPAM_PLUGIN_DIR . '/admin/ajax/logs.php' );
125
+ break;
126
+ }
127
+ }
128
+
129
+ /**
130
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
131
+ * @since 6.0
132
+ */
133
+ private function global_scripts() {
134
+ require_once( WANTISPAM_PLUGIN_DIR . '/includes/logger/class-logger-writter.php' );
135
+ require_once( WANTISPAM_PLUGIN_DIR . '/includes/class-protector.php' );
136
+
137
+ new \WBCR\Logger\Writter();
138
+ }
139
+ }
140
+
includes/class-protector.php ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Antispam;
4
+
5
+ /**
6
+ * The class implement some protections ways against spam
7
+ *
8
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
9
+ *
10
+ * @copyright (c) 2018 Webraftic Ltd
11
+ */
12
+ class Protector {
13
+
14
+ public function __construct() {
15
+ add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_script' ] );
16
+ add_action( 'comment_form', [ $this, 'form_part' ] ); // add anti-spam inputs to the comment form
17
+
18
+ if ( \WBCR\Antispam\Plugin::app()->premium->is_activate() ) {
19
+ add_action( 'comment_form_after', [ $this, 'display_comment_form_privacy_notice' ] );
20
+ }
21
+
22
+ if ( ! is_admin() ) { // without this check it is not possible to add comment in admin section
23
+ add_filter( 'preprocess_comment', [ $this, 'check_comment' ], 1 );
24
+ }
25
+ }
26
+
27
+ public function enqueue_script() {
28
+ global $withcomments; // WP flag to show comments on all pages
29
+ if ( ( is_singular() || $withcomments ) && comments_open() ) { // load script only for pages with comments form
30
+ wp_enqueue_script( 'anti-spam-script', WANTISPAM_PLUGIN_URL . '/assets/js/anti-spam-5.5.js', null, null, true );
31
+ }
32
+ }
33
+
34
+ public function form_part() {
35
+ $rn = "\r\n"; // .chr(13).chr(10)
36
+
37
+ echo $rn . '<!-- Anti-spam plugin wordpress.org/plugins/anti-spam/ -->' . $rn;
38
+ echo '
39
+ <input type="hidden" name="antspm-j" class="antispam-control antispam-control-j" value="off" />
40
+ ' . $rn; // trap for simple bots that do not emulate the browser
41
+
42
+ echo '
43
+ <input type="hidden" name="antspm-t" class="antispam-control antispam-control-t" value="' . time() . '" />
44
+ ' . $rn; // Start time of form filling
45
+
46
+ if ( ! is_user_logged_in() ) { // add anti-spam fields only for not logged in users
47
+
48
+ echo ' <p class="antispam-group antispam-group-q" style="clear: both;">
49
+ <label>Current ye@r <span class="required">*</span></label>
50
+ <input type="hidden" name="antspm-a" class="antispam-control antispam-control-a" value="' . date( 'Y' ) . '" />
51
+ <input type="text" name="antspm-q" class="antispam-control antispam-control-q" value="' . \WBCR\Antispam\Plugin::app()->getPluginVersion() . '" autocomplete="off" />
52
+ </p>' . $rn; // question (hidden with js)
53
+ echo ' <p class="antispam-group antispam-group-e" style="display: none;">
54
+ <label>Leave this field empty</label>
55
+ <input type="text" name="antspm-e-email-url-website" class="antispam-control antispam-control-e" value="" autocomplete="off" />
56
+ </p>' . $rn; // empty field (hidden with css); trap for spammers because many bots will try to put email or url here
57
+ }
58
+ }
59
+
60
+ public function check_comment( $commentdata ) {
61
+ $save_spam_comments = \WBCR\Antispam\Plugin::app()->getPopulateOption( 'save_spam_comments', true );
62
+
63
+ $comment_type = isset( $commentdata['comment_type'] ) ? $commentdata['comment_type'] : null;
64
+
65
+ if ( ! is_user_logged_in() && $comment_type != 'pingback' && $comment_type != 'trackback' ) { // logged in user is not a spammer
66
+ if ( $this->check_for_spam() ) {
67
+ if ( $save_spam_comments ) {
68
+ $this->store_comment( $commentdata );
69
+ }
70
+ $this->counter_stats();
71
+ wp_die( 'Comment is a spam.' ); // die - do not send comment and show error message
72
+ }
73
+ }
74
+
75
+ if ( $comment_type == 'trackback' ) {
76
+ if ( $save_spam_comments ) {
77
+ $this->store_comment( $commentdata );
78
+ }
79
+ $this->counter_stats();
80
+ wp_die( 'Trackbacks are disabled.' ); // die - do not send trackback and show error message
81
+ }
82
+
83
+ return $commentdata; // if comment does not looks like spam
84
+ }
85
+
86
+ public function counter_stats() {
87
+ $antispam_stats = get_option( 'antispam_stats', [] );
88
+ if ( array_key_exists( 'blocked_total', $antispam_stats ) ) {
89
+ $antispam_stats['blocked_total'] ++;
90
+ } else {
91
+ $antispam_stats['blocked_total'] = 1;
92
+ }
93
+ update_option( 'antispam_stats', $antispam_stats );
94
+ }
95
+
96
+ public function check_for_spam() {
97
+ $spam_flag = false;
98
+
99
+ $antspm_q = '';
100
+ if ( isset( $_POST['antspm-q'] ) ) {
101
+ $antspm_q = trim( $_POST['antspm-q'] );
102
+ }
103
+
104
+ $antspm_d = '';
105
+ if ( isset( $_POST['antspm-d'] ) ) {
106
+ $antspm_d = trim( $_POST['antspm-d'] );
107
+ }
108
+
109
+ $antspm_e = '';
110
+ if ( isset( $_POST['antspm-e-email-url-website'] ) ) {
111
+ $antspm_e = trim( $_POST['antspm-e-email-url-website'] );
112
+ }
113
+
114
+ if ( $antspm_q != date( 'Y' ) ) { // year-answer is wrong - it is spam
115
+ if ( $antspm_d != date( 'Y' ) ) { // extra js-only check: there is no js added input - it is spam
116
+ $spam_flag = true;
117
+ }
118
+ }
119
+
120
+ if ( ! empty( $antspm_e ) ) { // trap field is not empty - it is spam
121
+ $spam_flag = true;
122
+ }
123
+
124
+ return $spam_flag;
125
+ }
126
+
127
+ public function store_comment( $commentdata ) {
128
+ global $wpdb;
129
+
130
+ if ( isset( $commentdata['user_ID'] ) ) {
131
+ $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
132
+ }
133
+
134
+ $prefiltered_user_id = ( isset( $commentdata['user_id'] ) ) ? (int) $commentdata['user_id'] : 0;
135
+
136
+ $commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
137
+ if ( isset( $commentdata['user_ID'] ) && $prefiltered_user_id !== (int) $commentdata['user_ID'] ) {
138
+ $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
139
+ } else if ( isset( $commentdata['user_id'] ) ) {
140
+ $commentdata['user_id'] = (int) $commentdata['user_id'];
141
+ }
142
+
143
+ $commentdata['comment_parent'] = isset( $commentdata['comment_parent'] ) ? absint( $commentdata['comment_parent'] ) : 0;
144
+ $parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status( $commentdata['comment_parent'] ) : '';
145
+ $commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;
146
+
147
+ if ( ! isset( $commentdata['comment_author_IP'] ) ) {
148
+ $commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
149
+ }
150
+ $commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '', $commentdata['comment_author_IP'] );
151
+
152
+ if ( ! isset( $commentdata['comment_agent'] ) ) {
153
+ $commentdata['comment_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
154
+ }
155
+ $commentdata['comment_agent'] = substr( $commentdata['comment_agent'], 0, 254 );
156
+
157
+ if ( empty( $commentdata['comment_date'] ) ) {
158
+ $commentdata['comment_date'] = current_time( 'mysql' );
159
+ }
160
+
161
+ if ( empty( $commentdata['comment_date_gmt'] ) ) {
162
+ $commentdata['comment_date_gmt'] = current_time( 'mysql', 1 );
163
+ }
164
+
165
+ $commentdata = wp_filter_comment( $commentdata );
166
+
167
+ $commentdata['comment_approved'] = wp_allow_comment( $commentdata );
168
+ if ( is_wp_error( $commentdata['comment_approved'] ) ) {
169
+ return $commentdata['comment_approved'];
170
+ }
171
+
172
+ $comment_ID = wp_insert_comment( $commentdata );
173
+ if ( ! $comment_ID ) {
174
+ $fields = [ 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' ];
175
+
176
+ foreach ( $fields as $field ) {
177
+ if ( isset( $commentdata[ $field ] ) ) {
178
+ $commentdata[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->comments, $field, $commentdata[ $field ] );
179
+ }
180
+ }
181
+
182
+ $commentdata = wp_filter_comment( $commentdata );
183
+
184
+ $commentdata['comment_approved'] = wp_allow_comment( $commentdata );
185
+ if ( is_wp_error( $commentdata['comment_approved'] ) ) {
186
+ return $commentdata['comment_approved'];
187
+ }
188
+
189
+ $comment_ID = wp_insert_comment( $commentdata );
190
+ if ( ! $comment_ID ) {
191
+ return false;
192
+ }
193
+ }
194
+
195
+ wp_set_comment_status( $comment_ID, 'spam' );
196
+ }
197
+
198
+ /**
199
+ * Controls the display of a privacy related notice underneath the comment form using the `akismet_comment_form_privacy_notice` option and filter respectively.
200
+ * Default is top not display the notice, leaving the choice to site admins, or integrators.
201
+ */
202
+ public function display_comment_form_privacy_notice() {
203
+ if ( ! \WBCR\Antispam\Plugin::app()->getPopulateOption( 'comment_form_privacy_notice' ) ) {
204
+ return;
205
+ }
206
+ echo '<p class="wantispam-comment-form-privacy-notice" style="margin-top:10px;">' . sprintf( __( 'This site uses Antispam to reduce spam. <a href="%s" target="_blank" rel="nofollow noopener">Learn how your comment data is processed</a>.', 'anti-spam' ), 'https://anti-spam.space/antispam-privacy/' ) . '</p>';
207
+ }
208
+ }
209
+
210
+ new \WBCR\Antispam\Protector();
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
219
+
220
+
includes/functions.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, Alexander Kovalev <alex.kovalevv@gmail.com>
5
+ * @copyright (c) 12.12.2019, Webcraftic
6
+ * @version 1.0
7
+ */
8
+
9
+ /**
10
+ * Should show a page about the plugin or not.
11
+ *
12
+ * @return bool
13
+ */
14
+ function wantispam_is_need_show_about_page() {
15
+ if ( \WBCR\Antispam\Plugin::app()->isNetworkActive() ) {
16
+ $need_show_about = (int) get_site_option( \WBCR\Antispam\Plugin::app()->getOptionName( 'what_is_new_64' ) );
17
+ } else {
18
+ $need_show_about = (int) get_option( \WBCR\Antispam\Plugin::app()->getOptionName( 'what_is_new_64' ) );
19
+ }
20
+
21
+ $is_ajax = wantispam_doing_ajax();
22
+ $is_cron = wantispam_doing_cron();
23
+ $is_rest = wantispam_doing_rest_api();
24
+
25
+ if ( $need_show_about && ! $is_ajax && ! $is_cron && ! $is_rest ) {
26
+ return true;
27
+ }
28
+
29
+ return false;
30
+ }
31
+
32
+ /**
33
+ * Checks if the current request is a WP REST API request.
34
+ *
35
+ * Case #1: After WP_REST_Request initialisation
36
+ * Case #2: Support "plain" permalink settings
37
+ * Case #3: URL Path begins with wp-json/ (your REST prefix)
38
+ * Also supports WP installations in subfolders
39
+ *
40
+ * @author matzeeable https://wordpress.stackexchange.com/questions/221202/does-something-like-is-rest-exist
41
+ * @since 2.1.0
42
+ * @return boolean
43
+ */
44
+ function wantispam_doing_rest_api() {
45
+ $prefix = rest_get_url_prefix();
46
+ $rest_route = \WBCR\Antispam\Plugin::app()->request->get( 'rest_route', null );
47
+ if ( defined( 'REST_REQUEST' ) && REST_REQUEST // (#1)
48
+ || ! is_null( $rest_route ) // (#2)
49
+ && strpos( trim( $rest_route, '\\/' ), $prefix, 0 ) === 0 ) {
50
+ return true;
51
+ }
52
+
53
+ // (#3)
54
+ $rest_url = wp_parse_url( site_url( $prefix ) );
55
+ $current_url = wp_parse_url( add_query_arg( [] ) );
56
+
57
+ return strpos( $current_url['path'], $rest_url['path'], 0 ) === 0;
58
+ }
59
+
60
+ /**
61
+ * @since 2.1.0
62
+ * @return bool
63
+ */
64
+ function wantispam_doing_ajax() {
65
+ if ( function_exists( 'wp_doing_ajax' ) ) {
66
+ return wp_doing_ajax();
67
+ }
68
+
69
+ return defined( 'DOING_AJAX' ) && DOING_AJAX;
70
+ }
71
+
72
+ /**
73
+ * @since 2.1.0
74
+ * @return bool
75
+ */
76
+ function wantispam_doing_cron() {
77
+ if ( function_exists( 'wp_doing_cron' ) ) {
78
+ return wp_doing_cron();
79
+ }
80
+
81
+ return defined( 'DOING_CRON' ) && DOING_CRON;
82
+ }
includes/logger/assets/css/base.css ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .wbcr-factory-page-group-header {
2
+ margin-top: 0;
3
+ }
4
+ .wbcr-factory-page-group-body {
5
+ padding: 20px;
6
+ }
7
+ .wlogger-viewer {
8
+ width: 100%;
9
+ height: 650px;
10
+ font-family: "Menlo", "DejaVu Sans Mono", "Liberation Mono", "Consolas", "Ubuntu Mono", "Courier New", "andale mono", "lucida console", monospace;
11
+ font-size: 12px;
12
+ word-break: break-all;
13
+ word-wrap: break-word;
14
+ overflow: auto;
15
+ -ms-overflow-style: scrollbar;
16
+ background-color: #e9e9e9;
17
+ padding: 8px;
18
+ border: 1px solid #cfcfcf;
19
+ }
20
+ /*# sourceMappingURL=base.css.map */
includes/logger/assets/css/base.css.map ADDED
@@ -0,0 +1 @@
 
1
+ {"version":3,"sources":["base.less"],"names":[],"mappings":"AAAA;EACE,aAAA;;AAGF;EACE,aAAA;;AAGF;EACE,WAAA;EACA,aAAA;EACA,aAAa,SAAS,oBAAoB,mBAAmB,YAAY,eAAe,eAAe,eAAe,2BAAtH;EACA,eAAA;EACA,qBAAA;EACA,qBAAA;EACA,cAAA;EACA,6BAAA;EACA,yBAAA;EACA,YAAA;EACA,yBAAA","file":"base.css"}
includes/logger/assets/css/base.less ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .wbcr-factory-page-group-header {
2
+ margin-top: 0;
3
+ }
4
+
5
+ .wbcr-factory-page-group-body {
6
+ padding: 20px;
7
+ }
8
+
9
+ .wlogger-viewer {
10
+ width: 100%;
11
+ height: 650px;
12
+ font-family: "Menlo", "DejaVu Sans Mono", "Liberation Mono", "Consolas", "Ubuntu Mono", "Courier New", "andale mono", "lucida console", monospace;
13
+ font-size: 12px;
14
+ word-break: break-all;
15
+ word-wrap: break-word;
16
+ overflow: auto;
17
+ -ms-overflow-style: scrollbar;
18
+ background-color: #e9e9e9;
19
+ padding: 8px;
20
+ border: 1px solid #cfcfcf;
21
+ }
includes/logger/assets/js/base.js ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Base scripts for log reader
3
+ *
4
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
5
+ * @copyright (c) 29.10.2019, Webcraftic
6
+ * @version 1.0
7
+ */
8
+
9
+
10
+ (function($) {
11
+ 'use strict';
12
+
13
+ $('.js-wlogger-export-debug-report').click(function() {
14
+ var btn = $(this),
15
+ currentBtnText = btn.html();
16
+
17
+ btn.text(btn.data('working'));
18
+
19
+ $.ajax({
20
+ url: ajaxurl,
21
+ method: 'post',
22
+ data: {
23
+ action: 'wlogger-logs-cleanup',
24
+ nonce: btn.data('nonce')
25
+ },
26
+ success: function(data) {
27
+ btn.html(currentBtnText);
28
+
29
+ jQuery('#js-wlogger-viewer').html('');
30
+ jQuery('#js-wlogger-size').text('0B');
31
+ jQuery.wbcr_factory_clearfy_216.app.showNotice(data.message, data.type);
32
+ },
33
+ error: function(jqXHR, textStatus, errorThrown) {
34
+ jQuery.wbcr_factory_clearfy_216.app.showNotice('Error: ' + errorThrown + ', status: ' + textStatus, 'danger');
35
+ btn.html(currentBtnText);
36
+ }
37
+ });
38
+ });
39
+ })(jQuery);
includes/logger/class-logger-export.php ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Logger;
4
+
5
+ /**
6
+ * Prepares export files, ZIPs them and allows to download the package.
7
+ *
8
+ * Usage example:
9
+ *
10
+ * ```php
11
+ * $export_model = new WIO_Log_Export('package.zip');
12
+ * $prepared = $export_model->prepare();
13
+ *
14
+ * if($prepared) {
15
+ * // start streaming ZIP archive to be downloaded
16
+ * $export_model->download();
17
+ * }
18
+ * ```
19
+ *
20
+ * @author Alexander Teshabaev <sasha.tesh@gmail.com>
21
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
22
+ */
23
+ class Export {
24
+
25
+ /**
26
+ * @var string Default archive name on download. {datetime} will be replaced with current m-d-Y.
27
+ */
28
+ private $_archive_name = 'wio_export-{datetime}.zip';
29
+
30
+ /**
31
+ * @var string|null Archive save path.
32
+ */
33
+ private $_archive_save_path;
34
+
35
+ /**
36
+ * WIO_Log_Export constructor.
37
+ *
38
+ * @param null $archive_name
39
+ */
40
+ public function __construct( $archive_name = null ) {
41
+ if ( $archive_name !== null ) {
42
+ $this->_archive_name = $archive_name;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Prepare export.
48
+ *
49
+ * @return bool
50
+ */
51
+ public function prepare() {
52
+
53
+ if ( ! class_exists( '\ZipArchive' ) ) {
54
+ \WBCR\Logger\Writter::error( 'App does not have \ZipArchive class available. It is not possible to prepare export' );
55
+
56
+ return false;
57
+ }
58
+
59
+ $zip = new \ZipArchive();
60
+
61
+ $log_base_dir = \WBCR\Logger\Writter::get_base_dir();
62
+
63
+ if ( $log_base_dir === false ) {
64
+ \WBCR\Logger\Writter::error( sprintf( 'Failed to get log path %s', $log_base_dir ) );
65
+
66
+ return false;
67
+ }
68
+
69
+ $uploads = wp_get_upload_dir();
70
+
71
+ if ( isset( $uploads['error'] ) && $uploads['error'] !== false ) {
72
+ \WBCR\Logger\Writter::error( 'Unable to get save path of ZIP archive from wp_get_upload_dir()' );
73
+
74
+ return false;
75
+ }
76
+
77
+ $save_base_path = isset( $uploads['basedir'] ) ? $uploads['basedir'] : null;
78
+ $zip_archive_name = sprintf( "antispam_debug_report-%s.zip", date( 'Y-m-d' ) );
79
+ $zip_save_path = $save_base_path . DIRECTORY_SEPARATOR . $zip_archive_name;
80
+
81
+ if ( ! $zip->open( $zip_save_path, \ZipArchive::CREATE ) ) {
82
+ \WBCR\Logger\Writter::error( sprintf( 'Failed to created ZIP archive in path %s. Skipping export...', $zip_save_path ) );
83
+
84
+ return false;
85
+ }
86
+
87
+ // Add all logs to ZIP archive
88
+ $glob_path = $log_base_dir . '*.log';
89
+ $log_files = glob( $glob_path );
90
+
91
+ if ( ! empty( $log_files ) ) {
92
+ foreach ( $log_files as $file ) {
93
+ if ( ! $zip->addFile( $file, wp_basename( $file ) ) ) {
94
+ \WBCR\Logger\Writter::error( sprintf( 'Failed to add %s to %s archive. Skipping it.', $file, $zip_save_path ) );
95
+
96
+ return false;
97
+ }
98
+ }
99
+ }
100
+
101
+ $system_info = $this->prepare_system_info();
102
+
103
+ if ( ! empty( $system_info ) ) {
104
+ $system_info_file_name = 'wrio-system-info.txt';
105
+ $system_info_path = $save_base_path . DIRECTORY_SEPARATOR . $system_info_file_name;
106
+ if ( false !== @file_put_contents( $system_info_path, $system_info ) ) {
107
+ if ( ! $zip->addFile( $system_info_path, $system_info_file_name ) ) {
108
+ \WBCR\Logger\Writter::error( sprintf( 'Failed to add %s to %s archive. Skipping it.', $system_info_file_name, $system_info_path ) );
109
+ }
110
+ } else {
111
+ \WBCR\Logger\Writter::error( sprintf( 'Failed to save %s in %s', $system_info_file_name, $zip_save_path ) );
112
+ }
113
+ }
114
+
115
+ if ( ! $zip->close() ) {
116
+ \WBCR\Logger\Writter::error( sprintf( 'Failed to close ZIP archive %s for unknown reason. \ZipArchive::close() failed.' ) );
117
+ }
118
+
119
+ if ( isset( $system_info_path ) ) {
120
+ // Clean-up as this is just temp file
121
+ @unlink( $system_info_path );
122
+ }
123
+
124
+ $this->_archive_save_path = $zip_save_path;
125
+
126
+ return true;
127
+ }
128
+
129
+ /**
130
+ * Prepare generic system information, such as WordPress, PHP version, active plugins, loaded extenstions, etc.
131
+ *
132
+ * @return string
133
+ */
134
+ public function prepare_system_info() {
135
+
136
+ $space = PHP_EOL . PHP_EOL;
137
+ $nl = PHP_EOL;
138
+
139
+ $report = 'Plugin version: ' . \WBCR\Antispam\Plugin::app()->getPluginVersion() . $nl;
140
+
141
+ global $wp_version;
142
+
143
+ $report .= 'WordPress Version: ' . $wp_version . $nl;
144
+ $report .= 'PHP Version: ' . PHP_VERSION . $nl;
145
+ $report .= 'Locale: ' . get_locale() . $nl;
146
+ $report .= 'HTTP Accept: ' . ( isset( $_SERVER['HTTP_ACCEPT'] ) ? $_SERVER['HTTP_ACCEPT'] : '*empty*' ) . $nl;
147
+ $report .= 'HTTP User Agent: ' . ( isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '*empty*' ) . $nl;
148
+ $report .= 'Server software: ' . ( isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '*empty*' ) . $nl;
149
+
150
+ $report .= $space;
151
+
152
+ $active_plugins = get_option( 'active_plugins', null );
153
+
154
+ if ( $active_plugins !== null ) {
155
+
156
+ $prepared_plugins = [];
157
+
158
+ $all_plugins = get_plugins();
159
+
160
+ foreach ( $active_plugins as $active_plugin ) {
161
+ if ( isset( $all_plugins[ $active_plugin ] ) ) {
162
+ $advanced_info = $all_plugins[ $active_plugin ];
163
+ $name = isset( $advanced_info['Name'] ) ? $advanced_info['Name'] : '';
164
+ $version = isset( $advanced_info['Version'] ) ? $advanced_info['Version'] : '';
165
+ $prepared_plugins[] = sprintf( "%s (%s)", $name, $version );
166
+ }
167
+ }
168
+
169
+ $report .= 'Active plugins:' . PHP_EOL;
170
+ $report .= implode( PHP_EOL, $prepared_plugins );
171
+ }
172
+
173
+ if ( function_exists( 'get_loaded_extensions' ) ) {
174
+
175
+ $report .= PHP_EOL . PHP_EOL;
176
+ $report .= 'Active extensions: ' . $nl;
177
+ $report .= implode( ', ', get_loaded_extensions() );
178
+ }
179
+
180
+ $report .= $space;
181
+
182
+ $report .= 'Generated at: ' . date( 'c' );
183
+
184
+ return $report;
185
+ }
186
+
187
+ /**
188
+ * Download saved ZIP archive.
189
+ *
190
+ * It sets download headers, which streams content of the ZIP archive.
191
+ *
192
+ * Additionally it cleans-up by deleting the archive if `$and_delete` set to true.
193
+ *
194
+ * @param bool $should_clean_up Allows to delete temp ZIP archive if required.
195
+ *
196
+ * @return bool
197
+ */
198
+ public function download( $should_clean_up = true ) {
199
+
200
+ $zip_save_path = $this->_archive_save_path;
201
+
202
+ if ( empty( $zip_save_path ) ) {
203
+ return false;
204
+ }
205
+
206
+ $zip_content = @file_get_contents( $zip_save_path );
207
+
208
+ if ( $zip_save_path === false ) {
209
+ \WBCR\Logger\Writter::error( sprintf( 'Failed to get ZIP %s content as file_get_contents() returned false', $zip_save_path ) );
210
+
211
+ return false;
212
+ }
213
+
214
+ if ( $should_clean_up ) {
215
+ // Delete as ZIP is just for temporary usage
216
+ @unlink( $zip_save_path );
217
+ }
218
+
219
+ $archive_name = str_replace( '{datetime}', date( 'c' ), $this->_archive_name );
220
+
221
+ // Set-up headers to download export file
222
+ header( 'Content-Description: File Transfer' );
223
+ header( 'Content-Type: application/zip' );
224
+ header( 'Content-Disposition: attachment; filename=' . $archive_name );
225
+ header( 'Content-Transfer-Encoding: binary' );
226
+ header( 'Connection: Keep-Alive' );
227
+ header( 'Expires: 0' );
228
+ header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
229
+ header( 'Pragma: public' );
230
+ header( 'Content-Length: ' . strlen( $zip_content ) );
231
+
232
+ echo $zip_content;
233
+ exit();
234
+ }
235
+
236
+ /**
237
+ * Get temporary stored archive path.
238
+ *
239
+ * @return string
240
+ */
241
+ public function get_temp_archive_path() {
242
+ return $this->_archive_save_path;
243
+ }
244
+
245
+ /**
246
+ * Delete temporary stored archive path.
247
+ *
248
+ * @return bool
249
+ */
250
+ public function delete_temp_archive() {
251
+ return @unlink( $this->get_temp_archive_path() );
252
+ }
253
+ }
includes/logger/class-logger-reader.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Logger;
4
+
5
+ // Exit if accessed directly
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ /**
11
+ * Helps to convert log file content into easy-to-read HTML.
12
+ *
13
+ * Usage example:
14
+ *
15
+ * ```php
16
+ * $log_content = WIO_Log_Reader::prettify();
17
+ * ```
18
+ *
19
+ * @author Alexander Teshabaev <sasha.tesh@gmail.com>
20
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
21
+ * @see \WBCR\Logger\Writter::get_content() for method which is used to get file content.
22
+ *
23
+ * @see \WBCR\Logger\Writter for further information about logging.
24
+ */
25
+ class Reader {
26
+
27
+ /**
28
+ * Prettify log content.
29
+ *
30
+ * @return bool|mixed|string
31
+ * @see \WBCR\Logger\Writter::get_content()
32
+ */
33
+ public static function prettify() {
34
+ $content = \WBCR\Logger\Writter::get_content();
35
+
36
+ $search = [
37
+ "\r\n",
38
+ "\n\r",
39
+ "\025",
40
+ "\n",
41
+ "\r",
42
+ "\t",
43
+ ];
44
+
45
+ $replacement = [
46
+ '<br>',
47
+ '<br>',
48
+ '<br>',
49
+ '<br>',
50
+ '<br>',
51
+ str_repeat( '&nbsp;', 4 ),
52
+ ];
53
+
54
+ $content = str_replace( $search, $replacement, $content );
55
+
56
+ $color_map = [
57
+ \WBCR\Logger\Writter::LEVEL_INFO => [ 'color' => '#fff', 'bg' => '#52d130' ],
58
+ \WBCR\Logger\Writter::LEVEL_ERROR => [ 'color' => '#fff', 'bg' => '#ff5e5e' ],
59
+ \WBCR\Logger\Writter::LEVEL_WARNING => [ 'color' => '#fff', 'bg' => '#ef910a' ],
60
+ \WBCR\Logger\Writter::LEVEL_DEBUG => [ 'color' => '#fff', 'bg' => '#8f8d8b' ],
61
+ ];
62
+
63
+ /**
64
+ * Highlight log levels
65
+ */
66
+ foreach ( $color_map as $level => $item ) {
67
+ $content = preg_replace( "/\[([\d\w]{6})\]\[($level)\]/", "[$1][<span style=\"color: {$item['color']};background-color: {$item['bg']}\">$2</span>]", $content );
68
+ }
69
+
70
+ return $content;
71
+ }
72
+ }
includes/logger/class-logger-writter.php ADDED
@@ -0,0 +1,402 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Logger;
4
+
5
+ // Exit if accessed directly
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ /**
11
+ * Adds ability to log application message into .log file.
12
+ *
13
+ * It has 4 core levels:
14
+ * - info: generic log message
15
+ * - warning: log possible exceptions states or unusual
16
+ * - error: log error-related logs
17
+ * - debug: log stack traces, big outputs, etc.
18
+ *
19
+ * Each level has its constant. See LEVEL_* prefix.
20
+ *
21
+ * Additionally it is possible to configure flush interval and file name.
22
+ *
23
+ * Usage examples:
24
+ *
25
+ * ```php
26
+ * // Info message level
27
+ * \WBCR\Logger\Writter::info('Some generic message, good to know');
28
+ *
29
+ * // Warning message level
30
+ * \WBCR\Logger\Writter::warning('Something does not work or unusual');
31
+ *
32
+ * // Error message level
33
+ * \WBCR\Logger\Writter::error('Something critical happened');
34
+ *
35
+ * // Debug message level
36
+ * \WBCR\Logger\Writter::debug('Some message used for debug purposed. Could be stack trace.');
37
+ * ```
38
+ *
39
+ * @author Alexander Teshabaev <sasha.tesh@gmail.com>
40
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
41
+ * @copyright (c) 2018, Webcraftic
42
+ * @version 1.0
43
+ */
44
+ class Writter {
45
+
46
+ const LEVEL_INFO = 'info';
47
+ const LEVEL_WARNING = 'warning';
48
+ const LEVEL_ERROR = 'error';
49
+ const LEVEL_DEBUG = 'debug';
50
+
51
+ /**
52
+ * @var null|string Request hash.
53
+ */
54
+ public static $hash = null;
55
+
56
+ /**
57
+ * @var null|string Directory where log file would be saved.
58
+ */
59
+ public static $dir = null;
60
+
61
+ /**
62
+ * @var string File log name where logs would be flushed.
63
+ */
64
+ public static $file = 'app.log';
65
+
66
+ /**
67
+ * @var int Flushing interval. When $_logs would reach this number of items they would be flushed to log file.
68
+ */
69
+ public static $flush_interval = 1000;
70
+
71
+ /**
72
+ * @var int Rotate size in bytes. Default: 5 Mb.
73
+ */
74
+ public static $rotate_size = 5000000;
75
+
76
+ /**
77
+ * @var int Number of rotated files. When size of $rotate_size matches current file, current file would be rotated.
78
+ * For example, there are 3 files, current file became size of $rotate_size, third file would be deleted, two first
79
+ * shifted and empty one created.
80
+ */
81
+ public static $rotate_limit = 3;
82
+
83
+ /**
84
+ * @var array List of logs to be dumped.
85
+ */
86
+ private static $_logs = [];
87
+
88
+ /**
89
+ * WRIOP_BackupLogger constructor.
90
+ */
91
+ public function __construct() {
92
+ $this->init();
93
+ }
94
+
95
+ /**
96
+ * Initiate object.
97
+ */
98
+ public function init() {
99
+ static::$hash = substr( uniqid(), 0, 6 );
100
+
101
+ add_action( 'shutdown', [ '\WBCR\Logger\Writter', 'flush' ], 9999, 0 );
102
+ }
103
+
104
+ /**
105
+ * Get directory to save collected logs.
106
+ *
107
+ * In addition to that, it manages log rotation so that it does not become too big.
108
+ *
109
+ * @return string|false false on failure, string on success.
110
+ */
111
+ public static function get_dir() {
112
+
113
+ $base_dir = static::get_base_dir();
114
+
115
+ if ( $base_dir === null ) {
116
+ return false;
117
+ }
118
+
119
+ $root_file = $base_dir . static::$file;
120
+
121
+ // Check whether file exists and it exceeds rotate size, then should rotate it copy
122
+ if ( file_exists( $root_file ) && filesize( $root_file ) >= self::$rotate_size ) {
123
+ $name_split = explode( '.', self::$file );
124
+
125
+ if ( ! empty( $name_split ) && isset( $name_split[0] ) ) {
126
+ $name_split[0] = trim( $name_split[0] );
127
+
128
+ for ( $i = self::$rotate_limit; $i >= 0; $i -- ) {
129
+
130
+ $cur_name = $name_split[0] . $i;
131
+ $cur_path = $base_dir . $cur_name . '.log';
132
+
133
+ $next_path = $i !== 0 ? $base_dir . $name_split[0] . ( $i - 1 ) . '.log' : $root_file;
134
+
135
+ if ( file_exists( $next_path ) ) {
136
+ @copy( $next_path, $cur_path );
137
+ }
138
+ }
139
+ }
140
+
141
+ // Need to empty root file as it was supposed to be copied to next rotation :)
142
+ @file_put_contents( $root_file, '' );
143
+ }
144
+
145
+ return $root_file;
146
+ }
147
+
148
+ /**
149
+ * Get base directory, location of logs.
150
+ *
151
+ * @return null|string NULL in case of failure, string on success.
152
+ */
153
+ public static function get_base_dir() {
154
+ $wp_upload_dir = wp_upload_dir();
155
+
156
+ if ( isset( $wp_upload_dir['error'] ) && $wp_upload_dir['error'] !== false ) {
157
+ return null;
158
+ }
159
+
160
+ $base_path = wp_normalize_path( trailingslashit( $wp_upload_dir['basedir'] ) . 'wantispam-logger/' );
161
+
162
+ $folders = glob( $base_path . 'logs-*' );
163
+
164
+ if ( ! empty( $folders ) ) {
165
+ $exploded_path = explode( '/', trim( $folders[0] ) );
166
+ $selected_logs_folder = array_pop( $exploded_path );
167
+ } else {
168
+ if ( function_exists( 'wp_salt' ) ) {
169
+ $hash = md5( wp_salt() );
170
+ } else {
171
+ $hash = md5( AUTH_KEY );
172
+ }
173
+
174
+ $selected_logs_folder = 'logs-' . $hash;
175
+ }
176
+
177
+ $path = $base_path . $selected_logs_folder . '/';
178
+
179
+ if ( ! file_exists( $path ) ) {
180
+ @mkdir( $path, 0755, true );
181
+ }
182
+
183
+ // Create .htaccess file to protect log files
184
+ $htaccess_path = $path . '.htaccess';
185
+
186
+ if ( ! file_exists( $htaccess_path ) ) {
187
+ $htaccess_content = 'deny from all';
188
+ @file_put_contents( $htaccess_path, $htaccess_content );
189
+ }
190
+
191
+ // Create index.htm file in case .htaccess is not support as a fallback
192
+ $index_path = $path . 'index.html';
193
+
194
+ if ( ! file_exists( $index_path ) ) {
195
+ @file_put_contents( $index_path, '' );
196
+ }
197
+
198
+ return $path;
199
+ }
200
+
201
+ /**
202
+ * Get all available log paths.
203
+ *
204
+ * @return array|bool
205
+ */
206
+ public static function get_all() {
207
+ $base_dir = static::get_base_dir();
208
+
209
+ if ( $base_dir === null ) {
210
+ return false;
211
+ }
212
+
213
+ $glob_path = $base_dir . '*.log';
214
+
215
+ return glob( $glob_path );
216
+ }
217
+
218
+ /**
219
+ * Get total log size in bytes.
220
+ *
221
+ * @return int
222
+ * @see size_format() for formatting.
223
+ */
224
+ public static function get_total_size() {
225
+ $logs = static::get_all();
226
+ $bytes = 0;
227
+
228
+ if ( empty( $logs ) ) {
229
+ return $bytes;
230
+ }
231
+
232
+ foreach ( $logs as $log ) {
233
+ $bytes += @filesize( $log );
234
+ }
235
+
236
+ return $bytes;
237
+ }
238
+
239
+ /**
240
+ * Empty all log files and deleted rotated ones.
241
+ *
242
+ * @return bool
243
+ */
244
+ public static function clean_up() {
245
+
246
+ $base_dir = static::get_base_dir();
247
+
248
+ if ( $base_dir === null ) {
249
+ return false;
250
+ }
251
+
252
+ $glob_path = $base_dir . '*.log';
253
+
254
+ $files = glob( $glob_path );
255
+
256
+ if ( $files === false ) {
257
+ return false;
258
+ }
259
+
260
+ if ( empty( $files ) ) {
261
+ return true;
262
+ }
263
+
264
+ $unlinked_count = 0;
265
+
266
+ foreach ( $files as $file ) {
267
+ if ( @unlink( $file ) ) {
268
+ $unlinked_count ++;
269
+ }
270
+ }
271
+
272
+ return count( $files ) === $unlinked_count;
273
+ }
274
+
275
+ /**
276
+ * Flush all messages.
277
+ *
278
+ * @return bool
279
+ */
280
+ public static function flush() {
281
+
282
+ $messages = self::$_logs;
283
+
284
+ self::$_logs = [];
285
+
286
+ if ( empty( $messages ) ) {
287
+ return false;
288
+ }
289
+
290
+ $file_content = PHP_EOL . implode( PHP_EOL, $messages );
291
+ $is_put = @file_put_contents( self::get_dir(), $file_content, FILE_APPEND );
292
+
293
+ return $is_put !== false;
294
+ }
295
+
296
+ /**
297
+ *
298
+ * @param $level
299
+ * @param $message
300
+ *
301
+ * @return string
302
+ */
303
+ public static function get_format( $level, $message ) {
304
+
305
+ // Example: 2019-01-14 12:03:29.0593 [127.0.0.1][ee6a12][info] {message}
306
+ $template = '%s [%s][%s][%s] %s';
307
+
308
+ $ip = isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '';
309
+
310
+ return sprintf( $template, date( 'd-m-Y H:i:s' ) . '.' . microtime( true ), $ip, static::$hash, $level, $message );
311
+ }
312
+
313
+ /**
314
+ * Get latest file content.
315
+ *
316
+ * @return bool|string
317
+ */
318
+ public static function get_content() {
319
+ if ( ! file_exists( static::get_dir() ) ) {
320
+ return null;
321
+ }
322
+
323
+ return @file_get_contents( static::get_dir() );
324
+ }
325
+
326
+ /**
327
+ * Add new log message.
328
+ *
329
+ * @param string $level Log level.
330
+ * @param string $message Message to log.
331
+ *
332
+ * @return bool
333
+ */
334
+ public static function add( $level, $message ) {
335
+
336
+ //if ( $level === self::LEVEL_DEBUG ) {
337
+ //$log_debug = defined( 'WP_DEBUG' ) && WP_DEBUG;
338
+
339
+ //if ( ! $log_debug ) {
340
+ //return false;
341
+ //}
342
+ //}
343
+
344
+ static::$_logs[] = static::get_format( $level, $message );
345
+
346
+ if ( count( static::$_logs ) >= static::$flush_interval ) {
347
+ static::flush();
348
+ }
349
+
350
+ return true;
351
+ }
352
+
353
+ /**
354
+ * Add info level log.
355
+ *
356
+ * @param string $message Message to log.
357
+ */
358
+ public static function info( $message ) {
359
+ static::add( self::LEVEL_INFO, $message );
360
+ }
361
+
362
+ /**
363
+ * Add error level log.
364
+ *
365
+ * @param string $message Message to log.
366
+ */
367
+ public static function error( $message ) {
368
+ static::add( self::LEVEL_ERROR, $message );
369
+ }
370
+
371
+ /**
372
+ * Add debug level log.
373
+ *
374
+ * @param $message
375
+ */
376
+ public static function debug( $message ) {
377
+ static::add( self::LEVEL_DEBUG, $message );
378
+ }
379
+
380
+ /**
381
+ * Add warning level log.
382
+ *
383
+ * @param string $message Message to log.
384
+ */
385
+ public static function warning( $message ) {
386
+ static::add( self::LEVEL_WARNING, $message );
387
+ }
388
+
389
+ /**
390
+ * Writes information to log about memory.
391
+ *
392
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
393
+ * @since 1.3.6
394
+ */
395
+ public static function memory_usage() {
396
+ $memory_avail = ini_get( 'memory_limit' );
397
+ $memory_used = number_format( memory_get_usage( true ) / ( 1024 * 1024 ), 2 );
398
+ $memory_peak = number_format( memory_get_peak_usage( true ) / ( 1024 * 1024 ), 2 );
399
+
400
+ static::info( sprintf( "Memory: %s (avail) / %sM (used) / %sM (peak)", $memory_avail, $memory_used, $memory_peak ) );
401
+ }
402
+ }
index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
- // Silence is golden.
1
+ <?php
2
+ // Silence is golden.
libs/factory/bootstrap/assets/css-min/bootstrap.accordion.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .factory-accordion{margin:0 0 30px;border-top:1px solid #DDD;border-right:1px solid #DDD;border-left:1px solid #DDD;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.factory-bootstrap-425 .factory-accordion>h3{border-bottom:1px solid #DDD;cursor:pointer;padding:8px 15px;margin:0}.factory-bootstrap-425 .factory-accordion>div{display:none;margin:0;border-bottom:1px solid #DDD}.factory-bootstrap-425 .factory-accordion-item{display:none}.factory-bootstrap-425 .inner-factory-accordion-item{padding:10px 0}.factory-bootstrap-425 .factory-accordion>h3.active:hover{cursor:default}
libs/factory/bootstrap/assets/css-min/bootstrap.blue.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .btn-primary{background:#e1a948;border-color:#d39323;color:#fff;-webkit-box-shadow:inset 0 1px 0 #ecc88a,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #ecc88a,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:focus,.factory-bootstrap-425 .btn-primary:hover{background:#db9825;border-color:#bd831f;color:#fff;-webkit-box-shadow:inset 0 1px 0 #e8be74,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #e8be74,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:active{background:#db9825;border-color:#bd831f;color:#fff;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}.factory-bootstrap-425 .btn-primary:disabled,.factory-bootstrap-425 .btn-primary[disabled]{color:#d1cdc7!important;background:#db9825!important;border-color:#bd831f!important;text-shadow:none!important}.factory-bootstrap-425 .btn-group .btn.active.value{background-color:#e1a948;-webkit-box-shadow:inset 0 1px 2px #d39323;box-shadow:inset 0 1px 2px #d39323;border-top:1px solid #d39323;border-bottom:1px solid #d39323;border-left:1px solid #d39323}.factory-bootstrap-425 .pagination>.active>a,.factory-bootstrap-425 .pagination>.active>a:focus,.factory-bootstrap-425 .pagination>.active>a:hover,.factory-bootstrap-425 .pagination>.active>span,.factory-bootstrap-425 .pagination>.active>span:focus,.factory-bootstrap-425 .pagination>.active>span:hover{background-color:#e1a948;border-color:#d39323}
libs/factory/bootstrap/assets/css-min/bootstrap.coffee.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .btn-primary{background:#c7a589;border-color:#b78a66;color:#fff;-webkit-box-shadow:inset 0 1px 0 #e0cdbd,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #e0cdbd,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:focus,.factory-bootstrap-425 .btn-primary:hover{background:#ba906d;border-color:#ae7d55;color:#fff;-webkit-box-shadow:inset 0 1px 0 #d7bfac,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #d7bfac,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:active{background:#ba906d;border-color:#ae7d55;color:#fff;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}.factory-bootstrap-425 .btn-primary:disabled,.factory-bootstrap-425 .btn-primary[disabled]{color:#d1cbc7!important;background:#ba906d!important;border-color:#ae7d55!important;text-shadow:none!important}.factory-bootstrap-425 .btn-group .btn.active.value{background-color:#c7a589;-webkit-box-shadow:inset 0 1px 2px #b78a66;box-shadow:inset 0 1px 2px #b78a66;border-top:1px solid #b78a66;border-bottom:1px solid #b78a66;border-left:1px solid #b78a66}.factory-bootstrap-425 .pagination>.active>a,.factory-bootstrap-425 .pagination>.active>a:focus,.factory-bootstrap-425 .pagination>.active>a:hover,.factory-bootstrap-425 .pagination>.active>span,.factory-bootstrap-425 .pagination>.active>span:focus,.factory-bootstrap-425 .pagination>.active>span:hover{background-color:#c7a589;border-color:#b78a66}
libs/factory/bootstrap/assets/css-min/bootstrap.core.min.css ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 article,.factory-bootstrap-425 aside,.factory-bootstrap-425 details,.factory-bootstrap-425 figcaption,.factory-bootstrap-425 figure,.factory-bootstrap-425 footer,.factory-bootstrap-425 header,.factory-bootstrap-425 hgroup,.factory-bootstrap-425 main,.factory-bootstrap-425 nav,.factory-bootstrap-425 section,.factory-bootstrap-425 summary{display:block}.factory-bootstrap-425 audio,.factory-bootstrap-425 canvas,.factory-bootstrap-425 video{display:inline-block}.factory-bootstrap-425 audio:not([controls]){display:none;height:0}.factory-bootstrap-425 [hidden],.factory-bootstrap-425 template{display:none}.factory-bootstrap-425 body{margin:0}.factory-bootstrap-425 a{background:0 0}.factory-bootstrap-425 a:focus{outline:thin dotted}.factory-bootstrap-425 a:active,.factory-bootstrap-425 a:hover{outline:0}.factory-bootstrap-425 h1{margin:.67em 0}.factory-bootstrap-425 b,.factory-bootstrap-425 strong{font-weight:700}.factory-bootstrap-425 dfn{font-style:italic}.factory-bootstrap-425 hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}.factory-bootstrap-425 mark{color:#000;background:#ff0}.factory-bootstrap-425 code,.factory-bootstrap-425 kbd,.factory-bootstrap-425 pre,.factory-bootstrap-425 samp{font-size:1em}.factory-bootstrap-425 pre{white-space:pre-wrap}.factory-bootstrap-425 q{quotes:"\201C" "\201D" "\2018" "\2019"}.factory-bootstrap-425 sub,.factory-bootstrap-425 sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}.factory-bootstrap-425 sup{top:-.5em}.factory-bootstrap-425 sub{bottom:-.25em}.factory-bootstrap-425 img{border:0}.factory-bootstrap-425 svg:not(:root){overflow:hidden}.factory-bootstrap-425 figure{margin:0}.factory-bootstrap-425 button,.factory-bootstrap-425 input,.factory-bootstrap-425 select,.factory-bootstrap-425 textarea{margin:0}.factory-bootstrap-425 button,.factory-bootstrap-425 select{text-transform:none}.factory-bootstrap-425 select{padding-right:4px!important}.factory-bootstrap-425 button,.factory-bootstrap-425 input[type=reset],.factory-bootstrap-425 input[type=submit],html .factory-bootstrap-425 input[type=button]{cursor:pointer;-webkit-appearance:button}.factory-bootstrap-425 button[disabled],html .factory-bootstrap-425 input[disabled]{cursor:default}.factory-bootstrap-425 input[type=checkbox],.factory-bootstrap-425 input[type=radio]{padding:0;box-sizing:border-box}.factory-bootstrap-425 input[type=search]{-webkit-appearance:textfield}.factory-bootstrap-425 input[type=search]::-webkit-search-cancel-button,.factory-bootstrap-425 input[type=search]::-webkit-search-decoration{-webkit-appearance:none}.factory-bootstrap-425 button::-moz-focus-inner,.factory-bootstrap-425 input::-moz-focus-inner{padding:0;border:0}.factory-bootstrap-425 textarea{overflow:auto;vertical-align:top}.factory-bootstrap-425 table{border-collapse:collapse;border-spacing:0}@media print{.factory-bootstrap-425 *{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}.factory-bootstrap-425 a,.factory-bootstrap-425 a:visited{text-decoration:underline}.factory-bootstrap-425 a[href]:after{content:" (" attr(href) ")"}.factory-bootstrap-425 abbr[title]:after{content:" (" attr(title) ")"}.factory-bootstrap-425 a[href^="javascript:"]:after,.factory-bootstrap-425 a[href^="#"]:after{content:""}.factory-bootstrap-425 blockquote,.factory-bootstrap-425 pre{border:1px solid #999;page-break-inside:avoid}.factory-bootstrap-425 thead{display:table-header-group}.factory-bootstrap-425 img,.factory-bootstrap-425 tr{page-break-inside:avoid}.factory-bootstrap-425 img{max-width:100%!important}@page{margin:2cm .5cm}.factory-bootstrap-425 h2,.factory-bootstrap-425 h3,.factory-bootstrap-425 p{orphans:3;widows:3}.factory-bootstrap-425 h2,.factory-bootstrap-425 h3{page-break-after:avoid}.factory-bootstrap-425 select{background:#fff!important}.factory-bootstrap-425 .navbar{display:none}.factory-bootstrap-425 .table td,.factory-bootstrap-425 .table th{background-color:#fff!important}.factory-bootstrap-425 .btn>.caret,.factory-bootstrap-425 .dropup>.btn>.caret{border-top-color:#000!important}.factory-bootstrap-425 .label{border:1px solid #000}.factory-bootstrap-425 .table{border-collapse:collapse!important}.factory-bootstrap-425 .table-bordered td,.factory-bootstrap-425 .table-bordered th{border:1px solid #ddd!important}}.factory-bootstrap-425 *,.factory-bootstrap-425 :after,.factory-bootstrap-425 :before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html .factory-bootstrap-425{-webkit-tap-highlight-color:rgba(0,0,0,0)}.factory-bootstrap-425 body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}.factory-bootstrap-425 button,.factory-bootstrap-425 input,.factory-bootstrap-425 select,.factory-bootstrap-425 textarea{font-family:inherit;font-size:inherit;line-height:inherit}.factory-bootstrap-425 img{vertical-align:middle}.factory-bootstrap-425 .img-responsive{display:block;height:auto;max-width:100%}.factory-bootstrap-425 .img-rounded{border-radius:6px}.factory-bootstrap-425 .img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.factory-bootstrap-425 .img-circle{border-radius:50%}.factory-bootstrap-425 hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.factory-bootstrap-425 .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.factory-bootstrap-425 .h1,.factory-bootstrap-425 .h2,.factory-bootstrap-425 .h3,.factory-bootstrap-425 .h4,.factory-bootstrap-425 .h5,.factory-bootstrap-425 .h6,.factory-bootstrap-425 h1,.factory-bootstrap-425 h2,.factory-bootstrap-425 h3,.factory-bootstrap-425 h4,.factory-bootstrap-425 h5,.factory-bootstrap-425 h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}.factory-bootstrap-425 .h1 .small,.factory-bootstrap-425 .h1 small,.factory-bootstrap-425 .h2 .small,.factory-bootstrap-425 .h2 small,.factory-bootstrap-425 .h3 .small,.factory-bootstrap-425 .h3 small,.factory-bootstrap-425 .h4 .small,.factory-bootstrap-425 .h4 small,.factory-bootstrap-425 .h5 .small,.factory-bootstrap-425 .h5 small,.factory-bootstrap-425 .h6 .small,.factory-bootstrap-425 .h6 small,.factory-bootstrap-425 h1 .small,.factory-bootstrap-425 h1 small,.factory-bootstrap-425 h2 .small,.factory-bootstrap-425 h2 small,.factory-bootstrap-425 h3 .small,.factory-bootstrap-425 h3 small,.factory-bootstrap-425 h4 .small,.factory-bootstrap-425 h4 small,.factory-bootstrap-425 h5 .small,.factory-bootstrap-425 h5 small,.factory-bootstrap-425 h6 .small,.factory-bootstrap-425 h6 small{font-weight:400;line-height:1;color:#999}.factory-bootstrap-425 h1,.factory-bootstrap-425 h2,.factory-bootstrap-425 h3{margin-top:20px;margin-bottom:10px}.factory-bootstrap-425 h1 .small,.factory-bootstrap-425 h1 small,.factory-bootstrap-425 h2 .small,.factory-bootstrap-425 h2 small,.factory-bootstrap-425 h3 .small,.factory-bootstrap-425 h3 small{font-size:65%}.factory-bootstrap-425 h4,.factory-bootstrap-425 h5,.factory-bootstrap-425 h6{margin-top:10px;margin-bottom:10px}.factory-bootstrap-425 h4 .small,.factory-bootstrap-425 h4 small,.factory-bootstrap-425 h5 .small,.factory-bootstrap-425 h5 small,.factory-bootstrap-425 h6 .small,.factory-bootstrap-425 h6 small{font-size:75%}.factory-bootstrap-425 .h1,.factory-bootstrap-425 h1{font-size:36px}.factory-bootstrap-425 .h2,.factory-bootstrap-425 h2{font-size:30px}.factory-bootstrap-425 .h3,.factory-bootstrap-425 h3{font-size:24px}.factory-bootstrap-425 .h4,.factory-bootstrap-425 h4{font-size:18px}.factory-bootstrap-425 .h5,.factory-bootstrap-425 h5{font-size:14px}.factory-bootstrap-425 .h6,.factory-bootstrap-425 h6{font-size:12px}.factory-bootstrap-425 p{margin:0 0 10px}.factory-bootstrap-425 .lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.factory-bootstrap-425 .small,.factory-bootstrap-425 small{font-size:85%}.factory-bootstrap-425 cite{font-style:normal}.factory-bootstrap-425 .text-muted{color:#999}.factory-bootstrap-425 .text-primary{color:#428bca}.factory-bootstrap-425 .text-primary:hover{color:#3071a9}.factory-bootstrap-425 .text-warning{color:#8a6d3b}.factory-bootstrap-425 .text-warning:hover{color:#66512c}.factory-bootstrap-425 .text-danger{color:#a94442}.factory-bootstrap-425 .text-danger:hover{color:#843534}.factory-bootstrap-425 .text-success{color:#3c763d}.factory-bootstrap-425 .text-success:hover{color:#2b542c}.factory-bootstrap-425 .text-info{color:#31708f}.factory-bootstrap-425 .text-info:hover{color:#245269}.factory-bootstrap-425 .text-left{text-align:left}.factory-bootstrap-425 .text-right{text-align:right}.factory-bootstrap-425 .text-center{text-align:center}.factory-bootstrap-425 .page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}.factory-bootstrap-425 ol,.factory-bootstrap-425 ul{margin-top:0;margin-bottom:10px}.factory-bootstrap-425 ol ol,.factory-bootstrap-425 ol ul,.factory-bootstrap-425 ul ol,.factory-bootstrap-425 ul ul{margin-bottom:0}.factory-bootstrap-425 .list-inline,.factory-bootstrap-425 .list-unstyled{padding-left:0;list-style:none}.factory-bootstrap-425 .list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.factory-bootstrap-425 .list-inline>li:first-child{padding-left:0}.factory-bootstrap-425 dl{margin-top:0;margin-bottom:20px}.factory-bootstrap-425 dd,.factory-bootstrap-425 dt{line-height:1.428571429}.factory-bootstrap-425 dt{font-weight:700}.factory-bootstrap-425 dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:after,.dl-horizontal dd:before{display:table;content:" "}.dl-horizontal dd:after{clear:both}}.factory-bootstrap-425 abbr[data-original-title],.factory-bootstrap-425 abbr[title]{cursor:help;border-bottom:1px dotted #999}.factory-bootstrap-425 .initialism{font-size:90%;text-transform:uppercase}.factory-bootstrap-425 blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}.factory-bootstrap-425 blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}.factory-bootstrap-425 blockquote p:last-child{margin-bottom:0}.factory-bootstrap-425 blockquote .small,.factory-bootstrap-425 blockquote small{display:block;line-height:1.428571429;color:#999}.factory-bootstrap-425 blockquote .small:before,.factory-bootstrap-425 blockquote small:before{content:'\2014 \00A0'}.factory-bootstrap-425 blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}.factory-bootstrap-425 blockquote.pull-right .small,.factory-bootstrap-425 blockquote.pull-right p,.factory-bootstrap-425 blockquote.pull-right small{text-align:right}.factory-bootstrap-425 blockquote.pull-right .small:before,.factory-bootstrap-425 blockquote.pull-right small:before{content:''}.factory-bootstrap-425 blockquote.pull-right .small:after,.factory-bootstrap-425 blockquote.pull-right small:after{content:'\00A0 \2014'}.factory-bootstrap-425 blockquote:after,.factory-bootstrap-425 blockquote:before{content:""}.factory-bootstrap-425 address{margin-bottom:20px;font-style:normal;line-height:1.428571429}.factory-bootstrap-425 code,.factory-bootstrap-425 kbd,.factory-bootstrap-425 pre,.factory-bootstrap-425 samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}.factory-bootstrap-425 code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}.factory-bootstrap-425 pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}.factory-bootstrap-425 pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.factory-bootstrap-425 .pre-scrollable{max-height:340px;overflow-y:scroll}.factory-bootstrap-425 .container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.factory-bootstrap-425 .container:after,.factory-bootstrap-425 .container:before{display:table;content:" "}.factory-bootstrap-425 .container:after{clear:both}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.factory-bootstrap-425 .row{margin-right:-15px;margin-left:-15px}.factory-bootstrap-425 .row:after,.factory-bootstrap-425 .row:before{display:table;content:" "}.factory-bootstrap-425 .row:after{clear:both}.factory-bootstrap-425 .col-lg-1,.factory-bootstrap-425 .col-lg-10,.factory-bootstrap-425 .col-lg-11,.factory-bootstrap-425 .col-lg-12,.factory-bootstrap-425 .col-lg-2,.factory-bootstrap-425 .col-lg-3,.factory-bootstrap-425 .col-lg-4,.factory-bootstrap-425 .col-lg-5,.factory-bootstrap-425 .col-lg-6,.factory-bootstrap-425 .col-lg-7,.factory-bootstrap-425 .col-lg-8,.factory-bootstrap-425 .col-lg-9,.factory-bootstrap-425 .col-md-1,.factory-bootstrap-425 .col-md-10,.factory-bootstrap-425 .col-md-11,.factory-bootstrap-425 .col-md-12,.factory-bootstrap-425 .col-md-2,.factory-bootstrap-425 .col-md-3,.factory-bootstrap-425 .col-md-4,.factory-bootstrap-425 .col-md-5,.factory-bootstrap-425 .col-md-6,.factory-bootstrap-425 .col-md-7,.factory-bootstrap-425 .col-md-8,.factory-bootstrap-425 .col-md-9,.factory-bootstrap-425 .col-sm-1,.factory-bootstrap-425 .col-sm-10,.factory-bootstrap-425 .col-sm-11,.factory-bootstrap-425 .col-sm-12,.factory-bootstrap-425 .col-sm-2,.factory-bootstrap-425 .col-sm-3,.factory-bootstrap-425 .col-sm-4,.factory-bootstrap-425 .col-sm-5,.factory-bootstrap-425 .col-sm-6,.factory-bootstrap-425 .col-sm-7,.factory-bootstrap-425 .col-sm-8,.factory-bootstrap-425 .col-sm-9,.factory-bootstrap-425 .col-xs-1,.factory-bootstrap-425 .col-xs-10,.factory-bootstrap-425 .col-xs-11,.factory-bootstrap-425 .col-xs-12,.factory-bootstrap-425 .col-xs-2,.factory-bootstrap-425 .col-xs-3,.factory-bootstrap-425 .col-xs-4,.factory-bootstrap-425 .col-xs-5,.factory-bootstrap-425 .col-xs-6,.factory-bootstrap-425 .col-xs-7,.factory-bootstrap-425 .col-xs-8,.factory-bootstrap-425 .col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.factory-bootstrap-425 .col-xs-1,.factory-bootstrap-425 .col-xs-10,.factory-bootstrap-425 .col-xs-11,.factory-bootstrap-425 .col-xs-12,.factory-bootstrap-425 .col-xs-2,.factory-bootstrap-425 .col-xs-3,.factory-bootstrap-425 .col-xs-4,.factory-bootstrap-425 .col-xs-5,.factory-bootstrap-425 .col-xs-6,.factory-bootstrap-425 .col-xs-7,.factory-bootstrap-425 .col-xs-8,.factory-bootstrap-425 .col-xs-9{float:left}.factory-bootstrap-425 .col-xs-12{width:100%}.factory-bootstrap-425 .col-xs-11{width:91.66666666666666%}.factory-bootstrap-425 .col-xs-10{width:83.33333333333334%}.factory-bootstrap-425 .col-xs-9{width:75%}.factory-bootstrap-425 .col-xs-8{width:66.66666666666666%}.factory-bootstrap-425 .col-xs-7{width:58.333333333333336%}.factory-bootstrap-425 .col-xs-6{width:50%}.factory-bootstrap-425 .col-xs-5{width:41.66666666666667%}.factory-bootstrap-425 .col-xs-4{width:33.33333333333333%}.factory-bootstrap-425 .col-xs-3{width:25%}.factory-bootstrap-425 .col-xs-2{width:16.666666666666664%}.factory-bootstrap-425 .col-xs-1{width:8.333333333333332%}.factory-bootstrap-425 .col-xs-pull-12{right:100%}.factory-bootstrap-425 .col-xs-pull-11{right:91.66666666666666%}.factory-bootstrap-425 .col-xs-pull-10{right:83.33333333333334%}.factory-bootstrap-425 .col-xs-pull-9{right:75%}.factory-bootstrap-425 .col-xs-pull-8{right:66.66666666666666%}.factory-bootstrap-425 .col-xs-pull-7{right:58.333333333333336%}.factory-bootstrap-425 .col-xs-pull-6{right:50%}.factory-bootstrap-425 .col-xs-pull-5{right:41.66666666666667%}.factory-bootstrap-425 .col-xs-pull-4{right:33.33333333333333%}.factory-bootstrap-425 .col-xs-pull-3{right:25%}.factory-bootstrap-425 .col-xs-pull-2{right:16.666666666666664%}.factory-bootstrap-425 .col-xs-pull-1{right:8.333333333333332%}.factory-bootstrap-425 .col-xs-pull-0{right:0}.factory-bootstrap-425 .col-xs-push-12{left:100%}.factory-bootstrap-425 .col-xs-push-11{left:91.66666666666666%}.factory-bootstrap-425 .col-xs-push-10{left:83.33333333333334%}.factory-bootstrap-425 .col-xs-push-9{left:75%}.factory-bootstrap-425 .col-xs-push-8{left:66.66666666666666%}.factory-bootstrap-425 .col-xs-push-7{left:58.333333333333336%}.factory-bootstrap-425 .col-xs-push-6{left:50%}.factory-bootstrap-425 .col-xs-push-5{left:41.66666666666667%}.factory-bootstrap-425 .col-xs-push-4{left:33.33333333333333%}.factory-bootstrap-425 .col-xs-push-3{left:25%}.factory-bootstrap-425 .col-xs-push-2{left:16.666666666666664%}.factory-bootstrap-425 .col-xs-push-1{left:8.333333333333332%}.factory-bootstrap-425 .col-xs-push-0{left:0}.factory-bootstrap-425 .col-xs-offset-12{margin-left:100%}.factory-bootstrap-425 .col-xs-offset-11{margin-left:91.66666666666666%}.factory-bootstrap-425 .col-xs-offset-10{margin-left:83.33333333333334%}.factory-bootstrap-425 .col-xs-offset-9{margin-left:75%}.factory-bootstrap-425 .col-xs-offset-8{margin-left:66.66666666666666%}.factory-bootstrap-425 .col-xs-offset-7{margin-left:58.333333333333336%}.factory-bootstrap-425 .col-xs-offset-6{margin-left:50%}.factory-bootstrap-425 .col-xs-offset-5{margin-left:41.66666666666667%}.factory-bootstrap-425 .col-xs-offset-4{margin-left:33.33333333333333%}.factory-bootstrap-425 .col-xs-offset-3{margin-left:25%}.factory-bootstrap-425 .col-xs-offset-2{margin-left:16.666666666666664%}.factory-bootstrap-425 .col-xs-offset-1{margin-left:8.333333333333332%}.factory-bootstrap-425 .col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}.factory-bootstrap-425 table{max-width:100%;background-color:transparent}.factory-bootstrap-425 th{text-align:left}.factory-bootstrap-425 .table{width:100%;margin-bottom:20px}.factory-bootstrap-425 .table>tbody>tr>td,.factory-bootstrap-425 .table>tbody>tr>th,.factory-bootstrap-425 .table>tfoot>tr>td,.factory-bootstrap-425 .table>tfoot>tr>th,.factory-bootstrap-425 .table>thead>tr>td,.factory-bootstrap-425 .table>thead>tr>th{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.factory-bootstrap-425 .table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.factory-bootstrap-425 .table>caption+thead>tr:first-child>td,.factory-bootstrap-425 .table>caption+thead>tr:first-child>th,.factory-bootstrap-425 .table>colgroup+thead>tr:first-child>td,.factory-bootstrap-425 .table>colgroup+thead>tr:first-child>th,.factory-bootstrap-425 .table>thead:first-child>tr:first-child>td,.factory-bootstrap-425 .table>thead:first-child>tr:first-child>th{border-top:0}.factory-bootstrap-425 .table>tbody+tbody{border-top:2px solid #ddd}.factory-bootstrap-425 .table .table{background-color:#fff}.factory-bootstrap-425 .table-condensed>tbody>tr>td,.factory-bootstrap-425 .table-condensed>tbody>tr>th,.factory-bootstrap-425 .table-condensed>tfoot>tr>td,.factory-bootstrap-425 .table-condensed>tfoot>tr>th,.factory-bootstrap-425 .table-condensed>thead>tr>td,.factory-bootstrap-425 .table-condensed>thead>tr>th{padding:5px}.factory-bootstrap-425 .table-bordered,.factory-bootstrap-425 .table-bordered>tbody>tr>td,.factory-bootstrap-425 .table-bordered>tbody>tr>th,.factory-bootstrap-425 .table-bordered>tfoot>tr>td,.factory-bootstrap-425 .table-bordered>tfoot>tr>th,.factory-bootstrap-425 .table-bordered>thead>tr>td,.factory-bootstrap-425 .table-bordered>thead>tr>th{border:1px solid #ddd}.factory-bootstrap-425 .table-bordered>thead>tr>td,.factory-bootstrap-425 .table-bordered>thead>tr>th{border-bottom-width:2px}.factory-bootstrap-425 .table-striped>tbody>tr:nth-child(odd)>td,.factory-bootstrap-425 .table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.factory-bootstrap-425 .table-hover>tbody>tr:hover>td,.factory-bootstrap-425 .table-hover>tbody>tr:hover>th{background-color:#f5f5f5}.factory-bootstrap-425 table col[class*=col-]{position:static;display:table-column;float:none}.factory-bootstrap-425 table td[class*=col-],.factory-bootstrap-425 table th[class*=col-]{display:table-cell;float:none}.factory-bootstrap-425 .table>tbody>.active>td,.factory-bootstrap-425 .table>tbody>.active>th,.factory-bootstrap-425 .table>tbody>tr>.active,.factory-bootstrap-425 .table>tfoot>.active>td,.factory-bootstrap-425 .table>tfoot>.active>th,.factory-bootstrap-425 .table>tfoot>tr>.active,.factory-bootstrap-425 .table>thead>.active>td,.factory-bootstrap-425 .table>thead>.active>th,.factory-bootstrap-425 .table>thead>tr>.active{background-color:#f5f5f5}.factory-bootstrap-425 .table-hover>tbody>.active:hover>td,.factory-bootstrap-425 .table-hover>tbody>.active:hover>th,.factory-bootstrap-425 .table-hover>tbody>tr>.active:hover{background-color:#e8e8e8}.factory-bootstrap-425 .table>tbody>.success>td,.factory-bootstrap-425 .table>tbody>.success>th,.factory-bootstrap-425 .table>tbody>tr>.success,.factory-bootstrap-425 .table>tfoot>.success>td,.factory-bootstrap-425 .table>tfoot>.success>th,.factory-bootstrap-425 .table>tfoot>tr>.success,.factory-bootstrap-425 .table>thead>.success>td,.factory-bootstrap-425 .table>thead>.success>th,.factory-bootstrap-425 .table>thead>tr>.success{background-color:#dff0d8}.factory-bootstrap-425 .table-hover>tbody>.success:hover>td,.factory-bootstrap-425 .table-hover>tbody>.success:hover>th,.factory-bootstrap-425 .table-hover>tbody>tr>.success:hover{background-color:#d0e9c6}.factory-bootstrap-425 .table>tbody>.danger>td,.factory-bootstrap-425 .table>tbody>.danger>th,.factory-bootstrap-425 .table>tbody>tr>.danger,.factory-bootstrap-425 .table>tfoot>.danger>td,.factory-bootstrap-425 .table>tfoot>.danger>th,.factory-bootstrap-425 .table>tfoot>tr>.danger,.factory-bootstrap-425 .table>thead>.danger>td,.factory-bootstrap-425 .table>thead>.danger>th,.factory-bootstrap-425 .table>thead>tr>.danger{background-color:#f2dede}.factory-bootstrap-425 .table-hover>tbody>.danger:hover>td,.factory-bootstrap-425 .table-hover>tbody>.danger:hover>th,.factory-bootstrap-425 .table-hover>tbody>tr>.danger:hover{background-color:#ebcccc}.factory-bootstrap-425 .table>tbody>.warning>td,.factory-bootstrap-425 .table>tbody>.warning>th,.factory-bootstrap-425 .table>tbody>tr>.warning,.factory-bootstrap-425 .table>tfoot>.warning>td,.factory-bootstrap-425 .table>tfoot>.warning>th,.factory-bootstrap-425 .table>tfoot>tr>.warning,.factory-bootstrap-425 .table>thead>.warning>td,.factory-bootstrap-425 .table>thead>.warning>th,.factory-bootstrap-425 .table>thead>tr>.warning{background-color:#fcf8e3}.factory-bootstrap-425 .table-hover>tbody>.warning:hover>td,.factory-bootstrap-425 .table-hover>tbody>.warning:hover>th,.factory-bootstrap-425 .table-hover>tbody>tr>.warning:hover{background-color:#faf2cc}@media (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}.factory-bootstrap-425 fieldset{padding:0;margin:0;border:0}.factory-bootstrap-425 legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5;-moz-box-sizing:content-box;box-sizing:content-box}.factory-bootstrap-425 label{display:inline-block;margin-bottom:5px;font-weight:700}.factory-bootstrap-425 input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.factory-bootstrap-425 input[type=checkbox],.factory-bootstrap-425 input[type=radio]{margin:4px 0 0;margin-top:1px \9;line-height:normal}.factory-bootstrap-425 input[type=file]{display:block}.factory-bootstrap-425 select[multiple],.factory-bootstrap-425 select[size]{height:auto}.factory-bootstrap-425 select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}.factory-bootstrap-425 input[type=checkbox]:focus,.factory-bootstrap-425 input[type=file]:focus,.factory-bootstrap-425 input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.factory-bootstrap-425 input[type=number]::-webkit-inner-spin-button,.factory-bootstrap-425 input[type=number]::-webkit-outer-spin-button{height:auto}.factory-bootstrap-425 output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.factory-bootstrap-425 .form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.factory-bootstrap-425 .form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.factory-bootstrap-425 .form-control:-moz-placeholder{color:#999}.factory-bootstrap-425 .form-control::-moz-placeholder{color:#999;opacity:1}.factory-bootstrap-425 .form-control:-ms-input-placeholder{color:#999}.factory-bootstrap-425 .form-control::-webkit-input-placeholder{color:#999}.factory-bootstrap-425 .form-control[disabled],.factory-bootstrap-425 .form-control[readonly],.factory-bootstrap-425 fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}.factory-bootstrap-425 textarea.form-control{height:auto}.factory-bootstrap-425 .form-group{margin-bottom:15px}.factory-bootstrap-425 .checkbox,.factory-bootstrap-425 .radio{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.factory-bootstrap-425 .checkbox label,.factory-bootstrap-425 .radio label{display:inline;margin-bottom:0;font-weight:400;cursor:pointer}.factory-bootstrap-425 .checkbox input[type=checkbox],.factory-bootstrap-425 .checkbox-inline input[type=checkbox],.factory-bootstrap-425 .radio input[type=radio],.factory-bootstrap-425 .radio-inline input[type=radio]{float:left;margin-left:-20px}.factory-bootstrap-425 .checkbox+.checkbox,.factory-bootstrap-425 .radio+.radio{margin-top:-5px}.factory-bootstrap-425 .checkbox-inline,.factory-bootstrap-425 .radio-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.factory-bootstrap-425 .checkbox-inline+.checkbox-inline,.factory-bootstrap-425 .radio-inline+.radio-inline{margin-top:0;margin-left:10px}.factory-bootstrap-425 .checkbox-inline[disabled],.factory-bootstrap-425 .checkbox[disabled],.factory-bootstrap-425 .radio-inline[disabled],.factory-bootstrap-425 .radio[disabled],.factory-bootstrap-425 fieldset[disabled] .checkbox,.factory-bootstrap-425 fieldset[disabled] .checkbox-inline,.factory-bootstrap-425 fieldset[disabled] .radio,.factory-bootstrap-425 fieldset[disabled] .radio-inline,.factory-bootstrap-425 fieldset[disabled] input[type=checkbox],.factory-bootstrap-425 fieldset[disabled] input[type=radio],.factory-bootstrap-425 input[type=checkbox][disabled],.factory-bootstrap-425 input[type=radio][disabled]{cursor:not-allowed}.factory-bootstrap-425 .input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.factory-bootstrap-425 select.input-sm{height:30px;line-height:30px}.factory-bootstrap-425 textarea.input-sm{height:auto}.factory-bootstrap-425 .input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.factory-bootstrap-425 select.input-lg{height:46px;line-height:46px}.factory-bootstrap-425 textarea.input-lg{height:auto}.factory-bootstrap-425 .has-warning .checkbox,.factory-bootstrap-425 .has-warning .checkbox-inline,.factory-bootstrap-425 .has-warning .control-label,.factory-bootstrap-425 .has-warning .help-block,.factory-bootstrap-425 .has-warning .radio,.factory-bootstrap-425 .has-warning .radio-inline{color:#8a6d3b}.factory-bootstrap-425 .has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.factory-bootstrap-425 .has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.factory-bootstrap-425 .has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.factory-bootstrap-425 .has-error .checkbox,.factory-bootstrap-425 .has-error .checkbox-inline,.factory-bootstrap-425 .has-error .control-label,.factory-bootstrap-425 .has-error .help-block,.factory-bootstrap-425 .has-error .radio,.factory-bootstrap-425 .has-error .radio-inline{color:#a94442}.factory-bootstrap-425 .controls{display:block}.factory-bootstrap-425 .has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.factory-bootstrap-425 .has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.factory-bootstrap-425 .has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.factory-bootstrap-425 .has-success .checkbox,.factory-bootstrap-425 .has-success .checkbox-inline,.factory-bootstrap-425 .has-success .control-label,.factory-bootstrap-425 .has-success .help-block,.factory-bootstrap-425 .has-success .radio,.factory-bootstrap-425 .has-success .radio-inline{color:#3c763d}.factory-bootstrap-425 .has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.factory-bootstrap-425 .has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.factory-bootstrap-425 .has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.factory-bootstrap-425 .form-control-static{margin-bottom:0}.factory-bootstrap-425 .help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373;font-weight:400}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline select.form-control{width:auto}.form-inline .checkbox,.form-inline .radio{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{float:none;margin-left:0}}.factory-bootstrap-425 .form-horizontal .checkbox,.factory-bootstrap-425 .form-horizontal .checkbox-inline,.factory-bootstrap-425 .form-horizontal .control-label,.factory-bootstrap-425 .form-horizontal .radio,.factory-bootstrap-425 .form-horizontal .radio-inline{position:relative;padding-top:7px;margin-top:0;margin-bottom:0}.factory-bootstrap-425 .form-horizontal .control-label{max-width:200px}.factory-bootstrap-425 .form-horizontal .checkbox,.factory-bootstrap-425 .form-horizontal .radio{min-height:27px}.factory-bootstrap-425 .form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.factory-bootstrap-425 .form-horizontal .form-group:after,.factory-bootstrap-425 .form-horizontal .form-group:before{display:table;content:" "}.factory-bootstrap-425 .form-horizontal .form-group:after{clear:both}.factory-bootstrap-425 .form-horizontal .form-control-static{padding-top:7px}@media (min-width:768px){.form-horizontal .control-label{text-align:right}}.factory-bootstrap-425 .btn{display:inline-block;padding:5px 12px;margin-bottom:0;font-size:13px;font-weight:400;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:3px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.factory-bootstrap-425 .btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.factory-bootstrap-425 .btn{text-decoration:none}.factory-bootstrap-425 .btn:focus,.factory-bootstrap-425 .btn:hover{color:#333;text-decoration:none}.factory-bootstrap-425 .btn.disabled,.factory-bootstrap-425 .btn[disabled],.factory-bootstrap-425 fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.factory-bootstrap-425 .btn-default.active,.factory-bootstrap-425 .btn-default:active,.factory-bootstrap-425 .btn-default:focus,.factory-bootstrap-425 .btn-default:hover,.factory-bootstrap-425 .open .dropdown-toggle.btn-default{background:#fafafa;border-color:#999;color:#222}.factory-bootstrap-425 .btn-default.active,.factory-bootstrap-425 .btn-default:active,.factory-bootstrap-425 .open .dropdown-toggle.btn-default{background-image:none}.factory-bootstrap-425 .btn-default.disabled,.factory-bootstrap-425 .btn-default.disabled.active,.factory-bootstrap-425 .btn-default.disabled:active,.factory-bootstrap-425 .btn-default.disabled:focus,.factory-bootstrap-425 .btn-default.disabled:hover,.factory-bootstrap-425 .btn-default[disabled],.factory-bootstrap-425 .btn-default[disabled].active,.factory-bootstrap-425 .btn-default[disabled]:active,.factory-bootstrap-425 .btn-default[disabled]:focus,.factory-bootstrap-425 .btn-default[disabled]:hover,.factory-bootstrap-425 fieldset[disabled] .btn-default,.factory-bootstrap-425 fieldset[disabled] .btn-default.active,.factory-bootstrap-425 fieldset[disabled] .btn-default:active,.factory-bootstrap-425 fieldset[disabled] .btn-default:focus,.factory-bootstrap-425 fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.factory-bootstrap-425 .btn-default .badge{color:#fff;background-color:#fff}.factory-bootstrap-425 .btn-primary.active,.factory-bootstrap-425 .btn-primary:active,.factory-bootstrap-425 .btn-primary:focus,.factory-bootstrap-425 .btn-primary:hover,.factory-bootstrap-425 .open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.factory-bootstrap-425 .btn-primary.active,.factory-bootstrap-425 .btn-primary:active,.factory-bootstrap-425 .open .dropdown-toggle.btn-primary{background-image:none}.factory-bootstrap-425 .btn-primary.disabled,.factory-bootstrap-425 .btn-primary.disabled.active,.factory-bootstrap-425 .btn-primary.disabled:active,.factory-bootstrap-425 .btn-primary.disabled:focus,.factory-bootstrap-425 .btn-primary.disabled:hover,.factory-bootstrap-425 .btn-primary[disabled],.factory-bootstrap-425 .btn-primary[disabled].active,.factory-bootstrap-425 .btn-primary[disabled]:active,.factory-bootstrap-425 .btn-primary[disabled]:focus,.factory-bootstrap-425 .btn-primary[disabled]:hover,.factory-bootstrap-425 fieldset[disabled] .btn-primary,.factory-bootstrap-425 fieldset[disabled] .btn-primary.active,.factory-bootstrap-425 fieldset[disabled] .btn-primary:active,.factory-bootstrap-425 fieldset[disabled] .btn-primary:focus,.factory-bootstrap-425 fieldset[disabled] .btn-primary:hover{background-color:#428bca;border-color:#357ebd}.factory-bootstrap-425 .btn-primary .badge{color:#428bca;background-color:#fff}.factory-bootstrap-425 .btn-warning{color:#fff;background-color:#f0ad4e}.factory-bootstrap-425 .btn-warning.active,.factory-bootstrap-425 .btn-warning:active,.factory-bootstrap-425 .btn-warning:focus,.factory-bootstrap-425 .btn-warning:hover,.factory-bootstrap-425 .open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.factory-bootstrap-425 .btn-warning.active,.factory-bootstrap-425 .btn-warning:active,.factory-bootstrap-425 .open .dropdown-toggle.btn-warning{background-image:none}.factory-bootstrap-425 .btn-warning.disabled,.factory-bootstrap-425 .btn-warning.disabled.active,.factory-bootstrap-425 .btn-warning.disabled:active,.factory-bootstrap-425 .btn-warning.disabled:focus,.factory-bootstrap-425 .btn-warning.disabled:hover,.factory-bootstrap-425 .btn-warning[disabled],.factory-bootstrap-425 .btn-warning[disabled].active,.factory-bootstrap-425 .btn-warning[disabled]:active,.factory-bootstrap-425 .btn-warning[disabled]:focus,.factory-bootstrap-425 .btn-warning[disabled]:hover,.factory-bootstrap-425 fieldset[disabled] .btn-warning,.factory-bootstrap-425 fieldset[disabled] .btn-warning.active,.factory-bootstrap-425 fieldset[disabled] .btn-warning:active,.factory-bootstrap-425 fieldset[disabled] .btn-warning:focus,.factory-bootstrap-425 fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.factory-bootstrap-425 .btn-warning .badge{color:#f0ad4e;background-color:#fff}.factory-bootstrap-425 .btn-success{color:#fff;background-color:#5cb85c}.factory-bootstrap-425 .btn-success.active,.factory-bootstrap-425 .btn-success:active,.factory-bootstrap-425 .btn-success:focus,.factory-bootstrap-425 .btn-success:hover,.factory-bootstrap-425 .open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.factory-bootstrap-425 .btn-success.active,.factory-bootstrap-425 .btn-success:active,.factory-bootstrap-425 .open .dropdown-toggle.btn-success{background-image:none}.factory-bootstrap-425 .btn-success.disabled,.factory-bootstrap-425 .btn-success.disabled.active,.factory-bootstrap-425 .btn-success.disabled:active,.factory-bootstrap-425 .btn-success.disabled:focus,.factory-bootstrap-425 .btn-success.disabled:hover,.factory-bootstrap-425 .btn-success[disabled],.factory-bootstrap-425 .btn-success[disabled].active,.factory-bootstrap-425 .btn-success[disabled]:active,.factory-bootstrap-425 .btn-success[disabled]:focus,.factory-bootstrap-425 .btn-success[disabled]:hover,.factory-bootstrap-425 fieldset[disabled] .btn-success,.factory-bootstrap-425 fieldset[disabled] .btn-success.active,.factory-bootstrap-425 fieldset[disabled] .btn-success:active,.factory-bootstrap-425 fieldset[disabled] .btn-success:focus,.factory-bootstrap-425 fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.factory-bootstrap-425 .btn-success .badge{color:#5cb85c;background-color:#fff}.factory-bootstrap-425 .btn-info{color:#fff;background-color:#5bc0de}.factory-bootstrap-425 .btn-info.active,.factory-bootstrap-425 .btn-info:active,.factory-bootstrap-425 .btn-info:focus,.factory-bootstrap-425 .btn-info:hover,.factory-bootstrap-425 .open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.factory-bootstrap-425 .btn-info.active,.factory-bootstrap-425 .btn-info:active,.factory-bootstrap-425 .open .dropdown-toggle.btn-info{background-image:none}.factory-bootstrap-425 .btn-info.disabled,.factory-bootstrap-425 .btn-info.disabled.active,.factory-bootstrap-425 .btn-info.disabled:active,.factory-bootstrap-425 .btn-info.disabled:focus,.factory-bootstrap-425 .btn-info.disabled:hover,.factory-bootstrap-425 .btn-info[disabled],.factory-bootstrap-425 .btn-info[disabled].active,.factory-bootstrap-425 .btn-info[disabled]:active,.factory-bootstrap-425 .btn-info[disabled]:focus,.factory-bootstrap-425 .btn-info[disabled]:hover,.factory-bootstrap-425 fieldset[disabled] .btn-info,.factory-bootstrap-425 fieldset[disabled] .btn-info.active,.factory-bootstrap-425 fieldset[disabled] .btn-info:active,.factory-bootstrap-425 fieldset[disabled] .btn-info:focus,.factory-bootstrap-425 fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.factory-bootstrap-425 .btn-info .badge{color:#5bc0de;background-color:#fff}.factory-bootstrap-425 .btn-link{font-weight:400;color:#428bca;cursor:pointer;border-radius:0}.factory-bootstrap-425 .btn-link,.factory-bootstrap-425 .btn-link:active,.factory-bootstrap-425 .btn-link[disabled],.factory-bootstrap-425 fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.factory-bootstrap-425 .btn-link,.factory-bootstrap-425 .btn-link:active,.factory-bootstrap-425 .btn-link:focus,.factory-bootstrap-425 .btn-link:hover{border-color:transparent}.factory-bootstrap-425 .btn-link:focus,.factory-bootstrap-425 .btn-link:hover{color:#2a6496;text-decoration:underline;background-color:transparent}.factory-bootstrap-425 .btn-link[disabled]:focus,.factory-bootstrap-425 .btn-link[disabled]:hover,.factory-bootstrap-425 fieldset[disabled] .btn-link:focus,.factory-bootstrap-425 fieldset[disabled] .btn-link:hover{color:#999;text-decoration:none}.factory-bootstrap-425 .btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.factory-bootstrap-425 .btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.factory-bootstrap-425 .btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.factory-bootstrap-425 .btn-block{display:block;width:100%;padding-right:0;padding-left:0}.factory-bootstrap-425 .btn-block+.btn-block{margin-top:5px}.factory-bootstrap-425 input[type=button].btn-block,.factory-bootstrap-425 input[type=reset].btn-block,.factory-bootstrap-425 input[type=submit].btn-block{width:100%}.factory-bootstrap-425 .fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.factory-bootstrap-425 .fade.in{opacity:1}.factory-bootstrap-425 .collapse{display:none}.factory-bootstrap-425 .collapse.in{display:block}.factory-bootstrap-425 .collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular) format('svg')}.factory-bootstrap-425 .glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:400;line-height:1;-moz-osx-font-smoothing:grayscale}.factory-bootstrap-425 .glyphicon:empty{width:1em}.factory-bootstrap-425 .glyphicon-asterisk:before{content:"\2a"}.factory-bootstrap-425 .glyphicon-plus:before{content:"\2b"}.factory-bootstrap-425 .glyphicon-euro:before{content:"\20ac"}.factory-bootstrap-425 .glyphicon-minus:before{content:"\2212"}.factory-bootstrap-425 .glyphicon-cloud:before{content:"\2601"}.factory-bootstrap-425 .glyphicon-envelope:before{content:"\2709"}.factory-bootstrap-425 .glyphicon-pencil:before{content:"\270f"}.factory-bootstrap-425 .glyphicon-glass:before{content:"\e001"}.factory-bootstrap-425 .glyphicon-music:before{content:"\e002"}.factory-bootstrap-425 .glyphicon-search:before{content:"\e003"}.factory-bootstrap-425 .glyphicon-heart:before{content:"\e005"}.factory-bootstrap-425 .glyphicon-star:before{content:"\e006"}.factory-bootstrap-425 .glyphicon-star-empty:before{content:"\e007"}.factory-bootstrap-425 .glyphicon-user:before{content:"\e008"}.factory-bootstrap-425 .glyphicon-film:before{content:"\e009"}.factory-bootstrap-425 .glyphicon-th-large:before{content:"\e010"}.factory-bootstrap-425 .glyphicon-th:before{content:"\e011"}.factory-bootstrap-425 .glyphicon-th-list:before{content:"\e012"}.factory-bootstrap-425 .glyphicon-ok:before{content:"\e013"}.factory-bootstrap-425 .glyphicon-remove:before{content:"\e014"}.factory-bootstrap-425 .glyphicon-zoom-in:before{content:"\e015"}.factory-bootstrap-425 .glyphicon-zoom-out:before{content:"\e016"}.factory-bootstrap-425 .glyphicon-off:before{content:"\e017"}.factory-bootstrap-425 .glyphicon-signal:before{content:"\e018"}.factory-bootstrap-425 .glyphicon-cog:before{content:"\e019"}.factory-bootstrap-425 .glyphicon-trash:before{content:"\e020"}.factory-bootstrap-425 .glyphicon-home:before{content:"\e021"}.factory-bootstrap-425 .glyphicon-file:before{content:"\e022"}.factory-bootstrap-425 .glyphicon-time:before{content:"\e023"}.factory-bootstrap-425 .glyphicon-road:before{content:"\e024"}.factory-bootstrap-425 .glyphicon-download-alt:before{content:"\e025"}.factory-bootstrap-425 .glyphicon-download:before{content:"\e026"}.factory-bootstrap-425 .glyphicon-upload:before{content:"\e027"}.factory-bootstrap-425 .glyphicon-inbox:before{content:"\e028"}.factory-bootstrap-425 .glyphicon-play-circle:before{content:"\e029"}.factory-bootstrap-425 .glyphicon-repeat:before{content:"\e030"}.factory-bootstrap-425 .glyphicon-refresh:before{content:"\e031"}.factory-bootstrap-425 .glyphicon-list-alt:before{content:"\e032"}.factory-bootstrap-425 .glyphicon-lock:before{content:"\e033"}.factory-bootstrap-425 .glyphicon-flag:before{content:"\e034"}.factory-bootstrap-425 .glyphicon-headphones:before{content:"\e035"}.factory-bootstrap-425 .glyphicon-volume-off:before{content:"\e036"}.factory-bootstrap-425 .glyphicon-volume-down:before{content:"\e037"}.factory-bootstrap-425 .glyphicon-volume-up:before{content:"\e038"}.factory-bootstrap-425 .glyphicon-qrcode:before{content:"\e039"}.factory-bootstrap-425 .glyphicon-barcode:before{content:"\e040"}.factory-bootstrap-425 .glyphicon-tag:before{content:"\e041"}.factory-bootstrap-425 .glyphicon-tags:before{content:"\e042"}.factory-bootstrap-425 .glyphicon-book:before{content:"\e043"}.factory-bootstrap-425 .glyphicon-bookmark:before{content:"\e044"}.factory-bootstrap-425 .glyphicon-print:before{content:"\e045"}.factory-bootstrap-425 .glyphicon-camera:before{content:"\e046"}.factory-bootstrap-425 .glyphicon-font:before{content:"\e047"}.factory-bootstrap-425 .glyphicon-bold:before{content:"\e048"}.factory-bootstrap-425 .glyphicon-italic:before{content:"\e049"}.factory-bootstrap-425 .glyphicon-text-height:before{content:"\e050"}.factory-bootstrap-425 .glyphicon-text-width:before{content:"\e051"}.factory-bootstrap-425 .glyphicon-align-left:before{content:"\e052"}.factory-bootstrap-425 .glyphicon-align-center:before{content:"\e053"}.factory-bootstrap-425 .glyphicon-align-right:before{content:"\e054"}.factory-bootstrap-425 .glyphicon-align-justify:before{content:"\e055"}.factory-bootstrap-425 .glyphicon-list:before{content:"\e056"}.factory-bootstrap-425 .glyphicon-indent-left:before{content:"\e057"}.factory-bootstrap-425 .glyphicon-indent-right:before{content:"\e058"}.factory-bootstrap-425 .glyphicon-facetime-video:before{content:"\e059"}.factory-bootstrap-425 .glyphicon-picture:before{content:"\e060"}.factory-bootstrap-425 .glyphicon-map-marker:before{content:"\e062"}.factory-bootstrap-425 .glyphicon-adjust:before{content:"\e063"}.factory-bootstrap-425 .glyphicon-tint:before{content:"\e064"}.factory-bootstrap-425 .glyphicon-edit:before{content:"\e065"}.factory-bootstrap-425 .glyphicon-share:before{content:"\e066"}.factory-bootstrap-425 .glyphicon-check:before{content:"\e067"}.factory-bootstrap-425 .glyphicon-move:before{content:"\e068"}.factory-bootstrap-425 .glyphicon-step-backward:before{content:"\e069"}.factory-bootstrap-425 .glyphicon-fast-backward:before{content:"\e070"}.factory-bootstrap-425 .glyphicon-backward:before{content:"\e071"}.factory-bootstrap-425 .glyphicon-play:before{content:"\e072"}.factory-bootstrap-425 .glyphicon-pause:before{content:"\e073"}.factory-bootstrap-425 .glyphicon-stop:before{content:"\e074"}.factory-bootstrap-425 .glyphicon-forward:before{content:"\e075"}.factory-bootstrap-425 .glyphicon-fast-forward:before{content:"\e076"}.factory-bootstrap-425 .glyphicon-step-forward:before{content:"\e077"}.factory-bootstrap-425 .glyphicon-eject:before{content:"\e078"}.factory-bootstrap-425 .glyphicon-chevron-left:before{content:"\e079"}.factory-bootstrap-425 .glyphicon-chevron-right:before{content:"\e080"}.factory-bootstrap-425 .glyphicon-plus-sign:before{content:"\e081"}.factory-bootstrap-425 .glyphicon-minus-sign:before{content:"\e082"}.factory-bootstrap-425 .glyphicon-remove-sign:before{content:"\e083"}.factory-bootstrap-425 .glyphicon-ok-sign:before{content:"\e084"}.factory-bootstrap-425 .glyphicon-question-sign:before{content:"\e085"}.factory-bootstrap-425 .glyphicon-info-sign:before{content:"\e086"}.factory-bootstrap-425 .glyphicon-screenshot:before{content:"\e087"}.factory-bootstrap-425 .glyphicon-remove-circle:before{content:"\e088"}.factory-bootstrap-425 .glyphicon-ok-circle:before{content:"\e089"}.factory-bootstrap-425 .glyphicon-ban-circle:before{content:"\e090"}.factory-bootstrap-425 .glyphicon-arrow-left:before{content:"\e091"}.factory-bootstrap-425 .glyphicon-arrow-right:before{content:"\e092"}.factory-bootstrap-425 .glyphicon-arrow-up:before{content:"\e093"}.factory-bootstrap-425 .glyphicon-arrow-down:before{content:"\e094"}.factory-bootstrap-425 .glyphicon-share-alt:before{content:"\e095"}.factory-bootstrap-425 .glyphicon-resize-full:before{content:"\e096"}.factory-bootstrap-425 .glyphicon-resize-small:before{content:"\e097"}.factory-bootstrap-425 .glyphicon-exclamation-sign:before{content:"\e101"}.factory-bootstrap-425 .glyphicon-gift:before{content:"\e102"}.factory-bootstrap-425 .glyphicon-leaf:before{content:"\e103"}.factory-bootstrap-425 .glyphicon-fire:before{content:"\e104"}.factory-bootstrap-425 .glyphicon-eye-open:before{content:"\e105"}.factory-bootstrap-425 .glyphicon-eye-close:before{content:"\e106"}.factory-bootstrap-425 .glyphicon-warning-sign:before{content:"\e107"}.factory-bootstrap-425 .glyphicon-plane:before{content:"\e108"}.factory-bootstrap-425 .glyphicon-calendar:before{content:"\e109"}.factory-bootstrap-425 .glyphicon-random:before{content:"\e110"}.factory-bootstrap-425 .glyphicon-comment:before{content:"\e111"}.factory-bootstrap-425 .glyphicon-magnet:before{content:"\e112"}.factory-bootstrap-425 .glyphicon-chevron-up:before{content:"\e113"}.factory-bootstrap-425 .glyphicon-chevron-down:before{content:"\e114"}.factory-bootstrap-425 .glyphicon-retweet:before{content:"\e115"}.factory-bootstrap-425 .glyphicon-shopping-cart:before{content:"\e116"}.factory-bootstrap-425 .glyphicon-folder-close:before{content:"\e117"}.factory-bootstrap-425 .glyphicon-folder-open:before{content:"\e118"}.factory-bootstrap-425 .glyphicon-resize-vertical:before{content:"\e119"}.factory-bootstrap-425 .glyphicon-resize-horizontal:before{content:"\e120"}.factory-bootstrap-425 .glyphicon-hdd:before{content:"\e121"}.factory-bootstrap-425 .glyphicon-bullhorn:before{content:"\e122"}.factory-bootstrap-425 .glyphicon-bell:before{content:"\e123"}.factory-bootstrap-425 .glyphicon-certificate:before{content:"\e124"}.factory-bootstrap-425 .glyphicon-thumbs-up:before{content:"\e125"}.factory-bootstrap-425 .glyphicon-thumbs-down:before{content:"\e126"}.factory-bootstrap-425 .glyphicon-hand-right:before{content:"\e127"}.factory-bootstrap-425 .glyphicon-hand-left:before{content:"\e128"}.factory-bootstrap-425 .glyphicon-hand-up:before{content:"\e129"}.factory-bootstrap-425 .glyphicon-hand-down:before{content:"\e130"}.factory-bootstrap-425 .glyphicon-circle-arrow-right:before{content:"\e131"}.factory-bootstrap-425 .glyphicon-circle-arrow-left:before{content:"\e132"}.factory-bootstrap-425 .glyphicon-circle-arrow-up:before{content:"\e133"}.factory-bootstrap-425 .glyphicon-circle-arrow-down:before{content:"\e134"}.factory-bootstrap-425 .glyphicon-globe:before{content:"\e135"}.factory-bootstrap-425 .glyphicon-wrench:before{content:"\e136"}.factory-bootstrap-425 .glyphicon-tasks:before{content:"\e137"}.factory-bootstrap-425 .glyphicon-filter:before{content:"\e138"}.factory-bootstrap-425 .glyphicon-briefcase:before{content:"\e139"}.factory-bootstrap-425 .glyphicon-fullscreen:before{content:"\e140"}.factory-bootstrap-425 .glyphicon-dashboard:before{content:"\e141"}.factory-bootstrap-425 .glyphicon-paperclip:before{content:"\e142"}.factory-bootstrap-425 .glyphicon-heart-empty:before{content:"\e143"}.factory-bootstrap-425 .glyphicon-link:before{content:"\e144"}.factory-bootstrap-425 .glyphicon-phone:before{content:"\e145"}.factory-bootstrap-425 .glyphicon-pushpin:before{content:"\e146"}.factory-bootstrap-425 .glyphicon-usd:before{content:"\e148"}.factory-bootstrap-425 .glyphicon-gbp:before{content:"\e149"}.factory-bootstrap-425 .glyphicon-sort:before{content:"\e150"}.factory-bootstrap-425 .glyphicon-sort-by-alphabet:before{content:"\e151"}.factory-bootstrap-425 .glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.factory-bootstrap-425 .glyphicon-sort-by-order:before{content:"\e153"}.factory-bootstrap-425 .glyphicon-sort-by-order-alt:before{content:"\e154"}.factory-bootstrap-425 .glyphicon-sort-by-attributes:before{content:"\e155"}.factory-bootstrap-425 .glyphicon-sort-by-attributes-alt:before{content:"\e156"}.factory-bootstrap-425 .glyphicon-unchecked:before{content:"\e157"}.factory-bootstrap-425 .glyphicon-expand:before{content:"\e158"}.factory-bootstrap-425 .glyphicon-collapse-down:before{content:"\e159"}.factory-bootstrap-425 .glyphicon-collapse-up:before{content:"\e160"}.factory-bootstrap-425 .glyphicon-log-in:before{content:"\e161"}.factory-bootstrap-425 .glyphicon-flash:before{content:"\e162"}.factory-bootstrap-425 .glyphicon-log-out:before{content:"\e163"}.factory-bootstrap-425 .glyphicon-new-window:before{content:"\e164"}.factory-bootstrap-425 .glyphicon-record:before{content:"\e165"}.factory-bootstrap-425 .glyphicon-save:before{content:"\e166"}.factory-bootstrap-425 .glyphicon-open:before{content:"\e167"}.factory-bootstrap-425 .glyphicon-saved:before{content:"\e168"}.factory-bootstrap-425 .glyphicon-import:before{content:"\e169"}.factory-bootstrap-425 .glyphicon-export:before{content:"\e170"}.factory-bootstrap-425 .glyphicon-send:before{content:"\e171"}.factory-bootstrap-425 .glyphicon-floppy-disk:before{content:"\e172"}.factory-bootstrap-425 .glyphicon-floppy-saved:before{content:"\e173"}.factory-bootstrap-425 .glyphicon-floppy-remove:before{content:"\e174"}.factory-bootstrap-425 .glyphicon-floppy-save:before{content:"\e175"}.factory-bootstrap-425 .glyphicon-floppy-open:before{content:"\e176"}.factory-bootstrap-425 .glyphicon-credit-card:before{content:"\e177"}.factory-bootstrap-425 .glyphicon-transfer:before{content:"\e178"}.factory-bootstrap-425 .glyphicon-cutlery:before{content:"\e179"}.factory-bootstrap-425 .glyphicon-header:before{content:"\e180"}.factory-bootstrap-425 .glyphicon-compressed:before{content:"\e181"}.factory-bootstrap-425 .glyphicon-earphone:before{content:"\e182"}.factory-bootstrap-425 .glyphicon-phone-alt:before{content:"\e183"}.factory-bootstrap-425 .glyphicon-tower:before{content:"\e184"}.factory-bootstrap-425 .glyphicon-stats:before{content:"\e185"}.factory-bootstrap-425 .glyphicon-sd-video:before{content:"\e186"}.factory-bootstrap-425 .glyphicon-hd-video:before{content:"\e187"}.factory-bootstrap-425 .glyphicon-subtitles:before{content:"\e188"}.factory-bootstrap-425 .glyphicon-sound-stereo:before{content:"\e189"}.factory-bootstrap-425 .glyphicon-sound-dolby:before{content:"\e190"}.factory-bootstrap-425 .glyphicon-sound-5-1:before{content:"\e191"}.factory-bootstrap-425 .glyphicon-sound-6-1:before{content:"\e192"}.factory-bootstrap-425 .glyphicon-sound-7-1:before{content:"\e193"}.factory-bootstrap-425 .glyphicon-copyright-mark:before{content:"\e194"}.factory-bootstrap-425 .glyphicon-registration-mark:before{content:"\e195"}.factory-bootstrap-425 .glyphicon-cloud-download:before{content:"\e197"}.factory-bootstrap-425 .glyphicon-cloud-upload:before{content:"\e198"}.factory-bootstrap-425 .glyphicon-tree-conifer:before{content:"\e199"}.factory-bootstrap-425 .glyphicon-tree-deciduous:before{content:"\e200"}.factory-bootstrap-425 .caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.factory-bootstrap-425 .dropdown{position:relative}.factory-bootstrap-425 .dropdown-toggle:focus{outline:0}.factory-bootstrap-425 .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.factory-bootstrap-425 .dropdown-menu.pull-right{right:0;left:auto}.factory-bootstrap-425 .dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.factory-bootstrap-425 .dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.428571429;color:#333;white-space:nowrap}.factory-bootstrap-425 .dropdown-menu>li>a:focus,.factory-bootstrap-425 .dropdown-menu>li>a:hover{color:#262626;text-decoration:none}.factory-bootstrap-425 .dropdown-menu>.active>a,.factory-bootstrap-425 .dropdown-menu>.active>a:focus,.factory-bootstrap-425 .dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0}.factory-bootstrap-425 .dropdown-menu>.disabled>a,.factory-bootstrap-425 .dropdown-menu>.disabled>a:focus,.factory-bootstrap-425 .dropdown-menu>.disabled>a:hover{color:#999}.factory-bootstrap-425 .dropdown-menu>.disabled>a:focus,.factory-bootstrap-425 .dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.factory-bootstrap-425 .open>.dropdown-menu{display:block}.factory-bootstrap-425 .open>a{outline:0}.factory-bootstrap-425 .dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.factory-bootstrap-425 .dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.factory-bootstrap-425 .pull-right>.dropdown-menu{right:0;left:auto}.factory-bootstrap-425 .dropup .caret,.factory-bootstrap-425 .navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.factory-bootstrap-425 .dropup .dropdown-menu,.factory-bootstrap-425 .navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.factory-bootstrap-425 .btn-group,.factory-bootstrap-425 .btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.factory-bootstrap-425 .btn-group-vertical>.btn,.factory-bootstrap-425 .btn-group>.btn{position:relative;float:left}.factory-bootstrap-425 .btn-group-vertical>.btn.active,.factory-bootstrap-425 .btn-group-vertical>.btn:active,.factory-bootstrap-425 .btn-group-vertical>.btn:focus,.factory-bootstrap-425 .btn-group-vertical>.btn:hover,.factory-bootstrap-425 .btn-group>.btn.active,.factory-bootstrap-425 .btn-group>.btn:active,.factory-bootstrap-425 .btn-group>.btn:focus,.factory-bootstrap-425 .btn-group>.btn:hover{z-index:2}.factory-bootstrap-425 .btn-group-vertical>.btn:focus,.factory-bootstrap-425 .btn-group>.btn:focus{outline:0}.factory-bootstrap-425 .btn-group .btn+.btn,.factory-bootstrap-425 .btn-group .btn+.btn-group,.factory-bootstrap-425 .btn-group .btn-group+.btn,.factory-bootstrap-425 .btn-group .btn-group+.btn-group{margin-left:-1px}.factory-bootstrap-425 .btn-toolbar:after,.factory-bootstrap-425 .btn-toolbar:before{display:table;content:" "}.factory-bootstrap-425 .btn-toolbar:after{clear:both}.factory-bootstrap-425 .btn-toolbar .btn-group{float:left}.factory-bootstrap-425 .btn-toolbar>.btn+.btn,.factory-bootstrap-425 .btn-toolbar>.btn+.btn-group,.factory-bootstrap-425 .btn-toolbar>.btn-group+.btn,.factory-bootstrap-425 .btn-toolbar>.btn-group+.btn-group{margin-left:5px}.factory-bootstrap-425 .btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.factory-bootstrap-425 .btn-group>.btn:first-child{margin-left:0}.factory-bootstrap-425 .btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.factory-bootstrap-425 .btn-group>.btn:last-child:not(:first-child),.factory-bootstrap-425 .btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.factory-bootstrap-425 .btn-group>.btn-group{float:left}.factory-bootstrap-425 .btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.factory-bootstrap-425 .btn-group>.btn-group:first-child>.btn:last-child,.factory-bootstrap-425 .btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.factory-bootstrap-425 .btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.factory-bootstrap-425 .btn-group .dropdown-toggle:active,.factory-bootstrap-425 .btn-group.open .dropdown-toggle{outline:0}.factory-bootstrap-425 .btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.factory-bootstrap-425 .btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.factory-bootstrap-425 .btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.factory-bootstrap-425 .btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.factory-bootstrap-425 .btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.factory-bootstrap-425 .btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.factory-bootstrap-425 .btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.factory-bootstrap-425 .btn-group{border:4px solid #f9f9f9;border-radius:4px}.factory-bootstrap-425 .btn-group .btn.active.value{text-shadow:none;color:#fff;background-color:#33aad5;-webkit-box-shadow:inset 0 1px 1px #0074a2;box-shadow:inset 0 1px 3px #0074a2;border-top:1px solid #0074a2;border-bottom:1px solid #0074a2;border-left:1px solid #0074a2}.factory-bootstrap-425 .btn .caret{margin-left:0}.factory-bootstrap-425 .btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.factory-bootstrap-425 .dropup .btn-lg .caret{border-width:0 5px 5px}.factory-bootstrap-425 .btn-group-vertical>.btn,.factory-bootstrap-425 .btn-group-vertical>.btn-group,.factory-bootstrap-425 .btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.factory-bootstrap-425 .btn-group-vertical>.btn-group:after,.factory-bootstrap-425 .btn-group-vertical>.btn-group:before{display:table;content:" "}.factory-bootstrap-425 .btn-group-vertical>.btn-group:after{clear:both}.factory-bootstrap-425 .btn-group-vertical>.btn-group>.btn{float:none}.factory-bootstrap-425 .btn-group-vertical>.btn+.btn,.factory-bootstrap-425 .btn-group-vertical>.btn+.btn-group,.factory-bootstrap-425 .btn-group-vertical>.btn-group+.btn,.factory-bootstrap-425 .btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.factory-bootstrap-425 .btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.factory-bootstrap-425 .btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.factory-bootstrap-425 .btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.factory-bootstrap-425 .btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.factory-bootstrap-425 .btn-group-vertical>.btn-group:first-child>.btn:last-child,.factory-bootstrap-425 .btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.factory-bootstrap-425 .btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.factory-bootstrap-425 .btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.factory-bootstrap-425 .btn-group-justified>.btn,.factory-bootstrap-425 .btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.factory-bootstrap-425 .btn-group-justified>.btn-group .btn{width:100%}[data-toggle=buttons]>.btn>input[type=checkbox],[data-toggle=buttons]>.btn>input[type=radio]{display:none}.factory-bootstrap-425 .input-group{position:relative;display:table;border-collapse:separate}.factory-bootstrap-425 .input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.factory-bootstrap-425 .input-group .form-control{width:100%;margin-bottom:0}.factory-bootstrap-425 .input-group-lg>.form-control,.factory-bootstrap-425 .input-group-lg>.input-group-addon,.factory-bootstrap-425 .input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.factory-bootstrap-425 select.input-group-lg>.form-control,.factory-bootstrap-425 select.input-group-lg>.input-group-addon,.factory-bootstrap-425 select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}.factory-bootstrap-425 textarea.input-group-lg>.form-control,.factory-bootstrap-425 textarea.input-group-lg>.input-group-addon,.factory-bootstrap-425 textarea.input-group-lg>.input-group-btn>.btn{height:auto}.factory-bootstrap-425 .input-group-sm>.form-control,.factory-bootstrap-425 .input-group-sm>.input-group-addon,.factory-bootstrap-425 .input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.factory-bootstrap-425 select.input-group-sm>.form-control,.factory-bootstrap-425 select.input-group-sm>.input-group-addon,.factory-bootstrap-425 select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}.factory-bootstrap-425 textarea.input-group-sm>.form-control,.factory-bootstrap-425 textarea.input-group-sm>.input-group-addon,.factory-bootstrap-425 textarea.input-group-sm>.input-group-btn>.btn{height:auto}.factory-bootstrap-425 .input-group .form-control,.factory-bootstrap-425 .input-group-addon,.factory-bootstrap-425 .input-group-btn{display:table-cell}.factory-bootstrap-425 .input-group .form-control:not(:first-child):not(:last-child),.factory-bootstrap-425 .input-group-addon:not(:first-child):not(:last-child),.factory-bootstrap-425 .input-group-btn:not(:first-child):not(:last-child){border-radius:0}.factory-bootstrap-425 .input-group-addon,.factory-bootstrap-425 .input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.factory-bootstrap-425 .input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.factory-bootstrap-425 .input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.factory-bootstrap-425 .input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.factory-bootstrap-425 .input-group-addon input[type=checkbox],.factory-bootstrap-425 .input-group-addon input[type=radio]{margin-top:0}.factory-bootstrap-425 .input-group .form-control:first-child,.factory-bootstrap-425 .input-group-addon:first-child,.factory-bootstrap-425 .input-group-btn:first-child>.btn,.factory-bootstrap-425 .input-group-btn:first-child>.dropdown-toggle,.factory-bootstrap-425 .input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.factory-bootstrap-425 .input-group-addon:first-child{border-right:0}.factory-bootstrap-425 .input-group .form-control:last-child,.factory-bootstrap-425 .input-group-addon:last-child,.factory-bootstrap-425 .input-group-btn:first-child>.btn:not(:first-child),.factory-bootstrap-425 .input-group-btn:last-child>.btn,.factory-bootstrap-425 .input-group-btn:last-child>.dropdown-toggle{border-bottom-left-radius:0;border-top-left-radius:0}.factory-bootstrap-425 .input-group-addon:last-child{border-left:0}.factory-bootstrap-425 .input-group-btn{position:relative;white-space:nowrap}.factory-bootstrap-425 .input-group-btn:first-child>.btn{margin-right:-1px}.factory-bootstrap-425 .input-group-btn:last-child>.btn{margin-left:-1px}.factory-bootstrap-425 .input-group-btn>.btn{position:relative}.factory-bootstrap-425 .input-group-btn>.btn+.btn{margin-left:-4px}.factory-bootstrap-425 .input-group-btn>.btn:active,.factory-bootstrap-425 .input-group-btn>.btn:hover{z-index:2}.factory-bootstrap-425 .nav{padding-left:0;margin-bottom:0;list-style:none}.factory-bootstrap-425 .nav:after,.factory-bootstrap-425 .nav:before{display:table;content:" "}.factory-bootstrap-425 .nav:after{clear:both}.factory-bootstrap-425 .nav>li{position:relative;display:block}.factory-bootstrap-425 .nav>li>a{position:relative;display:block;padding:10px 15px}.factory-bootstrap-425 .nav>li>a:focus,.factory-bootstrap-425 .nav>li>a:hover{text-decoration:none;background-color:#eee}.factory-bootstrap-425 .nav>li.disabled>a{color:#999}.factory-bootstrap-425 .nav>li.disabled>a:focus,.factory-bootstrap-425 .nav>li.disabled>a:hover{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.factory-bootstrap-425 .nav .open>a,.factory-bootstrap-425 .nav .open>a:focus,.factory-bootstrap-425 .nav .open>a:hover{background-color:#eee;border-color:#428bca}.factory-bootstrap-425 .nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.factory-bootstrap-425 .nav>li>a>img{max-width:none}.factory-bootstrap-425 .nav-tabs{border-bottom:1px solid #ddd}.factory-bootstrap-425 .nav-tabs>li{float:left;margin-bottom:-1px}.factory-bootstrap-425 .nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.factory-bootstrap-425 .nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.factory-bootstrap-425 .nav-tabs>li.active>a,.factory-bootstrap-425 .nav-tabs>li.active>a:focus,.factory-bootstrap-425 .nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.factory-bootstrap-425 .nav-tabs.nav-justified{width:100%;border-bottom:0}.factory-bootstrap-425 .nav-tabs.nav-justified>li{float:none}.factory-bootstrap-425 .nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.factory-bootstrap-425 .nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.factory-bootstrap-425 .nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.factory-bootstrap-425 .nav-tabs.nav-justified>.active>a,.factory-bootstrap-425 .nav-tabs.nav-justified>.active>a:focus,.factory-bootstrap-425 .nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.factory-bootstrap-425 .nav-pills>li{float:left}.factory-bootstrap-425 .nav-pills>li>a{border-radius:4px}.factory-bootstrap-425 .nav-pills>li+li{margin-left:2px}.factory-bootstrap-425 .nav-pills>li.active>a,.factory-bootstrap-425 .nav-pills>li.active>a:focus,.factory-bootstrap-425 .nav-pills>li.active>a:hover{color:#fff;background-color:#428bca}.factory-bootstrap-425 .nav-stacked>li{float:none}.factory-bootstrap-425 .nav-stacked>li+li{margin-top:2px;margin-left:0}.factory-bootstrap-425 .nav-justified{width:100%}.factory-bootstrap-425 .nav-justified>li{float:none}.factory-bootstrap-425 .nav-justified>li>a{margin-bottom:5px;text-align:center}.factory-bootstrap-425 .nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.factory-bootstrap-425 .nav-tabs-justified{border-bottom:0}.factory-bootstrap-425 .nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.factory-bootstrap-425 .nav-tabs-justified>.active>a,.factory-bootstrap-425 .nav-tabs-justified>.active>a:focus,.factory-bootstrap-425 .nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.factory-bootstrap-425 .tab-content>.tab-pane{display:none}.factory-bootstrap-425 .tab-content>.active{display:block}.factory-bootstrap-425 .nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.factory-bootstrap-425 .navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.factory-bootstrap-425 .navbar:after,.factory-bootstrap-425 .navbar:before{display:table;content:" "}.factory-bootstrap-425 .navbar:after{clear:both}@media (min-width:768px){.navbar{border-radius:4px}}.factory-bootstrap-425 .navbar-header:after,.factory-bootstrap-425 .navbar-header:before{display:table;content:" "}.factory-bootstrap-425 .navbar-header:after{clear:both}@media (min-width:768px){.navbar-header{float:left}}.factory-bootstrap-425 .navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.factory-bootstrap-425 .navbar-collapse:after,.factory-bootstrap-425 .navbar-collapse:before{display:table;content:" "}.factory-bootstrap-425 .navbar-collapse:after{clear:both}.factory-bootstrap-425 .navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.factory-bootstrap-425 .container>.navbar-collapse,.factory-bootstrap-425 .container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.factory-bootstrap-425 .navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.factory-bootstrap-425 .navbar-fixed-bottom,.factory-bootstrap-425 .navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.factory-bootstrap-425 .navbar-fixed-top{top:0;border-width:0 0 1px}.factory-bootstrap-425 .navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.factory-bootstrap-425 .navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px}.factory-bootstrap-425 .navbar-brand:focus,.factory-bootstrap-425 .navbar-brand:hover{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.factory-bootstrap-425 .navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.factory-bootstrap-425 .navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.factory-bootstrap-425 .navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.factory-bootstrap-425 .navbar-nav{margin:7.5px -15px}.factory-bootstrap-425 .navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.factory-bootstrap-425 .navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form select.form-control{width:auto}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{float:none;margin-left:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.factory-bootstrap-425 .navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.factory-bootstrap-425 .navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.factory-bootstrap-425 .navbar-nav.pull-right>li>.dropdown-menu,.factory-bootstrap-425 .navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.factory-bootstrap-425 .navbar-btn{margin-top:8px;margin-bottom:8px}.factory-bootstrap-425 .navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.factory-bootstrap-425 .navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.factory-bootstrap-425 .navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.factory-bootstrap-425 .navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.factory-bootstrap-425 .navbar-default .navbar-brand{color:#777}.factory-bootstrap-425 .navbar-default .navbar-brand:focus,.factory-bootstrap-425 .navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.factory-bootstrap-425 .navbar-default .navbar-nav>li>a,.factory-bootstrap-425 .navbar-default .navbar-text{color:#777}.factory-bootstrap-425 .navbar-default .navbar-nav>li>a:focus,.factory-bootstrap-425 .navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.factory-bootstrap-425 .navbar-default .navbar-nav>.active>a,.factory-bootstrap-425 .navbar-default .navbar-nav>.active>a:focus,.factory-bootstrap-425 .navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.factory-bootstrap-425 .navbar-default .navbar-nav>.disabled>a,.factory-bootstrap-425 .navbar-default .navbar-nav>.disabled>a:focus,.factory-bootstrap-425 .navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.factory-bootstrap-425 .navbar-default .navbar-toggle{border-color:#ddd}.factory-bootstrap-425 .navbar-default .navbar-toggle:focus,.factory-bootstrap-425 .navbar-default .navbar-toggle:hover{background-color:#ddd}.factory-bootstrap-425 .navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.factory-bootstrap-425 .navbar-default .navbar-collapse,.factory-bootstrap-425 .navbar-default .navbar-form{border-color:#e7e7e7}.factory-bootstrap-425 .navbar-default .navbar-nav>.open>a,.factory-bootstrap-425 .navbar-default .navbar-nav>.open>a:focus,.factory-bootstrap-425 .navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.factory-bootstrap-425 .navbar-default .navbar-link{color:#777}.factory-bootstrap-425 .navbar-default .navbar-link:hover{color:#333}.factory-bootstrap-425 .navbar-inverse{background-color:#222;border-color:#080808}.factory-bootstrap-425 .navbar-inverse .navbar-brand{color:#999}.factory-bootstrap-425 .navbar-inverse .navbar-brand:focus,.factory-bootstrap-425 .navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.factory-bootstrap-425 .navbar-inverse .navbar-nav>li>a,.factory-bootstrap-425 .navbar-inverse .navbar-text{color:#999}.factory-bootstrap-425 .navbar-inverse .navbar-nav>li>a:focus,.factory-bootstrap-425 .navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.factory-bootstrap-425 .navbar-inverse .navbar-nav>.active>a,.factory-bootstrap-425 .navbar-inverse .navbar-nav>.active>a:focus,.factory-bootstrap-425 .navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.factory-bootstrap-425 .navbar-inverse .navbar-nav>.disabled>a,.factory-bootstrap-425 .navbar-inverse .navbar-nav>.disabled>a:focus,.factory-bootstrap-425 .navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.factory-bootstrap-425 .navbar-inverse .navbar-toggle{border-color:#333}.factory-bootstrap-425 .navbar-inverse .navbar-toggle:focus,.factory-bootstrap-425 .navbar-inverse .navbar-toggle:hover{background-color:#333}.factory-bootstrap-425 .navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.factory-bootstrap-425 .navbar-inverse .navbar-collapse,.factory-bootstrap-425 .navbar-inverse .navbar-form{border-color:#101010}.factory-bootstrap-425 .navbar-inverse .navbar-nav>.open>a,.factory-bootstrap-425 .navbar-inverse .navbar-nav>.open>a:focus,.factory-bootstrap-425 .navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.factory-bootstrap-425 .navbar-inverse .navbar-link{color:#999}.factory-bootstrap-425 .navbar-inverse .navbar-link:hover{color:#fff}.factory-bootstrap-425 .breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.factory-bootstrap-425 .breadcrumb>li{display:inline-block}.factory-bootstrap-425 .breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.factory-bootstrap-425 .breadcrumb>.active{color:#999}.factory-bootstrap-425 .pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.factory-bootstrap-425 .pagination>li{display:inline}.factory-bootstrap-425 .pagination>li>a,.factory-bootstrap-425 .pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.factory-bootstrap-425 .pagination>li:first-child>a,.factory-bootstrap-425 .pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.factory-bootstrap-425 .pagination>li:last-child>a,.factory-bootstrap-425 .pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.factory-bootstrap-425 .pagination>li>a:focus,.factory-bootstrap-425 .pagination>li>a:hover,.factory-bootstrap-425 .pagination>li>span:focus,.factory-bootstrap-425 .pagination>li>span:hover{background-color:#eee}.factory-bootstrap-425 .pagination>.active>a,.factory-bootstrap-425 .pagination>.active>a:focus,.factory-bootstrap-425 .pagination>.active>a:hover,.factory-bootstrap-425 .pagination>.active>span,.factory-bootstrap-425 .pagination>.active>span:focus,.factory-bootstrap-425 .pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#1e8cbe;border-color:#0074a2}.factory-bootstrap-425 .pagination>.disabled>a,.factory-bootstrap-425 .pagination>.disabled>a:focus,.factory-bootstrap-425 .pagination>.disabled>a:hover,.factory-bootstrap-425 .pagination>.disabled>span,.factory-bootstrap-425 .pagination>.disabled>span:focus,.factory-bootstrap-425 .pagination>.disabled>span:hover{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.factory-bootstrap-425 .pagination-lg>li>a,.factory-bootstrap-425 .pagination-lg>li>span{padding:10px 16px;font-size:18px}.factory-bootstrap-425 .pagination-lg>li:first-child>a,.factory-bootstrap-425 .pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.factory-bootstrap-425 .pagination-lg>li:last-child>a,.factory-bootstrap-425 .pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.factory-bootstrap-425 .pagination-sm>li>a,.factory-bootstrap-425 .pagination-sm>li>span{padding:5px 10px;font-size:12px}.factory-bootstrap-425 .pagination-sm>li:first-child>a,.factory-bootstrap-425 .pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.factory-bootstrap-425 .pagination-sm>li:last-child>a,.factory-bootstrap-425 .pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.factory-bootstrap-425 .pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.factory-bootstrap-425 .pager:after,.factory-bootstrap-425 .pager:before{display:table;content:" "}.factory-bootstrap-425 .pager:after{clear:both}.factory-bootstrap-425 .pager li{display:inline}.factory-bootstrap-425 .pager li>a,.factory-bootstrap-425 .pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.factory-bootstrap-425 .pager li>a:focus,.factory-bootstrap-425 .pager li>a:hover{text-decoration:none;background-color:#eee}.factory-bootstrap-425 .pager .next>a,.factory-bootstrap-425 .pager .next>span{float:right}.factory-bootstrap-425 .pager .previous>a,.factory-bootstrap-425 .pager .previous>span{float:left}.factory-bootstrap-425 .pager .disabled>a,.factory-bootstrap-425 .pager .disabled>a:focus,.factory-bootstrap-425 .pager .disabled>a:hover,.factory-bootstrap-425 .pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.factory-bootstrap-425 .label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.factory-bootstrap-425 .label[href]:focus,.factory-bootstrap-425 .label[href]:hover{color:#fff;text-decoration:none;cursor:pointer}.factory-bootstrap-425 .label:empty{display:none}.factory-bootstrap-425 .btn .label{position:relative;top:-1px}.factory-bootstrap-425 .label-default{background-color:#999}.factory-bootstrap-425 .label-default[href]:focus,.factory-bootstrap-425 .label-default[href]:hover{background-color:gray}.factory-bootstrap-425 .label-primary{background-color:#428bca}.factory-bootstrap-425 .label-primary[href]:focus,.factory-bootstrap-425 .label-primary[href]:hover{background-color:#3071a9}.factory-bootstrap-425 .label-success{background-color:#5cb85c}.factory-bootstrap-425 .label-success[href]:focus,.factory-bootstrap-425 .label-success[href]:hover{background-color:#449d44}.factory-bootstrap-425 .label-info{background-color:#5bc0de}.factory-bootstrap-425 .label-info[href]:focus,.factory-bootstrap-425 .label-info[href]:hover{background-color:#31b0d5}.factory-bootstrap-425 .label-warning{background-color:#f0ad4e}.factory-bootstrap-425 .label-warning[href]:focus,.factory-bootstrap-425 .label-warning[href]:hover{background-color:#ec971f}.factory-bootstrap-425 .label-danger{background-color:#d9534f}.factory-bootstrap-425 .label-danger[href]:focus,.factory-bootstrap-425 .label-danger[href]:hover{background-color:#c9302c}.factory-bootstrap-425 .badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.factory-bootstrap-425 .badge:empty{display:none}.factory-bootstrap-425 .btn .badge{position:relative;top:-1px}.factory-bootstrap-425 a.badge:focus,.factory-bootstrap-425 a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.factory-bootstrap-425 .nav-pills>.active>a>.badge,.factory-bootstrap-425 a.list-group-item.active>.badge{color:#428bca;background-color:#fff}.factory-bootstrap-425 .nav-pills>li>a>.badge{margin-left:3px}.factory-bootstrap-425 .jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.factory-bootstrap-425 .jumbotron .h1,.factory-bootstrap-425 .jumbotron h1{line-height:1;color:inherit}.factory-bootstrap-425 .jumbotron p{line-height:1.4}.factory-bootstrap-425 .container .jumbotron{border-radius:6px}.factory-bootstrap-425 .jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.factory-bootstrap-425 .thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.factory-bootstrap-425 .thumbnail a>img,.factory-bootstrap-425 .thumbnail>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}.factory-bootstrap-425 a.thumbnail.active,.factory-bootstrap-425 a.thumbnail:focus,.factory-bootstrap-425 a.thumbnail:hover{border-color:#428bca}.factory-bootstrap-425 .thumbnail .caption{padding:9px;color:#333}.factory-bootstrap-425 .alert{border:1px solid transparent;border-radius:4px}.factory-bootstrap-425 .alert h4{margin-top:0;color:inherit}.factory-bootstrap-425 .alert .alert-link{font-weight:700}.factory-bootstrap-425 .alert>p,.factory-bootstrap-425 .alert>ul{margin-bottom:0}.factory-bootstrap-425 .alert>p+p{margin-top:5px}.factory-bootstrap-425 .alert-dismissable{padding-right:35px}.factory-bootstrap-425 .alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.factory-bootstrap-425 .alert-info{color:#31708f;background-color:#d9edf7}.factory-bootstrap-425 .alert-info hr{border-top-color:#a6e1ec}.factory-bootstrap-425 .alert-info .alert-link{color:#245269}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.factory-bootstrap-425 .progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.factory-bootstrap-425 .progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#2ea2cc;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.factory-bootstrap-425 .progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.factory-bootstrap-425 .progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.factory-bootstrap-425 .progress-bar-success{background-color:#5cb85c}.factory-bootstrap-425 .progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.factory-bootstrap-425 .progress-bar-info{background-color:#5bc0de}.factory-bootstrap-425 .progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.factory-bootstrap-425 .progress-bar-warning{background-color:#f0ad4e}.factory-bootstrap-425 .progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.factory-bootstrap-425 .progress-bar-danger{background-color:#d9534f}.factory-bootstrap-425 .progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.factory-bootstrap-425 .media,.factory-bootstrap-425 .media-body{overflow:hidden;zoom:1}.factory-bootstrap-425 .media,.factory-bootstrap-425 .media .media{margin-top:15px}.factory-bootstrap-425 .media:first-child{margin-top:0}.factory-bootstrap-425 .media-object{display:block}.factory-bootstrap-425 .media-heading{margin:0 0 5px}.factory-bootstrap-425 .media>.pull-left{margin-right:10px}.factory-bootstrap-425 .media>.pull-right{margin-left:10px}.factory-bootstrap-425 .media-list{padding-left:0;list-style:none}.factory-bootstrap-425 .list-group{padding-left:0;margin-bottom:20px}.factory-bootstrap-425 .list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.factory-bootstrap-425 .list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.factory-bootstrap-425 .list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.factory-bootstrap-425 .list-group-item>.badge{float:right}.factory-bootstrap-425 .list-group-item>.badge+.badge{margin-right:5px}.factory-bootstrap-425 a.list-group-item{color:#555}.factory-bootstrap-425 a.list-group-item .list-group-item-heading{color:#333}.factory-bootstrap-425 a.list-group-item:focus,.factory-bootstrap-425 a.list-group-item:hover{text-decoration:none;background-color:#f5f5f5}.factory-bootstrap-425 a.list-group-item.active,.factory-bootstrap-425 a.list-group-item.active:focus,.factory-bootstrap-425 a.list-group-item.active:hover{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.factory-bootstrap-425 a.list-group-item.active .list-group-item-heading,.factory-bootstrap-425 a.list-group-item.active:focus .list-group-item-heading,.factory-bootstrap-425 a.list-group-item.active:hover .list-group-item-heading{color:inherit}.factory-bootstrap-425 a.list-group-item.active .list-group-item-text,.factory-bootstrap-425 a.list-group-item.active:focus .list-group-item-text,.factory-bootstrap-425 a.list-group-item.active:hover .list-group-item-text{color:#e1edf7}.factory-bootstrap-425 .list-group-item-heading{margin-top:0;margin-bottom:5px}.factory-bootstrap-425 .list-group-item-text{margin-bottom:0;line-height:1.3}.factory-bootstrap-425 .panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px}.factory-bootstrap-425 .panel-body{padding:15px}.factory-bootstrap-425 .panel-body:after,.factory-bootstrap-425 .panel-body:before{display:table;content:" "}.factory-bootstrap-425 .panel-body:after{clear:both}.factory-bootstrap-425 .panel>.list-group{margin-bottom:0}.factory-bootstrap-425 .panel>.list-group .list-group-item{border-width:1px 0}.factory-bootstrap-425 .panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.factory-bootstrap-425 .panel>.list-group .list-group-item:last-child{border-bottom:0}.factory-bootstrap-425 .panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.factory-bootstrap-425 .panel>.table,.factory-bootstrap-425 .panel>.table-responsive>.table{margin-bottom:0}.factory-bootstrap-425 .panel>.panel-body+.table,.factory-bootstrap-425 .panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.factory-bootstrap-425 .panel>.table>tbody:first-child td,.factory-bootstrap-425 .panel>.table>tbody:first-child th{border-top:0}.factory-bootstrap-425 .panel>.table-bordered,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered{border:0}.factory-bootstrap-425 .panel>.table-bordered>tbody>tr>td:first-child,.factory-bootstrap-425 .panel>.table-bordered>tbody>tr>th:first-child,.factory-bootstrap-425 .panel>.table-bordered>tfoot>tr>td:first-child,.factory-bootstrap-425 .panel>.table-bordered>tfoot>tr>th:first-child,.factory-bootstrap-425 .panel>.table-bordered>thead>tr>td:first-child,.factory-bootstrap-425 .panel>.table-bordered>thead>tr>th:first-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.factory-bootstrap-425 .panel>.table-bordered>tbody>tr>td:last-child,.factory-bootstrap-425 .panel>.table-bordered>tbody>tr>th:last-child,.factory-bootstrap-425 .panel>.table-bordered>tfoot>tr>td:last-child,.factory-bootstrap-425 .panel>.table-bordered>tfoot>tr>th:last-child,.factory-bootstrap-425 .panel>.table-bordered>thead>tr>td:last-child,.factory-bootstrap-425 .panel>.table-bordered>thead>tr>th:last-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.factory-bootstrap-425 .panel>.table-bordered>tbody>tr:last-child>td,.factory-bootstrap-425 .panel>.table-bordered>tbody>tr:last-child>th,.factory-bootstrap-425 .panel>.table-bordered>tfoot>tr:last-child>td,.factory-bootstrap-425 .panel>.table-bordered>tfoot>tr:last-child>th,.factory-bootstrap-425 .panel>.table-bordered>thead>tr:last-child>td,.factory-bootstrap-425 .panel>.table-bordered>thead>tr:last-child>th,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.factory-bootstrap-425 .panel>.table-responsive>.table-bordered>thead>tr:last-child>th{border-bottom:0}.factory-bootstrap-425 .panel>.table-responsive{margin-bottom:0;border:0}.factory-bootstrap-425 .panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.factory-bootstrap-425 .panel-heading>.dropdown .dropdown-toggle{color:inherit}.factory-bootstrap-425 .panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.factory-bootstrap-425 .panel-title>a{color:inherit}.factory-bootstrap-425 .panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.factory-bootstrap-425 .panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.factory-bootstrap-425 .panel-group .panel+.panel{margin-top:5px}.factory-bootstrap-425 .panel-group .panel-heading{border-bottom:0}.factory-bootstrap-425 .panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.factory-bootstrap-425 .panel-group .panel-footer{border-top:0}.factory-bootstrap-425 .panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.factory-bootstrap-425 .panel-default{border-color:#ddd}.factory-bootstrap-425 .panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.factory-bootstrap-425 .panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.factory-bootstrap-425 .panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.factory-bootstrap-425 .panel-primary{border-color:#428bca}.factory-bootstrap-425 .panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.factory-bootstrap-425 .panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.factory-bootstrap-425 .panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.factory-bootstrap-425 .panel-success{border-color:#d6e9c6}.factory-bootstrap-425 .panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.factory-bootstrap-425 .panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.factory-bootstrap-425 .panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.factory-bootstrap-425 .panel-warning{border-color:#faebcc}.factory-bootstrap-425 .panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.factory-bootstrap-425 .panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.factory-bootstrap-425 .panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.factory-bootstrap-425 .panel-danger{border-color:#ebccd1}.factory-bootstrap-425 .panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.factory-bootstrap-425 .panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.factory-bootstrap-425 .panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.factory-bootstrap-425 .panel-info{border-color:#bce8f1}.factory-bootstrap-425 .panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.factory-bootstrap-425 .panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.factory-bootstrap-425 .panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.factory-bootstrap-425 .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px}.factory-bootstrap-425 .well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.factory-bootstrap-425 .well-lg{padding:24px;border-radius:6px}.factory-bootstrap-425 .well-sm{padding:9px;border-radius:3px}.factory-bootstrap-425 .close{float:right;font-size:14px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.3;filter:alpha(opacity=30)}.factory-bootstrap-425 .alert .close{position:relative;top:-8px;right:-7px}.factory-bootstrap-425 .close:focus,.factory-bootstrap-425 .close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}.factory-bootstrap-425 button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.factory-bootstrap-425 .modal-open{overflow:hidden}.factory-bootstrap-425 .modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll;width:auto;margin-left:0;background-color:transparent;border:0}.factory-bootstrap-425 .modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.factory-bootstrap-425 .modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.factory-bootstrap-425 .modal-dialog{position:relative;z-index:1050;width:auto;margin:10px}.factory-bootstrap-425 .modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box}.factory-bootstrap-425 .modal-backdrop,.factory-bootstrap-425-modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.factory-bootstrap-425 .modal-backdrop.fade,.factory-bootstrap-425-modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.factory-bootstrap-425 .modal-backdrop.in,.factory-bootstrap-425-modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.factory-bootstrap-425 .modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.factory-bootstrap-425 .modal-header .close{margin-top:-2px}.factory-bootstrap-425 .modal-title{margin:0;line-height:1.428571429}.factory-bootstrap-425 .modal-body{position:relative;padding:20px;max-height:none}.factory-bootstrap-425 .modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.factory-bootstrap-425 .modal-footer:after,.factory-bootstrap-425 .modal-footer:before{display:table;content:" "}.factory-bootstrap-425 .modal-footer:after{clear:both}.factory-bootstrap-425 .modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.factory-bootstrap-425 .modal-footer .btn-group .btn+.btn{margin-left:-1px}.factory-bootstrap-425 .modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.factory-bootstrap-425 .modal-dialog{width:600px;margin:30px auto}.factory-bootstrap-425 .modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}}.factory-bootstrap-425 .tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.factory-bootstrap-425 .tooltip.in{opacity:.9;filter:alpha(opacity=90)}.factory-bootstrap-425 .tooltip.top{padding:5px 0;margin-top:-3px}.factory-bootstrap-425 .tooltip.right{padding:0 5px;margin-left:3px}.factory-bootstrap-425 .tooltip.bottom{padding:5px 0;margin-top:3px}.factory-bootstrap-425 .tooltip.left{padding:0 5px;margin-left:-3px}.factory-bootstrap-425 .tooltip-inner{width:400px;padding:15px 20px;color:#fff;text-align:left;text-decoration:none;background-color:#673ab7;border-radius:3px}.factory-bootstrap-425 .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.factory-bootstrap-425 .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#673ab7;border-width:5px 5px 0}.factory-bootstrap-425 .tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#673ab7;border-width:5px 5px 0}.factory-bootstrap-425 .tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#673ab7;border-width:5px 5px 0}.factory-bootstrap-425 .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#673ab7;border-width:5px 5px 5px 0}.factory-bootstrap-425 .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#673ab7;border-width:5px 0 5px 5px}.factory-bootstrap-425 .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#673ab7;border-width:0 5px 5px}.factory-bootstrap-425 .tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#673ab7;border-width:0 5px 5px}.factory-bootstrap-425 .tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#673ab7;border-width:0 5px 5px}.factory-bootstrap-425 .popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);background-clip:padding-box}.factory-bootstrap-425 .popover.top{margin-top:-10px}.factory-bootstrap-425 .popover.right{margin-left:10px}.factory-bootstrap-425 .popover.bottom{margin-top:10px}.factory-bootstrap-425 .popover.left{margin-left:-10px}.factory-bootstrap-425 .popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.factory-bootstrap-425 .popover-content{padding:9px 14px}.factory-bootstrap-425 .popover .arrow,.factory-bootstrap-425 .popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.factory-bootstrap-425 .popover .arrow{border-width:11px}.factory-bootstrap-425 .popover .arrow:after{border-width:10px;content:""}.factory-bootstrap-425 .popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.factory-bootstrap-425 .popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.factory-bootstrap-425 .popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.factory-bootstrap-425 .popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.factory-bootstrap-425 .popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);border-top-width:0}.factory-bootstrap-425 .popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.factory-bootstrap-425 .popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,.25);border-right-width:0}.factory-bootstrap-425 .popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.factory-bootstrap-425 .carousel{position:relative}.factory-bootstrap-425 .carousel-inner{position:relative;width:100%;overflow:hidden}.factory-bootstrap-425 .carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.factory-bootstrap-425 .carousel-inner>.item>a>img,.factory-bootstrap-425 .carousel-inner>.item>img{display:block;height:auto;max-width:100%;line-height:1}.factory-bootstrap-425 .carousel-inner>.active,.factory-bootstrap-425 .carousel-inner>.next,.factory-bootstrap-425 .carousel-inner>.prev{display:block}.factory-bootstrap-425 .carousel-inner>.active{left:0}.factory-bootstrap-425 .carousel-inner>.next,.factory-bootstrap-425 .carousel-inner>.prev{position:absolute;top:0;width:100%}.factory-bootstrap-425 .carousel-inner>.next{left:100%}.factory-bootstrap-425 .carousel-inner>.prev{left:-100%}.factory-bootstrap-425 .carousel-inner>.next.left,.factory-bootstrap-425 .carousel-inner>.prev.right{left:0}.factory-bootstrap-425 .carousel-inner>.active.left{left:-100%}.factory-bootstrap-425 .carousel-inner>.active.right{left:100%}.factory-bootstrap-425 .carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);opacity:.5;filter:alpha(opacity=50)}.factory-bootstrap-425 .carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.5) 0),color-stop(rgba(0,0,0,.0001) 100%));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.factory-bootstrap-425 .carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.0001) 0),color-stop(rgba(0,0,0,.5) 100%));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.factory-bootstrap-425 .carousel-control:focus,.factory-bootstrap-425 .carousel-control:hover{color:#fff;text-decoration:none;outline:0;opacity:.9;filter:alpha(opacity=90)}.factory-bootstrap-425 .carousel-control .glyphicon-chevron-left,.factory-bootstrap-425 .carousel-control .glyphicon-chevron-right,.factory-bootstrap-425 .carousel-control .icon-next,.factory-bootstrap-425 .carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.factory-bootstrap-425 .carousel-control .glyphicon-chevron-left,.factory-bootstrap-425 .carousel-control .icon-prev{left:50%}.factory-bootstrap-425 .carousel-control .glyphicon-chevron-right,.factory-bootstrap-425 .carousel-control .icon-next{right:50%}.factory-bootstrap-425 .carousel-control .icon-next,.factory-bootstrap-425 .carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.factory-bootstrap-425 .carousel-control .icon-prev:before{content:'\2039'}.factory-bootstrap-425 .carousel-control .icon-next:before{content:'\203a'}.factory-bootstrap-425 .carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.factory-bootstrap-425 .carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.factory-bootstrap-425 .carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.factory-bootstrap-425 .carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.factory-bootstrap-425 .carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.factory-bootstrap-425 .clearfix:after,.factory-bootstrap-425 .clearfix:before{display:table;content:" "}.factory-bootstrap-425 .clearfix:after{clear:both}.factory-bootstrap-425 .center-block{display:block;margin-right:auto;margin-left:auto}.factory-bootstrap-425 .pull-right{float:right!important}.factory-bootstrap-425 .pull-left{float:left!important}.factory-bootstrap-425 .hide{display:none!important}.factory-bootstrap-425 .show{display:block!important}.factory-bootstrap-425 .invisible{visibility:hidden}.factory-bootstrap-425 .text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.factory-bootstrap-425 .hidden{display:none!important;visibility:hidden!important}.factory-bootstrap-425 .affix{position:fixed}@-ms-viewport{width:device-width}.factory-bootstrap-425 .visible-lg,.factory-bootstrap-425 .visible-md,.factory-bootstrap-425 .visible-sm,.factory-bootstrap-425 .visible-xs,.factory-bootstrap-425 td.visible-lg,.factory-bootstrap-425 td.visible-md,.factory-bootstrap-425 td.visible-sm,.factory-bootstrap-425 td.visible-xs,.factory-bootstrap-425 th.visible-lg,.factory-bootstrap-425 th.visible-md,.factory-bootstrap-425 th.visible-sm,.factory-bootstrap-425 th.visible-xs,.factory-bootstrap-425 tr.visible-lg,.factory-bootstrap-425 tr.visible-md,.factory-bootstrap-425 tr.visible-sm,.factory-bootstrap-425 tr.visible-xs{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}table.visible-xs.visible-sm{display:table}tr.visible-xs.visible-sm{display:table-row!important}td.visible-xs.visible-sm,th.visible-xs.visible-sm{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}table.visible-xs.visible-md{display:table}tr.visible-xs.visible-md{display:table-row!important}td.visible-xs.visible-md,th.visible-xs.visible-md{display:table-cell!important}}@media (min-width:1200px){.visible-xs.visible-lg{display:block!important}table.visible-xs.visible-lg{display:table}tr.visible-xs.visible-lg{display:table-row!important}td.visible-xs.visible-lg,th.visible-xs.visible-lg{display:table-cell!important}}@media (max-width:767px){.visible-sm.visible-xs{display:block!important}table.visible-sm.visible-xs{display:table}tr.visible-sm.visible-xs{display:table-row!important}td.visible-sm.visible-xs,th.visible-sm.visible-xs{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}table.visible-sm.visible-md{display:table}tr.visible-sm.visible-md{display:table-row!important}td.visible-sm.visible-md,th.visible-sm.visible-md{display:table-cell!important}}@media (min-width:1200px){.visible-sm.visible-lg{display:block!important}table.visible-sm.visible-lg{display:table}tr.visible-sm.visible-lg{display:table-row!important}td.visible-sm.visible-lg,th.visible-sm.visible-lg{display:table-cell!important}}@media (max-width:767px){.visible-md.visible-xs{display:block!important}table.visible-md.visible-xs{display:table}tr.visible-md.visible-xs{display:table-row!important}td.visible-md.visible-xs,th.visible-md.visible-xs{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}table.visible-md.visible-sm{display:table}tr.visible-md.visible-sm{display:table-row!important}td.visible-md.visible-sm,th.visible-md.visible-sm{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:1200px){.visible-md.visible-lg{display:block!important}table.visible-md.visible-lg{display:table}tr.visible-md.visible-lg{display:table-row!important}td.visible-md.visible-lg,th.visible-md.visible-lg{display:table-cell!important}}@media (max-width:767px){.visible-lg.visible-xs{display:block!important}table.visible-lg.visible-xs{display:table}tr.visible-lg.visible-xs{display:table-row!important}td.visible-lg.visible-xs,th.visible-lg.visible-xs{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}table.visible-lg.visible-sm{display:table}tr.visible-lg.visible-sm{display:table-row!important}td.visible-lg.visible-sm,th.visible-lg.visible-sm{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}table.visible-lg.visible-md{display:table}tr.visible-lg.visible-md{display:table-row!important}td.visible-lg.visible-md,th.visible-lg.visible-md{display:table-cell!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}.factory-bootstrap-425 .hidden-xs{display:block!important}.factory-bootstrap-425 table.hidden-xs{display:table}.factory-bootstrap-425 tr.hidden-xs{display:table-row!important}.factory-bootstrap-425 td.hidden-xs,.factory-bootstrap-425 th.hidden-xs{display:table-cell!important}@media (max-width:767px){.hidden-xs,td.hidden-xs,th.hidden-xs,tr.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,td.hidden-xs.hidden-md,th.hidden-xs.hidden-md,tr.hidden-xs.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg{display:none!important}}.factory-bootstrap-425 .hidden-sm{display:block!important}.factory-bootstrap-425 table.hidden-sm{display:table}.factory-bootstrap-425 tr.hidden-sm{display:table-row!important}.factory-bootstrap-425 td.hidden-sm,.factory-bootstrap-425 th.hidden-sm{display:table-cell!important}@media (max-width:767px){.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm,td.hidden-sm,th.hidden-sm,tr.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,td.hidden-sm.hidden-md,th.hidden-sm.hidden-md,tr.hidden-sm.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg{display:none!important}}.factory-bootstrap-425 .hidden-md{display:block!important}.factory-bootstrap-425 table.hidden-md{display:table}.factory-bootstrap-425 tr.hidden-md{display:table-row!important}.factory-bootstrap-425 td.hidden-md,.factory-bootstrap-425 th.hidden-md{display:table-cell!important}@media (max-width:767px){.hidden-md.hidden-xs,td.hidden-md.hidden-xs,th.hidden-md.hidden-xs,tr.hidden-md.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,td.hidden-md.hidden-sm,th.hidden-md.hidden-sm,tr.hidden-md.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md,td.hidden-md,th.hidden-md,tr.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-md.hidden-lg,td.hidden-md.hidden-lg,th.hidden-md.hidden-lg,tr.hidden-md.hidden-lg{display:none!important}}.factory-bootstrap-425 .hidden-lg{display:block!important}.factory-bootstrap-425 table.hidden-lg{display:table}.factory-bootstrap-425 tr.hidden-lg{display:table-row!important}.factory-bootstrap-425 td.hidden-lg,.factory-bootstrap-425 th.hidden-lg{display:table-cell!important}@media (max-width:767px){.factory-bootstrap-425 .hidden-lg.hidden-xs,.factory-bootstrap-425 td.hidden-lg.hidden-xs,.factory-bootstrap-425 th.hidden-lg.hidden-xs,.factory-bootstrap-425 tr.hidden-lg.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.factory-bootstrap-425 .hidden-lg.hidden-sm,.factory-bootstrap-425 td.hidden-lg.hidden-sm,.factory-bootstrap-425 th.hidden-lg.hidden-sm,.factory-bootstrap-425 tr.hidden-lg.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.factory-bootstrap-425 .hidden-lg.hidden-md,.factory-bootstrap-425 td.hidden-lg.hidden-md,.factory-bootstrap-425 th.hidden-lg.hidden-md,.factory-bootstrap-425 tr.hidden-lg.hidden-md{display:none!important}}@media (min-width:1200px){.factory-bootstrap-425 .hidden-lg,.factory-bootstrap-425 td.hidden-lg,.factory-bootstrap-425 th.hidden-lg,.factory-bootstrap-425 tr.hidden-lg{display:none!important}}.factory-bootstrap-425 .visible-print,.factory-bootstrap-425 td.visible-print,.factory-bootstrap-425 th.visible-print,.factory-bootstrap-425 tr.visible-print{display:none!important}@media print{.factory-bootstrap-425 .visible-print{display:block!important}.factory-bootstrap-425 table.visible-print{display:table}.factory-bootstrap-425 tr.visible-print{display:table-row!important}.factory-bootstrap-425 td.visible-print,.factory-bootstrap-425 th.visible-print{display:table-cell!important}.factory-bootstrap-425 .hidden-print,.factory-bootstrap-425 td.hidden-print,.factory-bootstrap-425 th.hidden-print,.factory-bootstrap-425 tr.hidden-print{display:none!important}}/*!
12
+ * Factory Default Bootstrap Theme
13
+ *
14
+ * The code is based on Bootstrap v2.1.1
15
+ *
16
+ * Bootstrap v3.0.3 (http://getbootstrap.com)
17
+ * Copyright 2013 Twitter, Inc.
18
+ * Licensed under http://www.apache.org/licenses/LICENSE-2.0
19
+ *
20
+ * @author Paul Kashtanoff <paul@byonepress.com>
21
+ * @copyright (c) 2013, OnePress Ltd
22
+ *
23
+ * @package factory-bootstrap
24
+ * @since 1.0.0
25
+ */.factory-bootstrap-425 .btn-danger,.factory-bootstrap-425 .btn-default,.factory-bootstrap-425 .btn-info,.factory-bootstrap-425 .btn-primary,.factory-bootstrap-425 .btn-success,.factory-bootstrap-425 .btn-warning{-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.factory-bootstrap-425 .btn-danger.active,.factory-bootstrap-425 .btn-danger:active,.factory-bootstrap-425 .btn-default.active,.factory-bootstrap-425 .btn-default:active,.factory-bootstrap-425 .btn-info.active,.factory-bootstrap-425 .btn-info:active,.factory-bootstrap-425 .btn-primary.active,.factory-bootstrap-425 .btn-primary:active,.factory-bootstrap-425 .btn-success.active,.factory-bootstrap-425 .btn-success:active,.factory-bootstrap-425 .btn-warning.active,.factory-bootstrap-425 .btn-warning:active{-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.1);box-shadow:inset 0 1px 1px rgba(0,0,0,.1)}.factory-bootstrap-425 .btn.active,.factory-bootstrap-425 .btn:active{background-image:none}.factory-bootstrap-425 .btn-default{color:#555;border-color:#ccc;background:#f7f7f7;-webkit-box-shadow:inset 0 1px 0 #fff,0 1px 0 rgba(0,0,0,.08);box-shadow:inset 0 1px 0 #fff,0 1px 0 rgba(0,0,0,.08);vertical-align:top}.factory-bootstrap-425 .btn-default.active,.factory-bootstrap-425 .btn-default:active{background-color:#fff;border-color:#dbdbdb}.factory-bootstrap-425 .btn-gold{font-weight:700;padding:7px 12px;cursor:pointer;line-height:16px;display:inline-block;border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px;box-shadow:#e3e3e3 0 1px 1px;-moz-box-shadow:0 1px 1px rgba(000,000,000,.1),inset 0 1px 1px rgba(255,255,255,.7);-webkit-box-shadow:0 1px 1px rgba(000,000,000,.1),inset 0 1px 1px rgba(255,255,255,.7);text-shadow:1px 1px 0 #ffe8b2;color:#7c5d1b;border:1px solid #d6a437;background:#feeb80}.factory-bootstrap-425 .btn-gold:focus,.factory-bootstrap-425 .btn-gold:hover{background:#fef0a1}.factory-bootstrap-425 .btn-gold.active,.factory-bootstrap-425 .btn-gold:active{background:#fef0a1;-webkit-box-shadow:inset 0 3px 8px 0 #f8ba36;box-shadow:inset 0 3px 8px 0 #f8ba36}.factory-bootstrap-425 .btn-primary{background:#2ea2cc;border-color:#0074a2;-webkit-box-shadow:inset 0 1px 0 rgba(120,200,230,.5),0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 rgba(120,200,230,.5),0 1px 0 rgba(0,0,0,.15);color:#fff;text-decoration:none}.factory-bootstrap-425 .btn-primary:focus,.factory-bootstrap-425 .btn-primary:hover{background:#1e8cbe;border-color:#0074a2;-webkit-box-shadow:inset 0 1px 0 rgba(120,200,230,.6);box-shadow:inset 0 1px 0 rgba(120,200,230,.6);color:#fff}.factory-bootstrap-425 .btn-primary.active,.factory-bootstrap-425 .btn-primary:active{background-color:#2d6ca2;border-color:#2b669a}.factory-bootstrap-425 .btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.factory-bootstrap-425 .btn-success:focus,.factory-bootstrap-425 .btn-success:hover{background-color:#419641;background-position:0 -15px}.factory-bootstrap-425 .btn-success.active,.factory-bootstrap-425 .btn-success:active{background-color:#419641;border-color:#3e8f3e}.factory-bootstrap-425 .btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.factory-bootstrap-425 .btn-warning:focus,.factory-bootstrap-425 .btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.factory-bootstrap-425 .btn-warning.active,.factory-bootstrap-425 .btn-warning:active{background-color:#eb9316;border-color:#e38d13}.factory-bootstrap-425 .btn-danger{color:#fff;background:#d9534f;border-color:#d43f3a}.factory-bootstrap-425 .btn-danger.active,.factory-bootstrap-425 .btn-danger:active,.factory-bootstrap-425 .btn-danger:focus,.factory-bootstrap-425 .btn-danger:hover,.factory-bootstrap-425 .open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.factory-bootstrap-425 .btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.factory-bootstrap-425 .btn-info:focus,.factory-bootstrap-425 .btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.factory-bootstrap-425 .btn-info.active,.factory-bootstrap-425 .btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.factory-bootstrap-425 .img-thumbnail,.factory-bootstrap-425 .thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.factory-bootstrap-425 .dropdown-menu>li>a:focus,.factory-bootstrap-425 .dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.factory-bootstrap-425 .dropdown-menu>.active>a,.factory-bootstrap-425 .dropdown-menu>.active>a:focus,.factory-bootstrap-425 .dropdown-menu>.active>a:hover{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.factory-bootstrap-425 .navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.factory-bootstrap-425 .navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.factory-bootstrap-425 .navbar-brand,.factory-bootstrap-425 .navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.factory-bootstrap-425 .navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.factory-bootstrap-425 .navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.factory-bootstrap-425 .navbar-inverse .navbar-brand,.factory-bootstrap-425 .navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.factory-bootstrap-425 .navbar-fixed-bottom,.factory-bootstrap-425 .navbar-fixed-top,.factory-bootstrap-425 .navbar-static-top{border-radius:0}.factory-bootstrap-425 .alert{-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.factory-bootstrap-425 .alert .actions{padding-top:10px}.factory-bootstrap-425 .alert-success{color:#3c763d;background-color:#dff0d8;border-bottom:2px solid #c8e5bc}.factory-bootstrap-425 .alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0)}.factory-bootstrap-425 .alert{text-shadow:none;box-shadow:none;margin:0;margin-top:10px;margin-bottom:10px;padding:10px}.factory-bootstrap-425 .alert-normal,.factory-bootstrap-425 .alert-warning{background:#fcf8e3;color:#8a6d3b;border:1px solid #b8823b}.factory-bootstrap-425 .alert-danger{background:#cf4944;color:#fff;border-bottom:2px solid #b23e3a}.factory-bootstrap-425 .alert-danger a:not(.btn),.factory-bootstrap-425 .alert-error a:not(.btn){color:#fff}.factory-bootstrap-425 .progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.factory-bootstrap-425 .progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0)}.factory-bootstrap-425 .progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.factory-bootstrap-425 .progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.factory-bootstrap-425 .progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.factory-bootstrap-425 .progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.factory-bootstrap-425 .list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.factory-bootstrap-425 .list-group-item.active,.factory-bootstrap-425 .list-group-item.active:focus,.factory-bootstrap-425 .list-group-item.active:hover{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0)}.factory-bootstrap-425 .panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.factory-bootstrap-425 .panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.factory-bootstrap-425 .panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.factory-bootstrap-425 .panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0)}.factory-bootstrap-425 .panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0)}.factory-bootstrap-425 .panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0)}.factory-bootstrap-425 .panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0)}.factory-bootstrap-425 .well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}.factory-bootstrap-425 .factory-after{margin-left:7px;display:inline-block}.factory-bootstrap-425 .factory-hidden{display:none}.factory-bootstrap-425 .factory-ajax-loader{width:25px;height:25px;background:url(../assets/images/loader-sm-tr.gif)}.factory-control-error{background-color:rgba(0,0,0,.8);white-space:normal;z-index:10;font-weight:400;line-height:150%;border-radius:4px;color:#fff;font-size:13px;margin-top:5px;padding:4px 10px 3px;max-width:500px;display:inline-block}.factory-control-error i{margin:0 7px 0 1px}
libs/factory/bootstrap/assets/css-min/bootstrap.datepicker.min.css ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ /*!
12
+ * Datepicker for Bootstrap v1.5.0-dev (https://github.com/eternicode/bootstrap-datepicker)
13
+ *
14
+ * Copyright 2012 Stefan Petre
15
+ * Improvements by Andrew Rowls
16
+ * Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
17
+ */.datepicker{border-radius:4px;direction:ltr}.datepicker-inline{width:220px}.datepicker.datepicker-rtl{direction:rtl}.datepicker.datepicker-rtl table tr td span{float:right}.datepicker-dropdown{top:0;left:0}.datepicker-dropdown:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-top:0;border-bottom-color:rgba(0,0,0,.2);position:absolute}.datepicker-dropdown:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;border-top:0;position:absolute}.datepicker-dropdown.datepicker-orient-left:before{left:6px}.datepicker-dropdown.datepicker-orient-left:after{left:7px}.datepicker-dropdown.datepicker-orient-right:before{right:6px}.datepicker-dropdown.datepicker-orient-right:after{right:7px}.datepicker-dropdown.datepicker-orient-top:before{top:-7px}.datepicker-dropdown.datepicker-orient-top:after{top:-6px}.datepicker-dropdown.datepicker-orient-bottom:before{bottom:-7px;border-bottom:0;border-top:7px solid #999}.datepicker-dropdown.datepicker-orient-bottom:after{bottom:-6px;border-bottom:0;border-top:6px solid #fff}.datepicker>div{display:none}.datepicker.days .datepicker-days,.datepicker.months .datepicker-months,.datepicker.years .datepicker-years{display:block}.datepicker table{margin:0;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.datepicker table tr td,.datepicker table tr th{text-align:center;width:30px;height:30px;border-radius:4px;border:0}.table-striped .datepicker table tr td,.table-striped .datepicker table tr th{background-color:transparent}.datepicker table tr td.day.focused,.datepicker table tr td.day:hover{background:#eee;cursor:pointer}.datepicker table tr td.new,.datepicker table tr td.old{color:#999}.datepicker table tr td.disabled,.datepicker table tr td.disabled:hover{background:0 0;color:#999;cursor:default}.datepicker table tr td.today,.datepicker table tr td.today.disabled,.datepicker table tr td.today.disabled:hover,.datepicker table tr td.today:hover{color:#000;background-color:#ffdb99;border-color:#ffb733}.datepicker table tr td.today.active,.datepicker table tr td.today.disabled.active,.datepicker table tr td.today.disabled:active,.datepicker table tr td.today.disabled:focus,.datepicker table tr td.today.disabled:hover,.datepicker table tr td.today.disabled:hover.active,.datepicker table tr td.today.disabled:hover:active,.datepicker table tr td.today.disabled:hover:focus,.datepicker table tr td.today.disabled:hover:hover,.datepicker table tr td.today:active,.datepicker table tr td.today:focus,.datepicker table tr td.today:hover,.datepicker table tr td.today:hover.active,.datepicker table tr td.today:hover:active,.datepicker table tr td.today:hover:focus,.datepicker table tr td.today:hover:hover,.open .dropdown-toggle.datepicker table tr td.today,.open .dropdown-toggle.datepicker table tr td.today.disabled,.open .dropdown-toggle.datepicker table tr td.today.disabled:hover,.open .dropdown-toggle.datepicker table tr td.today:hover{color:#000;background-color:#ffcd70;border-color:#f59e00}.datepicker table tr td.today.active,.datepicker table tr td.today.disabled.active,.datepicker table tr td.today.disabled:active,.datepicker table tr td.today.disabled:hover.active,.datepicker table tr td.today.disabled:hover:active,.datepicker table tr td.today:active,.datepicker table tr td.today:hover.active,.datepicker table tr td.today:hover:active,.open .dropdown-toggle.datepicker table tr td.today,.open .dropdown-toggle.datepicker table tr td.today.disabled,.open .dropdown-toggle.datepicker table tr td.today.disabled:hover,.open .dropdown-toggle.datepicker table tr td.today:hover{background-image:none}.datepicker table tr td.today.disabled,.datepicker table tr td.today.disabled.active,.datepicker table tr td.today.disabled.disabled,.datepicker table tr td.today.disabled.disabled.active,.datepicker table tr td.today.disabled.disabled:active,.datepicker table tr td.today.disabled.disabled:focus,.datepicker table tr td.today.disabled.disabled:hover,.datepicker table tr td.today.disabled:active,.datepicker table tr td.today.disabled:focus,.datepicker table tr td.today.disabled:hover,.datepicker table tr td.today.disabled:hover.disabled,.datepicker table tr td.today.disabled:hover.disabled.active,.datepicker table tr td.today.disabled:hover.disabled:active,.datepicker table tr td.today.disabled:hover.disabled:focus,.datepicker table tr td.today.disabled:hover.disabled:hover,.datepicker table tr td.today.disabled:hover[disabled],.datepicker table tr td.today.disabled:hover[disabled].active,.datepicker table tr td.today.disabled:hover[disabled]:active,.datepicker table tr td.today.disabled:hover[disabled]:focus,.datepicker table tr td.today.disabled:hover[disabled]:hover,.datepicker table tr td.today.disabled[disabled],.datepicker table tr td.today.disabled[disabled].active,.datepicker table tr td.today.disabled[disabled]:active,.datepicker table tr td.today.disabled[disabled]:focus,.datepicker table tr td.today.disabled[disabled]:hover,.datepicker table tr td.today:hover.disabled,.datepicker table tr td.today:hover.disabled.active,.datepicker table tr td.today:hover.disabled:active,.datepicker table tr td.today:hover.disabled:focus,.datepicker table tr td.today:hover.disabled:hover,.datepicker table tr td.today:hover[disabled],.datepicker table tr td.today:hover[disabled].active,.datepicker table tr td.today:hover[disabled]:active,.datepicker table tr td.today:hover[disabled]:focus,.datepicker table tr td.today:hover[disabled]:hover,.datepicker table tr td.today[disabled],.datepicker table tr td.today[disabled].active,.datepicker table tr td.today[disabled]:active,.datepicker table tr td.today[disabled]:focus,.datepicker table tr td.today[disabled]:hover,fieldset[disabled] .datepicker table tr td.today,fieldset[disabled] .datepicker table tr td.today.active,fieldset[disabled] .datepicker table tr td.today.disabled,fieldset[disabled] .datepicker table tr td.today.disabled.active,fieldset[disabled] .datepicker table tr td.today.disabled:active,fieldset[disabled] .datepicker table tr td.today.disabled:focus,fieldset[disabled] .datepicker table tr td.today.disabled:hover,fieldset[disabled] .datepicker table tr td.today.disabled:hover.active,fieldset[disabled] .datepicker table tr td.today.disabled:hover:active,fieldset[disabled] .datepicker table tr td.today.disabled:hover:focus,fieldset[disabled] .datepicker table tr td.today.disabled:hover:hover,fieldset[disabled] .datepicker table tr td.today:active,fieldset[disabled] .datepicker table tr td.today:focus,fieldset[disabled] .datepicker table tr td.today:hover,fieldset[disabled] .datepicker table tr td.today:hover.active,fieldset[disabled] .datepicker table tr td.today:hover:active,fieldset[disabled] .datepicker table tr td.today:hover:focus,fieldset[disabled] .datepicker table tr td.today:hover:hover{background-color:#ffdb99;border-color:#ffb733}.datepicker table tr td.today:hover:hover{color:#000}.datepicker table tr td.today.active:hover{color:#fff}.datepicker table tr td.range,.datepicker table tr td.range.disabled,.datepicker table tr td.range.disabled:hover,.datepicker table tr td.range:hover{background:#eee;border-radius:0}.datepicker table tr td.range.today,.datepicker table tr td.range.today.disabled,.datepicker table tr td.range.today.disabled:hover,.datepicker table tr td.range.today:hover{color:#000;background-color:#f7ca77;border-color:#f1a417;border-radius:0}.datepicker table tr td.range.today.active,.datepicker table tr td.range.today.disabled.active,.datepicker table tr td.range.today.disabled:active,.datepicker table tr td.range.today.disabled:focus,.datepicker table tr td.range.today.disabled:hover,.datepicker table tr td.range.today.disabled:hover.active,.datepicker table tr td.range.today.disabled:hover:active,.datepicker table tr td.range.today.disabled:hover:focus,.datepicker table tr td.range.today.disabled:hover:hover,.datepicker table tr td.range.today:active,.datepicker table tr td.range.today:focus,.datepicker table tr td.range.today:hover,.datepicker table tr td.range.today:hover.active,.datepicker table tr td.range.today:hover:active,.datepicker table tr td.range.today:hover:focus,.datepicker table tr td.range.today:hover:hover,.open .dropdown-toggle.datepicker table tr td.range.today,.open .dropdown-toggle.datepicker table tr td.range.today.disabled,.open .dropdown-toggle.datepicker table tr td.range.today.disabled:hover,.open .dropdown-toggle.datepicker table tr td.range.today:hover{color:#000;background-color:#f4bb51;border-color:#bf800c}.datepicker table tr td.range.today.active,.datepicker table tr td.range.today.disabled.active,.datepicker table tr td.range.today.disabled:active,.datepicker table tr td.range.today.disabled:hover.active,.datepicker table tr td.range.today.disabled:hover:active,.datepicker table tr td.range.today:active,.datepicker table tr td.range.today:hover.active,.datepicker table tr td.range.today:hover:active,.open .dropdown-toggle.datepicker table tr td.range.today,.open .dropdown-toggle.datepicker table tr td.range.today.disabled,.open .dropdown-toggle.datepicker table tr td.range.today.disabled:hover,.open .dropdown-toggle.datepicker table tr td.range.today:hover{background-image:none}.datepicker table tr td.range.today.disabled,.datepicker table tr td.range.today.disabled.active,.datepicker table tr td.range.today.disabled.disabled,.datepicker table tr td.range.today.disabled.disabled.active,.datepicker table tr td.range.today.disabled.disabled:active,.datepicker table tr td.range.today.disabled.disabled:focus,.datepicker table tr td.range.today.disabled.disabled:hover,.datepicker table tr td.range.today.disabled:active,.datepicker table tr td.range.today.disabled:focus,.datepicker table tr td.range.today.disabled:hover,.datepicker table tr td.range.today.disabled:hover.disabled,.datepicker table tr td.range.today.disabled:hover.disabled.active,.datepicker table tr td.range.today.disabled:hover.disabled:active,.datepicker table tr td.range.today.disabled:hover.disabled:focus,.datepicker table tr td.range.today.disabled:hover.disabled:hover,.datepicker table tr td.range.today.disabled:hover[disabled],.datepicker table tr td.range.today.disabled:hover[disabled].active,.datepicker table tr td.range.today.disabled:hover[disabled]:active,.datepicker table tr td.range.today.disabled:hover[disabled]:focus,.datepicker table tr td.range.today.disabled:hover[disabled]:hover,.datepicker table tr td.range.today.disabled[disabled],.datepicker table tr td.range.today.disabled[disabled].active,.datepicker table tr td.range.today.disabled[disabled]:active,.datepicker table tr td.range.today.disabled[disabled]:focus,.datepicker table tr td.range.today.disabled[disabled]:hover,.datepicker table tr td.range.today:hover.disabled,.datepicker table tr td.range.today:hover.disabled.active,.datepicker table tr td.range.today:hover.disabled:active,.datepicker table tr td.range.today:hover.disabled:focus,.datepicker table tr td.range.today:hover.disabled:hover,.datepicker table tr td.range.today:hover[disabled],.datepicker table tr td.range.today:hover[disabled].active,.datepicker table tr td.range.today:hover[disabled]:active,.datepicker table tr td.range.today:hover[disabled]:focus,.datepicker table tr td.range.today:hover[disabled]:hover,.datepicker table tr td.range.today[disabled],.datepicker table tr td.range.today[disabled].active,.datepicker table tr td.range.today[disabled]:active,.datepicker table tr td.range.today[disabled]:focus,.datepicker table tr td.range.today[disabled]:hover,fieldset[disabled] .datepicker table tr td.range.today,fieldset[disabled] .datepicker table tr td.range.today.active,fieldset[disabled] .datepicker table tr td.range.today.disabled,fieldset[disabled] .datepicker table tr td.range.today.disabled.active,fieldset[disabled] .datepicker table tr td.range.today.disabled:active,fieldset[disabled] .datepicker table tr td.range.today.disabled:focus,fieldset[disabled] .datepicker table tr td.range.today.disabled:hover,fieldset[disabled] .datepicker table tr td.range.today.disabled:hover.active,fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:active,fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:focus,fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:hover,fieldset[disabled] .datepicker table tr td.range.today:active,fieldset[disabled] .datepicker table tr td.range.today:focus,fieldset[disabled] .datepicker table tr td.range.today:hover,fieldset[disabled] .datepicker table tr td.range.today:hover.active,fieldset[disabled] .datepicker table tr td.range.today:hover:active,fieldset[disabled] .datepicker table tr td.range.today:hover:focus,fieldset[disabled] .datepicker table tr td.range.today:hover:hover{background-color:#f7ca77;border-color:#f1a417}.datepicker table tr td.selected,.datepicker table tr td.selected.disabled,.datepicker table tr td.selected.disabled:hover,.datepicker table tr td.selected:hover{color:#fff;background-color:#999;border-color:#555;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.datepicker table tr td.selected.active,.datepicker table tr td.selected.disabled.active,.datepicker table tr td.selected.disabled:active,.datepicker table tr td.selected.disabled:focus,.datepicker table tr td.selected.disabled:hover,.datepicker table tr td.selected.disabled:hover.active,.datepicker table tr td.selected.disabled:hover:active,.datepicker table tr td.selected.disabled:hover:focus,.datepicker table tr td.selected.disabled:hover:hover,.datepicker table tr td.selected:active,.datepicker table tr td.selected:focus,.datepicker table tr td.selected:hover,.datepicker table tr td.selected:hover.active,.datepicker table tr td.selected:hover:active,.datepicker table tr td.selected:hover:focus,.datepicker table tr td.selected:hover:hover,.open .dropdown-toggle.datepicker table tr td.selected,.open .dropdown-toggle.datepicker table tr td.selected.disabled,.open .dropdown-toggle.datepicker table tr td.selected.disabled:hover,.open .dropdown-toggle.datepicker table tr td.selected:hover{color:#fff;background-color:#858585;border-color:#373737}.datepicker table tr td.selected.active,.datepicker table tr td.selected.disabled.active,.datepicker table tr td.selected.disabled:active,.datepicker table tr td.selected.disabled:hover.active,.datepicker table tr td.selected.disabled:hover:active,.datepicker table tr td.selected:active,.datepicker table tr td.selected:hover.active,.datepicker table tr td.selected:hover:active,.open .dropdown-toggle.datepicker table tr td.selected,.open .dropdown-toggle.datepicker table tr td.selected.disabled,.open .dropdown-toggle.datepicker table tr td.selected.disabled:hover,.open .dropdown-toggle.datepicker table tr td.selected:hover{background-image:none}.datepicker table tr td.selected.disabled,.datepicker table tr td.selected.disabled.active,.datepicker table tr td.selected.disabled.disabled,.datepicker table tr td.selected.disabled.disabled.active,.datepicker table tr td.selected.disabled.disabled:active,.datepicker table tr td.selected.disabled.disabled:focus,.datepicker table tr td.selected.disabled.disabled:hover,.datepicker table tr td.selected.disabled:active,.datepicker table tr td.selected.disabled:focus,.datepicker table tr td.selected.disabled:hover,.datepicker table tr td.selected.disabled:hover.disabled,.datepicker table tr td.selected.disabled:hover.disabled.active,.datepicker table tr td.selected.disabled:hover.disabled:active,.datepicker table tr td.selected.disabled:hover.disabled:focus,.datepicker table tr td.selected.disabled:hover.disabled:hover,.datepicker table tr td.selected.disabled:hover[disabled],.datepicker table tr td.selected.disabled:hover[disabled].active,.datepicker table tr td.selected.disabled:hover[disabled]:active,.datepicker table tr td.selected.disabled:hover[disabled]:focus,.datepicker table tr td.selected.disabled:hover[disabled]:hover,.datepicker table tr td.selected.disabled[disabled],.datepicker table tr td.selected.disabled[disabled].active,.datepicker table tr td.selected.disabled[disabled]:active,.datepicker table tr td.selected.disabled[disabled]:focus,.datepicker table tr td.selected.disabled[disabled]:hover,.datepicker table tr td.selected:hover.disabled,.datepicker table tr td.selected:hover.disabled.active,.datepicker table tr td.selected:hover.disabled:active,.datepicker table tr td.selected:hover.disabled:focus,.datepicker table tr td.selected:hover.disabled:hover,.datepicker table tr td.selected:hover[disabled],.datepicker table tr td.selected:hover[disabled].active,.datepicker table tr td.selected:hover[disabled]:active,.datepicker table tr td.selected:hover[disabled]:focus,.datepicker table tr td.selected:hover[disabled]:hover,.datepicker table tr td.selected[disabled],.datepicker table tr td.selected[disabled].active,.datepicker table tr td.selected[disabled]:active,.datepicker table tr td.selected[disabled]:focus,.datepicker table tr td.selected[disabled]:hover,fieldset[disabled] .datepicker table tr td.selected,fieldset[disabled] .datepicker table tr td.selected.active,fieldset[disabled] .datepicker table tr td.selected.disabled,fieldset[disabled] .datepicker table tr td.selected.disabled.active,fieldset[disabled] .datepicker table tr td.selected.disabled:active,fieldset[disabled] .datepicker table tr td.selected.disabled:focus,fieldset[disabled] .datepicker table tr td.selected.disabled:hover,fieldset[disabled] .datepicker table tr td.selected.disabled:hover.active,fieldset[disabled] .datepicker table tr td.selected.disabled:hover:active,fieldset[disabled] .datepicker table tr td.selected.disabled:hover:focus,fieldset[disabled] .datepicker table tr td.selected.disabled:hover:hover,fieldset[disabled] .datepicker table tr td.selected:active,fieldset[disabled] .datepicker table tr td.selected:focus,fieldset[disabled] .datepicker table tr td.selected:hover,fieldset[disabled] .datepicker table tr td.selected:hover.active,fieldset[disabled] .datepicker table tr td.selected:hover:active,fieldset[disabled] .datepicker table tr td.selected:hover:focus,fieldset[disabled] .datepicker table tr td.selected:hover:hover{background-color:#999;border-color:#555}.datepicker table tr td.active,.datepicker table tr td.active.disabled,.datepicker table tr td.active.disabled:hover,.datepicker table tr td.active:hover{color:#fff;background-color:#428bca;border-color:#357ebd;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.datepicker table tr td.active.active,.datepicker table tr td.active.disabled.active,.datepicker table tr td.active.disabled:active,.datepicker table tr td.active.disabled:focus,.datepicker table tr td.active.disabled:hover,.datepicker table tr td.active.disabled:hover.active,.datepicker table tr td.active.disabled:hover:active,.datepicker table tr td.active.disabled:hover:focus,.datepicker table tr td.active.disabled:hover:hover,.datepicker table tr td.active:active,.datepicker table tr td.active:focus,.datepicker table tr td.active:hover,.datepicker table tr td.active:hover.active,.datepicker table tr td.active:hover:active,.datepicker table tr td.active:hover:focus,.datepicker table tr td.active:hover:hover,.open .dropdown-toggle.datepicker table tr td.active,.open .dropdown-toggle.datepicker table tr td.active.disabled,.open .dropdown-toggle.datepicker table tr td.active.disabled:hover,.open .dropdown-toggle.datepicker table tr td.active:hover{color:#fff;background-color:#3276b1;border-color:#285e8e}.datepicker table tr td.active.active,.datepicker table tr td.active.disabled.active,.datepicker table tr td.active.disabled:active,.datepicker table tr td.active.disabled:hover.active,.datepicker table tr td.active.disabled:hover:active,.datepicker table tr td.active:active,.datepicker table tr td.active:hover.active,.datepicker table tr td.active:hover:active,.open .dropdown-toggle.datepicker table tr td.active,.open .dropdown-toggle.datepicker table tr td.active.disabled,.open .dropdown-toggle.datepicker table tr td.active.disabled:hover,.open .dropdown-toggle.datepicker table tr td.active:hover{background-image:none}.datepicker table tr td.active.disabled,.datepicker table tr td.active.disabled.active,.datepicker table tr td.active.disabled.disabled,.datepicker table tr td.active.disabled.disabled.active,.datepicker table tr td.active.disabled.disabled:active,.datepicker table tr td.active.disabled.disabled:focus,.datepicker table tr td.active.disabled.disabled:hover,.datepicker table tr td.active.disabled:active,.datepicker table tr td.active.disabled:focus,.datepicker table tr td.active.disabled:hover,.datepicker table tr td.active.disabled:hover.disabled,.datepicker table tr td.active.disabled:hover.disabled.active,.datepicker table tr td.active.disabled:hover.disabled:active,.datepicker table tr td.active.disabled:hover.disabled:focus,.datepicker table tr td.active.disabled:hover.disabled:hover,.datepicker table tr td.active.disabled:hover[disabled],.datepicker table tr td.active.disabled:hover[disabled].active,.datepicker table tr td.active.disabled:hover[disabled]:active,.datepicker table tr td.active.disabled:hover[disabled]:focus,.datepicker table tr td.active.disabled:hover[disabled]:hover,.datepicker table tr td.active.disabled[disabled],.datepicker table tr td.active.disabled[disabled].active,.datepicker table tr td.active.disabled[disabled]:active,.datepicker table tr td.active.disabled[disabled]:focus,.datepicker table tr td.active.disabled[disabled]:hover,.datepicker table tr td.active:hover.disabled,.datepicker table tr td.active:hover.disabled.active,.datepicker table tr td.active:hover.disabled:active,.datepicker table tr td.active:hover.disabled:focus,.datepicker table tr td.active:hover.disabled:hover,.datepicker table tr td.active:hover[disabled],.datepicker table tr td.active:hover[disabled].active,.datepicker table tr td.active:hover[disabled]:active,.datepicker table tr td.active:hover[disabled]:focus,.datepicker table tr td.active:hover[disabled]:hover,.datepicker table tr td.active[disabled],.datepicker table tr td.active[disabled].active,.datepicker table tr td.active[disabled]:active,.datepicker table tr td.active[disabled]:focus,.datepicker table tr td.active[disabled]:hover,fieldset[disabled] .datepicker table tr td.active,fieldset[disabled] .datepicker table tr td.active.active,fieldset[disabled] .datepicker table tr td.active.disabled,fieldset[disabled] .datepicker table tr td.active.disabled.active,fieldset[disabled] .datepicker table tr td.active.disabled:active,fieldset[disabled] .datepicker table tr td.active.disabled:focus,fieldset[disabled] .datepicker table tr td.active.disabled:hover,fieldset[disabled] .datepicker table tr td.active.disabled:hover.active,fieldset[disabled] .datepicker table tr td.active.disabled:hover:active,fieldset[disabled] .datepicker table tr td.active.disabled:hover:focus,fieldset[disabled] .datepicker table tr td.active.disabled:hover:hover,fieldset[disabled] .datepicker table tr td.active:active,fieldset[disabled] .datepicker table tr td.active:focus,fieldset[disabled] .datepicker table tr td.active:hover,fieldset[disabled] .datepicker table tr td.active:hover.active,fieldset[disabled] .datepicker table tr td.active:hover:active,fieldset[disabled] .datepicker table tr td.active:hover:focus,fieldset[disabled] .datepicker table tr td.active:hover:hover{background-color:#428bca;border-color:#357ebd}.datepicker table tr td span{display:block;width:23%;height:54px;line-height:54px;float:left;margin:1%;cursor:pointer;border-radius:4px}.datepicker table tr td span:hover{background:#eee}.datepicker table tr td span.disabled,.datepicker table tr td span.disabled:hover{background:0 0;color:#999;cursor:default}.datepicker table tr td span.active,.datepicker table tr td span.active.disabled,.datepicker table tr td span.active.disabled:hover,.datepicker table tr td span.active:hover{color:#fff;background-color:#428bca;border-color:#357ebd;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.datepicker table tr td span.active.active,.datepicker table tr td span.active.disabled.active,.datepicker table tr td span.active.disabled:active,.datepicker table tr td span.active.disabled:focus,.datepicker table tr td span.active.disabled:hover,.datepicker table tr td span.active.disabled:hover.active,.datepicker table tr td span.active.disabled:hover:active,.datepicker table tr td span.active.disabled:hover:focus,.datepicker table tr td span.active.disabled:hover:hover,.datepicker table tr td span.active:active,.datepicker table tr td span.active:focus,.datepicker table tr td span.active:hover,.datepicker table tr td span.active:hover.active,.datepicker table tr td span.active:hover:active,.datepicker table tr td span.active:hover:focus,.datepicker table tr td span.active:hover:hover,.open .dropdown-toggle.datepicker table tr td span.active,.open .dropdown-toggle.datepicker table tr td span.active.disabled,.open .dropdown-toggle.datepicker table tr td span.active.disabled:hover,.open .dropdown-toggle.datepicker table tr td span.active:hover{color:#fff;background-color:#3276b1;border-color:#285e8e}.datepicker table tr td span.active.active,.datepicker table tr td span.active.disabled.active,.datepicker table tr td span.active.disabled:active,.datepicker table tr td span.active.disabled:hover.active,.datepicker table tr td span.active.disabled:hover:active,.datepicker table tr td span.active:active,.datepicker table tr td span.active:hover.active,.datepicker table tr td span.active:hover:active,.open .dropdown-toggle.datepicker table tr td span.active,.open .dropdown-toggle.datepicker table tr td span.active.disabled,.open .dropdown-toggle.datepicker table tr td span.active.disabled:hover,.open .dropdown-toggle.datepicker table tr td span.active:hover{background-image:none}.datepicker table tr td span.active.disabled,.datepicker table tr td span.active.disabled.active,.datepicker table tr td span.active.disabled.disabled,.datepicker table tr td span.active.disabled.disabled.active,.datepicker table tr td span.active.disabled.disabled:active,.datepicker table tr td span.active.disabled.disabled:focus,.datepicker table tr td span.active.disabled.disabled:hover,.datepicker table tr td span.active.disabled:active,.datepicker table tr td span.active.disabled:focus,.datepicker table tr td span.active.disabled:hover,.datepicker table tr td span.active.disabled:hover.disabled,.datepicker table tr td span.active.disabled:hover.disabled.active,.datepicker table tr td span.active.disabled:hover.disabled:active,.datepicker table tr td span.active.disabled:hover.disabled:focus,.datepicker table tr td span.active.disabled:hover.disabled:hover,.datepicker table tr td span.active.disabled:hover[disabled],.datepicker table tr td span.active.disabled:hover[disabled].active,.datepicker table tr td span.active.disabled:hover[disabled]:active,.datepicker table tr td span.active.disabled:hover[disabled]:focus,.datepicker table tr td span.active.disabled:hover[disabled]:hover,.datepicker table tr td span.active.disabled[disabled],.datepicker table tr td span.active.disabled[disabled].active,.datepicker table tr td span.active.disabled[disabled]:active,.datepicker table tr td span.active.disabled[disabled]:focus,.datepicker table tr td span.active.disabled[disabled]:hover,.datepicker table tr td span.active:hover.disabled,.datepicker table tr td span.active:hover.disabled.active,.datepicker table tr td span.active:hover.disabled:active,.datepicker table tr td span.active:hover.disabled:focus,.datepicker table tr td span.active:hover.disabled:hover,.datepicker table tr td span.active:hover[disabled],.datepicker table tr td span.active:hover[disabled].active,.datepicker table tr td span.active:hover[disabled]:active,.datepicker table tr td span.active:hover[disabled]:focus,.datepicker table tr td span.active:hover[disabled]:hover,.datepicker table tr td span.active[disabled],.datepicker table tr td span.active[disabled].active,.datepicker table tr td span.active[disabled]:active,.datepicker table tr td span.active[disabled]:focus,.datepicker table tr td span.active[disabled]:hover,fieldset[disabled] .datepicker table tr td span.active,fieldset[disabled] .datepicker table tr td span.active.active,fieldset[disabled] .datepicker table tr td span.active.disabled,fieldset[disabled] .datepicker table tr td span.active.disabled.active,fieldset[disabled] .datepicker table tr td span.active.disabled:active,fieldset[disabled] .datepicker table tr td span.active.disabled:focus,fieldset[disabled] .datepicker table tr td span.active.disabled:hover,fieldset[disabled] .datepicker table tr td span.active.disabled:hover.active,fieldset[disabled] .datepicker table tr td span.active.disabled:hover:active,fieldset[disabled] .datepicker table tr td span.active.disabled:hover:focus,fieldset[disabled] .datepicker table tr td span.active.disabled:hover:hover,fieldset[disabled] .datepicker table tr td span.active:active,fieldset[disabled] .datepicker table tr td span.active:focus,fieldset[disabled] .datepicker table tr td span.active:hover,fieldset[disabled] .datepicker table tr td span.active:hover.active,fieldset[disabled] .datepicker table tr td span.active:hover:active,fieldset[disabled] .datepicker table tr td span.active:hover:focus,fieldset[disabled] .datepicker table tr td span.active:hover:hover{background-color:#428bca;border-color:#357ebd}.datepicker table tr td span.new,.datepicker table tr td span.old{color:#999}.datepicker .datepicker-switch{width:145px}.datepicker tfoot tr th,.datepicker thead tr:first-child th{cursor:pointer}.datepicker tfoot tr th:hover,.datepicker thead tr:first-child th:hover{background:#eee}.datepicker .cw{font-size:10px;width:12px;padding:0 2px 0 5px;vertical-align:middle}.datepicker thead tr:first-child .cw{cursor:default;background-color:transparent}.input-group.date .input-group-addon{cursor:pointer}.input-daterange{width:100%}.input-daterange input{text-align:center}.input-daterange input:first-child{border-radius:3px 0 0 3px}.input-daterange input:last-child{border-radius:0 3px 3px 0}.input-daterange .input-group-addon{width:auto;min-width:16px;padding:4px 5px;font-weight:400;line-height:1.42857143;text-align:center;text-shadow:0 1px 0 #fff;vertical-align:middle;background-color:#eee;border:solid #ccc;border-width:1px 0;margin-left:-5px;margin-right:-5px}.datepicker.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:5px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;color:#333;font-size:13px;line-height:1.42857143}.datepicker.datepicker-inline td,.datepicker.datepicker-inline th,.datepicker.dropdown-menu td,.datepicker.dropdown-menu th{padding:0 5px}
libs/factory/bootstrap/assets/css-min/bootstrap.ectoplasm.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .btn-primary{background:#a3b745;border-color:#839237;color:#fff;-webkit-box-shadow:inset 0 1px 0 #c0cd7b,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #c0cd7b,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:focus,.factory-bootstrap-425 .btn-primary:hover{background:#89993a;border-color:#727f30;color:#fff;-webkit-box-shadow:inset 0 1px 0 #b7c669,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #b7c669,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:active{background:#89993a;border-color:#727f30;color:#fff;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}.factory-bootstrap-425 .btn-primary:disabled,.factory-bootstrap-425 .btn-primary[disabled]{color:#cfd1c7!important;background:#89993a!important;border-color:#727f30!important;text-shadow:none!important}.factory-bootstrap-425 .btn-group .btn.active.value{background-color:#a3b745;-webkit-box-shadow:inset 0 1px 2px #839237;box-shadow:inset 0 1px 2px #839237;border-top:1px solid #839237;border-bottom:1px solid #839237;border-left:1px solid #839237}.factory-bootstrap-425 .pagination>.active>a,.factory-bootstrap-425 .pagination>.active>a:focus,.factory-bootstrap-425 .pagination>.active>a:hover,.factory-bootstrap-425 .pagination>.active>span,.factory-bootstrap-425 .pagination>.active>span:focus,.factory-bootstrap-425 .pagination>.active>span:hover{background-color:#a3b745;border-color:#839237}
libs/factory/bootstrap/assets/css-min/bootstrap.form-group.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .factory-form-group .factory-legend{padding:9px 12px;background-color:#f9f9f9}.factory-bootstrap-425 .factory-form-group .factory-title{font-weight:700;font-size:14px;line-height:14px;color:#555;margin:0}.factory-bootstrap-425 .factory-form-group .factory-hint-icon{display:block;width:16px;height:16px;line-height:13px;padding:0;font-size:11px;text-align:center;position:absolute;top:-5px;right:-3px;color:#fff;background:#E91E63;border-radius:3px}.factory-bootstrap-425 .factory-form-group .factory-hint-icon.factory-hint-icon-green{background:#8bc34a}.factory-bootstrap-425 .factory-form-group .factory-hint-icon.factory-hint-icon-grey{background:#9e9e9e}.factory-bootstrap-425 .factory-form-group .factory-hint-icon.factory-hint-icon-red{background:#E91E63}.factory-bootstrap-425 .factory-form-group .factory-hint{margin:0;font-size:12px;line-height:16px;margin-top:6px}.factory-bootstrap-425 .factory-form-group+.factory-form-group{margin-top:30px}.factory-bootstrap-425 .factory-form-group legend+.control-group{margin-top:0}
libs/factory/bootstrap/assets/css-min/bootstrap.light.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .btn-primary{background:#04a4cc;border-color:#037c9a;color:#fff;-webkit-box-shadow:inset 0 1px 0 #22cffb,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #22cffb,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:focus,.factory-bootstrap-425 .btn-primary:hover{background:#0384a4;border-color:#036881;color:#fff;-webkit-box-shadow:inset 0 1px 0 #09cafa,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #09cafa,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:active{background:#0384a4;border-color:#036881;color:#fff;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}.factory-bootstrap-425 .btn-primary:disabled,.factory-bootstrap-425 .btn-primary[disabled]{color:#c7cfd1!important;background:#0384a4!important;border-color:#036881!important;text-shadow:none!important}.factory-bootstrap-425 .btn-group .btn.active.value{background-color:#04a4cc;-webkit-box-shadow:inset 0 1px 2px #037c9a;box-shadow:inset 0 1px 2px #037c9a;border-top:1px solid #037c9a;border-bottom:1px solid #037c9a;border-left:1px solid #037c9a}.factory-bootstrap-425 .pagination>.active>a,.factory-bootstrap-425 .pagination>.active>a:focus,.factory-bootstrap-425 .pagination>.active>a:hover,.factory-bootstrap-425 .pagination>.active>span,.factory-bootstrap-425 .pagination>.active>span:focus,.factory-bootstrap-425 .pagination>.active>span:hover{background-color:#04a4cc;border-color:#037c9a}
libs/factory/bootstrap/assets/css-min/bootstrap.midnight.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .btn-primary{background:#e14d43;border-color:#d02a21;color:#fff;-webkit-box-shadow:inset 0 1px 0 #ec8a85,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #ec8a85,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:focus,.factory-bootstrap-425 .btn-primary:hover{background:#d92c23;border-color:#ba251e;color:#fff;-webkit-box-shadow:inset 0 1px 0 #e8756f,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #e8756f,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:active{background:#d92c23;border-color:#ba251e;color:#fff;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}.factory-bootstrap-425 .btn-primary:disabled,.factory-bootstrap-425 .btn-primary[disabled]{color:#d1c7c7!important;background:#d92c23!important;border-color:#ba251e!important;text-shadow:none!important}.factory-bootstrap-425 .btn-group .btn.active.value{background-color:#e14d43;-webkit-box-shadow:inset 0 1px 2px #d02a21;box-shadow:inset 0 1px 2px #d02a21;border-top:1px solid #d02a21;border-bottom:1px solid #d02a21;border-left:1px solid #d02a21}.factory-bootstrap-425 .pagination>.active>a,.factory-bootstrap-425 .pagination>.active>a:focus,.factory-bootstrap-425 .pagination>.active>a:hover,.factory-bootstrap-425 .pagination>.active>span,.factory-bootstrap-425 .pagination>.active>span:focus,.factory-bootstrap-425 .pagination>.active>span:hover{background-color:#e14d43;border-color:#d02a21}
libs/factory/bootstrap/assets/css-min/bootstrap.ocean.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .btn-primary{background:#9ebaa0;border-color:#80a583;color:#fff;-webkit-box-shadow:inset 0 1px 0 #cbdacc,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #cbdacc,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:focus,.factory-bootstrap-425 .btn-primary:hover{background:#86a988;border-color:#719a74;color:#fff;-webkit-box-shadow:inset 0 1px 0 #bccfbd,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #bccfbd,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:active{background:#86a988;border-color:#719a74;color:#fff;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}.factory-bootstrap-425 .btn-primary:disabled,.factory-bootstrap-425 .btn-primary[disabled]{color:#c7d1c8!important;background:#86a988!important;border-color:#719a74!important;text-shadow:none!important}.factory-bootstrap-425 .btn-group .btn.active.value{background-color:#9ebaa0;-webkit-box-shadow:inset 0 1px 2px #80a583;box-shadow:inset 0 1px 2px #80a583;border-top:1px solid #80a583;border-bottom:1px solid #80a583;border-left:1px solid #80a583}.factory-bootstrap-425 .pagination>.active>a,.factory-bootstrap-425 .pagination>.active>a:focus,.factory-bootstrap-425 .pagination>.active>a:hover,.factory-bootstrap-425 .pagination>.active>span,.factory-bootstrap-425 .pagination>.active>span:focus,.factory-bootstrap-425 .pagination>.active>span:hover{background-color:#9ebaa0;border-color:#80a583}
libs/factory/bootstrap/assets/css-min/bootstrap.separator.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .factory-separator{border-bottom:1px solid #f9f9f9;border-top:1px solid #d1d1d1;margin-bottom:25px}
libs/factory/bootstrap/assets/css-min/bootstrap.sunrise.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .btn-primary{background:#dd823b;border-color:#c36822;color:#fff;-webkit-box-shadow:inset 0 1px 0 #e8ab7c,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #e8ab7c,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:focus,.factory-bootstrap-425 .btn-primary:hover{background:#cc6c23;border-color:#ad5c1e;color:#fff;-webkit-box-shadow:inset 0 1px 0 #e59d66,0 1px 0 rgba(0,0,0,.15);box-shadow:inset 0 1px 0 #e59d66,0 1px 0 rgba(0,0,0,.15)}.factory-bootstrap-425 .btn-primary:active{background:#cc6c23;border-color:#ad5c1e;color:#fff;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}.factory-bootstrap-425 .btn-primary:disabled,.factory-bootstrap-425 .btn-primary[disabled]{color:#d1cbc7!important;background:#cc6c23!important;border-color:#ad5c1e!important;text-shadow:none!important}.factory-bootstrap-425 .btn-group .btn.active.value{background-color:#dd823b;-webkit-box-shadow:inset 0 1px 2px #c36822;box-shadow:inset 0 1px 2px #c36822;border-top:1px solid #c36822;border-bottom:1px solid #c36822;border-left:1px solid #c36822}.factory-bootstrap-425 .pagination>.active>a,.factory-bootstrap-425 .pagination>.active>a:focus,.factory-bootstrap-425 .pagination>.active>a:hover,.factory-bootstrap-425 .pagination>.active>span,.factory-bootstrap-425 .pagination>.active>span:focus,.factory-bootstrap-425 .pagination>.active>span:hover{background-color:#dd823b;border-color:#c36822}
libs/factory/bootstrap/assets/css-min/control.checkbox.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ #side-sortables .factory-bootstrap-425 .factory-buttons-way{float:right;position:relative;top:-25px;left:5px;border:3px solid #f9f9f9;border-radius:4px}.factory-bootstrap-425 .factory-buttons-way{border:3px solid #f9f9f9;border-radius:4px}.factory-bootstrap-425 .factory-buttons-way button{padding-left:10px;padding-right:10px}.factory-bootstrap-425 .factory-buttons-way .factory-on.active{text-shadow:none;color:#fff;background-color:#33aad5;-webkit-box-shadow:inset 0 1px 1px #0074a2;box-shadow:inset 0 1px 3px #0074a2;border-top:1px solid #0074a2;border-bottom:1px solid #0074a2;border-left:1px solid #0074a2}.factory-bootstrap-425 .factory-checkbox-tumbler-hint{margin-top:5px}.factory-bootstrap-425 .factory-checkbox-tumbler-hint .factory-tumbler-content{display:inline-block;background-color:#ffd;padding:1px 5px}.admin-color-light .factory-bootstrap-425 .factory-buttons-way .factory-on.active{background-color:#04a4cc;-webkit-box-shadow:inset 0 1px 2px #037c9a;box-shadow:inset 0 1px 2px #037c9a;border-top:1px solid #037c9a;border-bottom:1px solid #037c9a;border-left:1px solid #037c9a}.admin-color-blue .factory-bootstrap-425 .factory-buttons-way .factory-on.active{background-color:#e1a948;-webkit-box-shadow:inset 0 1px 2px #d39323;box-shadow:inset 0 1px 2px #d39323;border-top:1px solid #d39323;border-bottom:1px solid #d39323;border-left:1px solid #d39323}.admin-color-coffee .factory-bootstrap-425 .factory-buttons-way .factory-on.active{background-color:#c7a589;-webkit-box-shadow:inset 0 1px 2px #b78a66;box-shadow:inset 0 1px 2px #b78a66;border-top:1px solid #b78a66;border-bottom:1px solid #b78a66;border-left:1px solid #b78a66}.admin-color-ectoplasm .factory-bootstrap-425 .factory-buttons-way .factory-on.active{background-color:#a3b745;-webkit-box-shadow:inset 0 1px 2px #839237;box-shadow:inset 0 1px 2px #839237;border-top:1px solid #839237;border-bottom:1px solid #839237;border-left:1px solid #839237}.admin-color-midnight .factory-bootstrap-425 .factory-buttons-way .factory-on.active{background-color:#e14d43;-webkit-box-shadow:inset 0 1px 2px #d02a21;box-shadow:inset 0 1px 2px #d02a21;border-top:1px solid #d02a21;border-bottom:1px solid #d02a21;border-left:1px solid #d02a21}.admin-color-ocean .factory-bootstrap-425 .factory-buttons-way .factory-on.active{background-color:#9ebaa0;-webkit-box-shadow:inset 0 1px 2px #80a583;box-shadow:inset 0 1px 2px #80a583;border-top:1px solid #80a583;border-bottom:1px solid #80a583;border-left:1px solid #80a583}.admin-color-sunrise .factory-bootstrap-425 .factory-buttons-way .factory-on.active{background-color:#dd823b;-webkit-box-shadow:inset 0 1px 2px #c36822;box-shadow:inset 0 1px 2px #c36822;border-top:1px solid #c36822;border-bottom:1px solid #c36822;border-left:1px solid #c36822}
libs/factory/bootstrap/assets/css-min/control.dropdown.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .factory-dropdown.factory-buttons-way .fa{margin-right:6px;position:relative}.factory-bootstrap-425 .factory-dropdown.factory-buttons-way{border:0;border-radius:0}.factory-bootstrap-425 .factory-hints .factory-hint{margin-top:5px;display:inline-block;background-color:#ffd;padding:1px 5px}.admin-color-light .factory-bootstrap-425 .factory-dropdown.factory-buttons-way .active{background-color:#04a4cc;-webkit-box-shadow:inset 0 1px 2px #037c9a;box-shadow:inset 0 1px 2px #037c9a;border-top:1px solid #037c9a;border-bottom:1px solid #037c9a;border-left:1px solid #037c9a}.admin-color-blue .factory-bootstrap-425 .factory-dropdown.factory-buttons-way .active{background-color:#e1a948;-webkit-box-shadow:inset 0 1px 2px #d39323;box-shadow:inset 0 1px 2px #d39323;border-top:1px solid #d39323;border-bottom:1px solid #d39323;border-left:1px solid #d39323}.admin-color-coffee .factory-bootstrap-425 .factory-dropdown.factory-buttons-way .active{background-color:#c7a589;-webkit-box-shadow:inset 0 1px 2px #b78a66;box-shadow:inset 0 1px 2px #b78a66;border-top:1px solid #b78a66;border-bottom:1px solid #b78a66;border-left:1px solid #b78a66}.admin-color-ectoplasm .factory-bootstrap-425 .factory-dropdown.factory-buttons-way .active{background-color:#a3b745;-webkit-box-shadow:inset 0 1px 2px #839237;box-shadow:inset 0 1px 2px #839237;border-top:1px solid #839237;border-bottom:1px solid #839237;border-left:1px solid #839237}.admin-color-midnight .factory-bootstrap-425 .factory-dropdown.factory-buttons-way .active{background-color:#e14d43;-webkit-box-shadow:inset 0 1px 2px #d02a21;box-shadow:inset 0 1px 2px #d02a21;border-top:1px solid #d02a21;border-bottom:1px solid #d02a21;border-left:1px solid #d02a21}.admin-color-ocean .factory-bootstrap-425 .factory-dropdown.factory-buttons-way .active{background-color:#9ebaa0;-webkit-box-shadow:inset 0 1px 2px #80a583;box-shadow:inset 0 1px 2px #80a583;border-top:1px solid #80a583;border-bottom:1px solid #80a583;border-left:1px solid #80a583}.admin-color-sunrise .factory-bootstrap-425 .factory-dropdown.factory-buttons-way .active{background-color:#dd823b;-webkit-box-shadow:inset 0 1px 2px #c36822;box-shadow:inset 0 1px 2px #c36822;border-top:1px solid #c36822;border-bottom:1px solid #c36822;border-left:1px solid #c36822}.factory-bootstrap-425 .factory-dropdown.factory-ddslick-way .dd-select{background-color:#fff!important}.factory-bootstrap-425 .factory-dropdown.factory-ddslick-way label{margin-bottom:1px}.factory-bootstrap-425 .factory-dropdown.factory-ddslick-way .dd-option,.factory-bootstrap-425 .factory-dropdown.factory-ddslick-way .dd-selected{padding:8px 12px 8px 11px!important}
libs/factory/bootstrap/assets/css-min/control.multiple-textbox.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .factory-mtextbox-item{position:relative;margin-bottom:5px}.factory-bootstrap-425 .factory-mtextbox-item input,.factory-mtextbox-remove-item{display:inline-block}.factory-bootstrap-425 .factory-mtextbox-item .factory-mtextbox-remove-item{position:absolute;top:0;right:0;bottom:0;width:40px;border-radius:0 3px 3px 0;outline:0}.factory-bootstrap-425 .factory-mtextbox-item .factory-mtextbox-remove-item:focus,.factory-bootstrap-425 .factory-mtextbox-item .factory-mtextbox-remove-item:hover{box-shadow:none;outline:0}.factory-bootstrap-425 .factory-mtextbox-add-item{display:block;margin-top:10px}
libs/factory/bootstrap/assets/css-min/holder.more-link.min.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+
11
+ .factory-bootstrap-425 .factory-more-link-content{border-top:1px dashed #DDD;padding-top:25px;width:100%;padding-right:20px;position:relative}.factory-bootstrap-425 .factory-tab .factory-more-link-show{display:inline-block;text-decoration:none;border-bottom:1px dotted #21759b;position:relative}.factory-bootstrap-425 .factory-tab .factory-more-link-show:hover{border-color:#d54e21}.factory-bootstrap-425 .factory-tab .factory-more-link-hide{position:absolute;margin-top:-35px;background-color:#fff;padding:0 5px;right:20px;color:#bbb;text-decoration:none}.factory-bootstrap-425 .factory-tab .factory-more-link-hide:hover{color:#999}
libs/factory/bootstrap/assets/images/loader-sm-f6f6f6.gif ADDED
Binary file
libs/factory/bootstrap/assets/images/loader-sm-tr.gif ADDED
Binary file
libs/factory/bootstrap/assets/js-min/bootstrap.dropdown.min.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+ +function(a){"use strict";function b(){a(d).remove(),a(e).each(function(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=factory-dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b),f.trigger(d=a.Event("show.bs.dropdown")),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown"),e.focus()}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).focus(),d.click();var h=a("[role=menu] li:not(.divider):visible a",f);if(h.length){var i=h.index(h.filter(":focus"));38==b.keyCode&&i>0&&i--,40==b.keyCode&&i<h.length-1&&i++,~i||(i=0),h.eq(i).focus()}}}},a.fn.factoryBootstrap425_dropdown=function(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new f(this)),"string"==typeof b&&d[b].call(c)})},a.fn.factoryBootstrap425_dropdown.Constructor=f,a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",e,f.prototype.toggle).on("keydown.bs.dropdown.data-api",e+", [role=menu]",f.prototype.keydown)}(jQuery);
libs/factory/bootstrap/assets/js-min/bootstrap.tooltip.min.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+ +function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focus",i="hover"==g?"mouseleave":"blur";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this.tip();this.setContent(),this.options.animation&&c.addClass("fade");var d="function"==typeof this.options.placement?this.options.placement.call(this,c[0],this.$element[0]):this.options.placement,e=/\s?auto?\s?/i,f=e.test(d);f&&(d=d.replace(e,"")||"top"),c.detach().css({top:0,left:0,display:"block"}).addClass(d),this.options.container?c.appendTo(this.options.container):c.insertAfter(this.$element);var g=this.getPosition(),h=c[0].offsetWidth,i=c[0].offsetHeight;if(f){var j=this.$element.parent(),k=d,l=document.documentElement.scrollTop||document.body.scrollTop,m="body"==this.options.container?window.innerWidth:j.outerWidth(),n="body"==this.options.container?window.innerHeight:j.outerHeight(),o="body"==this.options.container?0:j.offset().left;d="bottom"==d&&g.top+g.height+i-l>n?"top":"top"==d&&g.top-l-i<0?"bottom":"right"==d&&g.right+h>m?"left":"left"==d&&g.left-h<o?"right":d,c.removeClass(k).addClass(d)}var p=this.getCalculatedOffset(d,g,h,i);this.applyPlacement(p,d),this.$element.trigger("shown.bs."+this.type)}},b.prototype.applyPlacement=function(a,b){var c,d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),a.top=a.top+g,a.left=a.left+h,d.offset(a).addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;if("top"==b&&j!=f&&(c=!0,a.top=a.top+f-j),/bottom|top/.test(b)){var k=0;a.left<0&&(k=-2*a.left,a.left=0,d.offset(a),i=d[0].offsetWidth,j=d[0].offsetHeight),this.replaceArrow(k-e+i,i,"left")}else this.replaceArrow(j-f,j,"top");c&&d.offset(a)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach()}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.$element.trigger("hidden.bs."+this.type),this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this},a(function(){a('[data-toggle="factory-tooltip"]').tooltip({html:!0})})}(jQuery);
libs/factory/bootstrap/assets/js-min/control.checkbox.min.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+ !function(a){var b=function(b){var c=this;this.$element=a(b),this.$result=this.$element.find(".factory-result"),this.$on=this.$element.find(".factory-on"),this.$off=this.$element.find(".factory-off");var d=this.$element.is(".factory-tumbler"),e=this.$element.is(".factory-has-tumbler-hint"),f=this.$element.data("tumbler-function"),g=this.$element.data("tumbler-delay");g||(g=3e3),this.callByPath=function(a,b){for(var c=a.split("."),d=window,e=0;e<c.length;e++)d=d[c[e]];d.apply(d,b)},this.$on.click(function(){return c.$off.removeClass("active"),c.$on.addClass("active"),d?setTimeout(function(){c.$on.removeClass("active"),c.$off.addClass("active");var a=e?c.$element.next():null;f?c.callByPath(f,[c.$element,a]):e&&(c.$element.next().fadeIn(300),setTimeout(function(){c.$element.next().fadeOut(500)},g))},300):(c.$result.attr("checked","checked"),c.$result.val(1),c.$result.trigger("change")),!1}),this.$off.click(function(){return c.$on.removeClass("active"),c.$off.addClass("active"),d?setTimeout(function(){c.$off.removeClass("active"),c.$on.addClass("active");var a=e?c.$element.next():null;f?c.callByPath(f,[c.$element,a]):e&&(c.$element.next().fadeIn(300),setTimeout(function(){c.$element.next().fadeOut(500)},g))},300):(c.$result.removeAttr("checked"),c.$result.val(0),c.$result.trigger("change")),!1}),this.hashCode=function(a){var b=0;if(!a||0===a.length)return b;for(var c=0;c<a.length;c++){var d=a.charCodeAt(c);b=(b<<5)-b+d,b&=b}return b=b.toString(16),b=b.replace("-","")},this.executeEvents=function(a){(void 0!==window.__factory_checkbox_control_events_off_data||void 0!==window.__factory_checkbox_control_events_on_data)&&(a.change(function(){c.eventsProcess(a)}),c.eventsProcess(a))},this.eventsProcess=function(b){var d=b.attr("name"),e=b.prop("checked"),f=window.__factory_checkbox_control_events_on_data[d],g=window.__factory_checkbox_control_events_off_data[d];if(f||g){var h,i;void 0===window.__factory_checkbox_control_detach_elements&&(window.__factory_checkbox_control_detach_elements={}),h=window.__factory_checkbox_control_detach_elements,i=e?f:g;for(var j in i)if(i.hasOwnProperty(j)){var k,l=i[j];a.isArray(l)||(k=c.hashCode(d+l));var m;switch(j){case"hide":"string"==typeof l&&a(l).hide(0);break;case"show":"string"==typeof l&&a(l).fadeIn(200);break;case"detach":"string"==typeof l&&a(l).each(function(b){h[k]||(h[k]={}),h[k][b]||(h[k][b]={}),h[k][b].recovery_contanier=a(this).parent(),h[k][b].element=a(this).clone(!0),a(this).remove()});break;case"recovery":if(h[k]){for(var n in h[k])h[k].hasOwnProperty(n)&&h[k][n].recovery_contanier&&h[k][n].element&&h[k][n].recovery_contanier.append(h[k][n].element);delete h[k]}break;case"removeClasses":if("object"==typeof l)for(m in l)l.hasOwnProperty(m)&&l[m]&&a(m).removeClass(l[m]);break;case"addClasses":if("object"==typeof l)for(m in l)l.hasOwnProperty(m)&&l[m]&&a(m).addClass(l[m]);break;case"setValue":if("object"==typeof l)for(m in l)l.hasOwnProperty(m)&&void 0!==l[m]&&null!==l[m]&&(console.log(l[m]),a(m).val(l[m]))}}}},this.executeEvents(this.$result)};a.fn.factoryBootstrap425_checkboxControl=function(c){if("string"==typeof c){var d=a(this).data("factory.checkbox.control");return d?d[c]():null}return this.each(function(){var c=a(this),d=c.data("factory.checkbox.control");d||c.data("factory.checkbox.control",d=new b(this))})},a.fn.factoryBootstrap425_checkboxControl.Constructor=b,a(function(){a(".factory-bootstrap-425 .factory-checkbox.factory-buttons-way").factoryBootstrap425_checkboxControl()})}(jQuery);
libs/factory/bootstrap/assets/js-min/control.dropdown.min.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+ !function(a){var b=function(b){var c=this;if(this.$element=a(b),this.way=this.$element.data("way"),this.name=this.$element.data("name")||this.$element.attr("name"),this.hashCode=function(a){var b=0;if(!a||0===a.length)return b;for(var c=0;c<a.length;c++){var d=a.charCodeAt(c);b=(b<<5)-b+d,b&=b}return b=b.toString(16),b=b.replace("-","")},this.executeEvents=function(a){void 0!==window.factory_dropdown_control_events_data&&(a.change(function(){c.eventsProcess(a)}),c.eventsProcess(a))},this.eventsProcess=function(b){var d=b.attr("name"),e=b.val(),f=window.factory_dropdown_control_events_data[d];if(f&&f[e]){var g;void 0===window.__factory_dropdown_control_detach_elements&&(window.__factory_dropdown_control_detach_elements={}),g=window.__factory_dropdown_control_detach_elements;for(var h in f[e])if(f[e].hasOwnProperty(h)){var i,j=f[e][h];switch(a.isArray(j)||(i=c.hashCode(d+j)),h){case"hide":"string"==typeof j&&a(j).hide(0);break;case"show":"string"==typeof j&&a(j).fadeIn(200);break;case"detach":"string"==typeof j&&a(j).each(function(b){g[i]||(g[i]={}),g[i][b]||(g[i][b]={}),g[i][b].recovery_contanier=a(this).parent(),g[i][b].element=a(this).clone(!0),a(this).remove()});break;case"recovery":if(g[i]){for(var k in g[i])g[i].hasOwnProperty(k)&&g[i][k].recovery_contanier&&g[i][k].element&&g[i][k].recovery_contanier.append(g[i][k].element);delete g[i]}break;case"removeClasses":if("object"==typeof j)for(var l in j)j.hasOwnProperty(l)&&j[l]&&a(l).removeClass(j[l]);break;case"addClasses":if("object"==typeof j)for(var l in j)j.hasOwnProperty(l)&&j[l]&&a(l).addClass(j[l])}}}},"buttons"===this.way)this.$result=this.$element.find(".factory-result"),this.$hints=this.$element.find(".factory-hints"),this.$buttons=this.$element.find(".btn"),c.executeEvents(this.$result),this.$buttons.click(function(){var b=a(this).data("value");return c.$buttons.removeClass("active"),a(this).addClass("active"),c.$hints.find(".factory-hint").hide(),c.$hints.find(".factory-hint-"+b).fadeIn(),c.$result.val(b),c.$result.trigger("change"),!1});else if("ddslick"===this.way){c.executeEvents(c.$element.find(".factory-result"));var d=window["factory_"+this.name+"_data"],e=this.$element.find(".factory-ddslick"),f=this.$element.data("width")||300,g=this.$element.data("align")||"right";a(d).each(function(){return this.imageHoverSrc?void(a("<img/>")[0].src=this.imageHoverSrc):!0}),e.ddslick({data:d,width:f,imagePosition:g,selectText:"- select -",onSelected:function(a){a.selectedData.imageHoverSrc&&c.$element.find(".dd-selected-image").attr("src",a.selectedData.imageHoverSrc);var b=c.$element.find(".factory-result").val(a.selectedData.value);b.change()}})}else{c.executeEvents(this.$element),this.$hints=this.$element.next(),this.$hints.hasClass("factory-hints")&&(this.$element.change(function(){return c.updateHints(),!1}),this.updateHints=function(){var a=c.$element.val();c.$hints.find(".factory-hint").hide(),c.$hints.find(".factory-hint-"+a).show()},c.updateHints()),this.getAjaxData=function(){var a=c.$element.data("ajax-data-id");return window[a]},this.loadData=function(){var b=c.getAjaxData();a.ajax({url:b.url,data:b.data,dataType:"json",success:function(a){return a.error?c.showError(a.error):void c.fill(a.items)},error:function(a){console&&console.log&&console.log(a.responseText),c.showError("Unexpected error occurred during the ajax request.")},complete:function(){c.removeLoader()}})},this.fill=function(a){this.clearList();var b=c.getAjaxData();if(a&&a.length)for(var d in a){var e=a[d];c.addListItem(e)}else this.$element.append("<option>"+b.emptyList+"</li>");this.$element.trigger("factory-loaded")},this.clearList=function(){this.$element.html("")},this.addListItem=function(b){var d=a("<option />").attr("value",b.value).text(b.title).appendTo(this.$element),e=c.getAjaxData();e.selected&&e.selected==b.value&&d.attr("selected","selected")},this.showError=function(b){this.clearList();var d=a("<div class='factory-control-error'></div>").append(a("<i class='fa fa-exclamation-triangle'></i>")).append(b),e=c.getAjaxData();this.$element.append("<option>"+e.emptyList+"</li>"),this.$element.after(d),this.$element.addClass("factory-has-error")},this.removeLoader=function(){this.$element.removeClass("factory-hidden");var b=c.getAjaxData();a(b.loader).remove()};var h=this.$element.data("ajax");h&&this.loadData()}};a.fn.factoryBootstrap425_dropdownControl=function(c){if("string"==typeof c){var d=a(this).data("factory.dropdown.control");return d?d[c]():null}return this.each(function(){var c=a(this),d=c.data("factory.dropdown.control");d||c.data("factory.dropdown.control",d=new b(this))})},a.fn.factoryBootstrap425_dropdownControl.Constructor=b,a(function(){a(".factory-bootstrap-425 .factory-dropdown").factoryBootstrap425_dropdownControl()})}(jQuery);
libs/factory/bootstrap/assets/js-min/control.list.min.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+ !function(a){var b=function(b){var c=this;if(this.$element=a(b),this.way=this.$element.data("way"),this.name=this.$element.data("name"),"checklist"===this.way){this.getAjaxData=function(){var a=c.$element.data("ajax-data-id");return window[a]},this.loadData=function(){var b=c.getAjaxData();a.ajax({url:b.url,data:b.data,dataType:"json",success:function(a){return a.error?c.showError(a.error):void c.fill(a.items)},error:function(){c.showError("Unexpected error occurred during the ajax request.")},complete:function(){c.removeLoader()}})},this.fill=function(a){this.clearList();var b=c.getAjaxData();if(a&&a.length){this.$element.removeClass("factory-empty");for(var d in a){var e=a[d];c.addListItem(e)}}else this.$element.addClass("factory-empty"),this.$element.append("<li>"+b.emptyList+"</li>")},this.clearList=function(){this.$element.html("")},this.addListItem=function(b){var d=a("<li>"),e=a("<label>").attr("for","factory-checklist-"+c.name+"-"+b.value).appendTo(d),f=a("<span>").appendTo(e),g=a("<input />").attr("type","checkbox").attr("name",c.name+"[]").val(b.value).attr("id","factory-checklist-"+c.name+"-"+b.value).appendTo(f),h=(a("<span>"+b.title+"</span>").appendTo(e),c.getAjaxData());h.selected.length&&a.inArray(b.value,h.selected)>=0&&g.attr("checked","checked"),this.$element.append(d)},this.showError=function(b){this.$element.html("").append(a("<i class='fa fa-exclamation-triangle'></i>")).append(b),this.$element.addClass("factory-list-error")},this.removeLoader=function(){this.$element.removeClass("factory-hidden");var b=c.getAjaxData();a(b.loader).remove()};var d=this.$element.data("ajax");d&&this.loadData()}};a.fn.factoryBootstrap425_listControl=function(c){if("string"==typeof c){var d=a(this).data("factory.list.control");return d?d[c]():null}return this.each(function(){var c=a(this),d=c.data("factory.list.control");d||c.data("factory.list.control",d=new b(this))})},a.fn.factoryBootstrap425_listControl.Constructor=b,a(function(){a(".factory-bootstrap-425 .factory-list").factoryBootstrap425_listControl()})}(jQuery);
libs/factory/bootstrap/assets/js-min/control.multiple-textbox.min.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap generator - v1.0.1, 2018-02-26
3
+ * Webcraftic factory build
4
+ *
5
+ * Copyright 2018, Alex Kovalev <alex.kovalevv@gmail.com>, Webcraftic <wordpress.webraftic@gmail.com>
6
+ * Site: http://webcraftic.com
7
+ * Support: http://webcraftic.com/contact-us/
8
+ */
9
+
10
+ !function(a){"use strict";var b=function(b){this.$element=a(b);var c=a(".factory-mtextbox-item",this.$element).eq(0).clone(!0);a(".factory-mtextbox-add-item",this.$element).on("click",function(){var b=a(this).closest(".factory-multiple-textbox-group").find(".factory-mtextbox-items"),d=c.clone(!0),e=a('<button class="btn btn-default btn-small factory-mtextbox-remove-item"><i class="fa fa-times" aria-hidden="true"></i></button>');return b.append(d.append(e)),d.find('input[type="text"]').val("").focus(),!1}),a(document).on("click",".factory-mtextbox-remove-item",function(){return a(this).closest(".factory-mtextbox-item").remove(),!1})};a.fn.factoryBootstrap425_MultipleTextboxControl=function(){return this.each(function(){new b(this)})},a(function(){a(".factory-bootstrap-425 .factory-multiple-textbox-group").factoryBootstrap425_MultipleTextboxControl()})}(jQuery);
libs/factory/bootstrap/boot.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Factory Bootstrap
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @since 1.0.0
7
+ * @package factory-bootstrap
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ // module provides function only for the admin area
18
+ if ( ! is_admin() ) {
19
+ return;
20
+ }
21
+
22
+ if ( defined( 'FACTORY_BOOTSTRAP_425_LOADED' ) ) {
23
+ return;
24
+ }
25
+
26
+ define( 'FACTORY_BOOTSTRAP_425_VERSION', '4.2.5' );
27
+ define( 'FACTORY_BOOTSTRAP_425_LOADED', true );
28
+
29
+ if ( ! defined( 'FACTORY_FLAT_ADMIN' ) ) {
30
+ define( 'FACTORY_FLAT_ADMIN', true );
31
+ }
32
+
33
+ define( 'FACTORY_BOOTSTRAP_425_DIR', dirname( __FILE__ ) );
34
+ define( 'FACTORY_BOOTSTRAP_425_URL', plugins_url( null, __FILE__ ) );
35
+
36
+ require_once( FACTORY_BOOTSTRAP_425_DIR . '/includes/functions.php' );
37
+
38
+ /**
39
+ * @param Wbcr_Factory424_Plugin $plugin
40
+ */
41
+ add_action( 'wbcr_factory_bootstrap_425_plugin_created', function ( $plugin ) {
42
+ $manager = new Wbcr_FactoryBootstrap425_Manager( $plugin );
43
+ $plugin->setBootstap( $manager );
44
+ } );
45
+
46
+
libs/factory/bootstrap/includes/functions.php ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file manages assets of the Factory Bootstap.
4
+ *
5
+ * @author Alex Kovalev <alex@byonepress.com>
6
+ * @author Paul Kashtanoff <paul@byonepress.com>
7
+ * @since 1.0.0
8
+ * @package factory-bootstrap
9
+ * @copyright (c) 2018, OnePress Ltd
10
+ *
11
+ */
12
+
13
+ // Exit if accessed directly
14
+ if ( ! defined( 'ABSPATH' ) ) {
15
+ exit;
16
+ }
17
+
18
+ /**
19
+ * The Bootstrap Manager class.
20
+ *
21
+ * @since 3.2.0
22
+ */
23
+ class Wbcr_FactoryBootstrap425_Manager {
24
+
25
+ /**
26
+ * A plugin for which the manager was created.
27
+ *
28
+ * @since 3.2.0
29
+ * @var Wbcr_Factory424_Plugin
30
+ */
31
+ public $plugin;
32
+
33
+ /**
34
+ * Contains scripts to include.
35
+ *
36
+ * @since 3.2.0
37
+ * @var string[]
38
+ */
39
+ public $scripts = [];
40
+
41
+ /**
42
+ * Contains styles to include.
43
+ *
44
+ * @since 3.2.0
45
+ * @var string[]
46
+ */
47
+ public $styles = [];
48
+
49
+ /**
50
+ * Createas a new instance of the license api for a given plugin.
51
+ *
52
+ * @since 1.0.0
53
+ */
54
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
55
+ $this->plugin = $plugin;
56
+
57
+ add_action( 'admin_enqueue_scripts', [ $this, 'loadAssets' ] );
58
+ add_filter( 'admin_body_class', [ $this, 'adminBodyClass' ] );
59
+ }
60
+
61
+ /**
62
+ * Includes the Bootstrap scripts.
63
+ *
64
+ * @since 3.2.0
65
+ *
66
+ * @param array|string $scripts
67
+ */
68
+ public function enqueueScript( $scripts ) {
69
+ if ( is_array( $scripts ) ) {
70
+ foreach ( $scripts as $script ) {
71
+ if ( ! in_array( $script, $this->scripts ) ) {
72
+ $this->scripts[] = $script;
73
+ }
74
+ }
75
+ } else {
76
+ if ( ! in_array( $scripts, $this->scripts ) ) {
77
+ $this->scripts[] = $scripts;
78
+ }
79
+ }
80
+ }
81
+
82
+ /**
83
+ * * Includes the Bootstrap styles.
84
+ *
85
+ * @since 3.2.0
86
+ *
87
+ * @param array|string $styles
88
+ */
89
+ public function enqueueStyle( $styles ) {
90
+
91
+ if ( is_array( $styles ) ) {
92
+ foreach ( $styles as $style ) {
93
+ if ( ! in_array( $style, $this->styles ) ) {
94
+ $this->styles[] = $style;
95
+ }
96
+ }
97
+ } else {
98
+ if ( ! in_array( $styles, $this->styles ) ) {
99
+ $this->styles[] = $styles;
100
+ }
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Loads Bootstrap assets.
106
+ *
107
+ * @since 3.2.0
108
+ * @return void
109
+ * @see admin_enqueue_scripts
110
+ *
111
+ */
112
+ public function loadAssets( $hook ) {
113
+
114
+ do_action( 'wbcr_factory_424_bootstrap_enqueue_scripts', $hook );
115
+ do_action( 'wbcr_factory_424_bootstrap_enqueue_scripts_' . $this->plugin->getPluginName(), $hook );
116
+
117
+ $dependencies = [];
118
+ if ( ! empty( $this->scripts ) ) {
119
+ $dependencies[] = 'jquery';
120
+ $dependencies[] = 'jquery-ui-core';
121
+ $dependencies[] = 'jquery-ui-widget';
122
+ }
123
+
124
+ foreach ( $this->scripts as $script ) {
125
+ switch ( $script ) {
126
+ case 'plugin.iris':
127
+ $dependencies[] = 'jquery-ui-widget';
128
+ $dependencies[] = 'jquery-ui-slider';
129
+ $dependencies[] = 'jquery-ui-draggable';
130
+ break;
131
+ }
132
+ }
133
+
134
+ if ( ! empty( $this->scripts ) ) {
135
+ $this->enqueueScripts( $this->scripts, 'js', $dependencies );
136
+ }
137
+ if ( ! empty( $this->styles ) ) {
138
+ $this->enqueueScripts( $this->styles, 'css', $dependencies );
139
+ }
140
+ }
141
+
142
+ /**
143
+ * @param array $scripts
144
+ * @param string $type
145
+ * @param array $dependencies
146
+ */
147
+ protected function enqueueScripts( array $scripts, $type, array $dependencies ) {
148
+
149
+ $is_first = true;
150
+
151
+ /**
152
+ * Sets permission for file caching and combining into one file.
153
+ *
154
+ * @since 4.1.0
155
+ */
156
+ $cache_enable = apply_filters( 'wbcr/factory/bootstrap/cache_enable', true );
157
+
158
+ $cache_id = md5( implode( ',', $this->scripts ) . $type . $this->plugin->getPluginVersion() );
159
+ $cache_dir_path = FACTORY_BOOTSTRAP_425_DIR . '/assets/cache/';
160
+ $cache_dir_url = FACTORY_BOOTSTRAP_425_URL . '/assets/cache/';
161
+
162
+ $cache_filepath = $cache_dir_path . $cache_id . ".min." . $type;
163
+ $cache_fileurl = $cache_dir_url . $cache_id . ".min." . $type;
164
+
165
+ if ( $cache_enable && file_exists( $cache_filepath ) ) {
166
+ if ( $type == 'js' ) {
167
+ wp_enqueue_script( 'wbcr-factory-bootstrap-' . $cache_id, $cache_fileurl, $dependencies, $this->plugin->getPluginVersion() );
168
+ } else {
169
+ wp_enqueue_style( 'wbcr-factory-bootstrap-' . $cache_id, $cache_fileurl, [], $this->plugin->getPluginVersion() );
170
+ }
171
+ } else {
172
+ $cache_dir_exists = false;
173
+ if ( ! file_exists( $cache_dir_path ) ) {
174
+ if ( @mkdir( $cache_dir_path, 0755 ) && wp_is_writable( $cache_dir_path ) ) {
175
+ $cache_dir_exists = true;
176
+ }
177
+ } else {
178
+ if ( wp_is_writable( $cache_dir_path ) ) {
179
+ $cache_dir_exists = true;
180
+ }
181
+ }
182
+
183
+ $concat_files = [];
184
+ foreach ( $scripts as $script_to_load ) {
185
+ $script_to_load = sanitize_text_field( $script_to_load );
186
+ if ( $cache_enable && $cache_dir_exists ) {
187
+ $fname = FACTORY_BOOTSTRAP_425_DIR . "/assets/$type-min/$script_to_load.min." . $type;
188
+ if ( file_exists( $fname ) ) {
189
+ $f = @fopen( $fname, 'r' );
190
+ $concat_files[] = @fread( $f, filesize( $fname ) );
191
+ @fclose( $f );
192
+ }
193
+ } else {
194
+ if ( $type == 'js' ) {
195
+ wp_enqueue_script( md5( $script_to_load ), FACTORY_BOOTSTRAP_425_URL . "/assets/$type-min/$script_to_load.min." . $type, $is_first ? $dependencies : false, $this->plugin->getPluginVersion() );
196
+ } else {
197
+ wp_enqueue_style( md5( $script_to_load ), FACTORY_BOOTSTRAP_425_URL . "/assets/$type-min/$script_to_load.min." . $type, [], $this->plugin->getPluginVersion() );
198
+ }
199
+ $is_first = false;
200
+ }
201
+ }
202
+
203
+ if ( $cache_enable && $cache_dir_exists && ! empty( $concat_files ) ) {
204
+
205
+ $cf = @fopen( $cache_filepath, 'w' );
206
+ $write_content = implode( PHP_EOL, $concat_files );
207
+ @fwrite( $cf, $write_content );
208
+ @fclose( $cf );
209
+ chmod( $cache_filepath, 0755 );
210
+
211
+ if ( file_exists( $cache_filepath ) ) {
212
+ if ( $type == 'js' ) {
213
+ wp_enqueue_script( 'wbcr-factory-bootstrap-' . $cache_id, $cache_fileurl, $dependencies, $this->plugin->getPluginVersion() );
214
+ } else {
215
+ wp_enqueue_style( 'wbcr-factory-bootstrap-' . $cache_id, $cache_fileurl, [], $this->plugin->getPluginVersion() );
216
+ }
217
+ }
218
+ }
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Adds the body classes: 'factory-flat or 'factory-volumetric'.
224
+ *
225
+ * @since 3.2.0
226
+ *
227
+ * @param string $classes
228
+ *
229
+ * @return string
230
+ */
231
+ public function adminBodyClass( $classes ) {
232
+ $classes .= FACTORY_FLAT_ADMIN ? ' factory-flat ' : ' factory-volumetric ';
233
+
234
+ return $classes;
235
+ }
236
+ }
libs/factory/bootstrap/includes/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/bootstrap/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/clearfy/assets/css/clearfy-base.css ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Базовые стили для всех копомпонентов Clearfy
3
+
4
+ * @author Webcraftic <wordpress.webraftic@gmail.com>
5
+ * @copyright Webcraftic 06.10.2018
6
+ * @sicne 2.0.5
7
+ */
8
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-clearfy-216-multisite-suggetion {
9
+ padding: 30px 80px;
10
+ }
11
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-clearfy-216-multisite-suggetion h3 {
12
+ margin: 0 0 20px;
13
+ }
14
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-clearfy-216-multisite-suggetion .wbcr-factory-inner-contanier {
15
+ border: 2px dashed #8bc34a;
16
+ background: #fff;
17
+ padding: 20px;
18
+ }
19
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-clearfy-216-multisite-suggetion .wbcr-factory-activate-premium {
20
+ display: inline-block;
21
+ cursor: pointer;
22
+ line-height: 16px;
23
+ font-size: 13px;
24
+ font-weight: 600;
25
+ padding: 12px 20px;
26
+ text-align: center;
27
+ text-decoration: none;
28
+ text-transform: uppercase;
29
+ border-radius: 2px;
30
+ -moz-border-radius: 2px;
31
+ -webkit-border-radius: 2px;
32
+ color: #353535;
33
+ background: #e8e8e8;
34
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
35
+ -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
36
+ -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
37
+ }
38
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-clearfy-216-multisite-suggetion .wbcr-factory-activate-premium:active {
39
+ box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.2);
40
+ -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.2);
41
+ -webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.2);
42
+ }
43
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-clearfy-216-multisite-suggetion .wbcr-factory-activate-premium:focus {
44
+ outline: none;
45
+ border: 0;
46
+ }
47
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-clearfy-216-multisite-suggetion .wbcr-factory-purchase-premium {
48
+ display: inline-block;
49
+ cursor: pointer;
50
+ line-height: 16px;
51
+ font-size: 13px;
52
+ font-weight: 600;
53
+ padding: 12px 20px;
54
+ text-align: center;
55
+ text-decoration: none;
56
+ text-transform: uppercase;
57
+ border-radius: 2px;
58
+ -moz-border-radius: 2px;
59
+ -webkit-border-radius: 2px;
60
+ color: #755c0e;
61
+ background: #fdd868;
62
+ box-shadow: 0 1px 0 rgba(60, 45, 2, 0.31);
63
+ -moz-box-shadow: 0 1px 0 rgba(60, 45, 2, 0.31);
64
+ -webkit-box-shadow: 0 1px 0 rgba(60, 45, 2, 0.31);
65
+ }
66
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-clearfy-216-multisite-suggetion .wbcr-factory-purchase-premium:active {
67
+ box-shadow: inset 0 1px 0 rgba(60, 45, 2, 0.31);
68
+ -moz-box-shadow: inset 0 1px 0 rgba(60, 45, 2, 0.31);
69
+ -webkit-box-shadow: inset 0 1px 0 rgba(60, 45, 2, 0.31);
70
+ }
71
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-clearfy-216-multisite-suggetion .wbcr-factory-purchase-premium:focus {
72
+ outline: none;
73
+ border: 0;
74
+ }
75
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion {
76
+ background: #fff;
77
+ color: #353535;
78
+ font-weight: 600;
79
+ border: 2px dashed #8bc34a;
80
+ }
81
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion h3 {
82
+ margin: 0 0 20px;
83
+ padding: 10px 0;
84
+ text-align: center;
85
+ border-bottom: 2px solid #e6e6e6;
86
+ color: #636363;
87
+ font-size: 17px;
88
+ font-weight: 600;
89
+ vertical-align: middle;
90
+ text-transform: uppercase;
91
+ }
92
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion ul {
93
+ position: relative;
94
+ margin-bottom: 20px;
95
+ }
96
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion ul li {
97
+ font-size: 15px;
98
+ padding: 7px;
99
+ padding-left: 20px;
100
+ }
101
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion ul li:before {
102
+ content: " ";
103
+ display: inline-block;
104
+ width: 0.4em;
105
+ height: 0.7em;
106
+ border: solid #8bc34a;
107
+ border-width: 0 0.2em 0.2em 0;
108
+ left: 0;
109
+ margin-right: 10px;
110
+ -webkit-transform: rotate(45deg);
111
+ -moz-transform: rotate(45deg);
112
+ -o-transform: rotate(45deg);
113
+ transform: rotate(45deg);
114
+ }
115
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion .wbcr-factory-purchase-premium {
116
+ display: block;
117
+ cursor: pointer;
118
+ line-height: 16px;
119
+ font-size: 13px;
120
+ font-weight: 600;
121
+ padding: 12px 20px;
122
+ text-align: center;
123
+ text-decoration: none;
124
+ text-transform: uppercase;
125
+ border-radius: 2px;
126
+ -moz-border-radius: 2px;
127
+ -webkit-border-radius: 2px;
128
+ color: #353535;
129
+ background: #e8e8e8;
130
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
131
+ -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
132
+ -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
133
+ }
134
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion .wbcr-factory-purchase-premium:active {
135
+ box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.2);
136
+ -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.2);
137
+ -webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.2);
138
+ }
139
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion .wbcr-factory-purchase-premium:focus {
140
+ outline: none;
141
+ border: 0;
142
+ }
143
+ @media screen and (max-width: 1550px) {
144
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-clearfy-216-multisite-pro-suggetion {
145
+ padding: 10px 80px;
146
+ }
147
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion {
148
+ padding: 10px;
149
+ }
150
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion h3 {
151
+ margin: 0 0 20px;
152
+ padding: 10px 0;
153
+ font-size: 13px;
154
+ font-weight: 600;
155
+ }
156
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion ul {
157
+ margin-bottom: 20px;
158
+ }
159
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion ul li {
160
+ font-size: 13px;
161
+ padding: 2px;
162
+ padding-left: 10px;
163
+ }
164
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion ul li:before {
165
+ width: 0.4em;
166
+ height: 0.7em;
167
+ border-width: 0 0.2em 0.2em 0;
168
+ left: 0;
169
+ margin-right: 10px;
170
+ }
171
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-clearfy-216-pro-suggettion .wbcr-factory-purchase-premium {
172
+ font-weight: 700;
173
+ line-height: 16px;
174
+ font-size: 12px;
175
+ padding: 8px 12px;
176
+ border-radius: 2px;
177
+ -moz-border-radius: 2px;
178
+ -webkit-border-radius: 2px;
179
+ }
180
+ }
181
+ /*# sourceMappingURL=clearfy-base.css.map */
libs/factory/clearfy/assets/css/clearfy-base.css.map ADDED
@@ -0,0 +1 @@
 
1
+ {"version":3,"sources":["clearfy-base.less"],"names":[],"mappings":";;;;;;;AAoCA,KAEE,iDACE;EACE,kBAAA;;AAJN,KAEE,iDACE,8CAGE;EACE,gBAAA;;AAPR,KAEE,iDACE,8CAOE;EACE,0BAAA;EACA,gBAAA;EACA,aAAA;;AAbR,KAEE,iDACE,8CAaE;EACE,qBAAA;EA5CN,eAAA;EACA,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,kBAAA;EACA,kBAAA;EACA,qBAAA;EACA,yBAAA;EACA,kBAAA;EACA,uBAAA;EACA,0BAAA;EACA,cAAA;EACA,mBAAA;EACA,sCAAA;EACA,2CAAA;EACA,8CAAA;;AACA,KAaA,iDACE,8CAaE,+BA3BH;EACC,4CAAA;EACA,iDAAA;EACA,oDAAA;;AAEF,KAQA,iDACE,8CAaE,+BAtBH;EACC,aAAA;EACA,SAAA;;AAIJ,KAEE,iDACE,8CAiBE;EACE,qBAAA;EAhDN,eAAA;EACA,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,kBAAA;EACA,kBAAA;EACA,qBAAA;EACA,yBAAA;EACA,kBAAA;EACA,uBAAA;EACA,0BAAA;EACA,cAAA;EACA,mBAAA;EACA,yCAAA;EACA,8CAAA;EACA,iDAAA;;AACA,KAaA,iDACE,8CAiBE,+BA/BH;EACC,+CAAA;EACA,oDAAA;EACA,uDAAA;;AAEF,KAQA,iDACE,8CAiBE,+BA1BH;EACC,aAAA;EACA,SAAA;;AAIJ,KAEE,iDAwBE,oCACE;EACE,gBAAA;EACA,cAAA;EACA,gBAAA;EACA,0BAAA;;AA/BR,KAEE,iDAwBE,oCACE,yCAME;EACE,gBAAA;EACA,eAAA;EACA,kBAAA;EACA,gCAAA;EACA,cAAA;EACA,eAAA;EACA,gBAAA;EACA,sBAAA;EACA,yBAAA;;AA1CV,KAEE,iDAwBE,oCACE,yCAkBE;EAEE,kBAAA;EACA,mBAAA;;AAhDV,KAEE,iDAwBE,oCACE,yCAkBE,GAKE;EACE,eAAA;EACA,YAAA;EACA,kBAAA;;AAIA,KAvDV,iDAwBE,oCACE,yCAkBE,GAKE,GAOG;EACC,SAAS,GAAT;EACA,qBAAA;EACA,YAAA;EACA,aAAA;EACA,qBAAA;EACA,6BAAA;EACA,OAAA;EACA,kBAAA;EACA,mBAAmB,aAAnB;EACA,gBAAgB,aAAhB;EACA,cAAc,aAAd;EACA,WAAW,aAAX;;AArEd,KAEE,iDAwBE,oCACE,yCAgDE;EACE,cAAA;EAvGR,eAAA;EACA,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,kBAAA;EACA,kBAAA;EACA,qBAAA;EACA,yBAAA;EACA,kBAAA;EACA,uBAAA;EACA,0BAAA;EACA,cAAA;EACA,mBAAA;EACA,sCAAA;EACA,2CAAA;EACA,8CAAA;;AACA,KAaA,iDAwBE,oCACE,yCAgDE,+BAtFL;EACC,4CAAA;EACA,iDAAA;EACA,oDAAA;;AAEF,KAQA,iDAwBE,oCACE,yCAgDE,+BAjFL;EACC,aAAA;EACA,SAAA;;AAwFJ,mBAAsC;EACpC,KACE,iDACE;IACE,kBAAA;;EAHN,KACE,iDAKE,oCACE;IACE,aAAA;;EARR,KACE,iDAKE,oCACE,yCAGE;IACE,gBAAA;IACA,eAAA;IACA,eAAA;IACA,gBAAA;;EAdV,KACE,iDAKE,oCACE,yCAUE;IACE,mBAAA;;EAlBV,KACE,iDAKE,oCACE,yCAUE,GAGE;IACE,eAAA;IACA,YAAA;IACA,kBAAA;;EAEA,KAxBV,iDAKE,oCACE,yCAUE,GAGE,GAKG;IACC,YAAA;IACA,aAAA;IACA,6BAAA;IACA,OAAA;IACA,kBAAA;;EA9Bd,KACE,iDAKE,oCACE,yCA4BE;IACE,gBAAA;IACA,iBAAA;IACA,eAAA;IACA,iBAAA;IACA,kBAAA;IACA,uBAAA;IACA,0BAAA","file":"clearfy-base.css"}
libs/factory/clearfy/assets/css/clearfy-base.less ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Базовые стили для всех копомпонентов Clearfy
3
+
4
+ * @author Webcraftic <wordpress.webraftic@gmail.com>
5
+ * @copyright Webcraftic 06.10.2018
6
+ * @sicne 2.0.5
7
+ */
8
+
9
+ .button(@backgroundColor: #e8e8e8,@color:#353535, @boxShadow:rgba(0, 0, 0, 0.2)) {
10
+ cursor: pointer;
11
+ line-height: 16px;
12
+ font-size: 13px;
13
+ font-weight: 600;
14
+ padding: 12px 20px;
15
+ text-align: center;
16
+ text-decoration: none;
17
+ text-transform: uppercase;
18
+ border-radius: 2px;
19
+ -moz-border-radius: 2px;
20
+ -webkit-border-radius: 2px;
21
+ color: @color;
22
+ background: @backgroundColor;
23
+ box-shadow: 0 1px 0 @boxShadow;
24
+ -moz-box-shadow: 0 1px 0 @boxShadow;
25
+ -webkit-box-shadow: 0 1px 0 @boxShadow;
26
+ &:active {
27
+ box-shadow: inset 0 1px 0 @boxShadow;
28
+ -moz-box-shadow: inset 0 1px 0 @boxShadow;
29
+ -webkit-box-shadow: inset 0 1px 0 @boxShadow;
30
+ }
31
+ &:focus {
32
+ outline: none;
33
+ border: 0;
34
+ }
35
+ }
36
+
37
+ #WBCR {
38
+
39
+ .wbcr-factory-pages-000-impressive-page-template {
40
+ .wbcr-factory-clearfy-000-multisite-suggetion {
41
+ padding: 30px 80px;
42
+
43
+ h3 {
44
+ margin: 0 0 20px;
45
+ }
46
+
47
+ .wbcr-factory-inner-contanier {
48
+ border: 2px dashed #8bc34a;
49
+ background: #fff;
50
+ padding: 20px;
51
+ }
52
+
53
+ .wbcr-factory-activate-premium {
54
+ display: inline-block;
55
+ .button();
56
+ }
57
+ .wbcr-factory-purchase-premium {
58
+ display: inline-block;
59
+ .button(#fdd868, #755c0e, rgba(60, 45, 2, 0.31));
60
+ }
61
+ }
62
+
63
+ .wbcr-factory-right-sidebar-section {
64
+ .wbcr-factory-clearfy-000-pro-suggettion {
65
+ background: #fff;
66
+ color: #353535;
67
+ font-weight: 600;
68
+ border: 2px dashed #8bc34a;
69
+
70
+ h3 {
71
+ margin: 0 0 20px;
72
+ padding: 10px 0;
73
+ text-align: center;
74
+ border-bottom: 2px solid #e6e6e6;
75
+ color: #636363;
76
+ font-size: 17px;
77
+ font-weight: 600;
78
+ vertical-align: middle;
79
+ text-transform: uppercase;
80
+ }
81
+
82
+ ul {
83
+ //list-style: circle;
84
+ position: relative;
85
+ margin-bottom: 20px;
86
+
87
+ li {
88
+ font-size: 15px;
89
+ padding: 7px;
90
+ padding-left: 20px;
91
+ &:before {
92
+ }
93
+
94
+ &:before {
95
+ content: " ";
96
+ display: inline-block;
97
+ width: 0.4em;
98
+ height: 0.7em;
99
+ border: solid #8bc34a;
100
+ border-width: 0 0.2em 0.2em 0;
101
+ left: 0;
102
+ margin-right: 10px;
103
+ -webkit-transform: rotate(45deg);
104
+ -moz-transform: rotate(45deg);
105
+ -o-transform: rotate(45deg);
106
+ transform: rotate(45deg);
107
+ }
108
+
109
+ }
110
+ }
111
+
112
+ .wbcr-factory-purchase-premium {
113
+ display: block;
114
+ .button();
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
120
+
121
+ @media screen and (max-width: 1550px) {
122
+ #WBCR {
123
+ .wbcr-factory-pages-000-impressive-page-template {
124
+ .wbcr-factory-clearfy-000-multisite-pro-suggetion {
125
+ padding: 10px 80px;
126
+ }
127
+
128
+ .wbcr-factory-right-sidebar-section {
129
+ .wbcr-factory-clearfy-000-pro-suggettion {
130
+ padding: 10px;
131
+
132
+ h3 {
133
+ margin: 0 0 20px;
134
+ padding: 10px 0;
135
+ font-size: 13px;
136
+ font-weight: 600;
137
+ }
138
+
139
+ ul {
140
+ margin-bottom: 20px;
141
+
142
+ li {
143
+ font-size: 13px;
144
+ padding: 2px;
145
+ padding-left: 10px;
146
+
147
+ &:before {
148
+ width: 0.4em;
149
+ height: 0.7em;
150
+ border-width: 0 0.2em 0.2em 0;
151
+ left: 0;
152
+ margin-right: 10px;
153
+ }
154
+ }
155
+ }
156
+
157
+ .wbcr-factory-purchase-premium {
158
+ font-weight: 700;
159
+ line-height: 16px;
160
+ font-size: 12px;
161
+ padding: 8px 12px;
162
+ border-radius: 2px;
163
+ -moz-border-radius: 2px;
164
+ -webkit-border-radius: 2px;
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
libs/factory/clearfy/assets/css/license-manager.css ADDED
@@ -0,0 +1,663 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ .not-visible-in-manager {
3
+ display: none;
4
+ }
5
+
6
+ /**
7
+ * Global License Message
8
+ */
9
+ .global-license-message {
10
+ width: 600px;
11
+ margin: auto;
12
+ /*margin-top: 100px;*/
13
+ font-size: 14px;
14
+ line-height: 170%;
15
+ }
16
+
17
+ .global-license-message h2, .global-license-message h3 {
18
+ padding: 0px;
19
+ margin: 5px 0;
20
+ }
21
+
22
+ .onp-page-wrap {
23
+ max-width: 720px;
24
+ margin: auto;
25
+ margin-top: 40px;
26
+ font-size: 14px;
27
+ line-height: 170%;
28
+ }
29
+
30
+ .onp-container {
31
+ border: 0px;
32
+ padding: 0px;
33
+ border-radius: 5px;
34
+ background: rgb(255, 255, 255) !important;
35
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
36
+ -moz-box-sizing: border-box;
37
+ box-sizing: border-box;
38
+ }
39
+
40
+ #license-manager {
41
+ padding: 0 0 40px;
42
+ }
43
+
44
+ #license-manager .onp-container {
45
+ background: -moz-linear-gradient(top, rgba(255, 255, 255, 1) 63%, rgba(246, 246, 246, 1) 100%); /* FF3.6+ */
46
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(63%, rgba(255, 255, 255, 1)), color-stop(100%, rgba(246, 246, 246, 1))); /* Chrome,Safari4+ */
47
+ background: -webkit-linear-gradient(top, rgba(255, 255, 255, 1) 63%, rgba(246, 246, 246, 1) 100%); /* Chrome10+,Safari5.1+ */
48
+ background: -o-linear-gradient(top, rgba(255, 255, 255, 1) 63%, rgba(246, 246, 246, 1) 100%); /* Opera 11.10+ */
49
+ background: -ms-linear-gradient(top, rgba(255, 255, 255, 1) 63%, rgba(246, 246, 246, 1) 100%); /* IE10+ */
50
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 1) 63%, rgba(246, 246, 246, 1) 100%); /* W3C */
51
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f6f6f6', GradientType=0); /* IE6-9 */
52
+ }
53
+
54
+ .onp-container h2 {
55
+ margin: 0px;
56
+ padding: 0px;
57
+ }
58
+
59
+ .onp-container p {
60
+ margin: 0 0 2px 0;
61
+ padding: 0px;
62
+ line-height: 170%;
63
+ }
64
+
65
+ .btn-uppercase {
66
+ font-size: 12px;
67
+ letter-spacing: 1px;
68
+ text-transform: uppercase;
69
+ text-decoration: none;
70
+ }
71
+
72
+ .btn-uppercase *[class^=icon] {
73
+ position: relative;
74
+ top: -1px;
75
+ left: -1px;
76
+ }
77
+
78
+ .onp-page-wrap .license-message {
79
+ margin-bottom: 20px;
80
+ overflow: hidden;
81
+ }
82
+
83
+ .onp-page-wrap .license-message .alert {
84
+ margin: 0px;
85
+ }
86
+
87
+ .onp-page-wrap .license-message strong {
88
+ display: block;
89
+ margin-bottom: 0px;
90
+ }
91
+
92
+ .onp-page-wrap .license-message p {
93
+ margin: 1px 0 1px 0;
94
+ padding: 0px;
95
+ }
96
+
97
+ .onp-page-wrap .license-message a {
98
+ font-weight: bold;
99
+ }
100
+
101
+ .license-message .alert-warning-icon {
102
+ padding-left: 60px;
103
+ background-image: url("../img/warning.png");
104
+ background-position: 15px 11px;
105
+ background-repeat: no-repeat;
106
+ }
107
+
108
+ #onp-hide-license-manager {
109
+ position: absolute;
110
+ top: 2px;
111
+ right: 15px;
112
+ font-size: 12px;
113
+ color: #777;
114
+ font-weight: bold;
115
+ }
116
+
117
+ #onp-hide-license-manager:hover {
118
+ text-decoration: none;
119
+ }
120
+
121
+ #onp-hide-license-manager,
122
+ #onp-hide-license-manager:focus,
123
+ #onp-hide-license-manager:hover {
124
+ outline: none;
125
+ border: 0px;
126
+ box-shadow: none;
127
+ }
128
+
129
+ #onp-hide-license-manager .fa {
130
+ margin-right: 5px;
131
+ }
132
+
133
+ #license-manager .license-details-wrap {
134
+ border: 1px solid #e9e9e9;
135
+ padding: 0px;
136
+ border-radius: 5px;
137
+
138
+ background: rgb(255, 255, 255); /* Old browsers */
139
+ background: -moz-linear-gradient(top, rgba(255, 255, 255, 1) 63%, rgba(246, 246, 246, 1) 100%); /* FF3.6+ */
140
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(63%, rgba(255, 255, 255, 1)), color-stop(100%, rgba(246, 246, 246, 1))); /* Chrome,Safari4+ */
141
+ background: -webkit-linear-gradient(top, rgba(255, 255, 255, 1) 63%, rgba(246, 246, 246, 1) 100%); /* Chrome10+,Safari5.1+ */
142
+ background: -o-linear-gradient(top, rgba(255, 255, 255, 1) 63%, rgba(246, 246, 246, 1) 100%); /* Opera 11.10+ */
143
+ background: -ms-linear-gradient(top, rgba(255, 255, 255, 1) 63%, rgba(246, 246, 246, 1) 100%); /* IE10+ */
144
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 1) 63%, rgba(246, 246, 246, 1) 100%); /* W3C */
145
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f6f6f6', GradientType=0); /* IE6-9 */
146
+
147
+ box-shadow: 0px 2px 1px #c9c9c9;
148
+ }
149
+
150
+ #license-manager .activate-trial-hint {
151
+ background-color: #f8f8f8;
152
+ padding: 10px 20px;
153
+ position: relative;
154
+ -moz-box-sizing: content-box;
155
+ box-sizing: content-box;
156
+ }
157
+
158
+ #license-manager .activate-error-hint {
159
+ background-color: #fb7976;
160
+ color: #f5f5f5;
161
+ text-shadow: none;
162
+ padding: 2px 9px;
163
+ width: 100%;
164
+ position: relative;
165
+ margin-left: -9px;
166
+ -moz-box-sizing: content-box;
167
+ box-sizing: content-box;
168
+ }
169
+
170
+ #license-manager .license-details {
171
+ padding: 20px;
172
+ padding-bottom: 0px;
173
+ -webkit-border-top-left-radius: 5px;
174
+ -webkit-border-top-right-radius: 5px;
175
+ -moz-border-radius-topleft: 5px;
176
+ -moz-border-radius-topright: 5px;
177
+ border-top-left-radius: 5px;
178
+ border-top-right-radius: 5px;
179
+
180
+ position: relative;
181
+ z-index: 10;
182
+ }
183
+
184
+ #license-manager .license-key-identity {
185
+ font-style: italic;
186
+ position: relative;
187
+ top: -6px;
188
+ }
189
+
190
+ #license-manager .license-key-identity code {
191
+ display: inline-block;
192
+ padding: 2px 5px;
193
+ font-size: 16px;
194
+ }
195
+
196
+ #license-manager .license-key-description {
197
+ font-size: 12px;
198
+ }
199
+
200
+ #license-manager .license-delete-button {
201
+ float: right;
202
+ text-decoration: none;
203
+ position: relative;
204
+ top: -7px;
205
+ left: 10px;
206
+ }
207
+
208
+ #license-manager .license-synchronization-button {
209
+ float: right;
210
+ text-decoration: none;
211
+ position: relative;
212
+ top: -7px;
213
+ left: 5px;
214
+ }
215
+
216
+ #license-manager .license-details-block {
217
+ padding: 28px 35px 15px 35px;
218
+ margin-left: -35px;
219
+ width: 100%;
220
+ position: relative;
221
+ margin-top: 20px;
222
+
223
+ background: #fff;
224
+ border: 0px;
225
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
226
+ color: #333;
227
+
228
+ border-radius: 5px;
229
+
230
+ -webkit-box-sizing: content-box;
231
+ -moz-box-sizing: content-box;
232
+ box-sizing: content-box;
233
+ }
234
+
235
+ #license-manager .license-details-block p + p {
236
+ margin-top: 10px;
237
+ }
238
+
239
+ #license-manager .license-details-block a {
240
+ font-weight: bold;
241
+ }
242
+
243
+ #license-manager .license-details-block.trial-details-block {
244
+ background: #ffdede;
245
+
246
+ border: 0;
247
+ box-shadow: 0 0 7px #cf4944;
248
+ color: #a04342;
249
+ text-shadow: 1px 1px 2px #fff2f2;
250
+ }
251
+
252
+ #license-manager .license-details-block.trial-details-block a {
253
+ color: #a04342;
254
+ }
255
+
256
+ #license-manager .license-details-block.paid-details-block {
257
+ border: 0;
258
+ box-shadow: 0 0 7px #b8823b;
259
+ color: #8a6d3b;
260
+ background: #fcf8e3;
261
+ }
262
+
263
+ #license-manager .license-details-block.paid-details-block a {
264
+ color: #7a4c00;
265
+ }
266
+
267
+ #license-manager .license-details-block.gift-details-block {
268
+ background: #DFF0D8;
269
+ border: 1px solid #D6E9C6;
270
+ box-shadow: 0px 0px 5px #D6E9C6;
271
+ color: #468847;
272
+ }
273
+
274
+ #license-manager .license-details-block.gift-details-block a {
275
+ color: #468847;
276
+ }
277
+
278
+ #license-manager .license-params {
279
+ margin-top: 15px;
280
+ position: relative;
281
+ left: -2px;
282
+ }
283
+
284
+ #license-manager .license-value {
285
+ display: block;
286
+ font-size: 16px;
287
+ font-weight: bold;
288
+ }
289
+
290
+ #license-manager .license-value small {
291
+ font-weight: normal;
292
+ }
293
+
294
+ #license-manager .license-value-name {
295
+ display: block;
296
+ font-size: 12px;
297
+ }
298
+
299
+ #license-manager .license-param {
300
+ white-space: nowrap;
301
+ line-height: 130%;
302
+ padding: 10px 0 10px 35px;
303
+ vertical-align: top;
304
+ }
305
+
306
+ #license-manager .license-param-domain {
307
+ padding-left: 65px;
308
+ background: url('../img/free-license-chip.png') -3px 0px no-repeat;
309
+ }
310
+
311
+ #license-manager .trial-details-block .license-param-domain {
312
+ background: url('../img/trial-license-chip.png') -3px 0px no-repeat;
313
+ }
314
+
315
+ #license-manager .paid-details-block .license-param-domain {
316
+ background: url('../img/paid-license-chip.png') -3px 0px no-repeat;
317
+ }
318
+
319
+ #license-manager .license-details-block h3 {
320
+ margin: 0px;
321
+ padding: 0px;
322
+ font-size: 22px;
323
+ margin-bottom: 10px;
324
+ }
325
+
326
+ #license-manager .license-details-block a {
327
+ color: #a04342;
328
+ }
329
+
330
+ #license-manager .license-input {
331
+
332
+ padding: 20px;
333
+ -webkit-border-bottom-right-radius: 5px;
334
+ -webkit-border-bottom-left-radius: 5px;
335
+ -moz-border-radius-bottomright: 5px;
336
+ -moz-border-radius-bottomleft: 5px;
337
+ border-bottom-right-radius: 5px;
338
+ border-bottom-left-radius: 5px;
339
+ }
340
+
341
+ #license-manager .license-input .btn {
342
+ text-decoration: none;
343
+ }
344
+
345
+ #license-manager .license-key-wrap {
346
+ padding-right: 110px;
347
+ }
348
+
349
+ #license-key {
350
+ width: 100%;
351
+ position: relative;
352
+ font-size: 18px;
353
+ line-height: 20px;
354
+ position: relative;
355
+ top: -1px;
356
+ height: 36px;
357
+ color: #000;
358
+ }
359
+
360
+ #license-submit {
361
+ float: right;
362
+ padding: 7px 14px 6px 14px;
363
+ }
364
+
365
+ #plugin-update-block {
366
+ padding-top: 10px;
367
+ font-size: 10px;
368
+ color: #666;
369
+ max-width: 700px;
370
+ margin: auto;
371
+ }
372
+
373
+ #plugin-update-block a {
374
+ color: #000;
375
+ }
376
+
377
+ .purchase-premium {
378
+ float: right;
379
+ position: relative;
380
+ top: -11px;
381
+ left: 8px;
382
+ text-decoration: none;
383
+ font-weight: bold;
384
+ background: #fffaea;
385
+ padding: 0px;
386
+ border-radius: 4px;
387
+ outline: none;
388
+ margin-top: 4px;
389
+ box-shadow: 0 0 8px #fddf67;
390
+ }
391
+
392
+ .purchase-premium .fa {
393
+ position: relative;
394
+ margin-right: 3px;
395
+ margin-left: 3px;
396
+ }
397
+
398
+ /*
399
+ * Manual Trial Activation
400
+ */
401
+ #trial-manual .onp-container {
402
+ padding: 20px;
403
+ overflow: hidden;
404
+ }
405
+
406
+ #trial-manual ul {
407
+ margin: 0px;
408
+ padding: 0px;
409
+ margin-top: 10px;
410
+ }
411
+
412
+ #trial-manual ul li {
413
+ margin-bottom: 10px;
414
+ }
415
+
416
+ #trial-manual .license-reponse-code {
417
+ width: 100%;
418
+ height: 150px;
419
+ margin-top: 5px;
420
+ }
421
+
422
+ /*
423
+ * Manual Key Activation
424
+ */
425
+ #activate-key-manual .onp-container {
426
+ padding: 20px;
427
+ overflow: hidden;
428
+ }
429
+
430
+ #activate-key-manual ul {
431
+ margin: 0px;
432
+ padding: 0px;
433
+ margin-top: 10px;
434
+ }
435
+
436
+ #activate-key-manual ul li {
437
+ margin-bottom: 10px;
438
+ }
439
+
440
+ #activate-key-manual .license-reponse-code {
441
+ width: 100%;
442
+ height: 150px;
443
+ margin-top: 5px;
444
+ }
445
+
446
+ /**
447
+ * FAQ
448
+ */
449
+
450
+ #faq-block {
451
+ border-top: 1px solid #d7d7d7;
452
+
453
+ margin-top: 20px;
454
+ width: 100%;
455
+
456
+ padding: 10px 20px;
457
+ position: relative;
458
+ }
459
+
460
+ #faq-block .faq-header {
461
+ border-bottom: 1px dotted #333;
462
+ display: inline-block;
463
+ cursor: pointer;
464
+ font-weight: bold;
465
+ line-height: 16px;
466
+ font-size: 13px;
467
+ color: #333;
468
+ }
469
+
470
+ #faq-block .faq-header:hover {
471
+ border-bottom: 0px;
472
+ }
473
+
474
+ #faq-block .faq-header:focus, #faq-block .faq-header:active {
475
+ outline: 0;
476
+ }
477
+
478
+ #faq-block li > div {
479
+ display: none;
480
+ }
481
+
482
+ #faq-block p {
483
+ margin: 6px 0 10px 0;
484
+ font-size: 13px;
485
+ line-height: 170%;
486
+ }
487
+
488
+ #open-faq {
489
+ color: #000 !important;
490
+ text-decoration: none;
491
+ border-bottom: 1px dotted #000;
492
+ margin-left: 4px;
493
+ }
494
+
495
+ #open-faq:hover {
496
+ border-bottom: 0px;
497
+ }
498
+
499
+ .gray-link, .gray-link a {
500
+ color: #666666 !important;
501
+ }
502
+
503
+ /**
504
+ * A form to create a customer account
505
+ */
506
+
507
+ .onp-single-block .onp-header {
508
+ text-align: center;
509
+ padding: 10px;
510
+ }
511
+
512
+ .onp-single-block .onp-header h4 {
513
+ font-size: 26px;
514
+ line-height: 130%;
515
+ }
516
+
517
+ .onp-single-block .onp-container {
518
+ padding: 50px 60px;
519
+ border: 1px solid #bbb;
520
+ position: relative;
521
+ }
522
+
523
+ .onp-single-block .onp-container .onp-container-header {
524
+ margin-bottom: 20px;
525
+ }
526
+
527
+ .onp-single-block .onp-container .onp-container-header h4 {
528
+ color: #000;
529
+ margin: 0px;
530
+ font-size: 20px;
531
+ }
532
+
533
+ .onp-single-block .onp-container .onp-container-header .onp-key-info {
534
+ color: #666;
535
+ }
536
+
537
+ .onp-single-block .onp-container .onp-container-header .onp-key-info .fa {
538
+ color: #777;
539
+ }
540
+
541
+ .onp-single-block .onp-container .onp-container-header .onp-icon {
542
+ position: absolute;
543
+ top: 30px;
544
+ right: 30px;
545
+ }
546
+
547
+ .onp-single-block .onp-container p,
548
+ .onp-single-block .onp-container li {
549
+ color: #333;
550
+ font-size: 14px;
551
+ }
552
+
553
+ .onp-single-block .onp-container p + p {
554
+ margin-top: 15px;
555
+ }
556
+
557
+ .onp-single-block .onp-container .onp-form {
558
+ text-align: left;
559
+ padding: 10px 0 0 0;
560
+ }
561
+
562
+ .onp-single-block #email {
563
+ font-size: 26px;
564
+ line-height: 26px;
565
+ height: 50px;
566
+ }
567
+
568
+ .onp-single-block .checkbox {
569
+ padding-left: 25px;
570
+ color: #999;
571
+ font-style: italic;
572
+ }
573
+
574
+ .onp-single-block .checkbox input {
575
+ margin-left: -25px;
576
+ }
577
+
578
+ .onp-single-block .onp-actions {
579
+ padding-top: 20px;
580
+ }
581
+
582
+ .onp-single-block .onp-actions .btn-primary {
583
+ margin-right: 15px;
584
+ }
585
+
586
+ .onp-single-block .onp-actions a.onp-cancel {
587
+ text-decoration: none;
588
+ color: #111;
589
+ }
590
+
591
+ .onp-single-block .onp-actions a.onp-cancel:hover {
592
+ text-decoration: none;
593
+ border-bottom: 1px solid #111;
594
+ background-color: #f9f9f9;
595
+ }
596
+
597
+ .onp-single-block .onp-benefits {
598
+ padding-left: 25px;
599
+ margin-top: 15px;
600
+ list-style: initial;
601
+ }
602
+
603
+ .onp-single-block .onp-login-details {
604
+
605
+ }
606
+
607
+ .onp-single-block .onp-text-seporator {
608
+ border-top: 1px solid #eee;
609
+ margin: 30px 0;
610
+ }
611
+
612
+ #create-account .onp-container {
613
+ background: #fff url("../img/create-account-bg.png") no-repeat 370px 230px !important;
614
+ }
615
+
616
+ #account-created .onp-step {
617
+ overflow: hidden;
618
+ }
619
+
620
+ #account-created .onp-steps {
621
+ padding: 25px 0 20px 10px;
622
+ }
623
+
624
+ #account-created .onp-step + .onp-step {
625
+ margin-top: 20px;
626
+ }
627
+
628
+ #account-created .onp-step .onp-num {
629
+ font-size: 25px;
630
+ line-height: 40px;
631
+ background-color: #f5f5f5;
632
+ width: 40px;
633
+ height: 40px;
634
+ display: inline-block;
635
+ border-radius: 7px;
636
+ text-align: center;
637
+ -moz-box-sizing: border-box;
638
+ box-sizing: border-box;
639
+ margin-right: 10px;
640
+ vertical-align: middle;
641
+ font-weight: bolder;
642
+ font-family: Arial, sans-serif;
643
+ }
644
+
645
+ #account-created .onp-step .onp-desc {
646
+ width: 490px;
647
+ display: inline-block;
648
+ vertical-align: middle;
649
+ line-height: 150%;
650
+ }
651
+
652
+ #finish .onp-container {
653
+ background: #fff url("../img/finish.png") no-repeat 0 -90px !important;
654
+ padding-left: 260px;
655
+ min-height: 250px;
656
+
657
+ border-bottom: 3px solid #ccc;
658
+ }
659
+
660
+ .wcl-loader {
661
+ float: right;
662
+ width: 32px;
663
+ }
libs/factory/clearfy/assets/img/loader.gif ADDED
Binary file
libs/factory/clearfy/assets/js/globals.js ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Глобальный JS файл, который регистрирует глобальные переменные с общими методами для всех компонентов Clearfy
3
+ * и самого Clearfy.
4
+ *
5
+ * $.wbcr_factory_clearfy_216.app - методы для работы с приложением. Скрыть, показать уведомления.
6
+ * $.wbcr_factory_clearfy_216.hooks - это иммитация хуков и фильтров аналогично тем, что используются в Wordpress
7
+ *
8
+ * Copyright 2018, Webcraftic, http://webcraftic.com
9
+ *
10
+ * @since 2.0.5
11
+ * @pacakge clearfy
12
+ */
13
+ (function($) {
14
+ 'use strict';
15
+
16
+ if( !$.wbcr_factory_clearfy_216 ) {
17
+ $.wbcr_factory_clearfy_216 = {};
18
+ }
19
+
20
+ $.wbcr_factory_clearfy_216.app = $.wbcr_factory_clearfy_216.app || {
21
+ /**
22
+ * Создает и показывает уведомление внутри интерфейса Clearfy
23
+ *
24
+ * @param {string} message - сообщение об ошибке или предупреждение
25
+ * @param {string} type - тип уведомления (error, warning, success)
26
+ */
27
+ showNotice: function(message, type) {
28
+ var noticeContanier = $('<div></div>'),
29
+ noticeInnerWrap = $('<p></p>'),
30
+ dashicon = $('<span></span>'),
31
+ dashiconClass,
32
+ noticeId = this.makeid();
33
+
34
+ if( !type ) {
35
+ type = 'warning';
36
+ }
37
+
38
+ noticeContanier.addClass('alert', 'wbcr-factory-warning-notice')
39
+ .addClass('alert-' + type).addClass('wbcr-factory-' + type + '-notice');
40
+
41
+ noticeContanier.append(noticeInnerWrap);
42
+ noticeContanier.attr('id', 'uq-' + noticeId);
43
+
44
+ if( type == 'success' ) {
45
+ dashiconClass = 'dashicons-plus';
46
+ } else if( type == 'error' ) {
47
+ dashiconClass = 'dashicons-no';
48
+ } else {
49
+ dashiconClass = 'dashicons-warning';
50
+ }
51
+
52
+ dashicon.addClass('dashicons').addClass(dashiconClass);
53
+ noticeInnerWrap.prepend(dashicon);
54
+ dashicon.after(message);
55
+
56
+ $([document.documentElement, document.body]).animate({
57
+ scrollTop: $('.wbcr-factory-content').offset().top - 100
58
+ }, 300, function() {
59
+ noticeContanier.hide();
60
+ $('.wbcr-factory-content').prepend(noticeContanier);
61
+ noticeContanier.fadeIn();
62
+
63
+ /**
64
+ * Хук выполняет проивольную функцию, после того как уведомление отображено
65
+ * Реализация системы фильтров и хуков в файле libs/clearfy/admin/assests/js/global.js
66
+ * Пример регистрации хука $.wbcr_factory_clearfy_216.hooks.add('wbcr/factory_clearfy_216/updated',
67
+ * function(noticeId) {});
68
+ * @param {string} noticeId - id уведомления
69
+ */
70
+ $.wbcr_factory_clearfy_216.hooks.run('wbcr/factory_clearfy_216/showed_notice', [noticeId]);
71
+ $.wbcr_factory_clearfy_216.hooks.run('wbcr/clearfy/showed_notice', [noticeId]);
72
+ });
73
+
74
+ return noticeId;
75
+ },
76
+
77
+ /**
78
+ * Удаляет уведомление из интерфейса Clearfy
79
+ *
80
+ * @param {string} noticeId - id уведомления
81
+ */
82
+ hideNotice: function(noticeId) {
83
+ var el;
84
+ if( !noticeId ) {
85
+ el = $('.wbcr-factory-content').find('.alert');
86
+ } else {
87
+ el = $('#uq-' + noticeId);
88
+ }
89
+
90
+ el.fadeOut(500, function(e) {
91
+ $(e).remove();
92
+
93
+ /**
94
+ * Хук выполняет проивольную функцию, после того как уведомление скрыто
95
+ * Реализация системы фильтров и хуков в файле libs/clearfy/admin/assests/js/global.js
96
+ * Пример регистрации хука $.wbcr_factory_clearfy_216.hooks.add('wbcr/factory_clearfy_216/updated',
97
+ * function(noticeId)
98
+ * {});
99
+ * @param {string} noticeId - id уведомления
100
+ */
101
+ $.wbcr_factory_clearfy_216.hooks.run('wbcr/factory_clearfy_216/hidded_notice', [noticeId]);
102
+ $.wbcr_factory_clearfy_216.hooks.run('wbcr/clearfy/hidded_notice', [noticeId]);
103
+ });
104
+ },
105
+
106
+ makeid: function() {
107
+ var text = "";
108
+ var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
109
+
110
+ for( var i = 0; i < 32; i++ ) {
111
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
112
+ }
113
+
114
+ return text;
115
+ }
116
+
117
+ };
118
+
119
+ $.wbcr_factory_clearfy_216.filters = $.wbcr_factory_clearfy_216.filters || {
120
+
121
+ /**
122
+ * A set of registered filters.
123
+ */
124
+ _items: {},
125
+
126
+ /**
127
+ * A set of priorities of registered filters.
128
+ */
129
+ _priorities: {},
130
+
131
+ /**
132
+ * Applies filters to a given input value.
133
+ */
134
+ run: function(filterName, args) {
135
+ var input = args && args.length > 0 ? args[0] : null;
136
+ if( !this._items[filterName] ) {
137
+ return input;
138
+ }
139
+
140
+ for( var i in this._priorities[filterName] ) {
141
+ if( !this._priorities[filterName].hasOwnProperty(i) ) {
142
+ continue;
143
+ }
144
+
145
+ var priority = this._priorities[filterName][i];
146
+
147
+ for( var k = 0; k < this._items[filterName][priority].length; k++ ) {
148
+ var f = this._items[filterName][priority][k];
149
+ input = f.apply(f, args);
150
+ }
151
+ }
152
+
153
+ return input;
154
+ },
155
+
156
+ /**
157
+ * Registers a new filter.
158
+ */
159
+ add: function(filterName, callback, priority) {
160
+
161
+ if( !priority ) {
162
+ priority = 10;
163
+ }
164
+
165
+ if( !this._items[filterName] ) {
166
+ this._items[filterName] = {};
167
+ }
168
+ if( !this._items[filterName][priority] ) {
169
+ this._items[filterName][priority] = [];
170
+ }
171
+ this._items[filterName][priority].push(callback);
172
+
173
+ if( !this._priorities[filterName] ) {
174
+ this._priorities[filterName] = [];
175
+ }
176
+ if( $.inArray(priority, this._priorities[filterName]) === -1 ) {
177
+ this._priorities[filterName].push(priority);
178
+ }
179
+
180
+ this._priorities[filterName].sort(function(a, b) {
181
+ return a - b;
182
+ });
183
+ }
184
+ };
185
+
186
+ $.wbcr_factory_clearfy_216.hooks = $.wbcr_factory_clearfy_216.hooks || {
187
+
188
+ /**
189
+ * Applies filters to a given input value.
190
+ */
191
+ run: function(filterName, args) {
192
+ $.wbcr_factory_clearfy_216.filters.run(filterName, args);
193
+ },
194
+
195
+ /**
196
+ * Registers a new filter.
197
+ */
198
+ add: function(filterName, callback, priority) {
199
+ $.wbcr_factory_clearfy_216.filters.add(filterName, callback, priority);
200
+ }
201
+ };
202
+
203
+ })(jQuery);
libs/factory/clearfy/assets/js/license-manager.js ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Этот файл содержит скрипт исполняелся во время процедур с формой лицензирования.
3
+ * Его основная роль отправка ajax запросов на проверку, активацию, деактивацию лицензии
4
+ * и вывод уведомлений об ошибка или успешно выполнении проверок.
5
+ *
6
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
7
+ * @copyright (c) 05.10.2018, Webcraftic
8
+ * @version 1.1
9
+ * @since 1.4.0
10
+ */
11
+ jQuery(function($) {
12
+
13
+ var allNotices = [];
14
+
15
+ $(document).on('click', '.wcl-control-btn', function() {
16
+ var wrapper = $('#wcl-license-wrapper'),
17
+ loader = wrapper.data('loader'),
18
+ pluginName = wrapper.data('plugin-name'),
19
+ wpnonce = wrapper.data('nonce'),
20
+ licenseAction = $(this).data('action');
21
+
22
+ for( i = 0; i < allNotices.length; i++ ) {
23
+ $.wbcr_factory_clearfy_216.app.hideNotice(allNotices[i]);
24
+ }
25
+
26
+ $('.wcl-control-btn').hide();
27
+
28
+ $(this).after('<img class="wcl-loader" src="' + loader + '">');
29
+
30
+ var data = {
31
+ action: 'wbcr-clearfy-activate-license-for-' + pluginName,
32
+ _wpnonce: wpnonce,
33
+ plugin_name: pluginName,
34
+ license_action: licenseAction,
35
+ licensekey: ''
36
+ };
37
+
38
+ if( $(this).data('action').trim() === 'activate' ) {
39
+ data.licensekey = $('#license-key').val().trim();
40
+ }
41
+
42
+ $.ajax(ajaxurl, {
43
+ type: 'post',
44
+ dataType: 'json',
45
+ data: data,
46
+ success: function(response) {
47
+ var noticeId;
48
+
49
+ if( !response || !response.success ) {
50
+
51
+ $('.wcl-control-btn').show();
52
+ $('.wcl-loader').remove();
53
+
54
+ if( response.data ) {
55
+ console.log(response.data.error_message);
56
+ noticeId = $.wbcr_factory_clearfy_216.app.showNotice('Error: [' + response.data.error_message + ']', 'danger');
57
+ allNotices.push(noticeId);
58
+ } else {
59
+ console.log(response);
60
+ }
61
+
62
+ return;
63
+ }
64
+
65
+ if( response.data && response.data.message ) {
66
+ noticeId = $.wbcr_factory_clearfy_216.app.showNotice(response.data.message, 'success');
67
+ allNotices.push(noticeId);
68
+
69
+ // todo: доработать генерацию формы, вместо перезагрузки страницы
70
+ window.location.reload();
71
+ }
72
+
73
+ },
74
+ error: function(xhr, ajaxOptions, thrownError) {
75
+
76
+ $('.wcl-control-btn').show();
77
+ $('.wcl-loader').remove();
78
+
79
+ console.log(xhr.status);
80
+ console.log(xhr.responseText);
81
+ console.log(thrownError);
82
+
83
+ var noticeId = $.wbcr_factory_clearfy_216.app.showNotice('Error: [' + thrownError + '] Status: [' + xhr.status + '] Error massage: [' + xhr.responseText + ']', 'danger');
84
+
85
+ allNotices.push(noticeId);
86
+ }
87
+ });
88
+
89
+ return false;
90
+ });
91
+
92
+ });
libs/factory/clearfy/boot.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Factory clearfy
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
6
+ * @since 1.0.0
7
+ * @package clearfy
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ if ( defined( 'FACTORY_CLEARFY_216_LOADED' ) ) {
18
+ return;
19
+ }
20
+
21
+ define( 'FACTORY_CLEARFY_216_LOADED', true );
22
+
23
+ define( 'FACTORY_CLEARFY_216', '2.1.6' );
24
+
25
+ define( 'FACTORY_CLEARFY_216_DIR', dirname( __FILE__ ) );
26
+ define( 'FACTORY_CLEARFY_216_URL', plugins_url( null, __FILE__ ) );
27
+
28
+ load_plugin_textdomain( 'wbcr_factory_clearfy_216', false, dirname( plugin_basename( __FILE__ ) ) . '/langs' );
29
+
30
+ require( FACTORY_CLEARFY_216_DIR . '/includes/ajax-handlers.php' );
31
+ require( FACTORY_CLEARFY_216_DIR . '/includes/class-helpers.php' );
32
+ require( FACTORY_CLEARFY_216_DIR . '/includes/class-configurate.php' );
33
+
34
+ // module provides function only for the admin area
35
+ if ( is_admin() ) {
36
+ /**
37
+ * Подключаем скрипты для установки компонентов Clearfy
38
+ * на все страницы админпанели.
39
+ */
40
+ add_action( 'admin_enqueue_scripts', function () {
41
+ wp_enqueue_script( 'wbcr-factory-clearfy-216-global', FACTORY_CLEARFY_216_URL . '/assets/js/globals.js', [ 'jquery' ], FACTORY_CLEARFY_216 );
42
+ } );
43
+
44
+ if ( defined( 'FACTORY_PAGES_424_LOADED' ) ) {
45
+ require( FACTORY_CLEARFY_216_DIR . '/pages/class-pages.php' );
46
+ require( FACTORY_CLEARFY_216_DIR . '/pages/class-page-more-features.php' );
47
+ require( FACTORY_CLEARFY_216_DIR . '/pages/class-page-license.php' );
48
+ }
49
+ }
libs/factory/clearfy/includes/ajax-handlers.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Ajax handlers
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
6
+ * @copyright (c) 2017 Webraftic Ltd
7
+ * @version 1.0
8
+ */
9
+
10
+ // Exit if accessed directly
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ exit;
13
+ }
14
+
15
+ /**
16
+ * Обработчик ajax запросов для проверки, активации, деактивации лицензионного ключа
17
+ *
18
+ * @since 2.0.7
19
+ *
20
+ * @param Wbcr_Factory424_Plugin $plugin_instance
21
+ *
22
+ */
23
+ function wbcr_factory_clearfy_216_check_license( $plugin_instance ) {
24
+
25
+ $plugin_name = $plugin_instance->request->post( 'plugin_name', null, true );
26
+
27
+ if ( ( $plugin_instance->getPluginName() !== $plugin_name ) || ! $plugin_instance->current_user_can() ) {
28
+ wp_die( - 1, 403 );
29
+ }
30
+
31
+ $action = $plugin_instance->request->post( 'license_action', false, true );
32
+ $license_key = $plugin_instance->request->post( 'licensekey', null );
33
+
34
+ check_admin_referer( "clearfy_activate_license_for_{$plugin_name}" );
35
+
36
+ if ( empty( $action ) || ! in_array( $action, [ 'activate', 'deactivate', 'sync', 'unsubscribe' ] ) ) {
37
+ wp_send_json_error( [ 'error_message' => __( 'Licensing action not passed or this action is prohibited!', 'wbcr_factory_clearfy_216' ) ] );
38
+ die();
39
+ }
40
+
41
+ $result = null;
42
+ $success_message = '';
43
+
44
+ try {
45
+ switch ( $action ) {
46
+ case 'activate':
47
+ if ( empty( $license_key ) || strlen( $license_key ) > 32 ) {
48
+ wp_send_json_error( [ 'error_message' => __( 'License key is empty or license key too long (license key is 32 characters long)', 'wbcr_factory_clearfy_216' ) ] );
49
+ } else {
50
+ $plugin_instance->premium->activate( $license_key );
51
+ $success_message = __( 'Your license has been successfully activated', 'wbcr_factory_clearfy_216' );
52
+ }
53
+ break;
54
+ case 'deactivate':
55
+ $plugin_instance->premium->deactivate();
56
+ $success_message = __( 'The license is deactivated', 'wbcr_factory_clearfy_216' );
57
+ break;
58
+ case 'sync':
59
+ $plugin_instance->premium->sync();
60
+ $success_message = __( 'The license has been updated', 'wbcr_factory_clearfy_216' );
61
+ break;
62
+ case 'unsubscribe':
63
+ $plugin_instance->premium->cancel_paid_subscription();
64
+ $success_message = __( 'Subscription success cancelled', 'wbcr_factory_clearfy_216' );
65
+ break;
66
+ }
67
+ } catch( Exception $e ) {
68
+
69
+ /**
70
+ * Экшен выполняется, когда проверка лицензии вернула ошибку
71
+ *
72
+ * @since 2.1.2 Переименован в {$plugin_name}/factory/clearfy/check_license_error
73
+ * @since 2.0.7
74
+ *
75
+ * @param string $license_key
76
+ * @param string $error_message
77
+ *
78
+ * @param string $action
79
+ */
80
+ do_action( "{$plugin_name}/factory/clearfy/check_license_error", $action, $license_key, $e->getMessage() );
81
+
82
+ wp_send_json_error( [ 'error_message' => $e->getMessage() ] );
83
+ die();
84
+ }
85
+
86
+ /**
87
+ * Экшен выполняется, когда проверка лицензии успешно завершена
88
+ *
89
+ * @since 2.1.2 Переименован в {$plugin_name}/factory/clearfy/check_license_success
90
+ * @since 2.0.7
91
+ *
92
+ * @param string $license_key
93
+ *
94
+ * @param string $action
95
+ */
96
+ do_action( "{$plugin_name}/factory/clearfy/check_license_success", $action, $license_key );
97
+
98
+ wp_send_json_success( [ 'message' => $success_message ] );
99
+
100
+ die();
101
+ }
libs/factory/clearfy/includes/class-configurate.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+ /**
8
+ * Configurate clearfy plugins
9
+ *
10
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
11
+ * @since 1.0.0
12
+ * @package clearfy
13
+ * @copyright (c) 2018, Webcraftic Ltd
14
+ *
15
+ */
16
+ abstract class Wbcr_FactoryClearfy216_Configurate {
17
+
18
+ /**
19
+ * @param Wbcr_Factory424_Plugin $plugin
20
+ */
21
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
22
+ $this->plugin = $plugin;
23
+ $this->registerActionsAndFilters();
24
+ }
25
+
26
+ /**
27
+ * Registers filters and actions
28
+ *
29
+ * @return mixed
30
+ */
31
+ abstract protected function registerActionsAndFilters();
32
+
33
+ /**
34
+ * Get options with namespace
35
+ *
36
+ * @param $option_name
37
+ * @param bool $default
38
+ *
39
+ * @return mixed|void
40
+ */
41
+ public function getPopulateOption( $option_name, $default = false ) {
42
+ return $this->plugin->getPopulateOption( $option_name, $default );
43
+ }
44
+
45
+ /**
46
+ * Get options with namespace
47
+ *
48
+ * @param $option_name
49
+ * @param bool $default
50
+ *
51
+ * @return mixed|void
52
+ */
53
+ public function getOption( $option_name, $default = false ) {
54
+ return $this->plugin->getOption( $option_name, $default );
55
+ }
56
+
57
+ /**
58
+ * Get network options with namespace
59
+ *
60
+ * @param $option_name
61
+ * @param bool $default
62
+ *
63
+ * @return mixed|void
64
+ */
65
+ public function getNetworkOption( $option_name, $default = false ) {
66
+ return $this->plugin->getNetworkOption( $option_name, $default );
67
+ }
68
+
69
+ /**
70
+ * @param $option_name
71
+ * @param $value
72
+ *
73
+ * @return bool
74
+ */
75
+ public function updatePopulateOption( $option_name, $value ) {
76
+ $this->plugin->updatePopulateOption( $option_name, $value );
77
+ }
78
+
79
+ /**
80
+ * @param $option_name
81
+ * @param $value
82
+ *
83
+ * @return bool
84
+ */
85
+ public function updateNetworkOption( $option_name, $value ) {
86
+ $this->plugin->updateNetworkOption( $option_name, $value );
87
+ }
88
+
89
+ /**
90
+ * @param $option_name
91
+ * @param $value
92
+ *
93
+ * @return bool
94
+ */
95
+ public function updateOption( $option_name, $value ) {
96
+ $this->plugin->updateOption( $option_name, $value );
97
+ }
98
+
99
+ /**
100
+ * @param $option_name
101
+ *
102
+ * @return bool
103
+ */
104
+ public function deletePopulateOption( $option_name ) {
105
+ $this->plugin->deletePopulateOption( $option_name );
106
+ }
107
+
108
+ /**
109
+ * @param $option_name
110
+ *
111
+ * @return bool
112
+ */
113
+ public function deleteOption( $option_name ) {
114
+ $this->plugin->deleteOption( $option_name );
115
+ }
116
+ }
libs/factory/clearfy/includes/class-helpers.php ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+
8
+ /**
9
+ * Helpers functions
10
+ *
11
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
12
+ * @since 1.0.0
13
+ * @package clearfy
14
+ * @copyright (c) 2018, Webcraftic Ltd
15
+ *
16
+ */
17
+ class WbcrFactoryClearfy216_Helpers {
18
+
19
+ /**
20
+ * Recursive sanitation for an array
21
+ *
22
+ * @since 2.0.5
23
+ *
24
+ * @param $array
25
+ *
26
+ * @return mixed
27
+ */
28
+ public static function recursiveSanitizeArray( $array, $function ) {
29
+ foreach ( $array as $key => &$value ) {
30
+ if ( is_array( $value ) ) {
31
+ $value = self::recursiveSanitizeArray( $value, $function );
32
+ } else {
33
+ if ( function_exists( $function ) ) {
34
+ $value = $function( $value );
35
+ }
36
+ }
37
+ }
38
+
39
+ return $array;
40
+ }
41
+
42
+ /**
43
+ * Is permalink enabled?
44
+ *
45
+ * @since 1.0.0
46
+ * @return bool
47
+ * @global WP_Rewrite $wp_rewrite
48
+ */
49
+ public static function isPermalink() {
50
+ global $wp_rewrite;
51
+
52
+ if ( ! isset( $wp_rewrite ) || ! is_object( $wp_rewrite ) || ! $wp_rewrite->using_permalinks() ) {
53
+ return false;
54
+ }
55
+
56
+ return true;
57
+ }
58
+
59
+ /**
60
+ * Display 404 page to bump bots and bad guys
61
+ *
62
+ * @param bool $simple If true force displaying basic 404 page
63
+ */
64
+ public static function setError404() {
65
+ global $wp_query;
66
+
67
+ if ( function_exists( 'status_header' ) ) {
68
+ status_header( '404' );
69
+ nocache_headers();
70
+ }
71
+
72
+ if ( $wp_query && is_object( $wp_query ) ) {
73
+ $wp_query->set_404();
74
+ get_template_part( 404 );
75
+ } else {
76
+ global $pagenow;
77
+
78
+ $pagenow = 'index.php';
79
+
80
+ if ( ! defined( 'WP_USE_THEMES' ) ) {
81
+ define( 'WP_USE_THEMES', true );
82
+ }
83
+
84
+ wp();
85
+
86
+ $_SERVER['REQUEST_URI'] = self::userTrailingslashit( '/hmwp_404' );
87
+
88
+ require_once( ABSPATH . WPINC . '/template-loader.php' );
89
+ }
90
+
91
+ exit();
92
+ }
93
+
94
+ public static function useTrailingSlashes() {
95
+ return ( '/' === substr( get_option( 'permalink_structure' ), - 1, 1 ) );
96
+ }
97
+
98
+ public static function userTrailingslashit( $string ) {
99
+ return self::useTrailingSlashes() ? trailingslashit( $string ) : untrailingslashit( $string );
100
+ }
101
+
102
+ /**
103
+ * Returns true if a needle can be found in a haystack
104
+ *
105
+ * @param string $string
106
+ * @param string $find
107
+ * @param bool $case_sensitive
108
+ *
109
+ * @return bool
110
+ */
111
+ public static function strContains( $string, $find, $case_sensitive = true ) {
112
+ if ( empty( $string ) || empty( $find ) ) {
113
+ return false;
114
+ }
115
+
116
+ $pos = $case_sensitive ? strpos( $string, $find ) : stripos( $string, $find );
117
+
118
+ return ! ( $pos === false );
119
+ }
120
+
121
+ /**
122
+ * Tests if a text starts with an given string.
123
+ *
124
+ * @param string $string
125
+ * @param string $find
126
+ * @param bool $case_sensitive
127
+ *
128
+ * @return bool
129
+ */
130
+ public static function strStartsWith( $string, $find, $case_sensitive = true ) {
131
+ if ( $case_sensitive ) {
132
+ return strpos( $string, $find ) === 0;
133
+ }
134
+
135
+ return stripos( $string, $find ) === 0;
136
+ }
137
+
138
+ /**
139
+ * Tests if a text ends with an given string.
140
+ *
141
+ * @param $string
142
+ * @param $find
143
+ * @param bool $case_sensitive
144
+ *
145
+ * @return bool
146
+ */
147
+ public static function strEndsWith( $string, $find, $case_sensitive = true ) {
148
+ $expected_position = strlen( $string ) - strlen( $find );
149
+
150
+ if ( $case_sensitive ) {
151
+ return strrpos( $string, $find, 0 ) === $expected_position;
152
+ }
153
+
154
+ return strripos( $string, $find, 0 ) === $expected_position;
155
+ }
156
+
157
+ public static function arrayMergeInsert( array $arr, array $inserted, $position = 'bottom', $key = null ) {
158
+ if ( $position == 'top' ) {
159
+ return array_merge( $inserted, $arr );
160
+ }
161
+ $key_position = ( $key === null ) ? false : array_search( $key, array_keys( $arr ) );
162
+ if ( $key_position === false OR ( $position != 'before' AND $position != 'after' ) ) {
163
+ return array_merge( $arr, $inserted );
164
+ }
165
+ if ( $position == 'after' ) {
166
+ $key_position ++;
167
+ }
168
+
169
+ return array_merge( array_slice( $arr, 0, $key_position, true ), $inserted, array_slice( $arr, $key_position, null, true ) );
170
+ }
171
+
172
+ public static function maybeGetPostJson( $name ) {
173
+ if ( isset( $_POST[ $name ] ) AND is_string( $_POST[ $name ] ) ) {
174
+ $result = json_decode( stripslashes( $_POST[ $name ] ), true );
175
+ if ( ! is_array( $result ) ) {
176
+ $result = [];
177
+ }
178
+
179
+ return $result;
180
+ } else {
181
+ return [];
182
+ }
183
+ }
184
+
185
+ public static function getEscapeJson( array $data ) {
186
+ return htmlspecialchars( json_encode( $data ), ENT_QUOTES, 'UTF-8' );
187
+ }
188
+
189
+ /**
190
+ * Replace url for multisite
191
+ *
192
+ * @param $string
193
+ *
194
+ * @return string
195
+ */
196
+ public static function replaceMsUrl( $string ) {
197
+ if ( is_multisite() && BLOG_ID_CURRENT_SITE != get_current_blog_id() ) {
198
+ return str_replace( get_site_url( BLOG_ID_CURRENT_SITE ), get_site_url( get_current_blog_id() ), $string );
199
+ }
200
+
201
+ return $string;
202
+ }
203
+
204
+ /*
205
+ * Flushes as many page cache plugin's caches as possible.
206
+ *
207
+ * @return void
208
+ */
209
+ public static function flushPageCache() {
210
+ if ( function_exists( 'wp_cache_clear_cache' ) ) {
211
+ if ( is_multisite() ) {
212
+ $blog_id = get_current_blog_id();
213
+ wp_cache_clear_cache( $blog_id );
214
+ } else {
215
+ wp_cache_clear_cache();
216
+ }
217
+ } else if ( has_action( 'cachify_flush_cache' ) ) {
218
+ do_action( 'cachify_flush_cache' );
219
+ } else if ( function_exists( 'w3tc_pgcache_flush' ) ) {
220
+ w3tc_pgcache_flush();
221
+ } else if ( function_exists( 'wp_fast_cache_bulk_delete_all' ) ) {
222
+ wp_fast_cache_bulk_delete_all();
223
+ } else if ( class_exists( 'WpFastestCache' ) ) {
224
+ $wpfc = new WpFastestCache();
225
+ $wpfc->deleteCache();
226
+ } else if ( class_exists( 'c_ws_plugin__qcache_purging_routines' ) ) {
227
+ c_ws_plugin__qcache_purging_routines::purge_cache_dir(); // quick cache
228
+ } else if ( class_exists( 'zencache' ) ) {
229
+ zencache::clear();
230
+ } else if ( class_exists( 'comet_cache' ) ) {
231
+ comet_cache::clear();
232
+ } else if ( class_exists( 'WpeCommon' ) ) {
233
+ // WPEngine cache purge/flush methods to call by default
234
+ $wpe_methods = [
235
+ 'purge_varnish_cache',
236
+ ];
237
+
238
+ // More agressive clear/flush/purge behind a filter
239
+ if ( apply_filters( 'wbcr/factory/flush_wpengine_aggressive', false ) ) {
240
+ $wpe_methods = array_merge( $wpe_methods, [ 'purge_memcached', 'clear_maxcdn_cache' ] );
241
+ }
242
+
243
+ // Filtering the entire list of WpeCommon methods to be called (for advanced usage + easier testing)
244
+ $wpe_methods = apply_filters( 'wbcr/factory/wpengine_methods', $wpe_methods );
245
+
246
+ foreach ( $wpe_methods as $wpe_method ) {
247
+ if ( method_exists( 'WpeCommon', $wpe_method ) ) {
248
+ WpeCommon::$wpe_method();
249
+ }
250
+ }
251
+ } else if ( function_exists( 'sg_cachepress_purge_cache' ) ) {
252
+ sg_cachepress_purge_cache();
253
+ } else if ( file_exists( WP_CONTENT_DIR . '/wp-cache-config.php' ) && function_exists( 'prune_super_cache' ) ) {
254
+ // fallback for WP-Super-Cache
255
+ global $cache_path;
256
+ if ( is_multisite() ) {
257
+ $blog_id = get_current_blog_id();
258
+ prune_super_cache( get_supercache_dir( $blog_id ), true );
259
+ prune_super_cache( $cache_path . 'blogs/', true );
260
+ } else {
261
+ prune_super_cache( $cache_path . 'supercache/', true );
262
+ prune_super_cache( $cache_path, true );
263
+ }
264
+ }
265
+ }
266
+ }
libs/factory/clearfy/includes/index.php ADDED
File without changes
libs/factory/clearfy/index.php ADDED
File without changes
libs/factory/clearfy/langs/wbcr_factory_clearfy_216-ru_RU.mo ADDED
Binary file
libs/factory/clearfy/langs/wbcr_factory_clearfy_216-ru_RU.po ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: clearfy\n"
4
+ "POT-Creation-Date: 2018-10-16 22:37+0300\n"
5
+ "PO-Revision-Date: 2018-10-16 22:41+0300\n"
6
+ "Last-Translator: alex.kovalevv@gmail.com <alex.kovalevv@gmail.com>\n"
7
+ "Language-Team: Alex Kovalev <alex.kovalevv@gmail.com>\n"
8
+ "Language: ru_RU\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 2.1.1\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
15
+ "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
16
+ "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c\n"
18
+ "X-Poedit-SearchPath-0: .\n"
19
+
20
+ #: includes/check-clearfy-compatibility.php:265
21
+ msgid "Clearfy warning"
22
+ msgstr "Clearfy предупреждение"
23
+
24
+ #: includes/check-clearfy-compatibility.php:266
25
+ #, php-format
26
+ msgid "The %s component"
27
+ msgstr "Работа компонента %s"
28
+
29
+ #: includes/check-clearfy-compatibility.php:268
30
+ msgid "warning"
31
+ msgstr "предупреждение"
32
+
33
+ #: includes/check-clearfy-compatibility.php:269
34
+ #, php-format
35
+ msgid "The %s plugin"
36
+ msgstr "Работа плагина %s"
37
+
38
+ #: includes/check-clearfy-compatibility.php:272
39
+ msgid "has stopped."
40
+ msgstr "была остановлена."
41
+
42
+ #: includes/check-clearfy-compatibility.php:273
43
+ msgid "Possible reasons:"
44
+ msgstr "Возможные причины:"
45
+
46
+ #: includes/check-clearfy-compatibility.php:279
47
+ #, php-format
48
+ msgid "You need to update the PHP version to %s or higher!"
49
+ msgstr "Вам нужно обновить версию PHP до %s или выше!"
50
+
51
+ #: includes/check-clearfy-compatibility.php:284
52
+ #, php-format
53
+ msgid "You need to update WordPress to %s or higher!"
54
+ msgstr "Вам нужно обновить WordPress до %s или выше!"
55
+
56
+ #: includes/check-clearfy-compatibility.php:289
57
+ #, php-format
58
+ msgid "You need to update the Clearfy plugin version to %s or higher!"
59
+ msgstr "Вам нужно обновить версию плагина Clearfy до %s или выше!"
60
+
61
+ #: includes/check-clearfy-compatibility.php:294
62
+ msgid "This plugin is already activated, you are trying to activate it again."
63
+ msgstr "Этот плагин уже активирован, вы пытаетесь активировать его снова."
64
+
65
+ #: includes/check-clearfy-compatibility.php:299
66
+ #, php-format
67
+ msgid ""
68
+ "Clearfy has the features of the %s plugin. Please, deactivate %s to avoid "
69
+ "conflicts of plugins!"
70
+ msgstr ""
71
+ "Плагин Clearfy уже включает в себя функции плагина %s. Пожалуйста, "
72
+ "деактивируйте плагин %s, чтобы не создавать конфликтов!"
73
+
74
+ #: pages/class.pages.php:212
75
+ msgid "Upgrade to Clearfy Business"
76
+ msgstr "Перейти на Clearfy Бизнес"
77
+
78
+ #: pages/class.pages.php:213
79
+ msgid "Oops... Sorry for the inconvenience caused!"
80
+ msgstr "Упс... Мы приносим свои извинения за неудобства!"
81
+
82
+ #: pages/class.pages.php:214
83
+ msgid ""
84
+ "Complete multisite support is available in Clearfy Business and Clearfy "
85
+ "Business Revolution packages only!"
86
+ msgstr ""
87
+ "Полная поддержка мультисайтов доступна только в пакете Clearfy Бизнес и "
88
+ "Clearfy Бизнес Революция!"
89
+
90
+ #: pages/class.pages.php:215
91
+ msgid ""
92
+ "You can activate the plugin on each website and use it with zero "
93
+ "limitations. But you can’t save the plugin’s settings under the Super "
94
+ "Administrator role!"
95
+ msgstr ""
96
+ "Вы можете активировать плагин отдельно для каждого сайта и использовать его "
97
+ "без ограничений, но в режиме суперадминистратора, вы не можете сохранять "
98
+ "настройки плагина!"
99
+
100
+ #: pages/class.pages.php:217
101
+ msgid "Activate license "
102
+ msgstr "Активировать лицензию "
103
+
104
+ #: pages/class.pages.php:218
105
+ #, php-format
106
+ msgid "Upgrade to Clearfy Business for $%d"
107
+ msgstr "Обновить до Clearfy Бизнес за $%d"
108
+
109
+ #: pages/class.pages.php:273
110
+ msgid "MORE IN CLEARFY <span>BUSINESS</span>"
111
+ msgstr "ЛУЧШЕЕ В CLEARFY <span>БИЗНЕС</span>"
112
+
113
+ #: pages/class.pages.php:275
114
+ msgid "4 premium components now;"
115
+ msgstr "4 премиум компонента сейчас;"
116
+
117
+ #: pages/class.pages.php:276
118
+ msgid "40 new premium components within a year for the single price;"
119
+ msgstr "40 новых премиум компонентов в год по одной цене;"
120
+
121
+ #: pages/class.pages.php:277
122
+ msgid "Multisite support;"
123
+ msgstr "Поддержка мультисайтов;"
124
+
125
+ #: pages/class.pages.php:278
126
+ msgid "Advanced settings;"
127
+ msgstr "Дополнительные настройки;"
128
+
129
+ #: pages/class.pages.php:279
130
+ msgid "No ads;"
131
+ msgstr "Нет рекламы;"
132
+
133
+ #: pages/class.pages.php:280
134
+ msgid "Perfect support."
135
+ msgstr "Лучшая поддержка."
136
+
137
+ #: pages/class.pages.php:283
138
+ #, php-format
139
+ msgid "Upgrade for $%s"
140
+ msgstr "Обновиться за $%s"
141
+
142
+ #: pages/class.pages.php:299
143
+ msgid ""
144
+ "A neutral setting that can not harm your site, but you must be sure that you "
145
+ "need to use it."
146
+ msgstr ""
147
+ "Нейтральная настройка, которая не может нанести вред вашему сайту, но вы "
148
+ "должны быть уверены, что вам нужно ее использовать."
149
+
150
+ #: pages/class.pages.php:305
151
+ msgid ""
152
+ "When set this option, you must be careful. Plugins and themes may depend on "
153
+ "this function. You must be sure that you can disable this feature for the "
154
+ "site."
155
+ msgstr ""
156
+ "При включении этой настройки, вы должны быть осторожны. Некоторые плагины и "
157
+ "темы могут зависеть от этой функции. Вы должны быть уверены, что эту функцию "
158
+ "можно отключить для сайта."
159
+
160
+ #: pages/class.pages.php:311
161
+ msgid "Absolutely safe setting, We recommend to use."
162
+ msgstr "Абсолютно безопасная настройка, рекомендуем использовать."
163
+
164
+ #: pages/class.pages.php:316
165
+ msgid "Hover to the icon to get help for the feature you selected."
166
+ msgstr ""
167
+ "Наведите указатель мыши на значок, чтобы получить справку по выбранной "
168
+ "функции."
169
+
170
+ #: pages/class.pages.php:334
171
+ msgid "Do you want the plugin to improved and update?"
172
+ msgstr "Вы хотите, чтобы плагин улучшался и обновлялся?"
173
+
174
+ #: pages/class.pages.php:337
175
+ msgid ""
176
+ "Help the author, leave a review on wordpress.org. Thanks to feedback, I will "
177
+ "know that the plugin is really useful to you and is needed."
178
+ msgstr ""
179
+ "Помогите автору, оставьте отзыв на wordpress.org. Благодаря отзывам, я буду "
180
+ "знать, что плагин действительно полезен для вас и необходим."
181
+
182
+ #: pages/class.pages.php:339
183
+ msgid "And also write your ideas on how to extend or improve the plugin."
184
+ msgstr "А также напишите свои идеи о том, как расширить или улучшить плагин."
185
+
186
+ #: pages/class.pages.php:344
187
+ msgid "Go rate us and push ideas"
188
+ msgstr "Оставить отзыв или поделиться идеей"
189
+
190
+ #: pages/class.pages.php:356
191
+ msgid "Donation for plugin development"
192
+ msgstr "Пожертвования на развитие плагина"
193
+
194
+ #: pages/more-features.php:31
195
+ msgid "More features (<b>free</b>)"
196
+ msgstr "Дополнительно"
197
+
198
+ #: pages/more-features.php:40
199
+ msgid "install the ultimate version of the plugin for free!"
200
+ msgstr "установите полную версию плагина бесплатно!"
201
+
202
+ #: pages/more-features.php:51
203
+ msgid "Code cleaning"
204
+ msgstr "Очищает код"
205
+
206
+ #: pages/more-features.php:53
207
+ msgid "Clears the source code of the page from unused code."
208
+ msgstr "Очищает исходный код страницы от неиспользуемого кода."
209
+
210
+ #: pages/more-features.php:60
211
+ msgid "Improve SEO"
212
+ msgstr "Улучшает SEO"
213
+
214
+ #: pages/more-features.php:62
215
+ msgid ""
216
+ "Removes duplicate pages, closes external links, changes the headers of the "
217
+ "server."
218
+ msgstr ""
219
+ "Удаляет дубликаты страниц, закрывает внешние ссылки, изменяет заголовки "
220
+ "сервера."
221
+
222
+ #: pages/more-features.php:69
223
+ msgid "Site protection"
224
+ msgstr "Защита сайта"
225
+
226
+ #: pages/more-features.php:71
227
+ msgid "Enables and disables features that improve the protection of your site."
228
+ msgstr "Включает и отключает функции, которые улучшают защиту вашего сайта."
229
+
230
+ #: pages/more-features.php:78
231
+ msgid "Disable comments"
232
+ msgstr "Отключает комментарии"
233
+
234
+ #: pages/more-features.php:80
235
+ msgid "Disables comments on the entire site or on specific pages."
236
+ msgstr "Отключает комментарии на всем сайте или у определенных страниц."
237
+
238
+ #: pages/more-features.php:87
239
+ msgid "Manage updates"
240
+ msgstr "Менеджер обновлений"
241
+
242
+ #: pages/more-features.php:89
243
+ msgid ""
244
+ "Enables or disables automatically updates for plugins, themes and core. It "
245
+ "is also possible\n"
246
+ "\t\t\t\t\t\t\tto disable all updates."
247
+ msgstr ""
248
+ "Включает или отключает автоматические обновление плагинов, тем и ядра. Также "
249
+ "возможно\n"
250
+ "отключение всех обновлений."
251
+
252
+ #: pages/more-features.php:97
253
+ msgid "Manage widgets"
254
+ msgstr "Управление виджетами"
255
+
256
+ #: pages/more-features.php:99
257
+ msgid "Allows you to remove unused widgets."
258
+ msgstr "Позволяет удалить неиспользуемые виджеты."
259
+
260
+ #: pages/more-features.php:106
261
+ msgid "Speed Optimization"
262
+ msgstr "Оптимизация производительности"
263
+
264
+ #: pages/more-features.php:108
265
+ msgid ""
266
+ "Increases performance by disabling unused functions and reducing the number "
267
+ "of requests."
268
+ msgstr ""
269
+ "Повышает производительность, отключая неиспользуемые функции и уменьшая "
270
+ "количество запросов."
271
+
272
+ #: pages/more-features.php:115
273
+ msgid "Site privacy"
274
+ msgstr "Конфиденциальность сайта"
275
+
276
+ #: pages/more-features.php:117
277
+ msgid ""
278
+ "Allows you to hide the version of the site and plugins. Allows you to hide "
279
+ "your\n"
280
+ "\t\t\t\t\t\t\tWordPress."
281
+ msgstr ""
282
+ "Позволяет скрыть версию сайта и плагинов. Позволяет скрыть ваш\n"
283
+ "WordPress."
284
+
285
+ #: pages/more-features.php:125
286
+ msgid "Easy setup"
287
+ msgstr "Простая настройка"
288
+
289
+ #: pages/more-features.php:127
290
+ msgid ""
291
+ "In quick mode, you can easily configure the plugin according to your needs."
292
+ msgstr ""
293
+ "В быстром режиме вы можете легко настроить плагин в соответствии с вашими "
294
+ "потребностями."
295
+
296
+ #: pages/more-features.php:142
297
+ msgid "Get the ultimate plugin 100% FREE"
298
+ msgstr "Получить полную версию бесплатно на 100%."
299
+
300
+ #~ msgid "component"
301
+ #~ msgstr "компонент"
302
+
303
+ #~ msgid "plugin"
304
+ #~ msgstr "плагин"
305
+
306
+ #~ msgid "Site ptotection"
307
+ #~ msgstr "Защищает ваш сайт"
libs/factory/clearfy/pages/class-page-license.php ADDED
@@ -0,0 +1,393 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
+ exit;
6
+ }
7
+
8
+ /**
9
+ * Class Wbcr_FactoryLicense000_LicensePage is used as template to display form to active premium functionality.
10
+ *
11
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
12
+ * @since 2.0.7
13
+ */
14
+ class Wbcr_FactoryClearfy216_LicensePage extends Wbcr_FactoryClearfy216_PageBase {
15
+
16
+ /**
17
+ * {@inheritdoc}
18
+ *
19
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
20
+ * @since 2.1.2
21
+ * @var string
22
+ */
23
+ public $type = "page";
24
+
25
+ /**
26
+ * {@inheritdoc}
27
+ *
28
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
29
+ * @since 2.1.2
30
+ * @var string
31
+ */
32
+ public $page_menu_dashicon = 'dashicons-admin-network';
33
+
34
+ /**
35
+ * {@inheritdoc}
36
+ *
37
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
38
+ * @since 2.1.2
39
+ * @var bool
40
+ */
41
+ public $show_right_sidebar_in_options = false;
42
+
43
+ /**
44
+ * {@inheritdoc}
45
+ *
46
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
47
+ * @since 2.1.2
48
+ * @var int
49
+ */
50
+ public $page_menu_position = 0;
51
+
52
+ /**
53
+ * {@inheritdoc}
54
+ *
55
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
56
+ * @since 2.1.2
57
+ * @var bool
58
+ */
59
+ public $available_for_multisite = true;
60
+
61
+ /**
62
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
63
+ * @since 2.1.2
64
+ * @var string
65
+ */
66
+ public $plugin_name;
67
+
68
+ /**
69
+ * @var string Name of the paid plan.
70
+ */
71
+ public $plan_name;
72
+
73
+ // PREMIUM SECTION
74
+ // ------------------------------------------------------------------
75
+ /**
76
+ * @since 2.0.7
77
+ * @var bool
78
+ */
79
+ protected $is_premium;
80
+
81
+ /**
82
+ * @since 2.0.7
83
+ * @var \WBCR\Factory_424\Premium\Provider
84
+ */
85
+ protected $premium;
86
+
87
+ /**
88
+ * @since 2.0.7
89
+ * @var bool
90
+ */
91
+ protected $is_premium_active;
92
+
93
+ /**
94
+ * @since 2.0.7
95
+ * @var bool
96
+ */
97
+ protected $premium_has_subscription;
98
+
99
+ /**
100
+ * @since 2.0.7
101
+ * @var \WBCR\Factory_424\Premium\Interfaces\License
102
+ */
103
+ protected $premium_license;
104
+
105
+ // END PREMIUM SECTION
106
+ // ------------------------------------------------------------------
107
+
108
+ /**
109
+ * {@inheritdoc}
110
+ * @param Wbcr_Factory424_Plugin $plugin
111
+ */
112
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
113
+ $this->plugin = $plugin;
114
+
115
+ parent::__construct( $plugin );
116
+
117
+ if ( ! $this->id ) {
118
+ $this->id = $this->plugin->getPrefix() . 'license';
119
+ }
120
+
121
+ $this->plugin_name = $this->plugin->getPluginName();
122
+ $this->premium = $plugin->premium;
123
+ $this->is_premium = $this->premium->is_activate();
124
+ $this->is_premium_active = $this->premium->is_active();
125
+ $this->premium_has_subscription = $this->premium->has_paid_subscription();
126
+ $this->premium_license = $this->premium->get_license();
127
+
128
+ add_action( "wp_ajax_wbcr-clearfy-activate-license-for-{$this->plugin_name}", [ $this, 'ajax_handler' ] );
129
+ }
130
+
131
+ /**
132
+ * [MAGIC] Magic method that configures assets for a page.
133
+ */
134
+ public function assets( $scripts, $styles ) {
135
+ parent::assets( $scripts, $styles );
136
+
137
+ $this->styles->add( FACTORY_CLEARFY_216_URL . '/assets/css/license-manager.css' );
138
+ $this->scripts->add( FACTORY_CLEARFY_216_URL . '/assets/js/license-manager.js' );
139
+ }
140
+
141
+ /**
142
+ * Регистрируем ajax обработчик для текущей страницы
143
+ *
144
+ * @since 2.0.7
145
+ */
146
+ public function ajax_handler() {
147
+ wbcr_factory_clearfy_216_check_license( $this->plugin );
148
+ }
149
+
150
+ /**
151
+ * {@inheritdoc}
152
+ */
153
+ public function showPageContent() {
154
+ ?>
155
+ <div id="wcl-license-wrapper"
156
+ data-loader="<?php echo FACTORY_CLEARFY_216_URL . '/assets/img/loader.gif'; ?>"
157
+ data-plugin-name="<?php echo esc_attr( $this->plugin_name ); ?>"
158
+ data-nonce="<?php echo wp_create_nonce( "clearfy_activate_license_for_{$this->plugin_name}" ) ?>">
159
+ <?php $this->show_license_form(); ?>
160
+ </div>
161
+ <?php
162
+ }
163
+
164
+ /**
165
+ * Get before content.
166
+ *
167
+ * @return string Before content.
168
+ */
169
+ protected function get_plan_description() {
170
+ return '';
171
+ }
172
+
173
+ /**
174
+ * @return string
175
+ */
176
+ protected function get_hidden_license_key() {
177
+ if ( ! $this->is_premium ) {
178
+ return '';
179
+ }
180
+
181
+ return $this->premium_license->get_hidden_key();
182
+ }
183
+
184
+ /**
185
+ * @return string
186
+ */
187
+ protected function get_plan() {
188
+ if ( ! $this->is_premium ) {
189
+ return 'free';
190
+ }
191
+
192
+ return $this->premium->get_plan();
193
+ }
194
+
195
+ /**
196
+ * @return mixed
197
+ */
198
+ protected function get_expiration_days() {
199
+ return $this->premium_license->get_expiration_time( 'days' );
200
+ }
201
+
202
+ /**
203
+ * @return string
204
+ */
205
+ protected function get_billing_cycle_readable() {
206
+ if ( ! $this->is_premium ) {
207
+ return '';
208
+ }
209
+
210
+ $billing_cycle = $this->premium->get_billing_cycle();
211
+ $billing = 'lifetime';
212
+
213
+ if ( 1 == $billing_cycle ) {
214
+ $billing = 'month';
215
+ } else if ( 12 == $billing_cycle ) {
216
+ $billing = 'year';
217
+ }
218
+
219
+ return $billing;
220
+ }
221
+
222
+ /**
223
+ * Тип лицензии, цветовое оформление для формы лицензирования
224
+ * free - бесплатная
225
+ * gift - пожизненная лицензия, лицензия на особых условиях
226
+ * trial - красный цвет, применяется для триалов, если лиценизия истекла или заблокирована
227
+ * paid - обычная оплаченная лицензия, в данный момент активна.
228
+ *
229
+ * @return string
230
+ */
231
+ protected function get_license_type() {
232
+ if ( ! $this->is_premium ) {
233
+ return 'free';
234
+ }
235
+
236
+ $license = $this->premium_license;
237
+
238
+ if ( $license->is_lifetime() ) {
239
+ return 'gift';
240
+ } else if ( $license->get_expiration_time( 'days' ) < 1 ) {
241
+ return 'trial';
242
+ }
243
+
244
+ return 'paid';
245
+ }
246
+
247
+ /**
248
+ * @param bool|WP_Error $notice
249
+ */
250
+ public function show_license_form( $notice = false ) {
251
+ ?>
252
+ <div id="license-manager"
253
+ class="factory-bootstrap-425 onp-page-wrap <?= $this->get_license_type() ?>-license-manager-content">
254
+ <div>
255
+ <h3><?php printf( __( 'Activate %s', 'wbcr_factory_clearfy_216' ), $this->plan_name ) ?></h3>
256
+ <?php echo $this->get_plan_description() ?>
257
+ </div>
258
+ <br>
259
+ <?php if ( is_wp_error( $notice ) ) : ?>
260
+ <div class="license-message <?= $this->get_license_type() ?>-license-message">
261
+ <div class="alert <?php echo esc_attr( $notice->get_error_code() ); ?>">
262
+ <h4 class="alert-heading"><?php _e( $notice->get_error_message(), 'wbcr_factory_clearfy_216' ) ?></h4>
263
+ </div>
264
+ </div>
265
+ <?php endif; ?>
266
+ <div class="onp-container">
267
+ <div class="license-details">
268
+ <?php if ( $this->get_license_type() == 'free' ): ?>
269
+ <a href="<?php echo $this->plugin->get_support()->get_pricing_url( true, 'license_page' ); ?>"
270
+ class="purchase-premium" target="_blank" rel="noopener">
271
+ <span class="btn btn-gold btn-inner-wrap">
272
+ <?php _e( 'Upgrade to Premium', 'wbcr_factory_clearfy_216' ) ?>
273
+ </span>
274
+ </a>
275
+ <p><?php printf( __( 'Your current license for %1$s:', 'wbcr_factory_clearfy_216' ), $this->plugin->getPluginTitle() ) ?></p>
276
+ <?php endif; ?>
277
+ <div class="license-details-block <?= $this->get_license_type() ?>-details-block">
278
+ <?php if ( $this->is_premium ): ?>
279
+ <a data-action="deactivate" href="#"
280
+ class="btn btn-default btn-small license-delete-button wcl-control-btn">
281
+ <?php _e( 'Delete Key', 'wbcr_factory_clearfy_216' ) ?>
282
+ </a>
283
+ <a data-action="sync" href="#"
284
+ class="btn btn-default btn-small license-synchronization-button wcl-control-btn">
285
+ <?php _e( 'Synchronization', 'wbcr_factory_clearfy_216' ) ?>
286
+ </a>
287
+ <?php endif; ?>
288
+ <h3>
289
+ <?php echo ucfirst( $this->get_plan() ); ?>
290
+
291
+ <?php if ( $this->is_premium && $this->premium_has_subscription ): ?>
292
+ <span style="font-size: 15px;">
293
+ (<?php printf( __( 'Automatic renewal, every %s', '' ), esc_attr( $this->get_billing_cycle_readable() ) ); ?>)
294
+ </span>
295
+ <?php endif; ?>
296
+ </h3>
297
+ <?php if ( $this->is_premium ): ?>
298
+ <div class="license-key-identity">
299
+ <code><?= esc_attr( $this->get_hidden_license_key() ) ?></code>
300
+ </div>
301
+ <?php endif; ?>
302
+ <div class="license-key-description">
303
+ <p><?php _e( 'Public License is a GPLv2 compatible license allowing you to change and use this version of the plugin for free. Please keep in mind this license covers only free edition of the plugin. Premium versions are distributed with other type of a license.', 'wbcr_factory_clearfy_216' ) ?>
304
+ </p>
305
+ <?php if ( $this->is_premium && $this->premium_has_subscription ): ?>
306
+ <p class="activate-trial-hint">
307
+ <?php _e( 'You use a paid subscription for the plugin updates. In case you don’t want to receive paid updates, please, click <a data-action="unsubscribe" class="wcl-control-btn" href="#">cancel subscription</a>', 'wbcr_factory_clearfy_216' ) ?>
308
+ </p>
309
+ <?php endif; ?>
310
+
311
+ <?php if ( $this->get_license_type() == 'trial' ): ?>
312
+ <p class="activate-error-hint">
313
+ <?php printf( __( 'Your license has expired, please extend the license to get updates and support.', 'wbcr_factory_clearfy_216' ), '' ) ?>
314
+ </p>
315
+ <?php endif; ?>
316
+ </div>
317
+ <table class="license-params" colspacing="0" colpadding="0">
318
+ <tr>
319
+ <!--<td class="license-param license-param-domain">
320
+ <span class="license-value"><?php echo esc_attr( $_SERVER['SERVER_NAME'] ); ?></span>
321
+ <span class="license-value-name"><?php _e( 'domain', 'wbcr_factory_clearfy_216' ) ?></span>
322
+ </td>-->
323
+ <td class="license-param license-param-days">
324
+ <span class="license-value"><?= $this->get_plan() ?></span>
325
+ <span class="license-value-name"><?php _e( 'plan', 'wbcr_factory_clearfy_216' ) ?></span>
326
+ </td>
327
+ <?php if ( $this->is_premium ) : ?>
328
+ <td class="license-param license-param-sites">
329
+ <span class="license-value">
330
+ <?php echo esc_attr( $this->premium_license->get_count_active_sites() ); ?>
331
+ <?php _e( 'of', 'wbcr_factory_clearfy_216' ) ?>
332
+ <?php echo esc_attr( $this->premium_license->get_sites_quota() ); ?></span>
333
+ <span class="license-value-name"><?php _e( 'active sites', 'wbcr_factory_clearfy_216' ) ?></span>
334
+ </td>
335
+ <?php endif; ?>
336
+ <td class="license-param license-param-version">
337
+ <span class="license-value"><?= $this->plugin->getPluginVersion() ?></span>
338
+ <span class="license-value-name"><span>version</span></span>
339
+ </td>
340
+ <?php if ( $this->is_premium ): ?>
341
+ <td class="license-param license-param-days">
342
+ <?php if ( $this->get_license_type() == 'trial' ): ?>
343
+ <span class="license-value"><?php _e( 'EXPIRED!', 'wbcr_factory_clearfy_216' ) ?></span>
344
+ <span class="license-value-name"><?php _e( 'please update the key', 'wbcr_factory_clearfy_216' ) ?></span>
345
+ <?php else: ?>
346
+ <span class="license-value">
347
+ <?php
348
+ if ( $this->premium_license->is_lifetime() ) {
349
+ echo 'infiniate';
350
+ } else {
351
+ echo $this->get_expiration_days();
352
+ }
353
+ ?>
354
+ <small> <?php _e( 'day(s)', 'wbcr_factory_clearfy_216' ) ?></small>
355
+ </span>
356
+ <span class="license-value-name"><?php _e( 'remained', 'wbcr_factory_clearfy_216' ) ?></span>
357
+ <?php endif; ?>
358
+ </td>
359
+ <?php endif; ?>
360
+ </tr>
361
+ </table>
362
+ </div>
363
+ </div>
364
+ <div class="license-input">
365
+ <form action="" method="post">
366
+ <?php if ( $this->is_premium ): ?>
367
+ <p><?php _e( 'Have a key to activate the premium version? Paste it here:', 'wbcr_factory_clearfy_216' ) ?><p>
368
+ <?php else: ?>
369
+ <p><?php _e( 'Have a key to activate the plugin? Paste it here:', 'wbcr_factory_clearfy_216' ) ?>
370
+ <p>
371
+ <?php endif; ?>
372
+ <button data-action="activate" class="btn btn-default wcl-control-btn" type="button" id="license-submit">
373
+ <?php _e( 'Submit Key', 'wbcr_factory_clearfy_216' ) ?>
374
+ </button>
375
+ <div class="license-key-wrap">
376
+ <input type="text" id="license-key" name="licensekey" value="" class="form-control"/>
377
+ </div>
378
+ <?php if ( $this->is_premium ): ?>
379
+ <p style="margin-top: 10px;">
380
+ <?php printf( __( '<a href="%s" target="_blank" rel="noopener">Lean more</a> about the premium version and get the license key to activate it now!', 'wbcr_factory_clearfy_216' ), $this->plugin->get_support()->get_pricing_url( true, 'license_page' ) ); ?>
381
+ </p>
382
+ <?php else: ?>
383
+ <p style="margin-top: 10px;">
384
+ <?php printf( __( 'Can’t find your key? Go to <a href="%s" target="_blank" rel="noopener">this page</a> and login using the e-mail address associated with your purchase.', 'wbcr_factory_clearfy_216' ), $this->plugin->get_support()->get_contacts_url( true, 'license_page' ) ) ?>
385
+ </p>
386
+ <?php endif; ?>
387
+ </form>
388
+ </div>
389
+ </div>
390
+ </div>
391
+ <?php
392
+ }
393
+ }
libs/factory/clearfy/pages/class-page-more-features.php ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The page Settings.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
6
+ * @since 1.0.1
7
+ * @package clearfy
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+
18
+ class Wbcr_FactoryClearfy216_MoreFeaturesPage extends Wbcr_FactoryPages424_ImpressiveThemplate {
19
+
20
+ /**
21
+ * {@inheritDoc}
22
+ *
23
+ * @var string
24
+ */
25
+ public $id = "more_features";
26
+
27
+ /**
28
+ * {@inheritDoc}
29
+ *
30
+ * @var string
31
+ */
32
+ public $page_menu_dashicon = 'dashicons-star-filled wbcr-factory-orange-color';
33
+
34
+ /**
35
+ * {@inheritDoc}
36
+ *
37
+ * @var string
38
+ */
39
+ public $page_menu_position = 5;
40
+
41
+ /**
42
+ * {@inheritDoc}
43
+ *
44
+ * @var string
45
+ */
46
+ public $type = 'page';
47
+
48
+ /**
49
+ * {@inheritDoc}
50
+ *
51
+ * @var bool
52
+ */
53
+ public $available_for_multisite = true;
54
+
55
+ /**
56
+ * {@inheritDoc}
57
+ *
58
+ * @since 2.0.6 - добавлен
59
+ * @var bool
60
+ */
61
+ public $internal = true;
62
+
63
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
64
+ $this->menu_title = __( 'More features (<b>free</b>)', 'wbcr_factory_clearfy_216' );
65
+
66
+ parent::__construct( $plugin );
67
+
68
+ $this->plugin = $plugin;
69
+ }
70
+
71
+ /**
72
+ * {@inheritDoc}
73
+ *
74
+ * @return string
75
+ */
76
+ public function getPageTitle() {
77
+ return __( 'More features', 'wbcr_factory_clearfy_216' );
78
+ }
79
+
80
+ /**
81
+ * {@inheritDoc}
82
+ *
83
+ * @return void
84
+ */
85
+ public function showPageContent() {
86
+ ?>
87
+ <div class="row">
88
+ <div class="col-sm-4">
89
+ <div class="wbcr-factory-feature-box">
90
+ <span class="dashicons dashicons-yes"></span>
91
+ <h3><?php _e( 'Code cleaning', 'wbcr_factory_clearfy_216' ) ?></h3>
92
+ <p><?php _e( 'Clears the source code of the page from unused code.', 'wbcr_factory_clearfy_216' ) ?></p>
93
+ </div>
94
+ </div>
95
+ <div class="col-sm-4">
96
+ <div class="wbcr-factory-feature-box">
97
+ <span class="dashicons dashicons-chart-bar"></span>
98
+ <h3><?php _e( 'Improve SEO', 'wbcr_factory_clearfy_216' ) ?></h3>
99
+ <p><?php _e( 'Removes duplicate pages, closes external links, changes the headers of the server.', 'wbcr_factory_clearfy_216' ) ?></p>
100
+ </div>
101
+ </div>
102
+ <div class="col-sm-4">
103
+ <div class="wbcr-factory-feature-box">
104
+ <span class="dashicons dashicons-shield-alt"></span>
105
+ <h3><?php _e( 'Site protection', 'wbcr_factory_clearfy_216' ) ?></h3>
106
+ <p><?php _e( 'Enables and disables features that improve the protection of your site.', 'wbcr_factory_clearfy_216' ) ?></p>
107
+ </div>
108
+ </div>
109
+ <div class="col-sm-4">
110
+ <div class="wbcr-factory-feature-box">
111
+ <span class="dashicons dashicons-welcome-comments"></span>
112
+ <h3><?php _e( 'Disable comments', 'wbcr_factory_clearfy_216' ) ?></h3>
113
+ <p><?php _e( 'Disables comments on the entire site or on specific pages.', 'wbcr_factory_clearfy_216' ) ?></p>
114
+ </div>
115
+ </div>
116
+ <div class="col-sm-4">
117
+ <div class="wbcr-factory-feature-box">
118
+ <span class="dashicons dashicons-update"></span>
119
+ <h3><?php _e( 'Manage updates', 'wbcr_factory_clearfy_216' ) ?></h3>
120
+ <p><?php _e( 'Enables or disables automatically updates for plugins, themes and core. It is also possible
121
+ to disable all updates.', 'wbcr_factory_clearfy_216' ) ?></p>
122
+ </div>
123
+ </div>
124
+ <div class="col-sm-4">
125
+ <div class="wbcr-factory-feature-box">
126
+ <span class="dashicons dashicons-admin-plugins"></span>
127
+ <h3><?php _e( 'Manage widgets', 'wbcr_factory_clearfy_216' ) ?></h3>
128
+ <p><?php _e( 'Allows you to remove unused widgets.', 'wbcr_factory_clearfy_216' ) ?></p>
129
+ </div>
130
+ </div>
131
+ <div class="col-sm-4">
132
+ <div class="wbcr-factory-feature-box">
133
+ <span class="dashicons dashicons-dashboard"></span>
134
+ <h3><?php _e( 'Speed Optimization', 'wbcr_factory_clearfy_216' ) ?></h3>
135
+ <p><?php _e( 'Increases performance by disabling unused functions and reducing the number of requests.', 'wbcr_factory_clearfy_216' ) ?></p>
136
+ </div>
137
+ </div>
138
+ <div class="col-sm-4">
139
+ <div class="wbcr-factory-feature-box">
140
+ <span class="dashicons dashicons-visibility"></span>
141
+ <h3><?php _e( 'Site privacy', 'wbcr_factory_clearfy_216' ) ?></h3>
142
+ <p><?php _e( 'Allows you to hide the version of the site and plugins. Allows you to hide your
143
+ WordPress.', 'wbcr_factory_clearfy_216' ) ?></p>
144
+ </div>
145
+ </div>
146
+ <div class="col-sm-4">
147
+ <div class="wbcr-factory-feature-box">
148
+ <span class="dashicons dashicons-admin-settings"></span>
149
+ <h3><?php _e( 'Easy setup', 'wbcr_factory_clearfy_216' ) ?></h3>
150
+ <p><?php _e( 'In quick mode, you can easily configure the plugin according to your needs.', 'wbcr_factory_clearfy_216' ) ?></p>
151
+ </div>
152
+ </div>
153
+ </div>
154
+ <div class="wbcr-factory-buttons-wrap">
155
+ <?php
156
+ $url = 'https://clearfy.pro';
157
+
158
+ if ( get_locale() == 'ru_RU' ) {
159
+ $url = 'https://ru.clearfy.pro';
160
+ }
161
+ $url .= '?utm_source=wordpress.org&utm_campaign=' . $this->plugin->getPluginName();
162
+ ?>
163
+ <a href="<?= $url ?>" class="wbcr-factory-premium-button" target="_blank">
164
+ <?php _e( 'Get the ultimate plugin 100% FREE', 'wbcr_factory_clearfy_216' ) ?>
165
+ </a>
166
+ </div>
167
+ <?php
168
+ }
169
+ }
170
+
libs/factory/clearfy/pages/class-pages.php ADDED
@@ -0,0 +1,439 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Общий класс прослойка для страниц Clearfy и его компоннетов.
5
+ * В этом классе добавляются общие ресурсы и элементы, необходимые для всех связанных плагинов.
6
+ *
7
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
8
+ * @since 2.0.5
9
+ */
10
+
11
+ // Exit if accessed directly
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
+
16
+ /**
17
+ * Class Wbcr_FactoryPages424_ImpressiveThemplate
18
+ *
19
+ * @method string getInfoWidget() - get widget content information
20
+ * @method string getRatingWidget( array $args = [] ) - get widget content rating
21
+ * @method string getDonateWidget() - get widget content donate
22
+ * @method string getBusinessSuggetionWidget()
23
+ * @method string getSupportWidget
24
+ */
25
+ class Wbcr_FactoryClearfy216_PageBase extends Wbcr_FactoryPages424_ImpressiveThemplate {
26
+
27
+ /**
28
+ * {@inheritDoc}
29
+ *
30
+ * @since 2.0.5 - добавлен
31
+ * @var bool
32
+ */
33
+ public $show_right_sidebar_in_options = true;
34
+
35
+ /**
36
+ * {@inheritDoc}
37
+ *
38
+ * @since 2.0.5 - добавлен
39
+ * @var bool
40
+ */
41
+ public $available_for_multisite = true;
42
+
43
+ /**
44
+ * {@inheritDoc}
45
+ *
46
+ * @since 2.0.6 - добавлен
47
+ * @var bool
48
+ */
49
+ public $internal = true;
50
+
51
+ /**
52
+ * @param Wbcr_Factory424_Plugin $plugin
53
+ */
54
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
55
+ parent::__construct( $plugin );
56
+ }
57
+
58
+ /**
59
+ * @param $name
60
+ * @param $arguments
61
+ *
62
+ * @return null|string
63
+ */
64
+ public function __call( $name, $arguments ) {
65
+ if ( substr( $name, 0, 3 ) == 'get' ) {
66
+ $called_method_name = 'show' . substr( $name, 3 );
67
+ if ( method_exists( $this, $called_method_name ) ) {
68
+ ob_start();
69
+
70
+ $this->$called_method_name( $arguments );
71
+ $content = ob_get_contents();
72
+ ob_end_clean();
73
+
74
+ return $content;
75
+ }
76
+ }
77
+
78
+ return null;
79
+ }
80
+
81
+ /**
82
+ * Requests assets (js and css) for the page.
83
+ *
84
+ * @param Wbcr_Factory424_ScriptList $scripts
85
+ * @param Wbcr_Factory424_StyleList $styles
86
+ *
87
+ * @return void
88
+ * @see Wbcr_FactoryPages424_AdminPage
89
+ *
90
+ */
91
+ public function assets( $scripts, $styles ) {
92
+ parent::assets( $scripts, $styles );
93
+
94
+ $this->styles->add( FACTORY_CLEARFY_216_URL . '/assets/css/clearfy-base.css' );
95
+
96
+ // todo: вынести все общие скрипты и стили фреймворка, продумать совместимость с другими плагинами
97
+ if ( defined( 'WCL_PLUGIN_URL' ) ) {
98
+ $this->styles->add( WCL_PLUGIN_URL . '/admin/assets/css/general.css' );
99
+ }
100
+
101
+ wbcr_factory_424_do_action_deprecated( 'wbcr_clearfy_page_enqueue_scripts', [
102
+ $this->getResultId(),
103
+ $scripts,
104
+ $styles
105
+ ], '1.4.0', 'wbcr/clearfy/page_assets' );
106
+
107
+ /**
108
+ * Allows you to enqueue scripts to the internal pages of the plugin.
109
+ * $this->getResultId() - page id + plugin name = quick_start-wbcr_clearfy
110
+ *
111
+ * @since 2.0.5
112
+ */
113
+ do_action( 'wbcr/clearfy/page_assets', $this->getResultId(), $scripts, $styles );
114
+ }
115
+
116
+ /**
117
+ * @return Wbcr_Factory424_Request
118
+ */
119
+ public function request() {
120
+ return $this->plugin->request;
121
+ }
122
+
123
+ /**
124
+ * @since 2.0.5
125
+ *
126
+ * @param $option_name
127
+ * @param bool $default *
128
+ *
129
+ * @return mixed|void
130
+ */
131
+ public function getPopulateOption( $option_name, $default = false ) {
132
+ return $this->plugin->getPopulateOption( $option_name, $default );
133
+ }
134
+
135
+ /**
136
+ * @param $option_name
137
+ * @param bool $default
138
+ *
139
+ * @return mixed|void
140
+ */
141
+ public function getOption( $option_name, $default = false ) {
142
+ return $this->plugin->getOption( $option_name, $default );
143
+ }
144
+
145
+ /**
146
+ * @param $option_name
147
+ * @param $value
148
+ *
149
+ * @return void
150
+ */
151
+ public function updatePopulateOption( $option_name, $value ) {
152
+ $this->plugin->updatePopulateOption( $option_name, $value );
153
+ }
154
+
155
+ /**
156
+ * @param $option_name
157
+ * @param $value
158
+ *
159
+ * @return void
160
+ */
161
+ public function updateOption( $option_name, $value ) {
162
+ $this->plugin->updateOption( $option_name, $value );
163
+ }
164
+
165
+ /**
166
+ * @param $option_name
167
+ *
168
+ * @return void
169
+ */
170
+ public function deletePopulateOption( $option_name ) {
171
+ $this->plugin->deletePopulateOption( $option_name );
172
+ }
173
+
174
+ /**
175
+ * @param $option_name
176
+ *
177
+ * @return void
178
+ */
179
+ public function deleteOption( $option_name ) {
180
+ $this->plugin->deleteOption( $option_name );
181
+ }
182
+
183
+
184
+ /**
185
+ * Действие выполняется для всех страниц Clearfy и его компонентах.
186
+ * Это простое предложение перейти на PRO версию.
187
+ */
188
+ public function multisiteProAction() {
189
+ if ( is_multisite() && $this->plugin->isNetworkActive() ) {
190
+
191
+ $license_page_url = $this->getBaseUrl( 'license' );
192
+ $upgrade_url = WbcrFactoryClearfy216_Helpers::getWebcrafticSitePageUrl( $this->plugin->getPluginName(), 'pricing', 'multisite_save_settings' );
193
+
194
+ $html = '<div class="wbcr-factory-clearfy-216-multisite-suggetion">';
195
+ $html .= '<div class="wbcr-factory-inner-contanier">';
196
+ $html .= '<h3>' . __( 'Upgrade to Clearfy Business', 'wbcr_factory_clearfy_216' ) . '</h3>';
197
+ $html .= '<p>' . __( 'Oops... Sorry for the inconvenience caused!', 'wbcr_factory_clearfy_216' ) . '</p>';
198
+ $html .= '<p>' . __( 'Complete multisite support is available in Clearfy Business and Clearfy Business Revolution packages only!', 'wbcr_factory_clearfy_216' ) . '</p>';
199
+ $html .= '<p>' . __( 'You can activate the plugin on each website and use it with zero limitations. But you can’t save the plugin’s settings under the Super Administrator role!', 'wbcr_factory_clearfy_216' ) . '</p>';
200
+ $html .= '<p style="margin-top:20px">';
201
+ $html .= '<a href="' . $license_page_url . '" class="wbcr-factory-activate-premium" rel="noopener">' . __( 'Activate license ', 'wbcr_factory_clearfy_216' ) . '</a> ';
202
+ $html .= '<a href="' . $upgrade_url . '" class="wbcr-factory-purchase-premium" target="_blank" rel="noopener">' . __( 'Upgrade to Clearfy Business', 'wbcr_factory_clearfy_216' ) . '</a>';
203
+ $html .= '</p>';
204
+ $html .= '</div>';
205
+ $html .= '</div>';
206
+
207
+ $this->showPage( $html );
208
+
209
+ return;
210
+ }
211
+
212
+ $this->redirectToAction( 'index' );
213
+ }
214
+
215
+ /**
216
+ * @param string $position
217
+ *
218
+ * @return mixed|void
219
+ */
220
+ protected function getPageWidgets( $position = 'bottom' ) {
221
+ $widgets = [];
222
+
223
+ if ( $position == 'bottom' ) {
224
+ $widgets['info_widget'] = $this->getInfoWidget();
225
+ $widgets['rating_widget'] = $this->getRatingWidget();
226
+ $widgets['support_widget'] = $this->getSupportWidget();
227
+ //$widgets['donate_widget'] = $this->getDonateWidget();
228
+ } else if ( $position == 'right' ) {
229
+ $widgets['business_suggetion'] = $this->getBusinessSuggetionWidget();
230
+ $widgets['info_widget'] = $this->getInfoWidget();
231
+ $widgets['rating_widget'] = $this->getRatingWidget();
232
+ }
233
+
234
+ /**
235
+ * @since 4.0.9 - является устаревшим
236
+ */
237
+ $widgets = wbcr_factory_424_apply_filters_deprecated( 'wbcr_factory_pages_424_imppage_get_widgets', [
238
+ $widgets,
239
+ $position,
240
+ $this->plugin,
241
+ $this
242
+ ], '4.0.9', 'wbcr/factory/pages/impressive/widgets' );
243
+
244
+ /**
245
+ * @since 4.0.1 - добавлен
246
+ * @since 4.0.9 - изменено имя
247
+ */
248
+ $widgets = apply_filters( 'wbcr/factory/pages/impressive/widgets', $widgets, $position, $this->plugin, $this );
249
+
250
+ return $widgets;
251
+ }
252
+
253
+ /**
254
+ * Создает Html разметку виджета для рекламы премиум версии
255
+ *
256
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
257
+ * @since 2.0.2
258
+ */
259
+ public function showBusinessSuggetionWidget() {
260
+ $plugin_name = $this->plugin->getPluginName();
261
+ $upgrade_price = $this->plugin->has_premium() ? $this->plugin->premium->get_price() : 0;
262
+ $purchase_url = $this->plugin->get_support()->get_pricing_url( true, 'right_sidebar_ads' );
263
+
264
+ $default_features = [
265
+ '4_premium' => __( '4 premium components now;', 'wbcr_factory_clearfy_216' ),
266
+ '40_premium' => __( '40 new premium components within a year for the single price;', 'wbcr_factory_clearfy_216' ),
267
+ 'multisite_support' => __( 'Multisite support;', 'wbcr_factory_clearfy_216' ),
268
+ 'advance_settings' => __( 'Advanced settings;', 'wbcr_factory_clearfy_216' ),
269
+ 'no_ads' => __( 'No ads;', 'wbcr_factory_clearfy_216' ),
270
+ 'perfect_support' => __( 'Perfect support.', 'wbcr_factory_clearfy_216' )
271
+ ];
272
+
273
+ /**
274
+ * @since 2.0.8 - added
275
+ */
276
+ $suggetion_title = __( 'MORE IN CLEARFY <span>BUSINESS</span>', 'wbcr_factory_clearfy_216' );
277
+ $suggetion_title = apply_filters( 'wbcr/clearfy/pages/suggetion_title', $suggetion_title, $plugin_name, $this->id );
278
+
279
+ /**
280
+ * @since 2.0.8 - deprecated
281
+ */
282
+ $suggetion_features = wbcr_factory_424_apply_filters_deprecated( 'wbcr/clearfy/page_bussines_suggetion_features', [
283
+ $default_features,
284
+ $this->plugin->getPluginName(),
285
+ $this->id
286
+ ], '2.0.8', 'wbcr/clearfy/pages/suggetion_features' );
287
+
288
+ /**
289
+ * @since 2.0.8 - renamed
290
+ * @since 2.0.6
291
+ */
292
+ $suggetion_features = apply_filters( 'wbcr/clearfy/pages/suggetion_features', $suggetion_features, $plugin_name, $this->id );
293
+
294
+ if ( empty( $suggetion_features ) ) {
295
+ $suggetion_features = $default_features;
296
+ }
297
+ ?>
298
+ <div class="wbcr-factory-sidebar-widget wbcr-factory-clearfy-216-pro-suggettion">
299
+ <h3><?php echo $suggetion_title; ?></h3>
300
+ <ul>
301
+ <?php if ( ! empty( $suggetion_features ) ): ?>
302
+ <?php foreach ( $suggetion_features as $feature ): ?>
303
+ <li><?= $feature ?></li>
304
+ <?php endforeach; ?>
305
+ <?php endif; ?>
306
+ </ul>
307
+ <a href="<?php echo $purchase_url ?>" class="wbcr-factory-purchase-premium" target="_blank" rel="noopener">
308
+ <?php printf( __( 'Upgrade for $%s', 'wbcr_factory_clearfy_216' ), $upgrade_price ) ?>
309
+ </a>
310
+ </div>
311
+ <?php
312
+ }
313
+
314
+ /**
315
+ * Создает html разметку виджета с информационными маркерами
316
+ *
317
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
318
+ * @since 2.0.0
319
+ */
320
+ public function showInfoWidget() {
321
+ ?>
322
+ <div class="wbcr-factory-sidebar-widget">
323
+ <ul>
324
+ <li>
325
+ <span class="wbcr-factory-hint-icon-simple wbcr-factory-simple-red">
326
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAQAAABKmM6bAAAAUUlEQVQIHU3BsQ1AQABA0X/komIrnQHYwyhqQ1hBo9KZRKL9CBfeAwy2ri42JA4mPQ9rJ6OVt0BisFM3Po7qbEliru7m/FkY+TN64ZVxEzh4ndrMN7+Z+jXCAAAAAElFTkSuQmCC" alt=""/>
327
+ </span>
328
+ - <?php _e( 'A neutral setting that can not harm your site, but you must be sure that you need to use it.', 'wbcr_factory_clearfy_216' ); ?>
329
+ </li>
330
+ <li>
331
+ <span class="wbcr-factory-hint-icon-simple wbcr-factory-simple-grey">
332
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAQAAABKmM6bAAAAUUlEQVQIHU3BsQ1AQABA0X/komIrnQHYwyhqQ1hBo9KZRKL9CBfeAwy2ri42JA4mPQ9rJ6OVt0BisFM3Po7qbEliru7m/FkY+TN64ZVxEzh4ndrMN7+Z+jXCAAAAAElFTkSuQmCC" alt=""/>
333
+ </span>
334
+ - <?php _e( 'When set this option, you must be careful. Plugins and themes may depend on this function. You must be sure that you can disable this feature for the site.', 'wbcr_factory_clearfy_216' ); ?>
335
+ </li>
336
+ <li>
337
+ <span class="wbcr-factory-hint-icon-simple wbcr-factory-simple-green">
338
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAQAAABKmM6bAAAAUUlEQVQIHU3BsQ1AQABA0X/komIrnQHYwyhqQ1hBo9KZRKL9CBfeAwy2ri42JA4mPQ9rJ6OVt0BisFM3Po7qbEliru7m/FkY+TN64ZVxEzh4ndrMN7+Z+jXCAAAAAElFTkSuQmCC" alt=""/>
339
+ </span>
340
+ - <?php _e( 'Absolutely safe setting, We recommend to use.', 'wbcr_factory_clearfy_216' ); ?>
341
+ </li>
342
+ </ul>
343
+ ----------<br>
344
+ <p><?php _e( 'Hover to the icon to get help for the feature you selected.', 'wbcr_factory_clearfy_216' ); ?></p>
345
+ </div>
346
+ <?php
347
+ }
348
+
349
+ /**
350
+ * Создает html разметку виджета рейтинга
351
+ *
352
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
353
+ * @since 2.0.0
354
+ *
355
+ * @param array $args
356
+ */
357
+ public function showRatingWidget( array $args ) {
358
+ if ( ! isset( $args[0] ) || empty( $args[0] ) ) {
359
+ $page_url = "https://goo.gl/tETE2X";
360
+ } else {
361
+ $page_url = $args[0];
362
+ }
363
+
364
+ $page_url = apply_filters( 'wbcr_factory_pages_424_imppage_rating_widget_url', $page_url, $this->plugin->getPluginName(), $this->getResultId() );
365
+
366
+ ?>
367
+ <div class="wbcr-factory-sidebar-widget">
368
+ <p>
369
+ <strong><?php _e( 'Do you want the plugin to improved and update?', 'wbcr_factory_clearfy_216' ); ?></strong>
370
+ </p>
371
+ <p><?php _e( 'Help the author, leave a review on wordpress.org. Thanks to feedback, I will know that the plugin is really useful to you and is needed.', 'wbcr_factory_clearfy_216' ); ?></p>
372
+ <p><?php _e( 'And also write your ideas on how to extend or improve the plugin.', 'wbcr_factory_clearfy_216' ); ?></p>
373
+ <p>
374
+ <i class="wbcr-factory-icon-5stars"></i>
375
+ <a href="<?= $page_url ?>" title="Go rate us" target="_blank">
376
+ <strong><?php _e( 'Go rate us and push ideas', 'wbcr_factory_clearfy_216' ); ?></strong>
377
+ </a>
378
+ </p>
379
+ </div>
380
+ <?php
381
+ }
382
+
383
+ /**
384
+ * Создает html размету виджета доната
385
+ *
386
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
387
+ * @since 2.0.0
388
+ */
389
+ public function showDonateWidget() {
390
+ ?>
391
+ <div class="wbcr-factory-sidebar-widget">
392
+ <p>
393
+ <strong><?php _e( 'Donation for plugin development', 'wbcr_factory_clearfy_216' ); ?></strong>
394
+ </p>
395
+ <?php if ( get_locale() !== 'ru_RU' ): ?>
396
+ <form id="wbcr-factory-paypal-donation-form" action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
397
+ <input type="hidden" name="cmd" value="_s-xclick">
398
+ <input type="hidden" name="hosted_button_id" value="VDX7JNTQPNPFW">
399
+ <div class="wbcr-factory-donation-price">5$</div>
400
+ <input type="image" src="<?= FACTORY_PAGES_424_URL ?>/templates/assets/img/paypal-donate.png" border="0" name="submit" alt="PayPal – The safer, easier way to pay online!">
401
+ </form>
402
+ <?php else: ?>
403
+ <iframe frameborder="0" allowtransparency="true" scrolling="no" src="https://money.yandex.ru/embed/donate.xml?account=410011242846510&quickpay=donate&payment-type-choice=on&mobile-payment-type-choice=on&default-sum=300&targets=%D0%9D%D0%B0+%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%BA%D1%83+%D0%BF%D0%BB%D0%B0%D0%B3%D0%B8%D0%BD%D0%B0+%D0%B8+%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D1%83+%D0%BD%D0%BE%D0%B2%D1%8B%D1%85+%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B9.+&target-visibility=on&project-name=Webcraftic&project-site=&button-text=05&comment=on&hint=%D0%9A%D0%B0%D0%BA%D1%83%D1%8E+%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8E+%D0%BD%D1%83%D0%B6%D0%BD%D0%BE+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%B8%D1%82%D1%8C+%D0%B2+%D0%BF%D0%BB%D0%B0%D0%B3%D0%B8%D0%BD%3F&mail=on&successURL=" width="508" height="187"></iframe>
404
+ <?php endif; ?>
405
+ </div>
406
+ <?php
407
+ }
408
+
409
+ /**
410
+ * Создает html разметку виджета поддержки
411
+ *
412
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
413
+ * @since 2.0.8
414
+ */
415
+ public function showSupportWidget() {
416
+ $free_support_url = $this->plugin->get_support()->get_contacts_url();
417
+ $hot_support_url = 'https://webcraftic.com/other-questions-support/';
418
+ ?>
419
+ <div id="wbcr-clr-support-widget" class="wbcr-factory-sidebar-widget">
420
+ <p><strong><?php _e( 'Having Issues?', 'clearfy' ); ?></strong></p>
421
+ <div class="wbcr-clr-support-widget-body">
422
+ <p>
423
+ <?php _e( 'We provide free support for this plugin. If you are pushed with a problem, just create a new ticket. We will definitely help you!', 'clearfy' ); ?>
424
+ </p>
425
+ <ul>
426
+ <li><span class="dashicons dashicons-sos"></span>
427
+ <a href="<?= $free_support_url ?>" target="_blank" rel="noopener"><?php _e( 'Get starting free support', 'clearfy' ); ?></a>
428
+ </li>
429
+ <li style="margin-top: 15px;background: #fff4f1;padding: 10px;color: #a58074;">
430
+ <span class="dashicons dashicons-warning"></span>
431
+ <?php printf( __( 'If you find a php error or a vulnerability in plugin, you can <a href="%s" target="_blank" rel="noopener">create ticket</a> in hot support that we responded instantly.', 'clearfy' ), $hot_support_url ); ?>
432
+ </li>
433
+ </ul>
434
+ </div>
435
+ </div>
436
+ <?php
437
+ }
438
+ }
439
+
libs/factory/clearfy/pages/index.php ADDED
File without changes
libs/factory/core/README.md ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ # Core Factory Framework
2
+
3
+ It performs the connection of system modules of the framework, is responsible for migrations, plugin updates, admin notifications, initialization of the plugin.
libs/factory/core/boot.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Factory Plugin
4
+ *
5
+ * @author @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
6
+ * @since 1.0.0
7
+ * @package core
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ if ( defined( 'FACTORY_424_LOADED' ) ) {
18
+ return;
19
+ }
20
+
21
+ define( 'FACTORY_424_LOADED', true );
22
+
23
+ define( 'FACTORY_424_VERSION', '4.2.4' );
24
+
25
+ define( 'FACTORY_424_DIR', dirname( __FILE__ ) );
26
+ define( 'FACTORY_424_URL', plugins_url( null, __FILE__ ) );
27
+
28
+ load_plugin_textdomain( 'wbcr_factory_424', false, dirname( plugin_basename( __FILE__ ) ) . '/langs' );
29
+
30
+ #comp merge
31
+ require_once( FACTORY_424_DIR . '/includes/functions.php' );
32
+
33
+ require_once( FACTORY_424_DIR . '/includes/entities/class-factory-paths.php' );
34
+ require_once( FACTORY_424_DIR . '/includes/entities/class-factory-support.php' );
35
+
36
+ require_once( FACTORY_424_DIR . '/includes/class-factory-requests.php' );
37
+ require_once( FACTORY_424_DIR . '/includes/class-factory-options.php' );
38
+ require_once( FACTORY_424_DIR . '/includes/class-factory-plugin-base.php' );
39
+ require_once( FACTORY_424_DIR . '/includes/class-factory-migrations.php' );
40
+ require_once( FACTORY_424_DIR . '/includes/class-factory-notices.php' );
41
+
42
+ // ASSETS
43
+ require_once( FACTORY_424_DIR . '/includes/assets-managment/class-factory-assets-list.php' );
44
+ require_once( FACTORY_424_DIR . '/includes/assets-managment/class-factory-script-list.php' );
45
+ require_once( FACTORY_424_DIR . '/includes/assets-managment/class-factory-style-list.php' );
46
+
47
+ // PREMIUM
48
+ require_once( FACTORY_424_DIR . '/includes/premium/class-factory-license-interface.php' );
49
+ require_once( FACTORY_424_DIR . '/includes/premium/class-factory-provider-abstract.php' );
50
+ require_once( FACTORY_424_DIR . '/includes/premium/class-factory-manager.php' );
51
+
52
+ // UPDATES
53
+ require_once( FACTORY_424_DIR . '/includes/updates/repositories/class-factory-repository-abstract.php' );
54
+ require_once( FACTORY_424_DIR . '/includes/updates/repositories/class-factory-wordpress.php' );
55
+ require_once( FACTORY_424_DIR . '/includes/updates/class-factory-upgrader.php' );
56
+ require_once( FACTORY_424_DIR . '/includes/updates/class-factory-premium-upgrader.php' );
57
+
58
+ require_once( FACTORY_424_DIR . '/includes/class-factory-plugin-abstract.php' );
59
+
60
+ require_once( FACTORY_424_DIR . '/includes/activation/class-factory-activator.php' );
61
+ require_once( FACTORY_424_DIR . '/includes/activation/class-factory-update.php' );
62
+ #endcomp
libs/factory/core/includes/activation/class-factory-activator.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains a base class for plugin activators.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
6
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
7
+ *
8
+ * @package factory-core
9
+ * @since 1.0.0
10
+ */
11
+ // Exit if accessed directly
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
+
16
+
17
+ /**
18
+ * Plugin Activator
19
+ *
20
+ * @since 1.0.0
21
+ */
22
+ abstract class Wbcr_Factory424_Activator {
23
+
24
+ /**
25
+ * Curent plugin.
26
+ *
27
+ * @var Wbcr_Factory424_Plugin
28
+ */
29
+ public $plugin;
30
+
31
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
32
+ $this->plugin = $plugin;
33
+ }
34
+
35
+ public function activate() {
36
+ }
37
+
38
+ public function deactivate() {
39
+ }
40
+
41
+ public function update() {
42
+ }
43
+ }
libs/factory/core/includes/activation/class-factory-update.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains a base class for update items of plugins.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
6
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
7
+ *
8
+ * @package factory-core
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+
18
+ /**
19
+ * Plugin Activator
20
+ *
21
+ * @since 1.0.0
22
+ */
23
+ abstract class Wbcr_Factory424_Update {
24
+
25
+ /**
26
+ * Current plugin
27
+ *
28
+ * @var Wbcr_Factory424_Plugin
29
+ */
30
+ var $plugin;
31
+
32
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
33
+ $this->plugin = $plugin;
34
+ }
35
+
36
+ abstract function install();
37
+
38
+ //abstract function rollback();
39
+ }
libs/factory/core/includes/activation/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/core/includes/assets-managment/class-factory-assets-list.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The class contains a base class for all lists of assets.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
6
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
7
+ *
8
+ * @package factory-core
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ /**
18
+ * Assets List
19
+ *
20
+ * @since 1.0.0
21
+ */
22
+ class Wbcr_Factory424_AssetsList {
23
+
24
+ protected $all = [];
25
+ public $header_place = [];
26
+ public $footer_place = [];
27
+ public $required = [];
28
+
29
+ protected $default_place;
30
+
31
+ /**
32
+ * @var Wbcr_Factory424_Plugin
33
+ */
34
+ protected $plugin;
35
+
36
+ /**
37
+ * @param Wbcr_Factory424_Plugin $plugin
38
+ * @param bool $defaultIsFooter
39
+ */
40
+ public function __construct( Wbcr_Factory424_Plugin $plugin, $defaultIsFooter = true ) {
41
+ $this->plugin = $plugin;
42
+
43
+ if ( $defaultIsFooter ) {
44
+ $this->default_place = &$this->footer_place;
45
+ }
46
+ if ( ! $defaultIsFooter ) {
47
+ $this->default_place = &$this->header_place;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Remove items from the collection
53
+ *
54
+ * @return $this
55
+ */
56
+ public function deregister() {
57
+ foreach ( func_get_args() as $item ) {
58
+
59
+ if ( ! is_string( $item ) ) {
60
+ return $this;
61
+ }
62
+
63
+ $key_in_all = array_search( $item, $this->all );
64
+ $key_in_default_place = array_search( $item, $this->default_place );
65
+ $key_in_header_place = array_search( $item, $this->header_place );
66
+ $key_inFooterPlace = array_search( $item, $this->footer_place );
67
+
68
+ if ( $key_in_all ) {
69
+ unset( $this->all[ $key_in_all ] );
70
+ }
71
+ if ( $key_in_default_place ) {
72
+ unset( $this->default_place[ $key_in_default_place ] );
73
+ }
74
+ if ( $key_in_header_place ) {
75
+ unset( $this->header_place[ $key_in_header_place ] );
76
+ }
77
+ if ( $key_inFooterPlace ) {
78
+ unset( $this->footer_place[ $key_inFooterPlace ] );
79
+ }
80
+ }
81
+
82
+ return $this;
83
+ }
84
+
85
+ /**
86
+ * Checks whether the collection is empty.
87
+ *
88
+ * @param string $source if the 'bootstrap' specified, checks only whether the bootstrap assets were required.
89
+ *
90
+ * @return boolean
91
+ */
92
+ public function isEmpty( $source = 'wordpress' ) {
93
+ if ( 'bootstrap' === $source ) {
94
+ return empty( $this->required[ $source ] );
95
+ }
96
+
97
+ return empty( $this->all ) && empty( $this->required );
98
+ }
99
+
100
+ public function IsHeaderEmpty() {
101
+ return empty( $this->header_place );
102
+ }
103
+
104
+ public function IsFooterEmpty() {
105
+ return empty( $this->footer_place );
106
+ }
107
+
108
+ /**
109
+ * Adds new items to the requried collection.
110
+ *
111
+ * @param mixed
112
+ */
113
+ public function request( $items, $source = 'wordpress' ) {
114
+
115
+ if ( is_array( $items ) ) {
116
+ foreach ( $items as $item ) {
117
+ $this->required[ $source ][] = $item;
118
+ }
119
+ } else {
120
+ $this->required[ $source ][] = $items;
121
+ }
122
+
123
+ return $this;
124
+ }
125
+ }
126
+
libs/factory/core/includes/assets-managment/class-factory-script-list.php ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains a class to manage script assets.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
6
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
7
+ *
8
+ * @package factory-core
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+
18
+ /**
19
+ * Script List
20
+ *
21
+ * @since 1.0.0
22
+ */
23
+ class Wbcr_Factory424_ScriptList extends Wbcr_Factory424_AssetsList {
24
+
25
+ public $localize_data = [];
26
+ public $use_ajax = false;
27
+
28
+ /**
29
+ * Adds new items to the collection (default place).
30
+ *
31
+ * @param mixed
32
+ *
33
+ * @version 2.0
34
+ */
35
+ public function add( $file_url, $deps = [ 'jquery' ], $handle = null, $version = false, $place = 'default' ) {
36
+
37
+ if ( empty( $file_url ) ) {
38
+ return $this;
39
+ }
40
+
41
+ $resource = [];
42
+ $resource['file_url'] = $file_url;
43
+ $resource['deps'] = $deps;
44
+ $resource['handle'] = $handle;
45
+ $resource['version'] = $version;
46
+
47
+ $this->all[] = $resource;
48
+
49
+ switch ( $place ) {
50
+ case 'header':
51
+ $this->header_place[] = $resource;
52
+ break;
53
+ case 'footer':
54
+ $this->footer_place[] = $resource;
55
+ break;
56
+ default:
57
+ $this->default_place[] = $resource;
58
+ break;
59
+ }
60
+
61
+ return $this;
62
+ }
63
+
64
+ /**
65
+ * Adds new items to the collection (header).
66
+ *
67
+ * @param mixed
68
+ */
69
+ public function addToHeader( $file_url, $deps = [ 'jquery' ], $handle = null ) {
70
+ return $this->add( $file_url, $deps, $handle, 'header' );
71
+ }
72
+
73
+ /**
74
+ * Adds new items to the collection (footer).
75
+ *
76
+ * @param mixed
77
+ */
78
+ public function addToFooter( $file_url, $deps = [ 'jquery' ], $handle = null ) {
79
+ return $this->add( $file_url, $deps, $handle, 'footer' );
80
+ }
81
+
82
+ /**
83
+ * Осуществляет подключение всех зарегистрированных скриптов
84
+ *
85
+ * @param string $source
86
+ */
87
+ public function connect( $source = 'wordpress' ) {
88
+
89
+ // register all global required scripts
90
+ if ( ! empty( $this->required[ $source ] ) ) {
91
+ foreach ( $this->required[ $source ] as $script ) {
92
+ if ( 'wordpress' === $source ) {
93
+ wp_enqueue_script( $script );
94
+ } else if ( 'bootstrap' === $source ) {
95
+ $this->plugin->bootstrap->enqueueScript( $script );
96
+ }
97
+ }
98
+ }
99
+
100
+ if ( $source == 'bootstrap' ) {
101
+ return;
102
+ }
103
+
104
+ $is_first_script = true;
105
+ $is_footer = false;
106
+
107
+ // register all other scripts
108
+ foreach ( [ $this->header_place, $this->footer_place ] as $script_place ) {
109
+ foreach ( $script_place as $script ) {
110
+
111
+ if ( empty( $script['file_url'] ) ) {
112
+ continue;
113
+ }
114
+
115
+ $handle = ! empty( $script['handle'] ) ? $script['handle'] : $script['file_url'];
116
+ $deps = ! is_array( $script['deps'] ) ? [] : $script['deps'];
117
+ $version = ! empty( $script['version'] ) ? $script['version'] : $this->plugin->getPluginVersion();
118
+
119
+ wp_register_script( $handle, $script['file_url'], $deps, $version, $is_footer );
120
+
121
+ if ( $is_first_script && $this->use_ajax ) {
122
+ wp_localize_script( $handle, 'factory', [ 'ajaxurl' => admin_url( 'admin-ajax.php' ) ] );
123
+ }
124
+
125
+ if ( ! empty( $this->localize_data[ $handle ] ) ) {
126
+ wp_localize_script( $handle, $this->localize_data[ $handle ][0], $this->localize_data[ $handle ][1] );
127
+ }
128
+
129
+ wp_enqueue_script( $handle );
130
+
131
+ $is_first_script = false;
132
+ }
133
+
134
+ $is_footer = true;
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Если вызвать этот метод, на странице будет обязательно добавлена
140
+ * глобальная JS переменная с ссылкой на ajax обработчик
141
+ */
142
+ public function useAjax() {
143
+ $this->use_ajax = true;
144
+ }
145
+
146
+ /**
147
+ * Регистрирует глобальную JS переменную с пользовательскими данными
148
+ *
149
+ * @param string $varname
150
+ * @param string $data
151
+ *
152
+ * @return Wbcr_Factory424_ScriptList $this
153
+ */
154
+ public function localize( $varname, $data ) {
155
+ $bindTo = count( $this->all ) == 0 ? null : end( $this->all );
156
+
157
+ if ( ! $bindTo ) {
158
+ return $this;
159
+ }
160
+
161
+ $this->localize_data[ $bindTo ] = [ $varname, $data ];
162
+
163
+ return $this;
164
+ }
165
+ }
166
+
libs/factory/core/includes/assets-managment/class-factory-style-list.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains a class to manage style assets.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
6
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
7
+ *
8
+ * @package factory-core
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+
18
+ /**
19
+ * Style List
20
+ *
21
+ * @since 1.0.0
22
+ */
23
+ class Wbcr_Factory424_StyleList extends Wbcr_Factory424_AssetsList {
24
+
25
+ /**
26
+ * Adds new items to the collection (default place).
27
+ *
28
+ * @param mixed
29
+ *
30
+ * @version 2.0
31
+ */
32
+ public function add( $file_url, $deps = [], $handle = null, $version = false, $media = 'all' ) {
33
+
34
+ if ( empty( $file_url ) ) {
35
+ return $this;
36
+ }
37
+
38
+ $resource = [];
39
+ $resource['file_url'] = $file_url;
40
+ $resource['deps'] = $deps;
41
+ $resource['handle'] = $handle;
42
+ $resource['version'] = $version;
43
+ $resource['media'] = $media;
44
+
45
+ $this->all[] = $resource;
46
+
47
+ return $this;
48
+ }
49
+
50
+ public function connect( $source = 'wordpress' ) {
51
+ // register all global required scripts
52
+ if ( ! empty( $this->required[ $source ] ) ) {
53
+
54
+ foreach ( $this->required[ $source ] as $style ) {
55
+ if ( 'wordpress' === $source ) {
56
+ wp_enqueue_style( $style );
57
+ } else if ( 'bootstrap' === $source ) {
58
+ $this->plugin->bootstrap->enqueueStyle( $style );
59
+ }
60
+ }
61
+ }
62
+
63
+ if ( $source == 'bootstrap' ) {
64
+ return;
65
+ }
66
+
67
+ if ( empty( $this->all ) ) {
68
+ return;
69
+ }
70
+
71
+ // register all other styles
72
+ foreach ( $this->all as $style ) {
73
+
74
+ if ( empty( $style['file_url'] ) ) {
75
+ continue;
76
+ }
77
+
78
+ $handle = ! empty( $style['handle'] ) ? $style['handle'] : md5( $style['file_url'] );
79
+ $deps = ! is_array( $style['deps'] ) ? [] : $style['deps'];
80
+ $version = ! empty( $style['version'] ) ? $style['version'] : $this->plugin->getPluginVersion();
81
+
82
+ wp_enqueue_style( $handle, $style['file_url'], $deps, $version );
83
+ }
84
+ }
85
+ }
86
+
libs/factory/core/includes/assets-managment/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/core/includes/class-check-compatibility.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Проверяет совместимость с плагинами Webcraftic, с версиями php, с версиями Wordpress
5
+ *
6
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
7
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
8
+ *
9
+ * @version 1.0.0
10
+ * @since 4.0.8
11
+ */
12
+
13
+ if ( ! class_exists( 'Wbcr_Factory_Compatibility' ) ) {
14
+ class Wbcr_Factory_Compatibility {
15
+
16
+ protected $plugin_prefix;
17
+ protected $plugin_class_prefix;
18
+ protected $plugin_name;
19
+ protected $plugin_title = "(no title)";
20
+ protected $required_php_version = '5.3';
21
+ protected $required_wp_version = '4.2.0';
22
+
23
+ function __construct( array $plugin_info ) {
24
+ foreach ( (array) $plugin_info as $property => $value ) {
25
+ $this->$property = $value;
26
+ }
27
+
28
+ add_action( 'admin_init', [ $this, 'registerNotices' ] );
29
+ }
30
+
31
+ /**
32
+ * Метод проверяет совместимость плагина с php и wordpress версией
33
+ *
34
+ * @return bool
35
+ */
36
+ public function check() {
37
+ if ( ! $this->isPhpCompatibility() ) {
38
+ return false;
39
+ }
40
+
41
+ if ( ! $this->isWpCompatibility() ) {
42
+ return false;
43
+ }
44
+
45
+ return true;
46
+ }
47
+
48
+ /**
49
+ * Метод проверяет совместимость плагина с php версией сервера
50
+ *
51
+ * @return mixed
52
+ */
53
+ public function isPhpCompatibility() {
54
+ return version_compare( PHP_VERSION, $this->required_php_version, '>=' );
55
+ }
56
+
57
+ /**
58
+ * Метод проверяет совместимость плагина с Wordpress версией сайта
59
+ *
60
+ * @return mixed
61
+ */
62
+ public function isWpCompatibility() {
63
+ // Get the WP Version global.
64
+ global $wp_version;
65
+
66
+ return version_compare( $wp_version, $this->required_wp_version, '>=' );
67
+ }
68
+
69
+ /**
70
+ * Метод возвращает текст уведомления
71
+ *
72
+ * @return string
73
+ */
74
+ public function getNoticeText() {
75
+ $notice_text = $notice_default_text = '';
76
+ $notice_default_text .= '<b>' . $this->plugin_title . ' ' . __( 'warning', '' ) . ':</b>' . '<br>';
77
+
78
+ $notice_default_text .= sprintf( __( 'The %s plugin has stopped.', 'wbcr_factory_clearfy_216' ), $this->plugin_title ) . ' ';
79
+ $notice_default_text .= __( 'Possible reasons:', '' ) . ' <br>';
80
+
81
+ $has_one = false;
82
+
83
+ if ( ! $this->isPhpCompatibility() ) {
84
+ $has_one = true;
85
+ $notice_text .= '- ' . sprintf( __( 'You need to update the PHP version to %s or higher!', 'wbcr_factory_424' ), $this->required_php_version ) . '<br>';
86
+ }
87
+
88
+ if ( ! $this->isWpCompatibility() ) {
89
+ $has_one = true;
90
+ $notice_text .= '- ' . sprintf( __( 'You need to update WordPress to %s or higher!', 'wbcr_factory_424' ), $this->required_wp_version ) . '<br>';
91
+ }
92
+
93
+ if ( $has_one ) {
94
+ $notice_text = $notice_default_text . $notice_text;
95
+ }
96
+
97
+ return $notice_text;
98
+ }
99
+
100
+ public function registerNotices() {
101
+ if ( current_user_can( 'activate_plugins' ) && current_user_can( 'edit_plugins' ) && current_user_can( 'install_plugins' ) ) {
102
+ if ( is_multisite() ) {
103
+ add_action( 'network_admin_notices', [ $this, 'showNotice' ] );
104
+ }
105
+
106
+ add_action( 'admin_notices', [ $this, 'showNotice' ] );
107
+ }
108
+ }
109
+
110
+ public function showNotice() {
111
+ $notice_text = $this->getNoticeText();
112
+
113
+ if ( empty( $notice_text ) ) {
114
+ return;
115
+ }
116
+
117
+ $notice_text = '<p>' . $this->getNoticeText() . '</p>';
118
+
119
+ echo '<div class="notice notice-error">' . apply_filters( 'wbcr/factory/check_compatibility/notice_text', $notice_text, $this->plugin_name ) . '</div>';
120
+ }
121
+ }
122
+ }
libs/factory/core/includes/class-factory-migrations.php ADDED
@@ -0,0 +1,541 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424;
4
+
5
+ use Exception;
6
+ use Wbcr_Factory424_Plugin;
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * Often when updating plugins, you need to make some changes to the database.
14
+ * This class automatically checks for plugin migrations and executes them when
15
+ * updating.
16
+ *
17
+ * The class has a debug mode, to enable the debug mode add constants to your plugin:
18
+ * define ('FACTORY_MIGRATIONS_DEBUG', true) - enables/disables debugging mode
19
+ * define ('FACTORY_MIGRATIONS_FORCE_OLD_VERSION', '1.1.9') - sets previous version
20
+ * for the plugin, if constant isn't set, then the previous version is taken from
21
+ * the database.
22
+ *
23
+ * todo: get_option and get_site_option are used because some caching plugins caching options, which causes problems
24
+ *
25
+ *
26
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
27
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
28
+ *
29
+ * @since 4.1.1
30
+ */
31
+ class Migrations {
32
+
33
+ protected $plugin;
34
+
35
+ /**
36
+ * Migrations constructor.
37
+ *
38
+ * @param Wbcr_Factory424_Plugin $plugin
39
+ *
40
+ * @throws Exception
41
+ */
42
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
43
+
44
+ $this->plugin = $plugin;
45
+ $plugin_name = $plugin->getPluginName();
46
+
47
+ if ( ! file_exists( $this->plugin->get_paths()->migrations ) ) {
48
+ throw new Exception( 'Starting with version 4.1.1 of the Core for Factory framework module, you must create a "migrations" folder in the root of your plugin to store the migration of the plugin.' );
49
+ }
50
+
51
+ if ( is_admin() ) {
52
+ add_action( "admin_init", [ $this, "check_migrations" ] );
53
+
54
+ add_action( "wbcr/factory/plugin_{$plugin_name}_activated", [ $this, 'activation_hook' ] );
55
+ add_action( "wbcr/factory/admin_notices", [ $this, "debug_bar_notice" ], 10, 2 );
56
+ add_action( "wbcr/factory/admin_notices", [ $this, "migration_error_notice" ], 10, 2 );
57
+ }
58
+ }
59
+
60
+ /**
61
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
62
+ * @since 4.1.1
63
+ * @return mixed|void
64
+ */
65
+ public function get_plugin_activated_time() {
66
+ if ( $this->plugin->isNetworkActive() ) {
67
+ return get_site_option( $this->plugin->getOptionName( 'plugin_activated' ), 0 );
68
+ }
69
+
70
+ return get_option( $this->plugin->getOptionName( 'plugin_activated' ), 0 );
71
+ }
72
+
73
+ /**
74
+ * Check if migration is necessary for plugin and if there are errors from previous migrations.
75
+ * In debug mode, migrations are not performed automatically.
76
+ */
77
+ public function check_migrations() {
78
+ if ( $this->is_migration_error() && isset( $_GET['wbcr_factory_fix_migration_error'] ) ) {
79
+ $this->fix_migration_error();
80
+ wp_redirect( remove_query_arg( 'wbcr_factory_fix_migration_error' ) );
81
+ die();
82
+ }
83
+
84
+ if ( $this->is_debug() && isset( $_GET['wbcr_factory_test_migration'] ) ) {
85
+ $this->make_migration();
86
+ wp_redirect( remove_query_arg( 'wbcr_factory_test_migration' ) );
87
+ die();
88
+ }
89
+
90
+ if ( $this->need_migration() && ! $this->is_debug() ) {
91
+ $this->make_migration();
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Notification displays the errors of outstanding migrations to fix errors
97
+ * you need to follow the instructions in the notification and click
98
+ * "I fixed, confirm migration".
99
+ *
100
+ * What is it for. Migrations are performed in background and on some sites,
101
+ * due to php errors or for some other reason, migration may be
102
+ * interrupted, because of what plugin will work incorrectly, you may lose settings.
103
+ *
104
+ * When creating new migrations, developer will add error handlers,
105
+ * and framework will intercept them safely for user and display them
106
+ * in this notice.
107
+ *
108
+ * @param array $notices
109
+ * @param static $plugin_name
110
+ *
111
+ * @return array
112
+ */
113
+ public function migration_error_notice( $notices, $plugin_name ) {
114
+
115
+ if ( $this->plugin->getPluginName() !== $plugin_name ) {
116
+ return $notices;
117
+ }
118
+
119
+ if ( ! $this->is_migration_error() || ! current_user_can( 'update_plugins' ) ) {
120
+ return $notices;
121
+ }
122
+
123
+ if ( $this->plugin->isNetworkActive() ) {
124
+ $migration_error_text = get_site_option( $this->plugin->getOptionName( 'plugin_migration_error' ), '' );
125
+ } else {
126
+ $migration_error_text = get_option( $this->plugin->getOptionName( 'plugin_migration_error' ), '' );
127
+ }
128
+
129
+ $fix_migration_error_url = add_query_arg( 'wbcr_factory_fix_migration_error', 1 );
130
+
131
+ $notice_text = $migration_error_text;
132
+ $notice_text .= "<br><br><a href='{$fix_migration_error_url}' class='button button-default'>" . __( 'I fixed, confirm migration', 'wbcr_factory_424' ) . "</a>";
133
+
134
+ $notices[] = [
135
+ 'id' => 'migration_debug_bar',
136
+ 'type' => 'error',
137
+ 'dismissible' => false,
138
+ 'dismiss_expires' => 0,
139
+ 'text' => '<p><b>' . $this->plugin->getPluginTitle() . ' ' . __( 'migration error', 'wbcr_factory_424' ) . '</b><br>' . $notice_text . '</p>'
140
+ ];
141
+
142
+ return $notices;
143
+ }
144
+
145
+ /**
146
+ * Debug panel, display some information from the database. Also allows
147
+ * perform manual migrations to test new migrations.
148
+ *
149
+ * @param array $notices
150
+ * @param string $plugin_name
151
+ *
152
+ * @return array
153
+ */
154
+ public function debug_bar_notice( $notices, $plugin_name ) {
155
+
156
+ if ( $this->plugin->getPluginName() !== $plugin_name ) {
157
+ return $notices;
158
+ }
159
+ if ( ! $this->is_debug() || ! current_user_can( 'update_plugins' ) ) {
160
+ return $notices;
161
+ }
162
+
163
+ $migrate_url = add_query_arg( 'wbcr_factory_test_migration', 1 );
164
+
165
+ $notice_text = __( "Plugin activated:", "wbcr_factory_424" ) . ' ' . date( "Y-m-d H:i:s", $this->get_plugin_activated_time() ) . "<br>";
166
+
167
+ $notice_text .= __( "Old plugin version (debug):", "wbcr_factory_424" ) . ' ' . $this->get_old_plugin_version() . "<br>";
168
+ $notice_text .= __( "Current plugin version:", "wbcr_factory_424" ) . ' ' . $this->get_current_plugin_version() . "<br>";
169
+ $notice_text .= __( "Need migration:", "wbcr_factory_424" ) . ' ' . ( $this->need_migration() ? "true" : "false" ) . "<br><br>";
170
+ $notice_text .= "<a href='{$migrate_url}' class='button button-default'>" . __( "Migrate now", "wbcr_factory_424" ) . "</a><br>";
171
+
172
+ $notices[] = [
173
+ 'id' => 'migration_debug_bar',
174
+ 'type' => 'warning',
175
+ 'dismissible' => false,
176
+ 'dismiss_expires' => 0,
177
+ 'text' => '<p><b style="color:red;">' . $this->plugin->getPluginTitle() . ' ' . __( 'migrations DEBUG bar', 'wbcr_factory_424' ) . '</b><br>' . $notice_text . '</p>'
178
+ ];
179
+
180
+ return $notices;
181
+ }
182
+
183
+ /**
184
+ * Runs when plugin is activated. Checks if you need to migrate
185
+ * and if necessary it does it. Also adds a option when the plugin
186
+ * was activated for the first time.
187
+ */
188
+ public function activation_hook() {
189
+ /*if ( $this->need_migration() && ! $this->is_debug() ) {
190
+ $this->make_migration();
191
+ }*/
192
+
193
+ // just time to know when the plugin was activated the first time
194
+ $activated = $this->get_plugin_activated_time();
195
+
196
+ if ( ! $activated ) {
197
+ if ( $this->plugin->isNetworkActive() ) {
198
+ update_site_option( $this->plugin->getOptionName( 'plugin_activated' ), time() );
199
+ update_site_option( $this->plugin->getOptionName( 'plugin_version' ), $this->get_current_plugin_version() );
200
+ } else {
201
+ update_option( $this->plugin->getOptionName( 'plugin_activated' ), time() );
202
+ update_option( $this->plugin->getOptionName( 'plugin_version' ), $this->get_current_plugin_version() );
203
+ }
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Checks if debug mode of migrations from version x.x.x to x.x.y is enabled.
209
+ *
210
+ * @return bool
211
+ */
212
+ protected function is_debug() {
213
+ return defined( 'FACTORY_MIGRATIONS_DEBUG' ) && FACTORY_MIGRATIONS_DEBUG;
214
+ }
215
+
216
+ /**
217
+ * Gets previous version of plugin that plugin had before updating to the new version.
218
+ *
219
+ * @return string|null
220
+ */
221
+ protected function get_old_plugin_version() {
222
+
223
+ if ( $this->is_debug() && defined( 'FACTORY_MIGRATIONS_FORCE_OLD_VERSION' ) ) {
224
+ return FACTORY_MIGRATIONS_FORCE_OLD_VERSION;
225
+ }
226
+
227
+ if ( $this->plugin->isNetworkActive() ) {
228
+ $plugin_version = get_site_option( $this->plugin->getOptionName( 'plugin_version' ), null );
229
+ } else {
230
+ $plugin_version = get_option( $this->plugin->getOptionName( 'plugin_version' ), null );
231
+ }
232
+
233
+ if ( ! empty( $plugin_version ) ) {
234
+ return $plugin_version;
235
+ }
236
+
237
+ # TODO: Remove after few releases
238
+ # This block for compatibility code with old version of framework < 4.1.1
239
+ #-------------------------------------------
240
+ if ( $this->plugin->isNetworkActive() ) {
241
+ $plugin_versions = get_site_option( 'factory_plugin_versions', [] );
242
+ } else {
243
+ $plugin_versions = get_option( 'factory_plugin_versions', [] );
244
+ }
245
+
246
+ $plugin_version = isset( $plugin_versions[ $this->plugin->getPluginName() ] ) ? $plugin_versions[ $this->plugin->getPluginName() ] : null;
247
+
248
+ if ( ! empty( $plugin_version ) ) {
249
+ $plugin_version = str_replace( [ 'free-', 'premium-', 'offline-' ], '', $plugin_version );
250
+ }
251
+
252
+ #-------------------------------------------
253
+
254
+ return $plugin_version;
255
+ }
256
+
257
+ /**
258
+ * Gets the current version of plugin.
259
+ *
260
+ * @return string
261
+ */
262
+ protected function get_current_plugin_version() {
263
+ return $this->plugin->getPluginVersion();
264
+ }
265
+
266
+ /**
267
+ * Do I need migration for plugin? If previous migration was with a error, then
268
+ * method will always return false to prevent looping.
269
+ *
270
+ * @return mixed
271
+ */
272
+ protected function need_migration() {
273
+ if ( $this->is_migration_error() ) {
274
+ return false;
275
+ }
276
+
277
+ return version_compare( $this->get_old_plugin_version(), $this->get_current_plugin_version(), '<' );
278
+ }
279
+
280
+ /**
281
+ * Are there errors from previous migrations?
282
+ *
283
+ * @return bool
284
+ */
285
+ protected function is_migration_error() {
286
+ if ( $this->plugin->isNetworkActive() ) {
287
+ $error = get_site_option( $this->plugin->getOptionName( 'plugin_migration_error' ), false );
288
+ } else {
289
+ $error = get_option( $this->plugin->getOptionName( 'plugin_migration_error' ), false );
290
+ }
291
+
292
+ return $error !== false;
293
+ }
294
+
295
+ /**
296
+ * Remove an option in database, thereby fix errors of the previous migration.
297
+ */
298
+ protected function fix_migration_error() {
299
+ if ( $this->plugin->isNetworkActive() ) {
300
+ delete_site_option( $this->plugin->getOptionName( 'plugin_migration_error' ) );
301
+
302
+ return;
303
+ }
304
+
305
+ delete_option( $this->plugin->getOptionName( 'plugin_migration_error' ) );
306
+ }
307
+
308
+ /**
309
+ * Migrates the plugin from version x.x.x to x.x.y. Automatically searches for files
310
+ * migrations to the plugin's root directory and executes them. Default files
311
+ * migrations are stored in wp-content/plugins/plugin-name/migrations and have names
312
+ * 0x0x0x.php, which corresponds to the version x.x.x. Method executes those migration files
313
+ * versions of which are between the previous version of plugin and current one.
314
+ *
315
+ */
316
+ protected function make_migration() {
317
+
318
+ if ( ! current_user_can( 'update_plugins' ) ) {
319
+ return;
320
+ }
321
+
322
+ $old_plugin_version = $this->get_old_plugin_version();
323
+ $new_plugin_version = $this->get_current_plugin_version();
324
+
325
+ if ( empty( $old_plugin_version ) ) {
326
+ $this->update_plugin_version_in_db();
327
+ }
328
+
329
+ // converts versions like 0.0.0 to 000000
330
+ $old_number = $this->get_version_number( $old_plugin_version );
331
+ $new_number = $this->get_version_number( $new_plugin_version );
332
+
333
+ try {
334
+
335
+ $update_files = $this->plugin->get_paths()->migrations;
336
+ $files = $this->find_files( $update_files );
337
+
338
+ if ( empty( $files ) ) {
339
+ $this->update_plugin_version_in_db();
340
+
341
+ return;
342
+ }
343
+
344
+ // finds updates that has intermediate version
345
+ foreach ( (array) $files as $item ) {
346
+ if ( ! preg_match( '/^\d+$/', $item['name'] ) ) {
347
+ continue;
348
+ }
349
+
350
+ $item_number = intval( $item['name'] );
351
+
352
+ if ( $item_number > $old_number && $item_number <= $new_number ) {
353
+ $classes = $this->get_classes( $item['path'] );
354
+
355
+ if ( count( $classes ) == 0 ) {
356
+ continue;
357
+ }
358
+
359
+ foreach ( $classes as $path => $class_data ) {
360
+ include_once( $path );
361
+ $update_class = $class_data['name'];
362
+
363
+ $update = new $update_class( $this->plugin );
364
+ $update->install();
365
+ }
366
+ }
367
+ }
368
+
369
+ $this->update_plugin_version_in_db();
370
+ } catch( Exception $e ) {
371
+ if ( $this->plugin->isNetworkActive() ) {
372
+ update_site_option( $this->plugin->getOptionName( 'plugin_migration_error' ), $e->getMessage() );
373
+
374
+ return;
375
+ }
376
+ update_option( $this->plugin->getOptionName( 'plugin_migration_error' ), $e->getMessage() );
377
+ }
378
+ }
379
+
380
+ /**
381
+ * Updates version of plugin in database. So that we can track which
382
+ * previous version of plugin was at the user, before he updated
383
+ * plugin.
384
+ */
385
+ protected function update_plugin_version_in_db() {
386
+
387
+ # TODO: Delete after few releases
388
+ # This block for compatibility code with the old version of framework.
389
+ # Cleans up old data, after the transition to new version of framework.
390
+ #-------------------------------------------
391
+ if ( $this->plugin->isNetworkActive() ) {
392
+ $plugin_versions = get_site_option( 'factory_plugin_versions', [] );
393
+ } else {
394
+ $plugin_versions = get_option( 'factory_plugin_versions', [] );
395
+ }
396
+
397
+ if ( isset( $plugin_versions[ $this->plugin->getPluginName() ] ) ) {
398
+ unset( $plugin_versions[ $this->plugin->getPluginName() ] );
399
+ }
400
+
401
+ if ( $this->plugin->isNetworkActive() ) {
402
+ if ( empty( $plugin_versions ) ) {
403
+ delete_site_option( 'factory_plugin_versions' );
404
+ }
405
+ update_site_option( 'factory_plugin_versions', $plugin_versions );
406
+ update_site_option( $this->plugin->getOptionName( 'plugin_version' ), $this->get_current_plugin_version() );
407
+
408
+ return;
409
+ }
410
+
411
+ if ( empty( $plugin_versions ) ) {
412
+ delete_option( 'factory_plugin_versions' );
413
+ }
414
+
415
+ update_option( 'factory_plugin_versions', $plugin_versions );
416
+ update_option( $this->plugin->getOptionName( 'plugin_version' ), $this->get_current_plugin_version() );
417
+ }
418
+
419
+ /**
420
+ * Converts string representation of the version to the numeric.
421
+ *
422
+ * @since 1.0.0
423
+ *
424
+ * @param string $version A string version to convert.
425
+ *
426
+ * @return integer
427
+ */
428
+ protected function get_version_number( $version ) {
429
+ preg_match( '/(\d+)\.(\d+)\.(\d+)/', $version, $matches );
430
+ if ( count( $matches ) == 0 ) {
431
+ return false;
432
+ }
433
+
434
+ $number = '';
435
+ $number .= ( strlen( $matches[1] ) == 1 ) ? '0' . $matches[1] : $matches[1];
436
+ $number .= ( strlen( $matches[2] ) == 1 ) ? '0' . $matches[2] : $matches[2];
437
+ $number .= ( strlen( $matches[3] ) == 1 ) ? '0' . $matches[3] : $matches[3];
438
+
439
+ return intval( $number );
440
+ }
441
+
442
+ /**
443
+ * Returns a list of files at a given path.
444
+ *
445
+ * @param string $path path for search
446
+ */
447
+ private function find_files( $path ) {
448
+ return $this->find_file_or_folders( $path, true );
449
+ }
450
+
451
+ /**
452
+ * Returns a list of folders at a given path.
453
+ *
454
+ * @param string $path path for search
455
+ */
456
+ /*private function find_folders( $path ) {
457
+ return $this->find_file_or_folders( $path, false );
458
+ }*/
459
+
460
+ /**
461
+ * Returns a list of files or folders at a given path.
462
+ *
463
+ * @param string $path path for search
464
+ * @param bool $files files or folders?
465
+ */
466
+ private function find_file_or_folders( $path, $areFiles = true ) {
467
+ if ( ! is_dir( $path ) ) {
468
+ return [];
469
+ }
470
+
471
+ $entries = scandir( $path );
472
+ if ( empty( $entries ) ) {
473
+ return [];
474
+ }
475
+
476
+ $files = [];
477
+ foreach ( $entries as $entryName ) {
478
+ if ( $entryName == '.' || $entryName == '..' ) {
479
+ continue;
480
+ }
481
+
482
+ $filename = $path . '/' . $entryName;
483
+ if ( ( $areFiles && is_file( $filename ) ) || ( ! $areFiles && is_dir( $filename ) ) ) {
484
+ $files[] = [
485
+ 'path' => str_replace( "\\", "/", $filename ),
486
+ 'name' => $areFiles ? str_replace( '.php', '', $entryName ) : $entryName
487
+ ];
488
+ }
489
+ }
490
+
491
+ return $files;
492
+ }
493
+
494
+ /**
495
+ * Gets php classes defined in a specified file.
496
+ *
497
+ * @param string $path
498
+ *
499
+ * @throws Exception
500
+ */
501
+ private function get_classes( $path ) {
502
+
503
+ $phpCode = file_get_contents( $path );
504
+
505
+ $classes = [];
506
+
507
+ if ( ! function_exists( 'token_get_all' ) ) {
508
+ throw new Exception( __( 'There is no PHP Tokenizer extension installed on your server, you cannot use the token_get_all function.', 'wbcr_factory_424' ) );
509
+ }
510
+
511
+ $tokens = token_get_all( $phpCode );
512
+
513
+ $count = count( $tokens );
514
+ for ( $i = 2; $i < $count; $i ++ ) {
515
+ if ( is_array( $tokens ) && $tokens[ $i - 2 ][0] == T_CLASS && $tokens[ $i - 1 ][0] == T_WHITESPACE && $tokens[ $i ][0] == T_STRING ) {
516
+
517
+ $extends = null;
518
+ if ( $tokens[ $i + 2 ][0] == T_EXTENDS && $tokens[ $i + 4 ][0] == T_STRING ) {
519
+ $extends = $tokens[ $i + 4 ][1];
520
+ }
521
+
522
+ $class_name = $tokens[ $i ][1];
523
+ $classes[ $path ] = [
524
+ 'name' => $class_name,
525
+ 'extends' => $extends
526
+ ];
527
+ }
528
+ }
529
+
530
+ /**
531
+ * result example:
532
+ *
533
+ * $classes['/plugin/items/filename.php'] = array(
534
+ * 'name' => 'PluginNameItem',
535
+ * 'extendes' => 'PluginNameItemBase'
536
+ * )
537
+ */
538
+
539
+ return $classes;
540
+ }
541
+ }
libs/factory/core/includes/class-factory-notices.php ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424;
4
+
5
+ use Wbcr_Factory424_Plugin;
6
+
7
+ // Exit if accessed directly
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * A class to manage notices.
14
+ *
15
+ * @since 1.0.0
16
+ */
17
+
18
+ /**
19
+ * A group of classes and methods to create and manage notices.
20
+ *
21
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
22
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
23
+ *
24
+ * @package factory-notices
25
+ * @since 1.0.0
26
+ */
27
+ class Notices {
28
+
29
+ /**
30
+ * @var Wbcr_Factory424_Plugin
31
+ */
32
+ protected $plugin;
33
+ /**
34
+ * @var array
35
+ */
36
+ protected $notices = [];
37
+
38
+ /**
39
+ * @var array
40
+ */
41
+ protected $default_where = [
42
+ 'plugins',
43
+ 'themes',
44
+ 'dashboard',
45
+ 'edit',
46
+ 'settings',
47
+ 'dashboard-network',
48
+ 'plugins-network',
49
+ 'themes-network',
50
+ 'settings-network',
51
+ ];
52
+
53
+ /**
54
+ * @var array
55
+ */
56
+ private $dissmised_notices;
57
+
58
+ /**
59
+ * Инициализируем уведомлений сразу после загрузки модуля уведомлений
60
+ *
61
+ * @param Wbcr_Factory424_Plugin $plugin
62
+ */
63
+ public function __construct( $plugin ) {
64
+ //default notices
65
+ //---
66
+
67
+ $this->plugin = $plugin;
68
+ $this->dissmised_notices = $this->plugin->getPopulateOption( 'factory_dismissed_notices', [] );
69
+
70
+ add_action( 'current_screen', [ $this, 'currentScreenAction' ] );
71
+
72
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
73
+ add_action( 'wp_ajax_' . $this->plugin->getPluginName() . '_dismiss_notice', [
74
+ $this,
75
+ 'dismiss_notice'
76
+ ] );
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Регистрирует экшены для работы с уведомлениями на текущем экране странице.
82
+ * Уведомления собираются через фильтр wbcr_factory_admin_notices, если в массиве уведомлений,
83
+ * хотя бы одно, соответствует условиям в параметре $notice['where'], то метод печает вспомогательные скрипты и уведомления.
84
+ */
85
+ public function currentScreenAction() {
86
+ /**
87
+ * @since 2.1.2 - является устаревшим
88
+ */
89
+ $this->notices = wbcr_factory_424_apply_filters_deprecated( 'wbcr_factory_notices_000_list', [
90
+ $this->notices,
91
+ $this->plugin->getPluginName(),
92
+ ], '2.1.2', 'wbcr/factory/admin_notices' );
93
+
94
+ /**
95
+ * @since 2.1.2 - Добавлен, модуль factory_notices_000 был удален. Поэтому в этому хуке мы заменили префикс на factory_424
96
+ */
97
+ $this->notices = apply_filters( 'wbcr/factory/admin_notices', $this->notices, $this->plugin->getPluginName() );
98
+
99
+ if ( count( $this->notices ) == 0 ) {
100
+ return;
101
+ }
102
+
103
+ $screen = get_current_screen();
104
+
105
+ $has_notices = false;
106
+ foreach ( (array) $this->notices as $notice ) {
107
+ if ( ! isset( $notice['id'] ) ) {
108
+ continue;
109
+ }
110
+
111
+ $where = ! isset( $notice['where'] ) || empty( $notice['where'] ) ? $this->default_where : $notice['where'];
112
+
113
+ if ( in_array( $screen->base, $where ) && ! $this->is_dissmissed( $notice['id'] ) ) {
114
+ $has_notices = true;
115
+ break;
116
+ };
117
+ }
118
+
119
+ if ( $has_notices ) {
120
+ add_action( 'admin_footer', [ $this, 'print_js_code' ] );
121
+
122
+ if ( $this->plugin->isNetworkActive() ) {
123
+ if ( current_user_can( 'manage_network' ) ) {
124
+ add_action( 'network_admin_notices', [ $this, 'show_notices' ] );
125
+ add_action( 'admin_notices', [ $this, 'show_notices' ] );
126
+ }
127
+ } else {
128
+ add_action( 'admin_notices', [ $this, 'show_notices' ] );
129
+ }
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Показывает все зарегистрированные уведомления для текущего плагина.
135
+ * Уведомления показываются только на определенных страницах через параметр $notice['where'],
136
+ * если уведомление ранее было скрыто или не соотвествует правилам $notice['where'], оно не будет показано!
137
+ */
138
+ public function show_notices() {
139
+ if ( count( $this->notices ) == 0 ) {
140
+ return;
141
+ }
142
+
143
+ if ( ! current_user_can( 'activate_plugins' ) || ! current_user_can( 'edit_plugins' ) || ! current_user_can( 'install_plugins' ) ) {
144
+ return;
145
+ }
146
+
147
+ $screen = get_current_screen();
148
+
149
+ foreach ( $this->notices as $notice ) {
150
+
151
+ if ( ! isset( $notice['id'] ) ) {
152
+ continue;
153
+ }
154
+
155
+ $where = ! isset( $notice['where'] ) || empty( $notice['where'] ) ? $this->default_where : $notice['where'];
156
+
157
+ if ( in_array( $screen->base, $where ) && ! $this->is_dissmissed( $notice['id'] ) ) {
158
+ $this->show_notice( $notice );
159
+ };
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Показывает уведомление, по переданным параметрам
165
+ *
166
+ * @param array $data - Параметры уведомления
167
+ * $data['id'] - Индентификатор уведомления
168
+ * $data['type'] - Тип уведомления (error, warning, success)
169
+ * $notice['where'] - На каких страницах показывать уведомление ('plugins', 'dashboard', 'edit')
170
+ * $data['text'] - Текст уведомления
171
+ * $data['dismissible'] - Если true, уведомление будет с кнопкой закрыть
172
+ * $data['dismiss_expires'] - Когда снова показать уведомление, нужно указывать время в unix timestamp.
173
+ * Пример time() + 3600 (1ч), уведомление будет скрыто на 1 час.
174
+ * $data['classes'] - Произвольный классы для контейнера уведомления.
175
+ */
176
+ public function show_notice( $data ) {
177
+ $settings = wp_parse_args( $data, [
178
+ 'id' => null,
179
+ 'text' => null,
180
+ 'type' => 'error',
181
+ 'dismissible' => false,
182
+ 'dismiss_expires' => 0,
183
+ 'classes' => []
184
+ ] );
185
+
186
+ if ( empty( $settings['id'] ) || empty( $settings['text'] ) ) {
187
+ return;
188
+ }
189
+
190
+ $plugin_name = str_replace( '_', '-', $this->plugin->getPluginName() );
191
+
192
+ $classes = array_merge( [
193
+ 'notice',
194
+ 'notice-' . $settings['type'],
195
+ $plugin_name . '-factory-notice'
196
+ ], $settings['classes'] );
197
+
198
+ if ( $settings['dismissible'] ) {
199
+ $classes[] = 'is-dismissible';
200
+ $classes[] = $plugin_name . '-factory-notice-dismiss';
201
+ }
202
+ ?>
203
+ <div data-name="wbcr_factory_notice_<?php echo esc_attr( $data['id'] ) ?>" data-expires="<?= esc_attr( $settings['dismiss_expires'] ) ?>" data-nonce="<?php echo wp_create_nonce( $this->plugin->getPluginName() . '_factory_dismiss_notice' ); ?>" class="<?php echo esc_attr( implode( ' ', $classes ) ) ?>">
204
+ <?= $data['text'] ?>
205
+ </div>
206
+ <?php
207
+ }
208
+
209
+ /**
210
+ * Когда пользователь нажимает кнопку закрыть уведомление,
211
+ * отправляется ajax запрос с вызовом текущего метода
212
+ */
213
+ public function dismiss_notice() {
214
+ if ( ! current_user_can( 'activate_plugins' ) || ! current_user_can( 'edit_plugins' ) || ! current_user_can( 'install_plugins' ) ) {
215
+ wp_die( - 1, 403 );
216
+ }
217
+
218
+ check_admin_referer( $this->plugin->getPluginName() . '_factory_dismiss_notice', 'nonce' );
219
+
220
+ // Имя уведомления (идентификатор)
221
+ $name = $this->plugin->request->post( 'name', null, true );
222
+
223
+ // Время в Unix timestamp, по истечению, которого уведомление снова будет показано
224
+ // Если передан 0, то уведомление будет скрыто навсегда
225
+ $expires = $this->plugin->request->post( 'expires', 0, 'intval' );
226
+
227
+ if ( empty( $name ) ) {
228
+ wp_send_json_error( [ 'error_message' => 'You must pass the notification "Name"! Action was rejected.' ] );
229
+ }
230
+
231
+ $notices = $this->plugin->getPopulateOption( "factory_dismissed_notices", [] );
232
+
233
+ if ( ! empty( $notices ) ) {
234
+ foreach ( (array) $notices as $notice_id => $notice_expires ) {
235
+ if ( $notice_expires !== 0 && $notice_expires < time() ) {
236
+ unset( $notices[ $notice_id ] );
237
+ }
238
+ }
239
+ }
240
+
241
+ $notices[ $name ] = $expires;
242
+
243
+ $this->plugin->updatePopulateOption( 'factory_dismissed_notices', $notices );
244
+
245
+ wp_send_json_success();
246
+ }
247
+
248
+ /**
249
+ * Javascript code
250
+ * Печает в подвале страницы код, для взаимодействия с сервером через ajax,
251
+ * код используется при нажатии на кнопку закрыть уведомление. *
252
+ */
253
+ public function print_js_code() {
254
+ $plugin_name = str_replace( '_', '-', $this->plugin->getPluginName() );
255
+
256
+ ?>
257
+ <script type="text/javascript">
258
+ jQuery(function($) {
259
+
260
+ $(document).on('click', '.<?php echo $plugin_name; ?>-factory-notice-dismiss .notice-dismiss', function() {
261
+ $.post(ajaxurl, {
262
+ 'action': '<?php echo $this->plugin->getPluginName(); ?>_dismiss_notice',
263
+ 'name': $(this).parent().data('name'),
264
+ 'expires': $(this).parent().data('expires'),
265
+ 'nonce': $(this).parent().attr('data-nonce')
266
+ });
267
+ });
268
+
269
+ });
270
+ </script>
271
+ <?php
272
+ }
273
+
274
+
275
+ /**
276
+ * Проверяет скрыто уведоление или нет
277
+ *
278
+ * @param string $notice_id - имя уведомления
279
+ *
280
+ * @return bool
281
+ */
282
+ protected function is_dissmissed( $notice_id ) {
283
+ if ( ! empty( $this->dissmised_notices ) && isset( $this->dissmised_notices[ 'wbcr_factory_notice_' . $notice_id ] ) ) {
284
+ $expires = (int) $this->dissmised_notices[ 'wbcr_factory_notice_' . $notice_id ];
285
+
286
+ return $expires === 0 || $expires > time();
287
+ }
288
+
289
+ return false;
290
+ }
291
+ }
libs/factory/core/includes/class-factory-options.php ADDED
@@ -0,0 +1,432 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424;
4
+
5
+ // Exit if accessed directly
6
+ use Exception;
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * Трейт используется для расширения базового класса плагина Wbcr_Factory424_Base, позволяя работать с опциями плагина.
14
+ *
15
+ * Этот трейт является оберткой для Wordpress функций get_option, get_site_option, update_option, update_site_option,
16
+ * delete_option, delete_site_option. Основная задача была получать, обновлять, удалять опции без использования префиксов,
17
+ * чтобы класс выполнял эту работу за программиста. В дополнение, трейт содержит методы для полной выгрузки всех опций
18
+ * плагина, что позволяет при инициализации плагина автоматически выгрузить все существующие опции плагина в объектный
19
+ * кеш. Все опции, с которыми работает плагин, могут быть отфильтрованы.
20
+ *
21
+ * Документация по трейту: https://webcraftic.atlassian.net/wiki/spaces/FFD/pages/393805831/
22
+ * Документация по созданию плагина: https://webcraftic.atlassian.net/wiki/spaces/CNCFC/pages/327828
23
+ * Репозиторий: https://github.com/alexkovalevv
24
+ *
25
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
26
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
27
+ *
28
+ * @since 4.0.8 - Добавлен
29
+ * @package factory-core
30
+ */
31
+ trait Options {
32
+
33
+ /**
34
+ * Абстрактный метод, должен быть реализован в классе использующем этот трейт. Метод позволяет получить префикс
35
+ * плагина для формирования имен опций в базе данных Wordpress. У опций должно быть свое пространство имен,
36
+ * иначе может быть конфликт с другими плагинами или с сами ядром Wordpress.
37
+ *
38
+ * @since 4.0.8 - Добавлен
39
+ * @return string Возвращает префикс плагина. Пример: wbcr_clearfy_
40
+ */
41
+ abstract public function getPrefix();
42
+
43
+ /**
44
+ * Выгружает все опции плагина в объектный кеш. Плагин может получить любую свою опцию без запроса к базе данных.
45
+ * Метод ускоряет работу плагина, если опций очень много.
46
+ *
47
+ * Используется только один раз при инициализации плагина.
48
+ *
49
+ * @since 4.0.8 - Добавлен
50
+ */
51
+ public function loadAllOptions() {
52
+ global $wpdb;
53
+
54
+ $is_option_loaded = wp_cache_get( $this->getPrefix() . 'all_options_loaded', $this->getPrefix() . 'options' );
55
+
56
+ if ( false === $is_option_loaded ) {
57
+ $result = $wpdb->get_results( "SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name LIKE '{$this->getPrefix()}%'" );
58
+
59
+ $options = [];
60
+
61
+ if ( ! empty( $result ) ) {
62
+ wp_cache_add( $this->getPrefix() . 'all_options_loaded', 1, $this->getPrefix() . 'options' );
63
+
64
+ foreach ( $result as $option ) {
65
+ $value = maybe_unserialize( $option->option_value );
66
+ $value = $this->normalizeValue( $value );
67
+
68
+ wp_cache_add( $option->option_name, $value, $this->getPrefix() . 'options' );
69
+ $options[ $option->option_name ] = $value;
70
+ }
71
+
72
+ /**
73
+ * Действие, которое будет выполнено, когда все опции плагина будут выгружены.
74
+ *
75
+ * @since 4.0.9 - Добавлен
76
+ *
77
+ * @param string $plugin_name Имя плагина
78
+ * @param array $options Ассоциативный массив опций плагина
79
+ */
80
+ do_action( 'wbcr/factory/all_options_loaded', $options, $this->plugin_name );
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Выгружает все сетевые опции плагина в объектный кеш. Плагин может получить любую свою опцию без запроса к базе
87
+ * данных. Метод ускоряет работу плагина, если опций очень много.
88
+ *
89
+ * Используется и работает только в режиме мультисайтов, один раз при инициализации плагина.!
90
+ *
91
+ * @since 4.0.8 - Добавлен
92
+ * @return void
93
+ */
94
+ public function loadAllNetworkOptions() {
95
+ global $wpdb;
96
+
97
+ $network_id = (int) get_current_network_id();
98
+
99
+ $is_option_loaded = wp_cache_get( $network_id . ":" . $this->getPrefix() . 'all_options_loaded', $this->getPrefix() . 'network_options' );
100
+
101
+ if ( false === $is_option_loaded ) {
102
+ wp_cache_add_global_groups( [ $this->getPrefix() . 'network_options' ] );
103
+
104
+ $result = $wpdb->get_results( "SELECT meta_key, meta_value FROM {$wpdb->sitemeta} WHERE site_id='{$network_id}' AND meta_key LIKE '{$this->getPrefix()}%'" );
105
+
106
+ $options = [];
107
+ if ( ! empty( $result ) ) {
108
+ wp_cache_add( $network_id . ":" . $this->getPrefix() . 'all_options_loaded', 1, $this->getPrefix() . 'network_options' );
109
+
110
+ foreach ( $result as $option ) {
111
+ $value = maybe_unserialize( $option->meta_value );
112
+ $value = $this->normalizeValue( $value );
113
+
114
+ $cache_key = $network_id . ":" . $option->meta_key;
115
+ wp_cache_add( $cache_key, $value, $this->getPrefix() . 'network_options' );
116
+ $options[ $option->meta_key ] = $value;
117
+ }
118
+
119
+ /**
120
+ *
121
+ * Действие, которое будет выполнено, когда все сетевые опции плагина будут выгружены.
122
+ *
123
+ * @since 4.0.9 - Добавлен
124
+ *
125
+ * @param array $options Ассоциативный массив опций плагина
126
+ * @param string $plugin_name Имя плагина
127
+ */
128
+ do_action( 'wbcr/factory/all_network_options_loaded', $options, $this->plugin_name );
129
+ }
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Позволяет получить популярную опцию. В случае если плагин установлен для сети (в режиме мультисайтов),
135
+ * то метод возвращает опции только для сети, иначе метод возвращает опцию для текущего сайта. Работает
136
+ * на основе self::getOption и self::getNetworkOption, смотрите полную реализацию в этих методах.
137
+ *
138
+ * @since 4.0.8 - Добавлен
139
+ *
140
+ * @param string $option_name Имя опции без префикса.
141
+ * @param mixed $default Значение по умолчанию. Если опции нет в базе данных, будет возвращено это значение. По умолчанию false
142
+ *
143
+ * @return mixed Возвращает значение опции, если это сериализованная строка, то автоматически распаковывает ее.
144
+ */
145
+ public function getPopulateOption( $option_name, $default = false ) {
146
+ if ( $this->isNetworkActive() ) {
147
+ $option_value = $this->getNetworkOption( $option_name, $default );
148
+ } else {
149
+ $option_value = $this->getOption( $option_name, $default );
150
+ }
151
+
152
+ /**
153
+ * Фильтр позволяет отфильтровать возвращаемое значение популярной опции.
154
+ *
155
+ * @since 4.0.9 - Добавлен
156
+ *
157
+ * @param mixed $option_value Значение опции
158
+ * @param string $option_name Имя опции
159
+ * @param mixed $default Значение опции по умолчанию
160
+ */
161
+ return apply_filters( "wbcr/factory/populate_option_{$option_name}", $option_value, $option_name, $default );
162
+ }
163
+
164
+ /**
165
+ * Позволяет получить сетевые опции. Если плагин установлен для сети (в режиме мультисайтов), то
166
+ * метод возвращает опции только для сети, иначе метод возвращает опцию для текущего сайта.
167
+ *
168
+ * Опция вытаскивается из объектного кеша, после выполнения метода self:loadAllNetworkOptions,
169
+ * а не напрямую из базы данных, из-за чего при работе с некоторыми кеширующими плагинами,
170
+ * может быть странное поведение в работе плагина.
171
+ *
172
+ * @since 4.0.8 - Добавлен
173
+ *
174
+ * @param string $option_name Имя опции без префикса.
175
+ * @param mixed $default Значение по умолчанию. Если опции нет в базе данных, будет возвращено это значение. По умолчанию false
176
+ *
177
+ * @return mixed Возвращает значение опции, если это сериализованная строка, то автоматически распаковывает ее.
178
+ */
179
+ public function getNetworkOption( $option_name, $default = false ) {
180
+ if ( empty( $option_name ) || ! is_string( $option_name ) ) {
181
+ throw new Exception( 'Option name must be a string and must not be empty.' );
182
+ }
183
+
184
+ if ( ! is_multisite() ) {
185
+ return $this->getOption( $option_name, $default );
186
+ }
187
+
188
+ $this->loadAllNetworkOptions();
189
+
190
+ $network_id = (int) get_current_network_id();
191
+ $cache_key = $network_id . ':' . $this->getPrefix() . $option_name;
192
+ $option_value = wp_cache_get( $cache_key, $this->getPrefix() . 'network_options' );
193
+
194
+ if ( false === $option_value ) {
195
+ $option_value = $default;
196
+ }
197
+
198
+ /**
199
+ * Фильтр позволяет отфильтровать возвращаемое значение сетевой опции.
200
+ *
201
+ * @since 4.0.9 - Добавлен
202
+ *
203
+ * @param mixed $option_value Значение опции
204
+ * @param string $option_name Имя опции
205
+ * @param mixed $default Значение опции по умолчанию
206
+ * @param int $network_id ID сети
207
+ */
208
+
209
+ return apply_filters( "wbcr/factory/network_option_{$option_name}", $option_value, $option_name, $default, $network_id );
210
+ }
211
+
212
+ /**
213
+ * Метод позволяет получить опцию для текущего сайта. Опция вытаскивается из объектного кеша, после выполнения метода
214
+ * self:loadAllOptions, а не напрямую из базы данных, из-за чего при работе с некоторыми кеширующими плагинами,
215
+ * может быть странное поведение в работе плагина.
216
+ *
217
+ * @since 4.0.0 - Добавлен
218
+ * @since 4.0.8 - Полностью переделан
219
+ *
220
+ * @param string $option_name Имя опции без префикса.
221
+ * @param mixed $default Значение по умолчанию. Если опции нет в базе данных, будет возвращено это значение. По умолчанию false
222
+ *
223
+ * @return mixed
224
+ */
225
+ public function getOption( $option_name, $default = false ) {
226
+ if ( empty( $option_name ) || ! is_string( $option_name ) ) {
227
+ throw new Exception( 'Option name must be a string and must not be empty.' );
228
+ }
229
+
230
+ $this->loadAllOptions();
231
+
232
+ $option_value = wp_cache_get( $this->getPrefix() . $option_name, $this->getPrefix() . 'options' );
233
+
234
+ if ( false === $option_value ) {
235
+ $option_value = $default;
236
+ }
237
+
238
+ /**
239
+ * Фильтр позволяет отфильтровать возвращаемое значение опции сайта.
240
+ *
241
+ * @since 4.0.9 - Добавлен
242
+ *
243
+ * @param mixed $option_value Значение опции
244
+ * @param string $option_name Имя опции
245
+ * @param mixed $default Значение опции по умолчанию
246
+ */
247
+
248
+ return apply_filters( "wbcr/factory/option_{$option_name}", $option_value, $option_name, $default );
249
+ }
250
+
251
+ /**
252
+ * Позволяет обновить популярную опцию в базе данных. Если плагин установлен для сети (в режиме мультисайтов), то метод обновляет опцию
253
+ * только в таблице sitemeta, иначе в таблице options для текущего сайта.
254
+ *
255
+ * @param string $option_name Имя опции без префикса.
256
+ * @param mixed $option_value Значение опции. Может принимать массив или объект.
257
+ */
258
+ public function updatePopulateOption( $option_name, $option_value ) {
259
+ if ( $this->isNetworkActive() ) {
260
+ $this->updateNetworkOption( $option_name, $option_value );
261
+ } else {
262
+ $this->updateOption( $option_name, $option_value );
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Обновляет сетевую опцию в БД таблица sitemeta. После успешного обновления опции в базе данных, метод добавляет опцию в объектный кеш,
268
+ * чтобы плагин мог приступить к работе с этой опцией незамедлительно.
269
+ *
270
+ * @since 4.0.8 - Добавлен
271
+ *
272
+ * @param string $option_name Имя опции без префикса.
273
+ * @param mixed $option_value Значение опции. Может принимать массив или объект.
274
+ */
275
+ public function updateNetworkOption( $option_name, $option_value ) {
276
+ $network_id = (int) get_current_network_id();
277
+ $cache_key = $network_id . ':' . $this->getPrefix() . $option_name;
278
+ wp_cache_set( $cache_key, $option_value, $this->getPrefix() . 'network_options' );
279
+
280
+ update_site_option( $this->getPrefix() . $option_name, $option_value );
281
+
282
+ /**
283
+ * Действие будет выполнено, когда сетевая опция будет обновлена.
284
+ *
285
+ * @since 4.0.8 - Добавлен
286
+ *
287
+ * @param string $option_name Имя опции без префикса.
288
+ * @param mixed $option_value Значение опции. Может принимать массив или объект.
289
+ */
290
+ do_action( "wbcr/factory/update_network_option", $option_name, $option_value );
291
+ }
292
+
293
+ /**
294
+ * Обновляет опцию сайта в БД таблица options. После успешного обновления опции в базе данных, метод добавляет опцию в объектный кеш,
295
+ * чтобы плагин мог приступить к работе с этой опцией незамедлительно.
296
+ *
297
+ * @since 4.0.0 - Добавлен
298
+ * @since 4.0.8 - Полностью переделан
299
+ *
300
+ * @param string $option_name Имя опции без префикса.
301
+ * @param mixed $option_value Значение опции. Может принимать массив или объект.
302
+ *
303
+ * @return bool
304
+ */
305
+ public function updateOption( $option_name, $option_value ) {
306
+ wp_cache_set( $this->getPrefix() . $option_name, $option_value, $this->getPrefix() . 'options' );
307
+ $result = update_option( $this->getPrefix() . $option_name, $option_value );
308
+
309
+ /**
310
+ * @since 4.0.8
311
+ *
312
+ * @param string $option_name
313
+ *
314
+ * @param mixed $option_value
315
+ */
316
+ do_action( "wbcr/factory/update_option", $option_name, $option_value );
317
+
318
+ return $result;
319
+ }
320
+
321
+ /**
322
+ * Позволяет удалять популярную опцию в базе данных. Если плагин установлен для сети (в режиме мультисайтов), то метод удаляет опцию
323
+ * только в таблице sitemeta, иначе в таблице options для текущего сайта.
324
+ *
325
+ * @since 4.0.0 - Добавлен
326
+ *
327
+ * @param string $option_name Имя опции без префикса.
328
+ */
329
+ public function deletePopulateOption( $option_name ) {
330
+ if ( $this->isNetworkActive() ) {
331
+ $this->deleteNetworkOption( $option_name );
332
+ } else {
333
+ $this->deleteOption( $option_name );
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Удаляет сетевую.опцию в БД таблица sitemeta, а если опция есть в кеше, индивидуально удаляет опцию из кеша.
339
+ *
340
+ * @since 4.0.0 - Добавлен
341
+ *
342
+ * @param string $option_name Имя опции без префикса.
343
+ *
344
+ * @return bool Возвращает true, если опция удалена успешно, false в случае ошибки.
345
+ */
346
+ public function deleteNetworkOption( $option_name ) {
347
+ $network_id = (int) get_current_network_id();
348
+ $cache_key = $network_id . ':' . $this->getPrefix() . $option_name;
349
+ $delete_cache = wp_cache_delete( $cache_key, $this->getPrefix() . 'network_options' );
350
+
351
+ $delete_opt1 = delete_site_option( $this->getPrefix() . $option_name );
352
+
353
+ return $delete_cache && $delete_opt1;
354
+ }
355
+
356
+ /**
357
+ * Удаляет опцию сайта в БД таблица options, а если опция есть в кеше, индивидуально удаляет опцию из кеша.
358
+ *
359
+ * @since 4.0.0 - Добавлен
360
+ *
361
+ * @param string $option_name Имя опции без префикса.
362
+ *
363
+ * @return bool Возвращает true, если опция удалена успешно, false в случае ошибки.
364
+ */
365
+ public function deleteOption( $option_name ) {
366
+ $delete_cache = wp_cache_delete( $this->getPrefix() . $option_name, $this->getPrefix() . 'options' );
367
+
368
+ // todo: удалить, когда большая часть пользователей обновятся до современных релизов
369
+ $delete_opt1 = delete_option( $this->getPrefix() . $option_name . '_is_active' );
370
+ $delete_opt2 = delete_option( $this->getPrefix() . $option_name );
371
+
372
+ return $delete_cache && $delete_opt1 && $delete_opt2;
373
+ }
374
+
375
+ /**
376
+ * Сбрасывает объектный кеш. Может использоваться для перезагрузки опций плагина и Wordpress в целом.
377
+ *
378
+ * @since 4.0.0 - Добавлен
379
+ * @return bool Возвращает true, если кеш сброшен успешно, false в случае ошибки.
380
+ */
381
+ public function flushOptionsCache() {
382
+ return wp_cache_flush();
383
+ }
384
+
385
+ /**
386
+ * Позволяет получить полное имя опции с префиксом. Может быть использовано в тех случаях, где нужно получить
387
+ * полное имя опции.
388
+ *
389
+ * @since 4.0.0 - Добавлен
390
+ *
391
+ * @param string $option_name Имя опции без префикса.
392
+ *
393
+ * @return null|string Возвращает имя опции с префиксом. Например wbcr_clearfy_{options_name}
394
+ */
395
+ public function getOptionName( $option_name ) {
396
+ $option_name = trim( rtrim( $option_name ) );
397
+ if ( empty( $option_name ) || ! is_string( $option_name ) ) {
398
+ return null;
399
+ }
400
+
401
+ return $this->getPrefix() . $option_name;
402
+ }
403
+
404
+ /**
405
+ * Позволяет нормализовать данные. В некоторых методах этого трейта, ожидаются данные определенного типа, чтобы
406
+ * выполнить различные логические операции. Как раз в этом случае этот метод можно использовать, чтобы привести
407
+ * все сырые данные в строгий тип. Такое решение позволит избежать ошибок в работе программиста.
408
+ *
409
+ * @since 4.0.0 - Добавлен
410
+ *
411
+ * @param mixed $data Данные, которые нужно нормализовать.
412
+ *
413
+ * @return mixed Возвращает нормализованное значение.
414
+ * - Если передана строка "true" или "false" вернет булево значение.
415
+ * - Если передана строка "1" или "0" вернет число.
416
+ */
417
+ public function normalizeValue( $data ) {
418
+ if ( is_string( $data ) ) {
419
+ $check_string = rtrim( trim( $data ) );
420
+
421
+ if ( $check_string == "1" || $check_string == "0" ) {
422
+ return intval( $data );
423
+ } else if ( $check_string === 'false' ) {
424
+ return false;
425
+ } else if ( $check_string === 'true' ) {
426
+ return true;
427
+ }
428
+ }
429
+
430
+ return $data;
431
+ }
432
+ }
libs/factory/core/includes/class-factory-plugin-abstract.php ADDED
@@ -0,0 +1,688 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+ /**
8
+ * Основной класс для создания плагина.
9
+ *
10
+ * Это основной класс плагина. который отвечает за подключение модулей фреймворка, линзирование, обновление,
11
+ * миграции разрабатываемого плагина. При создании нового плагина, вы должны создать основной класс реализующий
12
+ * функции плагина, этот класс будет наследовать текущий.
13
+ *
14
+ * Смотрите подробную инструкцию по созданию плагина и экземпляра основного класса в документации по созданию
15
+ * плагина для Wordpress.
16
+ *
17
+ * Документация по классу: https://webcraftic.atlassian.net/wiki/spaces/FFD/pages/393052164
18
+ * Документация по созданию плагина: https://webcraftic.atlassian.net/wiki/spaces/CNCFC/pages/327828
19
+ *
20
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
21
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
22
+ *
23
+ * @since 1.0.0
24
+ * @package factory-core
25
+ *
26
+ */
27
+ abstract class Wbcr_Factory424_Plugin extends Wbcr_Factory424_Base {
28
+
29
+ /**
30
+ * Instance class Wbcr_Factory424_Request, required manages http requests
31
+ *
32
+ * @see https://webcraftic.atlassian.net/wiki/spaces/FFD/pages/390561806
33
+ * @var Wbcr_Factory424_Request
34
+ */
35
+ public $request;
36
+
37
+ /**
38
+ * @see https://webcraftic.atlassian.net/wiki/spaces/FFD/pages/393936924
39
+ * @var \WBCR\Factory_424\Premium\Provider
40
+ */
41
+ public $premium;
42
+
43
+ /**
44
+ * The Bootstrap Manager class
45
+ *
46
+ * @var Wbcr_FactoryBootstrap425_Manager
47
+ */
48
+ public $bootstrap;
49
+
50
+ /**
51
+ * The Bootstrap Manager class
52
+ *
53
+ * @var Wbcr_FactoryForms422_Manager
54
+ */
55
+ public $forms;
56
+
57
+ /**
58
+ * Простой массив со списком зарегистрированных классов унаследованных от Wbcr_Factory424_Activator.
59
+ * Классы активации используются для упаковки набора функций, которые нужно выполнить во время
60
+ * активации плагина.
61
+ *
62
+ * @var array[] Wbcr_Factory424_Activator
63
+ */
64
+ protected $activator_class = [];
65
+
66
+ /**
67
+ * Ассоциативный массив со списком уже загруженных модулей фреймворка. Используется для того, чтобы
68
+ * проверить, каких модули уже были загружены, а какие еще нет.
69
+ *
70
+ * @var array
71
+ */
72
+ private $loaded_factory_modules = [];
73
+
74
+ /**
75
+ * Ассоциативный массив со списком аддонов плагина. Аддоны плагина являются частью одного проекта,
76
+ * но не как отдельный плагин.
77
+ *
78
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
79
+ * @since 4.2.0
80
+ * @var array
81
+ */
82
+ private $loaded_plugin_components = [];
83
+
84
+ /**
85
+ * The Adverts Manager class
86
+ *
87
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
88
+ * @since 4.1.9
89
+ * @var WBCR\Factory_Adverts_000\Base
90
+ */
91
+ private $adverts;
92
+
93
+ /**
94
+ * Инициализирует компоненты фреймворка и плагина.
95
+ *
96
+ * @since 1.0.0
97
+ *
98
+ * @param array $data A set of plugin data.
99
+ *
100
+ * @param string $plugin_path A full path to the main plugin file.
101
+ *
102
+ * @throws Exception
103
+ */
104
+ public function __construct( $plugin_path, $data ) {
105
+
106
+ parent::__construct( $plugin_path, $data );
107
+
108
+ $this->request = new Wbcr_Factory424_Request();
109
+ //$this->route = new Wbcr_Factory424_Route();
110
+
111
+ // INIT PLUGIN FRAMEWORK MODULES
112
+ // Framework modules should always be loaded first,
113
+ // since all other functions depend on them.
114
+ $this->init_framework_modules();
115
+
116
+ // INIT PLUGIN MIGRATIONS
117
+ $this->init_plugin_migrations();
118
+
119
+ // INIT PLUGIN NOTICES
120
+ $this->init_plugin_notices();
121
+
122
+ // INIT PLUGIN PREMIUM FEATURES
123
+ // License manager should be installed earlier
124
+ // so that other modules can access it.
125
+ $this->init_plugin_premium_features();
126
+
127
+ // INIT PLUGIN UPDATES
128
+ $this->init_plugin_updates();
129
+
130
+ // init actions
131
+ $this->register_plugin_hooks();
132
+
133
+ // INIT PLUGIN COMPONENTS
134
+ $this->init_plugin_components();
135
+ }
136
+
137
+ /**
138
+ * Устанавливает класс менеджер, которому плагин будет делегировать подключение ресурсов (картинок,
139
+ * скриптов, стилей) фреймворка.
140
+ *
141
+ * @param Wbcr_FactoryBootstrap425_Manager $bootstrap
142
+ */
143
+ public function setBootstap( Wbcr_FactoryBootstrap425_Manager $bootstrap ) {
144
+ $this->bootstrap = $bootstrap;
145
+ }
146
+
147
+ /**
148
+ * Устанавливает класс менеджер, которому будет делегирована работа с html формами фреймворка.
149
+ *
150
+ * @param Wbcr_FactoryForms422_Manager $forms
151
+ */
152
+ public function setForms( Wbcr_FactoryForms422_Manager $forms ) {
153
+ $this->forms = $forms;
154
+ }
155
+
156
+ /**
157
+ * Устанавливает класс менеджер, которому будет делегирована работа с объявлениями в Wordpress
158
+ *
159
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
160
+ * @since 4.1.9
161
+ */
162
+ public function set_adverts_manager( $class_name ) {
163
+ if ( empty( $this->adverts ) && $this->render_adverts ) {
164
+ $this->adverts = new $class_name( $this, $this->adverts_settings );
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Устанавливает класс провайдера лицензий
170
+ *
171
+ * С помощью этого класса, мы проверяем валидность лицензий и получаем дополнительную информацию
172
+ * о лицензии и ее покупателе. Класс используется в премиум менеджере.
173
+ *
174
+ * @since 4.1.6 - Добавлен
175
+ *
176
+ * @param string $name Имя провайдер
177
+ * @param string $class_name Имя класса провайдера
178
+ */
179
+ public function set_license_provider( $name, $class_name ) {
180
+ if ( ! isset( WBCR\Factory_424\Premium\Manager::$providers[ $name ] ) ) {
181
+ WBCR\Factory_424\Premium\Manager::$providers[ $name ] = $class_name;
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Регистрируем класс репозитория
187
+ *
188
+ * С помощью этого класса мы реализиуем доставку и откат обновлений плагина, на сайт пользователя.
189
+ * Скачиваение премиум версий происходит по защенному каналу. Класс используется в менеджере обновлений.
190
+ *
191
+ * @since 4.1.7 - Добавлен
192
+ *
193
+ * @param string $name Имя репозитория
194
+ * @param string $class_name Имя класса репозитория
195
+ */
196
+ public function set_update_repository( $name, $class_name ) {
197
+ if ( ! isset( WBCR\Factory_424\Updates\Upgrader::$repositories[ $name ] ) ) {
198
+ WBCR\Factory_424\Updates\Upgrader::$repositories[ $name ] = $class_name;
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Позволяет получить экземпляр менеджера объявления
204
+ *
205
+ * Доступен глобально через метод app(), чаще всего используется для создания точек для ротации
206
+ * рекламных объявлений.
207
+ *
208
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
209
+ * @since 1.1
210
+ * @return \WBCR\Factory_Adverts_000\Base
211
+ */
212
+ public function get_adverts_manager() {
213
+ return $this->adverts;
214
+ }
215
+
216
+ /**
217
+ * Устанавливает текстовый домен для плагина. Текстовый домен берется из заголовка входного
218
+ * файла плагина.
219
+ *
220
+ * @since 4.0.8 - Добавлен
221
+ *
222
+ * @see https://codex.wordpress.org/I18n_for_WordPress_Developers
223
+ * @see https://webcraftic.atlassian.net/wiki/spaces/CNCFC/pages/327828 - документация по входному файлу
224
+ */
225
+ public function set_text_domain() {
226
+ if ( empty( $this->plugin_text_domain ) ) {
227
+ return;
228
+ }
229
+
230
+ $locale = apply_filters( 'plugin_locale', is_admin() ? get_user_locale() : get_locale(), $this->plugin_text_domain );
231
+
232
+ $mofile = $this->plugin_text_domain . '-' . $locale . '.mo';
233
+
234
+ if ( ! load_textdomain( $this->plugin_text_domain, $this->paths->absolute . '/languages/' . $mofile ) ) {
235
+ load_muplugin_textdomain( $this->plugin_text_domain );
236
+ }
237
+ }
238
+
239
+ public function newScriptList() {
240
+ return new Wbcr_Factory424_ScriptList( $this );
241
+ }
242
+
243
+ public function newStyleList() {
244
+ return new Wbcr_Factory424_StyleList( $this );
245
+ }
246
+
247
+ /**
248
+ * Все страницы плагина создаются через специальную обертку, за которую отвечает модуль
249
+ * фреймворка pages. Разработчик создает собственный класс, унаследованный от
250
+ * Wbcr_FactoryPages424_AdminPage, а затем регистрирует его через этот метод.
251
+ * Метод выполняет подключение класса страницы и регистрирует его в модуле фреймворка
252
+ * pages.
253
+ *
254
+ * Больше информации о создании и регистрации страниц, вы можете узнать из документации по созданию
255
+ * страниц плагина.
256
+ *
257
+ * @see https://webcraftic.atlassian.net/wiki/spaces/CNCFC/pages/222887949 - документация по созданию страниц
258
+ *
259
+ * @param string $class_name Имя регистрируемого класса страницы. Пример: WCL_Page_Name.
260
+ * Регистрируемый класс должен быть унаследован от класса Wbcr_FactoryPages424_AdminPage.
261
+ * @param string $file_path Абсолютный путь к файлу с классом страницы.
262
+ *
263
+ * @throws Exception
264
+ */
265
+ public function registerPage( $class_name, $file_path ) {
266
+ // todo: https://webcraftic.atlassian.net/projects/PCS/issues/PCS-88
267
+ // if ( $this->isNetworkActive() && ! is_network_admin() ) {
268
+ // return;
269
+ // }
270
+
271
+ if ( ! file_exists( $file_path ) ) {
272
+ throw new Exception( 'The page file was not found by the path {' . $file_path . '} you set.' );
273
+ }
274
+
275
+ require_once( $file_path );
276
+
277
+ if ( ! class_exists( $class_name ) ) {
278
+ throw new Exception( 'A class with this name {' . $class_name . '} does not exist.' );
279
+ }
280
+
281
+ if ( ! class_exists( 'Wbcr_FactoryPages424' ) ) {
282
+ throw new Exception( 'The factory_pages_424 module is not included.' );
283
+ }
284
+
285
+ Wbcr_FactoryPages424::register( $this, $class_name );
286
+ }
287
+
288
+ /**
289
+ * Произвольные типы записей в плагине, создаются через специальную обертку, за которую отвечает
290
+ * модуль фреймворка types. Разработчик создает собственный класс, унаследованный от
291
+ * Wbcr_FactoryTypes000_Type, а затем регистрирует его через этот метод. Метод выполняет
292
+ * подключение класса с новым типом записи и регистрирует его в модуле фреймворка types. *
293
+ *
294
+ * @param string $class_name Имя регистрируемого класса страницы. Пример: WCL_Type_Name.
295
+ * Регистрируемый класс должен быть унаследован от класса Wbcr_FactoryTypes000_Type.
296
+ * @param string $file_path Абсолютный путь к файлу с классом страницы.
297
+ *
298
+ * @throws Exception
299
+ * @deprecated 4.1.7 You cannot use it!
300
+ */
301
+ public function registerType( $class_name, $file_path ) {
302
+ throw new Exception( 'As of factory core module 4.1.7, the "registerType" method is deprecated. You cannot use it!' );
303
+ }
304
+
305
+ /**
306
+ * Registers a class to activate the plugin.
307
+ *
308
+ * @since 1.0.0
309
+ *
310
+ * @param string $className class name of the plugin activator.
311
+ *
312
+ * @return void
313
+ */
314
+ public function registerActivation( $className ) {
315
+ $this->activator_class[] = $className;
316
+ }
317
+
318
+ /* end services region
319
+ /* -------------------------------------------------------------*/
320
+
321
+ /**
322
+ * It's invoked on plugin activation. Don't excite it directly.
323
+ *
324
+ * @since 1.0.0
325
+ * @return void
326
+ */
327
+ public function activation_hook() {
328
+
329
+ /**
330
+ * @since 4.1.1 - change hook name
331
+ */
332
+ if ( apply_filters( "wbcr/factory_424/cancel_plugin_activation_{$this->plugin_name}", false ) ) {
333
+ return;
334
+ }
335
+
336
+ /**
337
+ * wbcr_factory_424_plugin_activation
338
+ *
339
+ * @since 4.1.1 - deprecated
340
+ */
341
+ wbcr_factory_424_do_action_deprecated( 'wbcr_factory_424_plugin_activation', [
342
+ $this
343
+ ], '4.1.1', "wbcr/factory/plugin_activation" );
344
+
345
+ /**
346
+ * wbcr/factory/plugin_activation
347
+ *
348
+ * @since 4.1.2 - deprecated
349
+ */
350
+ wbcr_factory_424_do_action_deprecated( 'wbcr/factory/plugin_activation', [
351
+ $this
352
+ ], '4.1.2', "wbcr/factory/before_plugin_activation" );
353
+
354
+ /**
355
+ * wbcr/factory/before_plugin_activation
356
+ *
357
+ * @since 4.1.2 - added
358
+ */
359
+ do_action( 'wbcr/factory/before_plugin_activation', $this );
360
+
361
+ /**
362
+ * # wbcr/factory/plugin_{$this->plugin_name}_activation
363
+ *
364
+ * @since 4.1.2 - deprecated
365
+ */
366
+ wbcr_factory_424_do_action_deprecated( "wbcr/factory/plugin_{$this->plugin_name}_activation", [
367
+ $this
368
+ ], '4.1.2', "wbcr/factory/before_plugin_{$this->plugin_name}_activation" );
369
+
370
+ /**
371
+ * wbcr_factory_424_plugin_activation_' . $this->plugin_name
372
+ *
373
+ * @since 4.1.1 - deprecated
374
+ */
375
+ wbcr_factory_424_do_action_deprecated( 'wbcr_factory_424_plugin_activation_' . $this->plugin_name, [
376
+ $this
377
+ ], '4.1.1', "wbcr/factory/before_plugin_{$this->plugin_name}_activation" );
378
+
379
+ /**
380
+ * wbcr/factory/plugin_{$this->plugin_name}_activation
381
+ *
382
+ * @since 4.1.2 - added
383
+ */
384
+ do_action( "wbcr/factory/plugin_{$this->plugin_name}_activation", $this );
385
+
386
+ if ( ! empty( $this->activator_class ) ) {
387
+ foreach ( (array) $this->activator_class as $activator_class ) {
388
+ $activator = new $activator_class( $this );
389
+ $activator->activate();
390
+ }
391
+ }
392
+
393
+ /**
394
+ * @since 4.1.2 - added
395
+ */
396
+ do_action( 'wbcr/factory/plugin_activated', $this );
397
+
398
+ /**
399
+ * @since 4.1.2 - added
400
+ */
401
+ do_action( "wbcr/factory/plugin_{$this->plugin_name}_activated", $this );
402
+ }
403
+
404
+ /**
405
+ * It's invoked on plugin deactionvation. Don't excite it directly.
406
+ *
407
+ * @since 1.0.0
408
+ * @return void
409
+ */
410
+ public function deactivation_hook() {
411
+
412
+ /**
413
+ * @since 4.1.1 - change hook name
414
+ */
415
+ if ( apply_filters( "wbcr/factory_424/cancel_plugin_deactivation_{$this->plugin_name}", false ) ) {
416
+ return;
417
+ }
418
+
419
+ /**
420
+ * wbcr_factory_424_plugin_deactivation
421
+ *
422
+ * @since 4.1.1 - deprecated
423
+ */
424
+ wbcr_factory_424_do_action_deprecated( 'wbcr_factory_424_plugin_deactivation', [
425
+ $this
426
+ ], '4.1.1', "wbcr/factory/plugin_deactivation" );
427
+
428
+ /**
429
+ * wbcr/factory/plugin_deactivation
430
+ *
431
+ * @since 4.1.2 - deprecated
432
+ */
433
+ wbcr_factory_424_do_action_deprecated( 'wbcr/factory/plugin_deactivation', [
434
+ $this
435
+ ], '4.1.2', "wbcr/factory/before_plugin_deactivation" );
436
+
437
+ /**
438
+ * wbcr/factory/plugin_deactivation
439
+ *
440
+ * @since 4.1.2 - added
441
+ */
442
+ do_action( 'wbcr/factory/plugin_deactivation', $this );
443
+
444
+ /**
445
+ * wbcr_factory_424_plugin_deactivation_ . $this->plugin_name
446
+ *
447
+ * @since 4.1.1 - deprecated
448
+ */
449
+ wbcr_factory_424_do_action_deprecated( 'wbcr_factory_424_plugin_deactivation_' . $this->plugin_name, [
450
+ $this
451
+ ], '4.1.1', "wbcr/factory/before_plugin_{$this->plugin_name}_deactivation" );
452
+
453
+ /**
454
+ * wbcr/factory/plugin_{$this->plugin_name}_deactivation
455
+ *
456
+ * @since 4.1.2 - deprecated
457
+ */
458
+ wbcr_factory_424_do_action_deprecated( "wbcr/factory/plugin_{$this->plugin_name}_deactivation", [
459
+ $this
460
+ ], '4.1.2', "wbcr/factory/before_plugin_{$this->plugin_name}_deactivation" );
461
+
462
+ /**
463
+ * @since 4.1.2 - added
464
+ */
465
+ do_action( "wbcr/factory/before_plugin_{$this->plugin_name}_deactivation" );
466
+
467
+ if ( ! empty( $this->activator_class ) ) {
468
+ foreach ( (array) $this->activator_class as $activator_class ) {
469
+ $activator = new $activator_class( $this );
470
+ $activator->deactivate();
471
+ }
472
+ }
473
+
474
+ /**
475
+ * @since 4.1.2 - added
476
+ */
477
+ do_action( 'wbcr/factory/plugin_deactivated', $this );
478
+
479
+ /**
480
+ * @since 4.1.2 - added
481
+ */
482
+ do_action( "wbcr/factory/plugin_{$this->plugin_name}_deactivated", $this );
483
+ }
484
+
485
+ /**
486
+ * Возвращает ссылку на внутреннюю страницу плагина
487
+ *
488
+ * @param string $page_id
489
+ *
490
+ * @sicne: 4.0.8
491
+ * @return string|void
492
+ * @throws Exception
493
+ */
494
+ public function getPluginPageUrl( $page_id, $args = [] ) {
495
+ if ( ! class_exists( 'Wbcr_FactoryPages424' ) ) {
496
+ throw new Exception( 'The factory_pages_424 module is not included.' );
497
+ }
498
+
499
+ if ( ! is_admin() ) {
500
+ _doing_it_wrong( __METHOD__, __( 'You cannot use this feature on the frontend.' ), '4.0.8' );
501
+
502
+ return null;
503
+ }
504
+
505
+ return Wbcr_FactoryPages424::getPageUrl( $this, $page_id, $args );
506
+ }
507
+
508
+ /**
509
+ * Загружает аддоны для плагина, как часть проекта, а не как отдельный плагин
510
+ *
511
+ * @throws \Exception
512
+ */
513
+ private function init_plugin_components() {
514
+
515
+ $load_plugin_components = $this->get_load_plugin_components();
516
+
517
+ if ( empty( $load_plugin_components ) || ! is_array( $load_plugin_components ) ) {
518
+ return;
519
+ }
520
+
521
+ foreach ( $load_plugin_components as $component_ID => $component ) {
522
+ if ( ! isset( $this->loaded_plugin_components[ $component_ID ] ) ) {
523
+
524
+ if ( ! isset( $component['autoload'] ) || ! isset( $component['plugin_prefix'] ) ) {
525
+ throw new Exception( sprintf( "Component %s cannot be loaded, you must specify the path to the component autoload file and plugin prefix!", $component_ID ) );
526
+ }
527
+
528
+ $prefix = rtrim( $component['plugin_prefix'], '_' ) . '_';
529
+
530
+ if ( defined( $prefix . 'PLUGIN_ACTIVE' ) ) {
531
+ continue;
532
+ }
533
+
534
+ $autoload_file = trailingslashit( $this->get_paths()->absolute ) . $component['autoload'];
535
+
536
+ if ( ! file_exists( $autoload_file ) ) {
537
+ throw new Exception( sprintf( "Component %s autoload file not found!", $component_ID ) );
538
+ }
539
+
540
+ require_once( $autoload_file );
541
+
542
+ if ( defined( $prefix . 'PLUGIN_ACTIVE' ) && class_exists( $prefix . 'Plugin' ) ) {
543
+ $this->loaded_plugin_components[ $component_ID ] = [
544
+ 'plugin_dir' => constant( $prefix . 'PLUGIN_DIR' ),
545
+ 'plugin_url' => constant( $prefix . 'PLUGIN_URL' ),
546
+ 'plugin_base' => constant( $prefix . 'PLUGIN_BASE' ),
547
+ 'plugin_version' => constant( $prefix . 'PLUGIN_VERSION' )
548
+ ];
549
+
550
+ /**
551
+ * Оповещает внешние приложения, что компонент плагина был загружен
552
+ *
553
+ * @param array $load_plugin_components Информация о загруженном компоненте
554
+ * @param string $plugin_name Имя плагина
555
+ */
556
+ do_action( "wbcr/factory/component_{$component_ID}_loaded", $this->loaded_plugin_components[ $component_ID ], $this->getPluginName() );
557
+ } else {
558
+ throw new Exception( sprintf( "Сomponent %s does not meet development standards!", $component_ID ) );
559
+ }
560
+ }
561
+ }
562
+ }
563
+
564
+ /**
565
+ * Загружает специальные модули для расширения Factory фреймворка.
566
+ * Разработчик плагина сам выбирает, какие модули ему нужны для
567
+ * создания плагина.
568
+ *
569
+ * Модули фреймворка хранятся в libs/factory/framework
570
+ *
571
+ * @return void
572
+ * @throws Exception
573
+ */
574
+ private function init_framework_modules() {
575
+
576
+ if ( ! empty( $this->load_factory_modules ) ) {
577
+ foreach ( (array) $this->load_factory_modules as $module ) {
578
+ $scope = isset( $module[2] ) ? $module[2] : 'all';
579
+
580
+ if ( $scope == 'all' || ( is_admin() && $scope == 'admin' ) || ( ! is_admin() && $scope == 'public' ) ) {
581
+
582
+ if ( ! file_exists( $this->get_paths()->absolute . '/' . $module[0] . '/boot.php' ) ) {
583
+ throw new Exception( 'Module ' . $module[1] . ' is not included.' );
584
+ }
585
+
586
+ $module_boot_file = $this->get_paths()->absolute . '/' . $module[0] . '/boot.php';
587
+ require_once $module_boot_file;
588
+
589
+ $this->loaded_factory_modules[ $module[1] ] = $module_boot_file;
590
+
591
+ do_action( 'wbcr_' . $module[1] . '_plugin_created', $this );
592
+ }
593
+ }
594
+ }
595
+
596
+ /**
597
+ * @since 4.1.1 - deprecated
598
+ */
599
+ wbcr_factory_424_do_action_deprecated( 'wbcr_factory_424_core_modules_loaded-' . $this->plugin_name, [], '4.1.1', "wbcr/factory_424/modules_loaded-" . $this->plugin_name );
600
+
601
+ /**
602
+ * @since 4.1.1 - add
603
+ */
604
+ do_action( 'wbcr/factory_424/modules_loaded-' . $this->plugin_name );
605
+ }
606
+
607
+
608
+ /**
609
+ * Setups actions related with the Factory Plugin.
610
+ *
611
+ * @since 1.0.0
612
+ */
613
+ private function register_plugin_hooks() {
614
+
615
+ add_action( 'plugins_loaded', [ $this, 'set_text_domain' ] );
616
+
617
+ if ( is_admin() ) {
618
+ add_filter( 'wbcr_factory_424_core_admin_allow_multisite', '__return_true' );
619
+
620
+ register_activation_hook( $this->get_paths()->main_file, [ $this, 'activation_hook' ] );
621
+ register_deactivation_hook( $this->get_paths()->main_file, [ $this, 'deactivation_hook' ] );
622
+ }
623
+ }
624
+
625
+ /**
626
+ * Инициализируем миграции плагина
627
+ *
628
+ * @since 4.1.1
629
+ * @return void
630
+ * @throws Exception
631
+ */
632
+ protected function init_plugin_migrations() {
633
+ new WBCR\Factory_424\Migrations( $this );
634
+ }
635
+
636
+ /**
637
+ * Инициализируем уведомления плагина
638
+ *
639
+ * @since 4.1.1
640
+ * @return void
641
+ */
642
+ protected function init_plugin_notices() {
643
+ new Wbcr\Factory_424\Notices( $this );
644
+ }
645
+
646
+ /**
647
+ * Создает нового рабочего для проверки обновлений и апгрейда текущего плагина.
648
+ *
649
+ * @since 4.1.1
650
+ *
651
+ * @param array $data
652
+ *
653
+ * @return void
654
+ * @throws Exception
655
+ */
656
+ protected function init_plugin_updates() {
657
+ if ( $this->has_updates ) {
658
+ new WBCR\Factory_424\Updates\Upgrader( $this );
659
+ }
660
+ }
661
+
662
+ /**
663
+ * Начинает инициализацию лицензирования текущего плагина. Доступ к менеджеру лицензий можно
664
+ * получить через свойство license_manager.
665
+ *
666
+ * Дополнительно создает рабочего, чтобы совершить апгрейд до премиум версии
667
+ * и запустить проверку обновлений для этого модуля.
668
+ *
669
+ * @since 4.1.1
670
+ * @throws Exception
671
+ */
672
+ protected function init_plugin_premium_features() {
673
+ if ( ! $this->has_premium || ! $this->license_settings ) {
674
+ $this->premium = null;
675
+
676
+ return;
677
+ }
678
+
679
+ // Создаем экземляр премиум менеджера, мы сможем к нему обращаться глобально.
680
+ $this->premium = WBCR\Factory_424\Premium\Manager::instance( $this, $this->license_settings );
681
+
682
+ // Подключаем премиум апгрейдер
683
+ if ( isset( $this->license_settings['has_updates'] ) && $this->license_settings['has_updates'] ) {
684
+ new WBCR\Factory_424\Updates\Premium_Upgrader( $this );
685
+ }
686
+ }
687
+ }
688
+
libs/factory/core/includes/class-factory-plugin-base.php ADDED
@@ -0,0 +1,573 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+ /**
8
+ * Базовый класс для создания нового плагина. Полную реализацию класса смотрите в Wbcr_Factory424_Plugin
9
+ *
10
+ * Документация по классу: https://webcraftic.atlassian.net/wiki/spaces/FFD/pages/392724484
11
+ * Документация по созданию плагина: https://webcraftic.atlassian.net/wiki/spaces/CNCFC/pages/327828
12
+ * Репозиторий: https://github.com/alexkovalevv
13
+ *
14
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
15
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
16
+ *
17
+ * @since 1.0.0
18
+ * @package factory-core
19
+ */
20
+ class Wbcr_Factory424_Base {
21
+
22
+ use WBCR\Factory_424\Options;
23
+
24
+ /**
25
+ * Обязательное свойство. Префикс, используется для создания пространство имен.
26
+ * Чаще всего используется на именования опций в базе данных. Также может быть
27
+ * использован для именования полей html форм, создания уникальных имен, хуков.
28
+ * Пример: wrio_
29
+ *
30
+ * Для префикса всегда используете нижнее подчеркивание справа!
31
+ *
32
+ * @var string
33
+ */
34
+ protected $prefix;
35
+
36
+ /**
37
+ * Обязательное свойство. Заголовок плагина. Используете в интерфейсе плагина,
38
+ * может быть использован в уведомлениях для администратора, чтобы пользователь
39
+ * мог понять, с каким плагином он ведет коммуникацию. Пример: Robin image optimizer
40
+ *
41
+ * @var string
42
+ */
43
+ protected $plugin_title;
44
+
45
+ /**
46
+ * Обязательное свойство. Имя плагина. Используется аналогично префиксу, но с небольшим
47
+ * отличием. Имя плагина имеет человеку понятную строку, которую можно использовать в
48
+ * именовании хуков, созданию условной логики. Допустимые символы [A-z0-9_].
49
+ * Пример: wbcr_clearfy
50
+ *
51
+ * @var string
52
+ */
53
+ protected $plugin_name;
54
+
55
+ /**
56
+ * Обязательное свойство. Версия плагина в формате 0.0.0. Допустимые символы [0-9.]
57
+ *
58
+ * @var string
59
+ */
60
+ protected $plugin_version;
61
+
62
+ /**
63
+ * Обязательное свойство. Текстовый домен плагина, используется для подключения файлов
64
+ * переводов. Рекомендуется использовать slug плагина, идентичный slug в репозитории
65
+ * Wordpress.org
66
+ *
67
+ * @since 4.1.1
68
+ * @var string
69
+ */
70
+ protected $plugin_text_domain;
71
+
72
+ /**
73
+ * Обязательное свойство. Информация для поддержки клиента. Для начала работы плагина,
74
+ * достаточно только указать адрес лендинга в атрибут url. На лендинге должны быть
75
+ * созданы страницы features, pricing, support, docs. Если страницы (features, pricing,
76
+ * support, docs) не могут иметь такие же адреса, вы можете наложить карту адресов в
77
+ * атрибуте pages_map. К примеру: я создал страницу "Pro Features" и она имеет адрес
78
+ * {site}/premium-features, для pages_map в атрибуте features, я указал, что адрес
79
+ * страницы со списком функций имеет слаг premium-features. Теперь плагин будет понимать,
80
+ * что адрес страницы со списком функций будет таким:
81
+ * https://robin-image-optimizer.webcraftic.com/premium-features.
82
+ *
83
+ * Это свойство заполняется для того, чтобы в процессе разработки вы могли использовать
84
+ * экземпляр класса \WBCR\Factory_424\Entities\Support, для получения информации о сайте плагина.
85
+ * Тем самым вы избавляете себя от жесткого прописывания ссылок на лендинг плагина и
86
+ * можете изменить все ссылки в одном месте.
87
+ *
88
+ * @var array
89
+ */
90
+ protected $support_details;
91
+
92
+ /**
93
+ * Включение/отключение обновлений для бесплатного плагина. Если вашего плагина нет в репозитори
94
+ * Wordpress.org, вы можете включить собственный режим обновлений, например через GitHub или
95
+ * собственный репозиторий. Если установлено true, плагин будет проверять наличие обновлений
96
+ * для этого плагина.
97
+ *
98
+ * @var bool
99
+ */
100
+ protected $has_updates = false;
101
+
102
+ /**
103
+ * Настройка обновлений для бесплатного плагина. Если вы хотите настроить обновления для
104
+ * бесплатного плагина через собственный репозиторий (например: github), вам нужно указать имя
105
+ * репозитория и slug плагина. Slug может быть идентичен имени репозитория в github. Для Wordpress.org
106
+ * эти настройки не обязательны, так как в wordpress ядре есть встроенные функции для обновлений
107
+ * плагинов и тем.
108
+ *
109
+ * @var array
110
+ */
111
+ protected $updates_settings = [];
112
+
113
+ /**
114
+ * Включение/отключение премиум версии для плагина. Если вы создаете бесплатный плагин и хотите
115
+ * реализовать для него премиум версию, вам нужно начать с этого свойства. Если свойство установлено,
116
+ * как true, при инициализации плагина будут подключены функции лицензирования, проверки обновлений
117
+ * для премиум версии.
118
+ *
119
+ * @var bool
120
+ */
121
+ protected $has_premium = false;
122
+
123
+ /**
124
+ * Настройки лицензирования
125
+ *
126
+ * Лицензирование плагина может быть реализовано для любого провайдера,
127
+ * к примеру: freemius, codecanyon, templatemonster, вам нужно указать только настройки для
128
+ * взаимодействия с выбранным вами провайдером. Каждая реализация провайдера лицензий может иметь
129
+ * индивидуальный настройки, в этом примере приведены настройки для freemius провайдера
130
+ * WBCR\Factory_424\Premium\Provider > WBCR\Factory_Freemius_112\Premium\Provider
131
+ *
132
+ * На текущий момент существует только реализация для freemius провайдера.
133
+ *
134
+ * Для премиум плагина вы должны также указать настройки обновлений. Атрибут has_updates
135
+ * включает/отключает обновления для премиум плагина, в атрибуте updates_settings вы указываете
136
+ * дополнительные настройки обновлений.
137
+ *
138
+ * @var array
139
+ */
140
+ protected $license_settings = [];
141
+
142
+ /**
143
+ * Переключатель внутренней рекламы в плагине
144
+ *
145
+ * Если установить true, то плагин будет показывать рекламу компании в интерфейсе Wordpress.
146
+ * Рекламный модуль может отображать рекламу внутри инрефейса плагина, на странице dashboard
147
+ * и создавать сквозные уведомления на всех страницах админ панели Wordpress.
148
+ *
149
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
150
+ * @since 4.1.9
151
+ * @var bool
152
+ */
153
+ protected $render_adverts = false;
154
+
155
+ /**
156
+ * Настройки внутренней рекламы компании
157
+ *
158
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
159
+ * @since 4.1.9
160
+ * @var array
161
+ */
162
+ protected $adverts_settings = [];
163
+
164
+ /**
165
+ * Обязательное свойство. Подключаемые модули фреймворка.
166
+ *
167
+ * Модули фреймворка позволяют расширять его функциональность.
168
+ *
169
+ * @var array {
170
+ * Array with information about the loadable module
171
+ * {type} string $module [0] Relative path to the module directory
172
+ * {type} string $module [1] Module name with prefix 000
173
+ * {type} string $module [2] Scope:
174
+ * admin - Module will be loaded only in the admin panel,
175
+ * public - Module will be loaded only on the frontend
176
+ * all - Module will be loaded everywhere
177
+ * }
178
+ */
179
+ protected $load_factory_modules = [
180
+ [ 'libs/factory/bootstrap', 'factory_bootstrap_425', 'admin' ],
181
+ [ 'libs/factory/forms', 'factory_forms_422', 'admin' ],
182
+ [ 'libs/factory/pages', 'factory_pages_424', 'admin' ],
183
+ ];
184
+
185
+ /**
186
+ * Не обязательное свойство. Список подключаемых компонентов плагина.
187
+ *
188
+ * Компоненты плагина, это независимые плагины, которые расширяют возможности текущего плагина.
189
+ * Вы должны указать файл для автозагрузки компонента и префикс плагина, чтобы фреймворк
190
+ * мог обращаться к классам и константам компонентов.
191
+ *
192
+ *
193
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
194
+ * @since 4.2.0 Добавлен
195
+ * @var array Пример данных
196
+ * array(
197
+ * 'component_ID' => array(
198
+ * 'autoload' => 'relative_path/autoload_filename.php',
199
+ * 'plugin_prefix' => 'WPRFX_'
200
+ * ),
201
+ * // Реальный пример
202
+ * 'cyrlitera' => array(
203
+ * 'autoload' => 'components/cyrlitera/clearfy.php',
204
+ * 'plugin_prefix' => 'WCTR_'
205
+ * ),
206
+ * )
207
+ */
208
+ protected $load_plugin_components = [];
209
+
210
+
211
+ /**
212
+ * Экземпляр класса \WBCR\Factory_424\Entities\Support используется для получения информации
213
+ * о сайте плагина. Чаще всего используется для получения ссылки на страницу с тарифами или
214
+ * ссылки на форму обратной связи. Встроен механизм отслеживания по utm меткам.
215
+ *
216
+ * @var \WBCR\Factory_424\Entities\Support
217
+ */
218
+ protected $support;
219
+
220
+ /**
221
+ * Экземпляр класса \WBCR\Factory_424\Entities\Paths используется для получения информации о
222
+ * путях плагина. Часто используется для получения путей или ссылок на место хранения плагина
223
+ * или его входного файла.
224
+ *
225
+ * @var \WBCR\Factory_424\Entities\Paths
226
+ */
227
+ protected $paths;
228
+
229
+ /**
230
+ * Абсолютный путь к входному файлу плагина: C://server/site.dev/wp-content/plugins/plugin_name/plugin_name.php
231
+ *
232
+ * @var string
233
+ */
234
+ private $plugin_file;
235
+
236
+ /**
237
+ * Свойство хранит сырые настройки плагина, а также дополнительные настройки, которые не описаны
238
+ * в интерфейсе класса.
239
+ *
240
+ * @var array
241
+ */
242
+ private $plugin_data;
243
+
244
+ /**
245
+ * Конструктор:
246
+ * - Заполняет свойства класса из сырых данных плагина
247
+ * - Выполняет проверку на обязательные настройки
248
+ * - Инициализирует сущности support и paths
249
+ *
250
+ * @since 4.1.1 - добавил две сущности support, paths. Удалил свойства, plugin_build
251
+ * plugin_assembly, main_file, plugin_root, relative_path, plugin_url
252
+ * @since 4.0.8 - добавлена дополнительная логика
253
+ *
254
+ * @param string $plugin_file
255
+ * @param array $data
256
+ *
257
+ * @throws Exception
258
+ */
259
+ public function __construct( $plugin_file, $data ) {
260
+ $this->plugin_file = $plugin_file;
261
+ $this->plugin_data = $data;
262
+
263
+ foreach ( (array) $data as $option_name => $option_value ) {
264
+ if ( property_exists( $this, $option_name ) ) {
265
+ $this->$option_name = $option_value;
266
+ }
267
+ }
268
+
269
+ if ( empty( $this->prefix ) || empty( $this->plugin_name ) || empty( $this->plugin_title ) || empty( $this->plugin_version ) || empty( $this->plugin_text_domain ) ) {
270
+ throw new Exception( 'One of the required attributes has not been passed (prefix, plugin_title, plugin_name, plugin_version, plugin_text_domain).' );
271
+ }
272
+
273
+ $this->support = new \WBCR\Factory_424\Entities\Support( $this->support_details );
274
+ $this->paths = new \WBCR\Factory_424\Entities\Paths( $plugin_file );
275
+
276
+ // used only in the module 'updates'
277
+ $this->plugin_slug = ! empty( $this->plugin_name ) ? $this->plugin_name : basename( $plugin_file );
278
+ }
279
+
280
+ /**
281
+ * При обновлении фреймворка, некоторые свойства класса были удалены. Однако плагины на старом
282
+ * фреймворке по прежнему используют удаленные свойства. С помощью этого магического метода мы
283
+ * добавляем совместимость со старыми плагинами, но при этом выводим предупреждение, что нужно
284
+ * обновить некоторые свойства.
285
+ *
286
+ * @param string $name Имя свойства класса.
287
+ *
288
+ * @return mixed
289
+ */
290
+ public function __get( $name ) {
291
+
292
+ $deprecated_props = [
293
+ 'plugin_build',
294
+ 'plugin_assembly',
295
+ 'main_file',
296
+ 'plugin_root',
297
+ 'relative_path',
298
+ 'plugin_url'
299
+ ];
300
+
301
+ if ( in_array( $name, $deprecated_props ) ) {
302
+ $deprecated_message = 'In version 4.1.1 of the Factory framework, the class properties ';
303
+ $deprecated_message .= '(' . implode( ',', $deprecated_props ) . ')';
304
+ $deprecated_message .= 'have been removed. To get plugin paths, use the new paths property.' . PHP_EOL;
305
+
306
+ $backtrace = debug_backtrace();
307
+ if ( ! empty( $backtrace ) && isset( $backtrace[1] ) ) {
308
+ $deprecated_message .= 'BACKTRACE:(';
309
+ $deprecated_message .= 'File: ' . $backtrace[1]['file'];
310
+ $deprecated_message .= 'Function: ' . $backtrace[1]['function'];
311
+ $deprecated_message .= 'Line: ' . $backtrace[1]['line'];
312
+ $deprecated_message .= ')';
313
+ }
314
+
315
+ _deprecated_argument( __METHOD__, '4.1.1', $deprecated_message );
316
+
317
+ switch ( $name ) {
318
+ case 'plugin_build':
319
+ return null;
320
+ break;
321
+ case 'plugin_assembly':
322
+ return null;
323
+ break;
324
+ case 'main_file':
325
+ return $this->get_paths()->main_file;
326
+ break;
327
+ case 'plugin_root':
328
+ return $this->get_paths()->absolute;
329
+ break;
330
+ case 'relative_path':
331
+ return $this->get_paths()->basename;
332
+ break;
333
+ case 'plugin_url':
334
+ return $this->get_paths()->url;
335
+ break;
336
+ }
337
+ }
338
+
339
+ return null;
340
+ }
341
+
342
+ /**
343
+ * При обновлении фреймворка, некоторые методы класса были удалены. Однако плагины на старом фреймворке
344
+ * по прежнему используют удаленные методы. С помощью этого магического метода мы добавляем совместимость
345
+ * со старыми плагинами, но при этом выводим предупреждение, что нужно обновить некоторые методы.
346
+ *
347
+ * @param string $name Имя метода класса.
348
+ * @param array $arguments Массив аргументов метода класса.
349
+ *
350
+ * @return stdClass|null
351
+ * @throws Exception
352
+ */
353
+ public function __call( $name, $arguments ) {
354
+
355
+ $deprecated_methods = [
356
+ 'getPluginBuild',
357
+ 'getPluginAssembly',
358
+ 'getPluginPathInfo'
359
+ ];
360
+
361
+ if ( in_array( $name, $deprecated_methods ) ) {
362
+ $deprecated_message = 'In version 4.1.1 of the Factory framework, methods (' . implode( ',', $deprecated_methods ) . ') have been removed.';
363
+
364
+ $backtrace = debug_backtrace();
365
+ if ( ! empty( $backtrace ) && isset( $backtrace[1] ) ) {
366
+ $deprecated_message .= 'BACKTRACE:(';
367
+ $deprecated_message .= 'File: ' . $backtrace[1]['file'];
368
+ $deprecated_message .= 'Function: ' . $backtrace[1]['function'];
369
+ $deprecated_message .= 'Line: ' . $backtrace[1]['line'];
370
+ $deprecated_message .= ')';
371
+ }
372
+
373
+ _deprecated_argument( __METHOD__, '4.1.1', $deprecated_message );
374
+
375
+ if ( 'getPluginPathInfo' == $name ) {
376
+ $object = new stdClass;
377
+
378
+ $object->main_file = $this->get_paths()->main_file;
379
+ $object->plugin_root = $this->get_paths()->absolute;
380
+ $object->relative_path = $this->get_paths()->basename;
381
+ $object->plugin_url = $this->get_paths()->url;
382
+
383
+ return $object;
384
+ }
385
+ }
386
+
387
+ throw new Exception( "Method {$name} does not exist" );
388
+ }
389
+
390
+ /**
391
+ * Проверяет, включен ли премиум для этого плагина или нет.
392
+ *
393
+ * @return bool Возвращает true, если премиум пакет включен для этого плагина.
394
+ * См. Wbcr_Factory424_Base::has_premium
395
+ */
396
+ public function has_premium() {
397
+ return $this->has_premium;
398
+ }
399
+
400
+ /**
401
+ * Позволяет получить заголовок плагина.
402
+ *
403
+ * @return string Возвращает заголовок плагина. См. Wbcr_Factory424_Base::plugin_title
404
+ */
405
+ public function getPluginTitle() {
406
+ return $this->plugin_title;
407
+ }
408
+
409
+ /**
410
+ * Позволяет получить префикс плагина.
411
+ *
412
+ * @return string Возвращает префикс плагина.См. Wbcr_Factory424_Base::prefix
413
+ */
414
+ public function getPrefix() {
415
+ return $this->prefix;
416
+ }
417
+
418
+ /**
419
+ * Позволяет получить имя плагина.
420
+ *
421
+ * @return string Возвращает имя плагина. См. Wbcr_Factory424_Base::plugin_name
422
+ */
423
+ public function getPluginName() {
424
+ return $this->plugin_name;
425
+ }
426
+
427
+ /**
428
+ * Позволяет получить версию плагина.
429
+ *
430
+ * @return string Возвращает версию плагина. См. Wbcr_Factory424_Base::plugin_version
431
+ */
432
+ public function getPluginVersion() {
433
+ return $this->plugin_version;
434
+ }
435
+
436
+ /**
437
+ * Позволяет получить список подключаемых к плагином компонентов
438
+ *
439
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
440
+ * @since 4.2.0
441
+ * @return array
442
+ */
443
+ public function get_load_plugin_components() {
444
+ return $this->load_plugin_components;
445
+ }
446
+
447
+ /**
448
+ * Предоставляет доступ к сырым данным плагина. Может быть полезен, если вы хотите получить
449
+ * какие-то данные не описанные в интерфейсе этого плагина.
450
+ *
451
+ * @param string $attr_name Имя атрибута, который нужно получить. Идентично ключу в массиве
452
+ * Wbcr_Factory424_Base::plugin_data
453
+ *
454
+ * @return null
455
+ */
456
+ public function getPluginInfoAttr( $attr_name ) {
457
+ if ( isset( $this->plugin_data[ $attr_name ] ) ) {
458
+ return $this->plugin_data[ $attr_name ];
459
+ }
460
+
461
+ return null;
462
+ }
463
+
464
+ /**
465
+ * Предоставляет доступ к экземпляру класса \WBCR\Factory_424\Entities\Support.
466
+ *
467
+ * @return \WBCR\Factory_424\Entities\Support
468
+ */
469
+ public function get_support() {
470
+ return $this->support;
471
+ }
472
+
473
+ /**
474
+ * Предоставляет доступ к экземпляру класса \WBCR\Factory_424\Entities\Paths.
475
+ *
476
+ * @return \WBCR\Factory_424\Entities\Paths
477
+ */
478
+ public function get_paths() {
479
+ return $this->paths;
480
+ }
481
+
482
+ /**
483
+ * Позволяет получить сырые данные плагина в виде объекта StdClass.
484
+ *
485
+ * @return object Возвращает объект с сырыми данными плагина. См. Wbcr_Factory424_Base::plugin_data
486
+ */
487
+ public function getPluginInfo() {
488
+ return (object) $this->plugin_data;
489
+ }
490
+
491
+ /**
492
+ * Проверяет права пользователя
493
+ *
494
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
495
+ * @since 4.2.0 Добавлен
496
+ * @return bool
497
+ */
498
+ public function current_user_can( $capability = 'manage_options' ) {
499
+ // Просмотр страниц: read_pages
500
+ // Просмотр уведомлений: read_notices
501
+ // Редактирование: edit_forms
502
+
503
+ if ( 'manage_options' == $capability && is_multisite() && $this->isNetworkActive() ) {
504
+ $capability = 'manage_network';
505
+ }
506
+
507
+ return current_user_can( $capability );
508
+ }
509
+
510
+ /**
511
+ * Проверят, находится ли пользователь в панели усправления сетью сайтов
512
+ *
513
+ * @since 4.0.8 Добавлен
514
+ *
515
+ * @return bool
516
+ */
517
+ public function isNetworkAdmin() {
518
+ return is_multisite() && is_network_admin();
519
+ }
520
+
521
+ /**
522
+ * Проверяет активирован ли плагин для сети. Если проект работает в режиме мультисайтов..
523
+ *
524
+ * @since 4.0.8 Добавлен
525
+ * @return bool Если true, плагин активирован для сети или в текущий момент активируется для сети.
526
+ */
527
+ public function isNetworkActive() {
528
+ // Makes sure the plugin is defined before trying to use it
529
+ if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
530
+ require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
531
+ }
532
+
533
+ $activate = is_plugin_active_for_network( $this->get_paths()->basename );
534
+
535
+ if ( ! $activate && $this->isNetworkAdmin() && isset( $_GET['action'] ) && $_GET['action'] == 'activate' ) {
536
+ return isset( $_GET['networkwide'] ) && 1 == (int) $_GET['networkwide'];
537
+ }
538
+
539
+ return $activate;
540
+ }
541
+
542
+ /**
543
+ * Позволяет получить все активные сайты сети. Если проект работает в режиме мультисайтов.
544
+ *
545
+ * @since 4.0.8
546
+ * @return array|int
547
+ */
548
+ public function getActiveSites( $args = [ 'archived' => 0, 'mature' => 0, 'spam' => 0, 'deleted' => 0 ] ) {
549
+ global $wp_version;
550
+
551
+ if ( version_compare( $wp_version, '4.6', '>=' ) ) {
552
+ return get_sites( $args );
553
+ } else {
554
+ $converted_array = [];
555
+
556
+ $sites = wp_get_sites( $args );
557
+
558
+ if ( empty( $sites ) ) {
559
+ return $converted_array;
560
+ }
561
+
562
+ foreach ( (array) $sites as $key => $site ) {
563
+ $obj = new stdClass();
564
+ foreach ( $site as $attr => $value ) {
565
+ $obj->$attr = $value;
566
+ }
567
+ $converted_array[ $key ] = $obj;
568
+ }
569
+
570
+ return $converted_array;
571
+ }
572
+ }
573
+ }
libs/factory/core/includes/class-factory-requests.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+ /*
8
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
9
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
10
+ *
11
+ * @package factory-core
12
+ */
13
+
14
+ class Wbcr_Factory424_Request {
15
+
16
+ /**
17
+ * @param null $param
18
+ * @param bool|string $sanitize true/false or sanitize function name
19
+ * @param bool $default
20
+ * @param string $method_name
21
+ *
22
+ * @return array|bool|mixed
23
+ */
24
+ private function getBody( $param = null, $sanitize = false, $default = false, $method_name = 'REQUEST' ) {
25
+ $sanitize_function_name = 'sanitize_text_field';
26
+ $method = $_REQUEST;
27
+
28
+ switch ( strtoupper( $method_name ) ) {
29
+ case 'GET':
30
+ $method = $_GET;
31
+ break;
32
+ case 'POST':
33
+ $method = $_POST;
34
+ break;
35
+ case 'REQUEST':
36
+ $method = $_REQUEST;
37
+ break;
38
+ }
39
+
40
+ if ( ! empty( $sanitize ) && is_string( $sanitize ) && $sanitize !== $sanitize_function_name ) {
41
+ $sanitize_function_name = $sanitize;
42
+ }
43
+
44
+ if ( ! function_exists( $sanitize_function_name ) ) {
45
+ throw new Exception( 'Function ' . $sanitize_function_name . 'is undefined.' );
46
+ }
47
+
48
+ if ( ! empty( $param ) ) {
49
+ if ( isset( $method[ $param ] ) && ! empty( $method[ $param ] ) ) {
50
+ if ( is_array( $method[ $param ] ) ) {
51
+ return ! empty( $sanitize ) ? $this->recursiveArrayMap( $sanitize_function_name, $method[ $param ] ) : $method[ $param ];
52
+ } else {
53
+ return ! empty( $sanitize ) ? call_user_func( $sanitize_function_name, $method[ $param ] ) : $method[ $param ];
54
+ }
55
+ }
56
+
57
+ return $default;
58
+ }
59
+
60
+ return ! empty( $sanitize ) ? array_map( $sanitize_function_name, $method ) : $method;
61
+ }
62
+
63
+ /**
64
+ * Recursive sanitation for an array
65
+ *
66
+ * @param string $function_name
67
+ * @param $array
68
+ *
69
+ * @return mixed
70
+ */
71
+ public function recursiveArrayMap( $function_name, $array ) {
72
+ foreach ( $array as $key => &$value ) {
73
+ if ( is_array( $value ) ) {
74
+ $value = $this->recursiveArrayMap( $function_name, $value );
75
+ } else {
76
+ if ( ! function_exists( $function_name ) ) {
77
+ throw new Exception( 'Function ' . $function_name . 'is undefined.' );
78
+ }
79
+
80
+ $value = $function_name( $value );
81
+ }
82
+ }
83
+
84
+ return $array;
85
+ }
86
+
87
+ /**
88
+ * @param bool|string see method getBody
89
+ * @param array $default
90
+ *
91
+ * @return mixed|null
92
+ */
93
+ public function requestAll( $sanitize = false, $default = [] ) {
94
+ return $this->getBody( null, $sanitize, $default );
95
+ }
96
+
97
+ /**
98
+ * @param $param
99
+ * @param bool|string see method getBody
100
+ * @param bool $default
101
+ *
102
+ * @return mixed|null
103
+ */
104
+ public function request( $param, $default = false, $sanitize = false ) {
105
+ return $this->getBody( $param, $sanitize, $default );
106
+ }
107
+
108
+ /**
109
+ * @param bool|string see method getBody
110
+ * @param array $default
111
+ *
112
+ * @return mixed|null
113
+ */
114
+ public function getAll( $sanitize = false, $default = [] ) {
115
+ return $this->getBody( null, $sanitize, $default, 'get' );
116
+ }
117
+
118
+ /**
119
+ * @param null $param
120
+ * @param bool|string see method getBody
121
+ * @param bool $default
122
+ *
123
+ * @return mixed|null
124
+ */
125
+ public function get( $param, $default = false, $sanitize = false ) {
126
+ return $this->getBody( $param, $sanitize, $default, 'get' );
127
+ }
128
+
129
+ /**
130
+ * @param bool|string see method getBody
131
+ * @param array $default
132
+ *
133
+ * @return mixed|null
134
+ */
135
+ public function postAll( $sanitize = false, $default = [] ) {
136
+ return $this->getBody( null, $sanitize, $default, 'post' );
137
+ }
138
+
139
+ /**
140
+ * @param $param
141
+ * @param bool|string see method getBody
142
+ * @param bool $default
143
+ *
144
+ * @return mixed|null
145
+ */
146
+ public function post( $param, $default = false, $sanitize = false ) {
147
+ return $this->getBody( $param, $sanitize, $default, 'post' );
148
+ }
149
+ }
150
+
libs/factory/core/includes/class-factory-requirements.php ADDED
@@ -0,0 +1,294 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class to check if the current WordPress and PHP versions meet our requirements
5
+ *
6
+ * @see Docs https://webcraftic.atlassian.net/wiki/spaces/FFD/pages/21692485/WFF+Requirements
7
+ *
8
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
9
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
10
+ *
11
+ * @version 2.0.0
12
+ * @since 4.0.9
13
+ */
14
+ // @formatter:off
15
+ if ( ! class_exists( 'Wbcr_Factory424_Requirements' ) ) {
16
+ class Wbcr_Factory424_Requirements {
17
+
18
+ /**
19
+ * Factory framework version
20
+ *
21
+ * @var string
22
+ */
23
+ protected $factory_version;
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ protected $plugin_version;
29
+
30
+ /**
31
+ * Plugin file path
32
+ *
33
+ * @var string
34
+ */
35
+ protected $plugin_file;
36
+
37
+ /**
38
+ * Plugin dir
39
+ *
40
+ * @var string
41
+ */
42
+ protected $plugin_abs_path;
43
+
44
+ /**
45
+ * Plugin base dir
46
+ *
47
+ * @var string
48
+ */
49
+ protected $plugin_basename;
50
+
51
+ /**
52
+ * Plugin url
53
+ *
54
+ * @var string
55
+ */
56
+ protected $plugin_url;
57
+
58
+ /**
59
+ * Plugin prefix
60
+ *
61
+ * @var string
62
+ */
63
+ protected $plugin_prefix;
64
+
65
+ /**
66
+ * Plugin name
67
+ *
68
+ * @var string
69
+ */
70
+ protected $plugin_name;
71
+
72
+ /**
73
+ * Plugin title
74
+ *
75
+ * @var string
76
+ */
77
+ protected $plugin_title = "(no title)";
78
+
79
+ /**
80
+ * @var string
81
+ */
82
+ protected $plugin_text_domain;
83
+
84
+ /**
85
+ * Required PHP version
86
+ *
87
+ * @var string
88
+ */
89
+ protected $required_php_version = '5.3';
90
+
91
+ /**
92
+ * Required WordPress version
93
+ *
94
+ * @var string
95
+ */
96
+ protected $required_wp_version = '4.2.0';
97
+
98
+ /**
99
+ * Is this plugin already activated?
100
+ *
101
+ * @var bool
102
+ */
103
+ protected $plugin_already_activate = false;
104
+
105
+ /**
106
+ * WFF_Requirements constructor.
107
+ *
108
+ * @param string $plugin_file
109
+ * @param array $plugin_info
110
+ */
111
+ public function __construct( $plugin_file, array $plugin_info ) {
112
+
113
+ foreach ( (array) $plugin_info as $property => $value ) {
114
+ if ( property_exists( $this, $property ) ) {
115
+ $this->$property = $value;
116
+ }
117
+ }
118
+
119
+ $this->plugin_file = $plugin_file;
120
+ $this->plugin_abs_path = dirname( $plugin_file );
121
+ $this->plugin_basename = plugin_basename( $plugin_file );
122
+ $this->plugin_url = plugins_url( null, $plugin_file );
123
+
124
+ $plugin_info = get_file_data( $this->plugin_file, array(
125
+ 'Version' => 'Version',
126
+ 'FrameworkVersion' => 'Framework Version',
127
+ 'TextDomain' => 'Text Domain'
128
+ ), 'plugin' );
129
+
130
+ if ( isset( $plugin_info['FrameworkVersion'] ) ) {
131
+ $this->factory_version = $plugin_info['FrameworkVersion'];
132
+ }
133
+
134
+ if ( isset( $plugin_info['Version'] ) ) {
135
+ $this->plugin_version = $plugin_info['Version'];
136
+ }
137
+
138
+ if ( isset( $plugin_info['TextDomain'] ) ) {
139
+ $this->plugin_text_domain = $plugin_info['TextDomain'];
140
+ }
141
+
142
+ add_action( 'admin_init', array( $this, 'register_notices' ) );
143
+ }
144
+
145
+ public function get_plugin_version() {
146
+ return $this->plugin_version;
147
+ }
148
+
149
+ public function get_text_domain() {
150
+ return $this->plugin_text_domain;
151
+ }
152
+
153
+ /**
154
+ * @since 4.1.1
155
+ * @return void
156
+ */
157
+ public function register_notices() {
158
+ if ( current_user_can( 'activate_plugins' ) && current_user_can( 'edit_plugins' ) && current_user_can( 'install_plugins' ) ) {
159
+
160
+ if ( is_multisite() ) {
161
+ add_action( 'network_admin_notices', array( $this, 'show_notice' ) );
162
+
163
+ if ( ! empty( $this->plugin_basename ) && in_array( $this->plugin_basename, (array) get_option( 'active_plugins', array() ) ) ) {
164
+ add_action( 'admin_notices', array( $this, 'show_notice' ) );
165
+ }
166
+ } else {
167
+ add_action( 'admin_notices', array( $this, 'show_notice' ) );
168
+ }
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Shows the incompatibility notification.
174
+ *
175
+ * @since 4.1.1
176
+ * @return void
177
+ */
178
+ public function show_notice() {
179
+ if ( $this->check() ) {
180
+ return;
181
+ }
182
+
183
+ echo '<div class="notice notice-error"><p>' . $this->get_notice_text() . '</p></div>';
184
+ }
185
+
186
+
187
+ /**
188
+ * The method checks the compatibility of the plugin with php and wordpress version.
189
+ *
190
+ * @since 4.1.1
191
+ * @return bool
192
+ */
193
+ public function check() {
194
+
195
+ // Fix for ithemes sync. When the ithemes sync plugin accepts the request, set the WP_ADMIN constant,
196
+ // after which the plugin Clearfy begins to create errors, and how the logic of its work is broken.
197
+ // Solution to simply terminate the plugin if there is a request from ithemes sync
198
+ // --------------------------------------
199
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'ithemes_sync_request' ) {
200
+ return false;
201
+ }
202
+
203
+ if ( isset( $_GET['ithemes-sync-request'] ) && ! empty( $_GET['ithemes-sync-request'] ) ) {
204
+ return false;
205
+ }
206
+ // ----------------------------------------
207
+
208
+ if ( ! $this->check_php_compat() || ! $this->check_wp_compat() || $this->plugin_already_activate ) {
209
+ return false;
210
+ }
211
+
212
+ return true;
213
+ }
214
+
215
+ /**
216
+ * The method checks the compatibility of the plugin with the php version of the server.
217
+ *
218
+ * @return mixed
219
+ */
220
+ public function check_php_compat() {
221
+ return version_compare( PHP_VERSION, $this->required_php_version, '>=' );
222
+ }
223
+
224
+ /**
225
+ * The method checks the compatibility of the plugin with the Wordpress version of the site.
226
+ *
227
+ * @return mixed
228
+ */
229
+ public function check_wp_compat() {
230
+ // Get the WP Version global.
231
+ global $wp_version;
232
+
233
+ return version_compare( $wp_version, $this->required_wp_version, '>=' );
234
+ }
235
+
236
+ /**
237
+ * Method returns notification text
238
+ *
239
+ * @return string
240
+ */
241
+ protected function get_notice_text() {
242
+ $notice_text = $notice_default_text = '';
243
+ $notice_default_text .= '<b>' . $this->plugin_title . ' ' . __( 'warning', '' ) . ':</b>' . '<br>';
244
+
245
+ $notice_default_text .= sprintf( __( 'The %s plugin has stopped.', 'wbcr_factory_clearfy_216' ), $this->plugin_title ) . ' ';
246
+ $notice_default_text .= __( 'Possible reasons:', '' ) . ' <br>';
247
+
248
+ $has_one = false;
249
+
250
+ if ( ! $this->check_php_compat() ) {
251
+ $has_one = true;
252
+ $notice_text .= '- ' . $this->get_php_incompat_text() . '<br>';
253
+ }
254
+
255
+ if ( ! $this->check_wp_compat() ) {
256
+ $has_one = true;
257
+ $notice_text .= '- ' . $this->get_wp_incompat_text() . '<br>';
258
+ }
259
+
260
+ if ( $this->plugin_already_activate ) {
261
+ $has_one = true;
262
+ $notice_text = '- ' . $this->get_plugin_already_activate_text() . '<br>';
263
+ }
264
+
265
+ if ( $has_one ) {
266
+ $notice_text = $notice_default_text . $notice_text;
267
+ }
268
+
269
+ return $notice_text;
270
+ }
271
+
272
+ /**
273
+ * @return string
274
+ */
275
+ protected function get_php_incompat_text() {
276
+ return sprintf( __( 'You need to update the PHP version to %s or higher!', 'wbcr_factory_424' ), $this->required_php_version );
277
+ }
278
+
279
+ /**
280
+ * @return string
281
+ */
282
+ protected function get_wp_incompat_text() {
283
+ return sprintf( __( 'You need to update WordPress to %s or higher!', 'wbcr_factory_424' ), $this->required_wp_version );
284
+ }
285
+
286
+ /**
287
+ * @return string
288
+ */
289
+ protected function get_plugin_already_activate_text() {
290
+ return sprintf( __( 'Plugin %s is already activated, you are trying to activate it again.', 'wbcr_factory_424' ), $this->plugin_title );
291
+ }
292
+ }
293
+ }
294
+ // @formatter:on
libs/factory/core/includes/entities/class-factory-paths.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424\Entities;
4
+
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
+ }
8
+
9
+ /*
10
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
11
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
12
+ * @since 4.1.1
13
+ */
14
+
15
+ class Paths {
16
+
17
+ public $absolute;
18
+ public $main_file;
19
+ public $relative;
20
+ public $url;
21
+
22
+ protected $plugin_path;
23
+
24
+ public function __construct( $plugin_file ) {
25
+ $this->plugin_path = $plugin_file;
26
+
27
+ $this->main_file = $plugin_file;
28
+ $this->absolute = dirname( $plugin_file );
29
+ $this->basename = plugin_basename( $plugin_file );
30
+ $this->url = plugins_url( null, $plugin_file );
31
+ $this->migrations = $this->absolute . '/migrations';
32
+ }
33
+ }
libs/factory/core/includes/entities/class-factory-support.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424\Entities;
4
+
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
+ }
8
+
9
+ /*
10
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
11
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
12
+ * @since 4.1.1
13
+ */
14
+
15
+ class Support {
16
+
17
+ protected $plugin_name;
18
+ protected $site_url;
19
+
20
+ protected $features_page_slug = 'premium-features';
21
+ protected $pricing_page_slug = 'pricing';
22
+ protected $support_page_slug = 'support';
23
+ protected $docs_page_slug = 'docs';
24
+
25
+ /**
26
+ * Plugin_Site constructor.
27
+ *
28
+ * @param array $data
29
+ */
30
+ public function __construct( array $data ) {
31
+ $this->site_url = isset( $data['url'] ) ? $data['url'] : null;
32
+
33
+ if ( isset( $data['pages_map'] ) && is_array( $data['pages_map'] ) ) {
34
+ foreach ( $data['pages_map'] as $key => $def_value ) {
35
+ $attr = $key . '_page_slug';
36
+ $this->{$attr} = isset( $data[ $key ] ) ? $data[ $key ] : $def_value;
37
+ }
38
+ }
39
+ }
40
+
41
+ /**
42
+ * @return string
43
+ */
44
+ public function get_site_url( $track = false, $utm_content = null ) {
45
+ if ( $track ) {
46
+ return $this->get_tracking_page_url( $this->site_url, $utm_content );
47
+ }
48
+
49
+ return $this->site_url;
50
+ }
51
+
52
+
53
+ /**
54
+ * @return string
55
+ */
56
+ public function get_features_url( $track = false, $utm_content = null ) {
57
+ if ( $track ) {
58
+ return $this->get_tracking_page_url( $this->features_page_slug, $utm_content );
59
+ }
60
+
61
+ return $this->get_site_url() . '/' . $this->features_page_slug;
62
+ }
63
+
64
+
65
+ /**
66
+ * @return string
67
+ */
68
+ public function get_pricing_url( $track = false, $utm_content = null ) {
69
+ if ( $track ) {
70
+ return $this->get_tracking_page_url( $this->pricing_page_slug, $utm_content );
71
+ }
72
+
73
+ return $this->get_site_url() . '/' . $this->pricing_page_slug;
74
+ }
75
+
76
+
77
+ /**
78
+ * @return string
79
+ */
80
+ public function get_contacts_url( $track = false, $utm_content = null ) {
81
+ if ( $track ) {
82
+ return $this->get_tracking_page_url( $this->support_page_slug, $utm_content );
83
+ }
84
+
85
+ return $this->get_site_url() . '/' . $this->support_page_slug;
86
+ }
87
+
88
+
89
+ /**
90
+ * @return string
91
+ */
92
+ public function get_docs_url( $track = false, $utm_content = null ) {
93
+ if ( $track ) {
94
+ return $this->get_tracking_page_url( $this->docs_page_slug, $utm_content );
95
+ }
96
+
97
+ return $this->get_site_url() . '/' . $this->docs_page_slug;
98
+ }
99
+
100
+
101
+ /**
102
+ * @param null $page
103
+ * @param null $utm_content
104
+ * @param string $urm_source
105
+ *
106
+ * @return string
107
+ */
108
+ public function get_tracking_page_url( $page = null, $utm_content = null, $urm_source = 'wordpress.org' ) {
109
+
110
+ $args = [ 'utm_source' => $urm_source ];
111
+
112
+ if ( ! empty( $plugin_name ) ) {
113
+ $args['utm_campaign'] = $plugin_name;
114
+ }
115
+
116
+ if ( ! empty( $utm_content ) ) {
117
+ $args['utm_content'] = $utm_content;
118
+ }
119
+
120
+ $raw_url = add_query_arg( $args, $this->get_site_url() . '/' . $page . '/' );
121
+
122
+ return esc_url( $raw_url );
123
+ }
124
+ }
libs/factory/core/includes/functions.php ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Factory Function Library
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
6
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
7
+ *
8
+ * @package factory-core
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ if ( ! function_exists( 'get_user_locale' ) ) {
18
+ function get_user_locale( $user_id = 0 ) {
19
+ $user = false;
20
+ if ( 0 === $user_id && function_exists( 'wp_get_current_user' ) ) {
21
+ $user = wp_get_current_user();
22
+ } else if ( $user_id instanceof WP_User ) {
23
+ $user = $user_id;
24
+ } else if ( $user_id && is_numeric( $user_id ) ) {
25
+ $user = get_user_by( 'id', $user_id );
26
+ }
27
+
28
+ if ( ! $user ) {
29
+ return get_locale();
30
+ }
31
+
32
+ $locale = $user->locale;
33
+
34
+ return $locale ? $locale : get_locale();
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Fires functions attached to a deprecated filter hook.
40
+ *
41
+ * When a filter hook is deprecated, the apply_filters() call is replaced with
42
+ * apply_filters_deprecated(), which triggers a deprecation notice and then fires
43
+ * the original filter hook.
44
+ *
45
+ * This is a copy of `apply_filters_deprecated` introduced in WP 4.6.
46
+ *
47
+ * @since 1.0.0
48
+ *
49
+ * @param string $tag The name of the filter hook.
50
+ * @param array $args Array of additional function arguments to be passed to apply_filters().
51
+ * @param string $version The version of BP Block Users that deprecated the hook.
52
+ * @param string $replacement Optional. The hook that should have been used.
53
+ * @param string $message Optional. A message regarding the change.
54
+ *
55
+ * @return mixed
56
+ * @see wbcr_factory_424_deprecated_hook()
57
+ *
58
+ */
59
+ function wbcr_factory_424_apply_filters_deprecated( $tag, $args, $version, $replacement = false, $message = null ) {
60
+ if ( function_exists( 'apply_filters_deprecated' ) ) {
61
+ return apply_filters_deprecated( $tag, $args, $version, $replacement, $message );
62
+ }
63
+ if ( ! has_filter( $tag ) ) {
64
+ return $args[0];
65
+ }
66
+ wbcr_factory_424_deprecated_hook( $tag, $version, $replacement, $message );
67
+
68
+ return apply_filters_ref_array( $tag, $args );
69
+ }
70
+
71
+ /**
72
+ * Fires functions attached to a deprecated action hook.
73
+ *
74
+ * When an action hook is deprecated, the do_action() call is replaced with
75
+ * do_action_deprecated(), which triggers a deprecation notice and then fires
76
+ * the original hook.
77
+ *
78
+ * This is a copy of `do_action_deprecated` introduced in WP 4.6.
79
+ *
80
+ * @since 1.0.0
81
+ *
82
+ * @param string $tag The name of the action hook.
83
+ * @param array $args Array of additional function arguments to be passed to do_action().
84
+ * @param string $version The version of BP Block Users that deprecated the hook.
85
+ * @param string $replacement Optional. The hook that should have been used.
86
+ * @param string $message Optional. A message regarding the change.
87
+ *
88
+ * @return void
89
+ * @see _deprecated_hook()
90
+ *
91
+ */
92
+ function wbcr_factory_424_do_action_deprecated( $tag, $args, $version, $replacement = false, $message = null ) {
93
+ if ( function_exists( 'do_action_deprecated' ) ) {
94
+ do_action_deprecated( $tag, $args, $version, $replacement, $message );
95
+
96
+ return;
97
+ }
98
+ if ( ! has_action( $tag ) ) {
99
+ return;
100
+ }
101
+ wbcr_factory_424_deprecated_hook( $tag, $version, $replacement, $message );
102
+ do_action_ref_array( $tag, $args );
103
+ }
104
+
105
+ /**
106
+ * Marks a deprecated action or filter hook as deprecated and throws a notice.
107
+ *
108
+ * Use the 'wbcr_factory_424_deprecated_hook_run' action to get the backtrace describing where the
109
+ * deprecated hook was called.
110
+ *
111
+ * Default behavior is to trigger a user error if WP_DEBUG is true.
112
+ *
113
+ * This function is called by the do_action_deprecated() and apply_filters_deprecated()
114
+ * functions, and so generally does not need to be called directly.
115
+ *
116
+ * This is a copy of `_deprecated_hook` introduced in WP 4.6.
117
+ *
118
+ * @since 1.0.0
119
+ * @access private
120
+ *
121
+ * @param string $hook The hook that was used.
122
+ * @param string $version The version of WordPress that deprecated the hook.
123
+ * @param string $replacement Optional. The hook that should have been used.
124
+ * @param string $message Optional. A message regarding the change.
125
+ */
126
+ function wbcr_factory_424_deprecated_hook( $hook, $version, $replacement = null, $message = null ) {
127
+ /**
128
+ * Fires when a deprecated hook is called.
129
+ *
130
+ * @since 1.0.0
131
+ *
132
+ * @param string $hook The hook that was called.
133
+ * @param string $replacement The hook that should be used as a replacement.
134
+ * @param string $version The version of BP Block Users that deprecated the argument used.
135
+ * @param string $message A message regarding the change.
136
+ */
137
+ do_action( 'deprecated_hook_run', $hook, $replacement, $version, $message );
138
+
139
+ /**
140
+ * Filter whether to trigger deprecated hook errors.
141
+ *
142
+ * @since 1.0.0
143
+ *
144
+ * @param bool $trigger Whether to trigger deprecated hook errors. Requires
145
+ * `WP_DEBUG` to be defined true.
146
+ */
147
+ if ( WP_DEBUG && apply_filters( 'deprecated_hook_trigger_error', true ) ) {
148
+ $message = empty( $message ) ? '' : ' ' . $message;
149
+ if ( ! is_null( $replacement ) ) {
150
+ trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ), $hook, $version, $replacement ) . $message );
151
+ } else {
152
+ trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ), $hook, $version ) . $message );
153
+ }
154
+ }
155
+ }
156
+
157
+ if ( ! function_exists( '_sanitize_text_fields' ) ) {
158
+ function _sanitize_text_fields( $str, $keep_newlines = false ) {
159
+ $filtered = wp_check_invalid_utf8( $str );
160
+
161
+ if ( strpos( $filtered, '<' ) !== false ) {
162
+ $filtered = wp_pre_kses_less_than( $filtered );
163
+ // This will strip extra whitespace for us.
164
+ $filtered = wp_strip_all_tags( $filtered, false );
165
+
166
+ // Use html entities in a special case to make sure no later
167
+ // newline stripping stage could lead to a functional tag
168
+ $filtered = str_replace( "<\n", "&lt;\n", $filtered );
169
+ }
170
+
171
+ if ( ! $keep_newlines ) {
172
+ $filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered );
173
+ }
174
+ $filtered = trim( $filtered );
175
+
176
+ $found = false;
177
+ while( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match ) ) {
178
+ $filtered = str_replace( $match[0], '', $filtered );
179
+ $found = true;
180
+ }
181
+
182
+ if ( $found ) {
183
+ // Strip out the whitespace that may now exist after removing the octets.
184
+ $filtered = trim( preg_replace( '/ +/', ' ', $filtered ) );
185
+ }
186
+
187
+ return $filtered;
188
+ }
189
+ }
190
+
191
+ if ( ! function_exists( 'sanitize_textarea_field' ) ) {
192
+ function sanitize_textarea_field( $str ) {
193
+ $filtered = _sanitize_text_fields( $str, true );
194
+
195
+ /**
196
+ * Filters a sanitized textarea field string.
197
+ *
198
+ * @since 4.7.0
199
+ *
200
+ * @param string $filtered The sanitized string.
201
+ * @param string $str The string prior to being sanitized.
202
+ */
203
+ return apply_filters( 'sanitize_textarea_field', $filtered, $str );
204
+ }
205
+ }
libs/factory/core/includes/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/core/includes/premium/class-factory-license-interface.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424\Premium\Interfaces;
4
+
5
+ // Exit if accessed directly
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ /**
11
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
12
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
13
+ * @copyright (c) 2018 Webraftic Ltd
14
+ * @version 1.0
15
+ */
16
+ interface License {
17
+
18
+ public function get_key();
19
+
20
+ public function get_hidden_key();
21
+
22
+ public function get_expiration_time( $format = 'time' );
23
+
24
+ public function get_sites_quota();
25
+
26
+ public function get_count_active_sites();
27
+
28
+ public function is_valid();
29
+
30
+ public function is_lifetime();
31
+
32
+ }
libs/factory/core/includes/premium/class-factory-manager.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424\Premium;
4
+
5
+ use Exception;
6
+ use Wbcr_Factory424_Plugin;
7
+
8
+ // Exit if accessed directly
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
15
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
16
+ */
17
+ class Manager {
18
+
19
+ /**
20
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
21
+ * @since 4.1.6
22
+ * @var array
23
+ */
24
+ public static $providers;
25
+
26
+ /**
27
+ * @var Wbcr_Factory424_Plugin
28
+ */
29
+ protected $plugin;
30
+
31
+ /**
32
+ * @var array
33
+ */
34
+ protected $settings;
35
+
36
+ /**
37
+ * Manager constructor.
38
+ *
39
+ * @param Wbcr_Factory424_Plugin $plugin
40
+ * @param array $settings
41
+ *
42
+ * @throws Exception
43
+ */
44
+ public function __construct( Wbcr_Factory424_Plugin $plugin, array $settings ) {
45
+ $this->plugin = $plugin;
46
+ $this->settings = $settings;
47
+ }
48
+
49
+ /**
50
+ * @param Wbcr_Factory424_Plugin $plugin
51
+ * @param array $settings
52
+ *
53
+ * @return \WBCR\Factory_Freemius_112\Premium\Provider
54
+ * @throws Exception
55
+ */
56
+ public static function instance( Wbcr_Factory424_Plugin $plugin, array $settings ) {
57
+ $premium_manager = new Manager( $plugin, $settings );
58
+
59
+ return $premium_manager->instance_provider();
60
+ }
61
+
62
+ /**
63
+ * @param $provider_name
64
+ *
65
+ * @return \WBCR\Factory_Freemius_112\Premium\Provider
66
+ * @throws Exception
67
+ */
68
+ public function instance_provider() {
69
+ $provider_name = $this->get_setting( 'provider' );
70
+
71
+ if ( isset( self::$providers[ $provider_name ] ) && class_exists( self::$providers[ $provider_name ] ) ) {
72
+ if ( self::$providers[ $provider_name ] instanceof Provider ) {
73
+ throw new Exception( "Provider {$provider_name} must extend the class WBCR\Factory_424\Premium\Provider interface!" );
74
+ }
75
+
76
+ return new self::$providers[ $provider_name ]( $this->plugin, $this->settings );
77
+ }
78
+
79
+ throw new Exception( "Provider {$provider_name} is not supported!" );
80
+ }
81
+
82
+ /**
83
+ * @param string $name
84
+ *
85
+ * @return mixed
86
+ */
87
+ protected function get_setting( $name ) {
88
+ return isset( $this->settings[ $name ] ) ? $this->settings[ $name ] : null;
89
+ }
90
+ }
libs/factory/core/includes/premium/class-factory-provider-abstract.php ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424\Premium;
4
+
5
+ use Exception;
6
+ use Wbcr_Factory424_Plugin;
7
+
8
+ // Exit if accessed directly
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Выполняет проверку обновлений, обновления, скачивание плагинов
15
+ *
16
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
17
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
18
+ *
19
+ * @version 1.0
20
+ */
21
+ abstract class Provider {
22
+
23
+ /**
24
+ * @var Wbcr_Factory424_Plugin
25
+ */
26
+ protected $plugin;
27
+
28
+ /**
29
+ * @var array
30
+ */
31
+ protected $settings;
32
+
33
+ /**
34
+ * @var bool
35
+ */
36
+ private $is_install_package;
37
+
38
+ /**
39
+ * Provider constructor.
40
+ *
41
+ * @param Wbcr_Factory424_Plugin $plugin
42
+ * @param array $settings
43
+ */
44
+ public function __construct( Wbcr_Factory424_Plugin $plugin, array $settings ) {
45
+ $this->plugin = $plugin;
46
+ $this->settings = $settings;
47
+
48
+ $this->register_hooks();
49
+ }
50
+
51
+ /**
52
+ * @return array
53
+ */
54
+ public function get_settings() {
55
+ return $this->settings;
56
+ }
57
+
58
+ /**
59
+ * @param $name
60
+ * @param bool $default
61
+ *
62
+ * @return bool|mixed
63
+ */
64
+ public function get_setting( $name, $default = false ) {
65
+ return isset( $this->settings[ $name ] ) && ! empty( $this->settings[ $name ] ) ? $this->settings[ $name ] : $default;
66
+ }
67
+
68
+ /**
69
+ * @return bool|mixed
70
+ */
71
+ public function get_price() {
72
+ return $this->get_setting( 'price' );
73
+ }
74
+
75
+ /**
76
+ * @return bool
77
+ */
78
+ public function is_install_package() {
79
+ if ( ! is_null( $this->is_install_package ) ) {
80
+ return $this->is_install_package;
81
+ }
82
+
83
+ $premium_package = $this->get_package_data();
84
+
85
+ if ( ! empty( $premium_package ) && ! empty( $premium_package['basename'] ) ) {
86
+ $basename_part = explode( '/', $premium_package['basename'] );
87
+ $is_valid_basename = sizeof( $basename_part ) === 2;
88
+
89
+ if ( $is_valid_basename && ! file_exists( WP_PLUGIN_DIR . '/' . $premium_package['basename'] ) ) {
90
+ $this->delete_package();
91
+ $this->is_install_package = false;
92
+
93
+ return false;
94
+ }
95
+ }
96
+
97
+ $this->is_install_package = ! empty( $premium_package );
98
+
99
+ return $this->is_install_package;
100
+ }
101
+
102
+ /**
103
+ * @return bool|mixed|null
104
+ */
105
+ public function get_package_data() {
106
+ $premium_package = $this->plugin->getPopulateOption( 'premium_package' );
107
+
108
+ if ( ! empty( $premium_package ) ) {
109
+ return wp_parse_args( $premium_package, [
110
+ 'basename' => null,
111
+ 'version' => null,
112
+ 'framework_version' => null
113
+ ] );
114
+ }
115
+
116
+ return null;
117
+ }
118
+
119
+ /**
120
+ * @param $plugin_data
121
+ *
122
+ * @throws Exception
123
+ */
124
+ public function update_package_data( array $package ) {
125
+ $parsed_args = wp_parse_args( $package, [
126
+ 'basename' => null,
127
+ 'version' => null,
128
+ 'framework_version' => null
129
+ ] );
130
+
131
+ if ( empty( $parsed_args['basename'] ) || empty( $parsed_args['version'] ) ) {
132
+ throw new Exception( 'You must pass the required attributes (basename, version).' );
133
+ }
134
+
135
+ $this->plugin->updatePopulateOption( 'premium_package', $parsed_args );
136
+ $this->is_install_package = true;
137
+ }
138
+
139
+ public function delete_package() {
140
+ $this->plugin->deletePopulateOption( 'premium_package' );
141
+ $this->is_install_package = false;
142
+ }
143
+
144
+ protected function register_hooks() {
145
+ /**
146
+ * Добавляет крон задачу на синхронизацию лицензии
147
+ *
148
+ * @param array $license_info
149
+ * @param string $provider
150
+ */
151
+ add_action( "{$this->plugin->getPluginName()}/factory/premium/license_activate", function ( $provider, $license_info ) {
152
+ if ( ! wp_next_scheduled( "{$this->plugin->getPluginName()}_license_autosync" ) ) {
153
+ wp_schedule_event( time(), 'twicedaily', "{$this->plugin->getPluginName()}_license_autosync" );
154
+ }
155
+ }, 10, 2 );
156
+
157
+ /**
158
+ * Удаляет крон задачу на синхронизацию лицензии, когда лицензия деактивирована
159
+ *
160
+ * @param array $license_info
161
+ * @param string $provider
162
+ */
163
+ add_action( "{$this->plugin->getPluginName()}/factory/premium/license_deactivate", function ( $provider, $license_info ) {
164
+ if ( wp_next_scheduled( "{$this->plugin->getPluginName()}_license_autosync" ) ) {
165
+ wp_clear_scheduled_hook( "{$this->plugin->getPluginName()}_license_autosync" );
166
+ }
167
+ }, 10, 2 );
168
+
169
+ /**
170
+ * Обработчик крон задачи на синхронизацию лицензии, выполняется 2 раза в день.
171
+ */
172
+ add_action( "{$this->plugin->getPluginName()}_license_autosync", function () {
173
+ $this->sync();
174
+ } );
175
+ }
176
+
177
+ /**
178
+ * @return bool
179
+ */
180
+ abstract public function is_activate();
181
+
182
+ /**
183
+ * @return bool
184
+ */
185
+ abstract public function is_active();
186
+
187
+ /**
188
+ * @return string|null
189
+ */
190
+ abstract public function get_plan();
191
+
192
+ /**
193
+ * @return string|null
194
+ */
195
+ abstract public function get_billing_cycle();
196
+
197
+ /**
198
+ * @return \WBCR\Factory_424\Premium\Interfaces\License
199
+ */
200
+ abstract public function get_license();
201
+
202
+ /**
203
+ * @return string|null
204
+ */
205
+ abstract public function get_package_download_url();
206
+
207
+ /**
208
+ * @param string $key
209
+ *
210
+ * @return mixed
211
+ */
212
+ abstract public function activate( $key );
213
+
214
+ /**
215
+ * @return bool
216
+ */
217
+ abstract public function deactivate();
218
+
219
+ /**
220
+ * @return bool
221
+ */
222
+ abstract public function sync();
223
+
224
+ /**
225
+ * @return bool
226
+ */
227
+ abstract public function has_paid_subscription();
228
+
229
+ /**
230
+ * @return bool
231
+ */
232
+ abstract public function cancel_paid_subscription();
233
+
234
+ }
libs/factory/core/includes/premium/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/core/includes/updates/class-factory-premium-upgrader.php ADDED
@@ -0,0 +1,792 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424\Updates;
4
+
5
+ use Exception;
6
+ use Plugin_Installer_Skin;
7
+ use Plugin_Upgrader;
8
+ use Wbcr_Factory424_Plugin;
9
+ use Wbcr_FactoryPages424_ImpressiveThemplate;
10
+ use WP_Filesystem_Base;
11
+ use WP_Upgrader;
12
+ use WP_Upgrader_Skin;
13
+
14
+ // Exit if accessed directly
15
+ if ( ! defined( 'ABSPATH' ) ) {
16
+ exit;
17
+ }
18
+
19
+ /**
20
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
21
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
22
+ * @copyright (c) 2018 Webraftic Ltd
23
+ * @version 1.0
24
+ */
25
+ class Premium_Upgrader extends Upgrader {
26
+
27
+ /**
28
+ * Тип апгрейдера, может быть default, premium
29
+ *
30
+ * @var string
31
+ */
32
+ protected $type = 'premium';
33
+
34
+ /**
35
+ * Manager constructor.
36
+ *
37
+ * @since 4.1.1
38
+ *
39
+ * @param $args
40
+ * @param bool $is_premium
41
+ *
42
+ * @param Wbcr_Factory424_Plugin $plugin
43
+ *
44
+ * @throws Exception
45
+ */
46
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
47
+ parent::__construct( $plugin );
48
+
49
+ $this->plugin_basename = null;
50
+ $this->plugin_main_file = null;
51
+ $this->plugin_absolute_path = null;
52
+
53
+ if ( $this->plugin->premium->is_activate() && $this->plugin->premium->is_install_package() ) {
54
+ $premium_package = $this->plugin->premium->get_package_data();
55
+
56
+ if ( $premium_package ) {
57
+ $this->plugin_basename = $premium_package['basename'];
58
+ $this->plugin_main_file = WP_PLUGIN_DIR . '/' . $premium_package['basename'];
59
+ $this->plugin_absolute_path = dirname( WP_PLUGIN_DIR . '/' . $premium_package['basename'] );
60
+ }
61
+ }
62
+
63
+ if ( ! $this->repository->is_support_premium() ) {
64
+ $settings = $this->get_settings();
65
+ throw new Exception( "Repository {$settings['repository']} does not have support premium." );
66
+ }
67
+ }
68
+
69
+ /**
70
+ * @throws Exception
71
+ */
72
+ protected function set_repository() {
73
+ $settings = $this->get_settings();
74
+ $this->repository = $this->get_repository( $settings['repository'] );
75
+
76
+ if ( $this->plugin->premium->is_activate() ) {
77
+ $this->repository->init();
78
+ }
79
+ }
80
+
81
+ /**
82
+ * @since 4.1.1
83
+ * @throws Exception
84
+ */
85
+ protected function init_hooks() {
86
+ parent::init_hooks();
87
+
88
+ if ( $this->need_intall_or_activate_premium() || $this->need_renew_license() || $this->need_activate_license() ) {
89
+ // Показываем уведомление под бесплатным плагином, если требуется установить или активировать премиум пакет
90
+ if ( $this->need_intall_or_activate_premium() ) {
91
+ $free_plugin_base = $this->plugin->get_paths()->basename;
92
+
93
+ add_action( "after_plugin_row_{$free_plugin_base}", [ $this, "notice_in_plugin_row" ], 100, 3 );
94
+ }
95
+
96
+ // Если установлен премиум пакет, то показываем уведомление под премиум плагином.
97
+ if ( ( $this->need_renew_license() || $this->need_activate_license() ) && $this->plugin->premium->is_install_package() ) {
98
+ $package = $this->plugin->premium->get_package_data();
99
+ $premium_plugin_base = $package['basename'];
100
+
101
+ add_action( "after_plugin_row_{$premium_plugin_base}", [ $this, "notice_in_plugin_row" ], 100, 3 );
102
+ }
103
+
104
+ add_action( "admin_print_styles-plugins.php", [ $this, "print_styles_for_plugin_row" ] );
105
+ add_action( "wbcr/factory/admin_notices", [ $this, "admin_notices_hook" ], 10, 2 );
106
+ add_action( 'wbcr/factory/pages/impressive/print_all_notices', [
107
+ $this,
108
+ 'install_notice_in_plugin_interface'
109
+ ], 10, 2 );
110
+ }
111
+
112
+ add_action( 'admin_init', [ $this, 'init_admin_actions' ] );
113
+
114
+ add_action( 'deleted_plugin', [ $this, 'delete_plugin_hook' ], 10, 2 );
115
+ add_action( 'upgrader_process_complete', [ $this, 'upgrader_process_complete_hook' ], 10, 2 );
116
+ }
117
+
118
+ /**
119
+ * @since 4.2.2 Fixed bug with plugins namespace (ISW-4)
120
+ * @since 4.1.1
121
+ */
122
+ public function init_admin_actions() {
123
+ $plugin_slug = $this->plugin->request->get( 'wfactory_premium_updates_plugin', null );
124
+
125
+ if ( isset( $_GET['wfactory_premium_updates_action'] ) && $this->plugin_slug === $plugin_slug ) {
126
+ $action = $this->plugin->request->get( 'wfactory_premium_updates_action' );
127
+
128
+ check_admin_referer( "factory_premium_{$action}" );
129
+ try {
130
+ switch ( $action ) {
131
+ case 'install':
132
+ $this->install();
133
+ break;
134
+ case 'deactivate':
135
+ $this->deactivate();
136
+ break;
137
+ case 'delete':
138
+ $this->delete();
139
+ break;
140
+ case 'check_updates':
141
+ $this->check_updates();
142
+ break;
143
+ case 'cancel_license':
144
+ $this->plugin->premium->deactivate();
145
+
146
+ break;
147
+ }
148
+ } catch( Exception $e ) {
149
+ wp_die( $e->getMessage() );
150
+ }
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Удаляет данные о пакете, если пользовать удалил премиум плагин
156
+ *
157
+ * @since 4.1.1
158
+ *
159
+ * @param $success
160
+ *
161
+ * @param $plugin_basename
162
+ */
163
+ public function delete_plugin_hook( $plugin_basename, $success ) {
164
+ if ( ! $this->plugin->premium->is_install_package() ) {
165
+ return;
166
+ }
167
+
168
+ $package = $this->plugin->premium->get_package_data();
169
+
170
+ if ( $package['basename'] == $plugin_basename && $success ) {
171
+ $this->plugin->premium->delete_package();
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Выводит уведомление на всех страницах админ панели Wordpress
177
+ *
178
+ * @since 4.1.1
179
+ *
180
+ * @param $notices
181
+ *
182
+ * @return array
183
+ */
184
+ public function admin_notices_hook( $notices, $plugin_name ) {
185
+
186
+ if ( $plugin_name !== $this->plugin->getPluginName() || ! current_user_can( 'update_plugins' ) ) {
187
+ return $notices;
188
+ }
189
+
190
+ if ( $this->need_intall_or_activate_premium() ) {
191
+ $notice_text = $this->get_notice_text( 'please_activate_premium' );
192
+
193
+ if ( ! $this->plugin->premium->is_install_package() ) {
194
+ $notice_text = $this->get_notice_text( 'please_install_premium' );
195
+ }
196
+
197
+ $notices[] = [
198
+ 'id' => 'please_install_premium_for_' . $this->plugin->getPluginName(),
199
+ 'type' => 'warning',
200
+ 'dismissible' => false,
201
+ 'dismiss_expires' => 0,
202
+ 'text' => "<p><b>{$this->plugin->getPluginTitle()}:</b> " . $notice_text . '</p>'
203
+ ];
204
+ } else if ( $this->need_activate_license() ) {
205
+ $notices[] = [
206
+ 'id' => 'need_activate_premium_for_' . $this->plugin->getPluginName(),
207
+ 'type' => 'warning',
208
+ 'dismissible' => false,
209
+ 'dismiss_expires' => 0,
210
+ 'text' => "<p><b>{$this->plugin->getPluginTitle()}:</b> " . $this->get_notice_text( 'need_activate_license' ) . '</p>'
211
+ ];
212
+ } else if ( $this->need_renew_license() ) {
213
+ // todo: может быть перенести уведомление в премиум менеджер?
214
+ $notices[] = [
215
+ 'id' => 'license_exired_for_' . $this->plugin->getPluginName(),
216
+ 'type' => 'warning',
217
+ 'dismissible' => false,
218
+ 'dismiss_expires' => 0,
219
+ 'text' => "<p><b>{$this->plugin->getPluginTitle()}:</b> " . $this->get_notice_text( 'need_renew_license' ) . '</p>'
220
+ ];
221
+ }
222
+
223
+ return $notices;
224
+ }
225
+
226
+ /**
227
+ * Выводит уведомление внутри интерфейса плагина, на всех страницах плагина.
228
+ *
229
+ * @since 4.1.1
230
+ *
231
+ * @param Wbcr_FactoryPages424_ImpressiveThemplate $obj
232
+ *
233
+ * @param Wbcr_Factory424_Plugin $plugin
234
+ *
235
+ * @return void
236
+ */
237
+ public function install_notice_in_plugin_interface( $plugin, $obj ) {
238
+ if ( $plugin->getPluginName() != $this->plugin->getPluginName() ) {
239
+ return;
240
+ }
241
+
242
+ $notice_text = '';
243
+
244
+ if ( $this->need_intall_or_activate_premium() ) {
245
+ $notice_text = $this->get_notice_text( 'please_activate_premium' );
246
+
247
+ if ( ! $this->plugin->premium->is_install_package() ) {
248
+ $notice_text = $this->get_notice_text( 'please_install_premium' );
249
+ }
250
+ } else if ( $this->need_activate_license() ) {
251
+ $notice_text = $this->get_notice_text( 'need_activate_license' );
252
+ } else if ( $this->need_renew_license() ) {
253
+ $notice_text = $this->get_notice_text( 'need_renew_license' );
254
+ }
255
+
256
+ $obj->printWarningNotice( $notice_text );
257
+ }
258
+
259
+ /**
260
+ * Выводит уведомление в строке плагина (на странице плагинов),
261
+ * что нужно установить премиум плагин.
262
+ *
263
+ * @since 4.1.1
264
+ *
265
+ * @param array $plugin_data
266
+ * @param string $status
267
+ *
268
+ * @param string $plugin_file
269
+ *
270
+ * @return void
271
+ * @see WP_Plugins_List_Table
272
+ *
273
+ */
274
+ public function notice_in_plugin_row( $plugin_file, $plugin_data, $status ) {
275
+
276
+ if ( ! current_user_can( 'update_plugins' ) ) {
277
+ return;
278
+ };
279
+
280
+ $notice_text = '';
281
+
282
+ if ( $this->need_intall_or_activate_premium() ) {
283
+ $notice_text = $this->get_notice_text( 'please_activate_premium' );
284
+
285
+ if ( ! $this->plugin->premium->is_install_package() ) {
286
+ $notice_text = $this->get_notice_text( 'please_install_premium' );
287
+ }
288
+ } else if ( $this->need_activate_license() ) {
289
+ $notice_text = $this->get_notice_text( 'need_activate_license' );
290
+ } else if ( $this->need_renew_license() ) {
291
+ $notice_text = $this->get_notice_text( 'need_renew_license' );
292
+ }
293
+
294
+ ?>
295
+ <tr class="plugin-update-tr active update wbcr-factory-updates">
296
+ <td colspan="3" class="plugin-update colspanchange">
297
+ <div class="update-message notice inline notice-warning notice-alt">
298
+ <p>
299
+ <?php echo $notice_text; ?>
300
+ </p>
301
+ </div>
302
+ </td>
303
+ </tr>
304
+ <?php
305
+ }
306
+
307
+ /**
308
+ * Печатает стили для уведомления о загрузке премиум версии на странице плагинов.
309
+ *
310
+ * @since 4.1.1
311
+ * @return void
312
+ */
313
+ public function print_styles_for_plugin_row() {
314
+
315
+ if ( ! current_user_can( 'update_plugins' ) ) {
316
+ return;
317
+ }
318
+
319
+ $plugin_base = $this->plugin->get_paths()->basename;
320
+
321
+ if ( $this->need_intall_or_activate_premium() ) {
322
+ $message_background_color = '#f5e9f5';
323
+ $message_border_color = '#dab9da';
324
+ } else if ( $this->need_renew_license() || $this->need_activate_license() ) {
325
+ $message_background_color = '#ffe2e0';
326
+ $message_border_color = '#F44336';
327
+ if ( $this->plugin->premium->is_install_package() ) {
328
+ $package = $this->plugin->premium->get_package_data();
329
+ $plugin_base = $package['basename'];
330
+ }
331
+ }
332
+
333
+ ?>
334
+ <style>
335
+ tr[data-plugin="<?php echo $plugin_base; ?>"] th,
336
+ tr[data-plugin="<?php echo $plugin_base; ?>"] td {
337
+ box-shadow: none !important;
338
+ }
339
+
340
+ .wbcr-factory-updates .update-message {
341
+ background-color: <?php echo esc_attr($message_background_color); ?> !important;
342
+ border-color: <?php echo esc_attr($message_border_color); ?> !important;
343
+ }
344
+ </style>
345
+ <?php
346
+ }
347
+
348
+
349
+ /**
350
+ * Обновляет данные о премиум пакете в базе данных, после обновления плагина.
351
+ *
352
+ * @param WP_Upgrader $wp_upgrader WP_Upgrader instance.
353
+ * @param array $hook_extra Array of bulk item update data.
354
+ *
355
+ * @return void
356
+ * @throws Exception
357
+ */
358
+ public function upgrader_process_complete_hook( $upgrader_object, $hook_extra ) {
359
+ if ( ! empty( $hook_extra ) && $hook_extra['action'] == 'update' && $hook_extra['type'] == 'plugin' ) {
360
+
361
+ # if it isn't bulk upgrade
362
+ if ( isset( $hook_extra['plugin'] ) && $this->plugin_basename === $hook_extra['plugin'] ) {
363
+ $this->update_package_data();
364
+
365
+ return;
366
+ }
367
+
368
+ # if it is bulk upgrade
369
+ if ( is_array( $hook_extra['plugins'] ) && in_array( $this->plugin_basename, $hook_extra['plugins'] ) ) {
370
+ $this->update_package_data();
371
+ }
372
+ }
373
+ }
374
+
375
+ /**
376
+ * @since 4.1.1
377
+ * @return array
378
+ */
379
+ protected function get_settings() {
380
+ $settings = $this->plugin->getPluginInfoAttr( 'license_settings' );
381
+
382
+ $updates_settings = isset( $settings['updates_settings'] ) ? $settings['updates_settings'] : [];
383
+
384
+ if ( is_array( $settings ) ) {
385
+ $updates_settings['repository'] = $settings['provider'];
386
+ $updates_settings['slug'] = $settings['slug'];
387
+ }
388
+
389
+ return wp_parse_args( $updates_settings, [
390
+ 'repository' => 'wordpress',
391
+ 'slug' => '',
392
+ 'maybe_rollback' => false,
393
+ 'rollback_settings' => [
394
+ 'prev_stable_version' => '0.0.0'
395
+ ]
396
+ ] );
397
+ }
398
+
399
+ /**
400
+ * @since 4.1.1
401
+ * @return string
402
+ */
403
+ protected function get_plugin_version() {
404
+ if ( ! $this->plugin->premium->is_install_package() ) {
405
+ return '0.0.0';
406
+ }
407
+
408
+ $package = $this->plugin->premium->get_package_data();
409
+
410
+ return $package['version'];
411
+ }
412
+
413
+ /**
414
+ * @since 4.1.1
415
+ *
416
+ * @param $args
417
+ *
418
+ * @return string
419
+ */
420
+ protected function get_admin_url( $args ) {
421
+ $url = admin_url( 'plugins.php', $args );
422
+
423
+ if ( $this->plugin->isNetworkActive() ) {
424
+ $url = network_admin_url( 'plugins.php', $args );
425
+ }
426
+
427
+ return add_query_arg( $args, $url );
428
+ }
429
+
430
+ /**
431
+ * @since 4.1.1
432
+ *
433
+ * @param string $action
434
+ *
435
+ * @return string
436
+ */
437
+ protected function get_action_url( $action ) {
438
+ $args = [
439
+ 'wfactory_premium_updates_action' => $action,
440
+ 'wfactory_premium_updates_plugin' => $this->plugin_slug
441
+ ];
442
+
443
+ return wp_nonce_url( $this->get_admin_url( $args ), "factory_premium_{$action}" );
444
+ }
445
+
446
+ /**
447
+ * @since 4.1.1
448
+ * @return string
449
+ */
450
+ protected function get_activate_premium_url() {
451
+ $args = [
452
+ 'action' => 'activate',
453
+ 'plugin' => $this->plugin_basename,
454
+ ];
455
+
456
+ return wp_nonce_url( $this->get_admin_url( $args ), "activate-plugin_{$this->plugin_basename}" );
457
+ }
458
+
459
+ /**
460
+ * Нужно установить или обновить премиум?
461
+ *
462
+ * @since 4.1.1
463
+ * @return bool
464
+ */
465
+ protected function need_intall_or_activate_premium() {
466
+ if ( $this->plugin->premium->is_activate() && $this->plugin->premium->is_active() ) {
467
+ if ( $this->plugin->premium->is_install_package() && is_plugin_active( $this->plugin_basename ) ) {
468
+ return false;
469
+ }
470
+
471
+ return true;
472
+ }
473
+
474
+ return false;
475
+ }
476
+
477
+ /**
478
+ * Требуется активировать лицензию?
479
+ *
480
+ * @since 4.1.1
481
+ * @return bool
482
+ */
483
+ protected function need_activate_license() {
484
+ return ! $this->plugin->premium->is_activate() && $this->plugin->premium->is_install_package();
485
+ }
486
+
487
+ /**
488
+ * Нужно продлить лицензию?
489
+ *
490
+ * @since 4.1.1
491
+ * @return bool
492
+ */
493
+ protected function need_renew_license() {
494
+ return $this->plugin->premium->is_activate() && ! $this->plugin->premium->is_active();
495
+ }
496
+
497
+ /**
498
+ * @since 4.1.1
499
+ * @throws Exception
500
+ */
501
+ protected function install() {
502
+ global $wp_filesystem;
503
+
504
+ if ( ! current_user_can( 'install_plugins' ) ) {
505
+ throw new Exception( 'Sorry, you are not allowed to install plugins on this site.', 'not_allowed_install_plugin' );
506
+ }
507
+
508
+ if ( $this->plugin->premium->is_install_package() ) {
509
+ return;
510
+ }
511
+
512
+ if ( ! $wp_filesystem ) {
513
+ if ( ! function_exists( 'WP_Filesystem' ) ) {
514
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
515
+ }
516
+ WP_Filesystem();
517
+ }
518
+
519
+ if ( ! WP_Filesystem( false, WP_PLUGIN_DIR ) ) {
520
+ throw new Exception( 'You are not allowed to edt folders/files on this site', 'not_allowed_edit_filesystem' );
521
+ } else {
522
+
523
+ $download_url = $this->repository->get_download_url();
524
+
525
+ /**
526
+ * @since 4.1.1
527
+ *
528
+ * @param string $plugin_name Имя плагина
529
+ *
530
+ * @param string $package Дополнительная информация о лицензии
531
+ */
532
+ do_action( 'wbcr/factory/premium/install_package', $download_url, $this->plugin->getPluginName() );
533
+
534
+ // If plugin is installed before we update the premium package in database.
535
+ // ------------------------------------------------------------------------
536
+ $plugins = get_plugins( $plugin_folder = '' );
537
+
538
+ if ( ! empty( $plugins ) ) {
539
+ foreach ( (array) $plugins as $plugin_base => $plugin ) {
540
+ $basename_parts = explode( '/', $plugin_base );
541
+ if ( sizeof( $basename_parts ) == 2 && $basename_parts[0] == $this->plugin_slug ) {
542
+
543
+ $this->plugin_basename = $plugin_base;
544
+ $this->plugin_main_file = WP_PLUGIN_DIR . '/' . $plugin_base;
545
+ $this->plugin_absolute_path = dirname( WP_PLUGIN_DIR . '/' . $plugin_base );
546
+
547
+ $this->update_package_data();
548
+
549
+ $package = $this->plugin->premium->get_package_data();
550
+
551
+ /**
552
+ * @since 4.1.1
553
+ *
554
+ * @param string $plugin_name Имя плагина
555
+ *
556
+ * @param string $package Дополнительная информация о лицензии
557
+ */
558
+ do_action( 'wbcr/factory/premium/installed_package', $package, $this->plugin->getPluginName() );
559
+
560
+ return;
561
+ }
562
+ }
563
+ }
564
+ // ------------------------------------------------------------------------
565
+
566
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
567
+ require_once( ABSPATH . 'wp-admin/includes/misc.php' );
568
+
569
+ if ( ! class_exists( 'Plugin_Upgrader', false ) ) {
570
+ // Include required resources for the installation.
571
+ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
572
+ }
573
+
574
+ $skin_args = [
575
+ 'type' => 'web',
576
+ 'title' => sprintf( 'Installing plugin: %s', $this->plugin->getPluginTitle() . ' Premium' ),
577
+ 'url' => esc_url_raw( $download_url ),
578
+ 'nonce' => 'install-plugin_' . $this->plugin_slug,
579
+ 'plugin' => '',
580
+ 'api' => null,
581
+ 'extra' => [
582
+ 'slug' => $this->plugin_slug
583
+ ],
584
+ ];
585
+
586
+ require_once( ABSPATH . 'wp-admin/admin-header.php' );
587
+
588
+ if ( ! $this->plugin->premium->is_install_package() ) {
589
+ $skin = new Plugin_Installer_Skin( $skin_args );
590
+ } else {
591
+ $skin = new WP_Upgrader_Skin( $skin_args );
592
+ }
593
+
594
+ $upgrader = new Plugin_Upgrader( $skin );
595
+
596
+ if ( empty( $download_url ) ) {
597
+ throw new Exception( 'You must pass the download url to upgrade up premium package.', "not_passed_download_url" );
598
+ }
599
+
600
+ $install_result = $upgrader->install( $download_url );
601
+
602
+ include( ABSPATH . 'wp-admin/admin-footer.php' );
603
+
604
+ if ( is_wp_error( $install_result ) ) {
605
+ throw new Exception( $install_result->get_error_message(), $install_result->get_error_code() );
606
+ } else if ( is_wp_error( $skin->result ) ) {
607
+ throw new Exception( $skin->result->get_error_message(), $skin->result->get_error_code() );
608
+ } else if ( is_null( $install_result ) ) {
609
+ global $wp_filesystem;
610
+
611
+ $error_code = 'unable_to_connect_to_filesystem';
612
+ $error_message = 'Unable to connect to the filesystem. Please confirm your credentials.';
613
+
614
+ // Pass through the error from WP_Filesystem if one was raised.
615
+ if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
616
+ $error_message = $wp_filesystem->errors->get_error_message();
617
+ }
618
+
619
+ throw new Exception( $error_message, $error_code );
620
+ }
621
+
622
+ $this->plugin_basename = $upgrader->plugin_info();
623
+ $this->plugin_main_file = WP_PLUGIN_DIR . '/' . $this->plugin_basename;
624
+ $this->plugin_absolute_path = dirname( WP_PLUGIN_DIR . '/' . $this->plugin_basename );
625
+
626
+ $this->update_package_data();
627
+
628
+ $package = $this->plugin->premium->get_package_data();
629
+
630
+ /**
631
+ * @since 4.1.1
632
+ *
633
+ * @param string $plugin_name Имя плагина
634
+ *
635
+ * @param string $package Дополнительная информация о лицензии
636
+ */
637
+ do_action( 'wbcr/factory/premium/installed_package', $package, $this->plugin->getPluginName() );
638
+
639
+ die();
640
+ }
641
+ }
642
+
643
+ /**
644
+ * @return bool
645
+ * @throws Exception
646
+ */
647
+ protected function delete() {
648
+ if ( ! $this->plugin->premium->is_install_package() ) {
649
+ return false;
650
+ }
651
+
652
+ $package = $this->plugin->premium->get_package_data();
653
+
654
+ /**
655
+ * @since 4.1.1
656
+ *
657
+ * @param string $plugin_name Имя плагина
658
+ *
659
+ * @param string $package Дополнительная информация о лицензии
660
+ */
661
+ do_action( 'wbcr/factory/premium/delete_package', $package, $this->plugin->getPluginName() );
662
+
663
+ if ( is_plugin_active( $package['basename'] ) ) {
664
+ if ( is_multisite() && is_plugin_active_for_network( $package['basename'] ) ) {
665
+ deactivate_plugins( $package['basename'], false, true );
666
+ } else {
667
+ deactivate_plugins( $package['basename'] );
668
+ }
669
+ }
670
+
671
+ $result = delete_plugins( [ $package['basename'] ] );
672
+
673
+ if ( is_wp_error( $result ) ) {
674
+ throw new Exception( $result->get_error_message(), $result->get_error_code() );
675
+ }
676
+
677
+ $this->plugin->premium->delete_package();
678
+
679
+ /**
680
+ * @since 4.1.1
681
+ *
682
+ * @param string $plugin_name Имя плагина
683
+ *
684
+ * @param string $package Дополнительная информация о лицензии
685
+ */
686
+ do_action( 'wbcr/factory/premium/deleted_package', $package, $this->plugin->getPluginName() );
687
+
688
+ return true;
689
+ }
690
+
691
+ /**
692
+ * @since 4.1.1
693
+ * @return bool
694
+ */
695
+ protected function deactivate() {
696
+ if ( ! $this->plugin->premium->is_install_package() || ! is_plugin_active( $this->plugin_basename ) ) {
697
+ return false;
698
+ }
699
+
700
+ $package = $this->plugin->premium->get_package_data();
701
+
702
+ /**
703
+ * @since 4.1.1
704
+ *
705
+ * @param string $plugin_name Имя плагина
706
+ *
707
+ * @param string $package Дополнительная информация о лицензии
708
+ */
709
+ do_action( 'wbcr/factory/premium/deactivate_package', $package, $this->plugin->getPluginName() );
710
+
711
+ if ( is_multisite() && is_plugin_active_for_network( $this->plugin_basename ) ) {
712
+ deactivate_plugins( $this->plugin_basename, false, true );
713
+ } else {
714
+ deactivate_plugins( $this->plugin_basename );
715
+ }
716
+
717
+ /**
718
+ * @since 4.1.1
719
+ *
720
+ * @param string $plugin_name Имя плагина
721
+ *
722
+ * @param string $package Дополнительная информация о лицензии
723
+ */
724
+ do_action( 'wbcr/factory/premium/deactivated_package', $package, $this->plugin->getPluginName() );
725
+
726
+ return true;
727
+ }
728
+
729
+ /**
730
+ * @since 4.1.1
731
+ *
732
+ * @param array $plugin_data
733
+ *
734
+ * @throws Exception
735
+ */
736
+ protected function update_package_data() {
737
+
738
+ if ( ! $this->plugin_main_file ) {
739
+ return;
740
+ }
741
+
742
+ $default_headers = [
743
+ 'Version' => 'Version',
744
+ 'FrameworkVersion' => 'Framework Version'
745
+ ];
746
+
747
+ $plugin_data = get_file_data( $this->plugin_main_file, $default_headers, 'plugin' );
748
+
749
+ $this->plugin->premium->update_package_data( [
750
+ 'basename' => $this->plugin_basename,
751
+ 'version' => $plugin_data['Version'],
752
+ 'framework_version' => isset( $plugin_data['FrameworkVersion'] ) ? $plugin_data['FrameworkVersion'] : null,
753
+ ] );
754
+ }
755
+
756
+ /**
757
+ * @since 4.1.1
758
+ *
759
+ * @param string $type
760
+ *
761
+ * @return string|null
762
+ */
763
+ private function get_notice_text( $type ) {
764
+ $upgrade_url = $this->get_action_url( 'install' );
765
+ $activate_plugin_url = $this->get_activate_premium_url();
766
+ $cancel_license_url = $this->get_action_url( 'cancel_license' );
767
+
768
+ $texts = [
769
+ 'need_activate_license' => __( 'License activation required. A license is required to get premium plugin updates, as well as to get additional services.', 'wbcr_factory_424' ),
770
+ 'need_renew_license' => __( 'Your license has expired. You can no longer get premium plugin updates, premium support and your access to Webcraftic services has been suspended.', 'wbcr_factory_424' ),
771
+ 'please_install_premium' => sprintf( __( 'Congratulations, you have activated a premium license! Please install premium add-on to use pro features now.
772
+ <a href="%s">Install</a> premium add-on or <a href="%s">cancel</a> license.', 'wbcr_factory_424' ), $upgrade_url, $cancel_license_url ),
773
+ 'please_activate_premium' => sprintf( __( 'Congratulations, you have activated a premium license! Please activate premium add-on to use pro features now.
774
+ <a href="%s">Activate</a> premium add-on or <a href="%s">cancel</a> license.', 'wbcr_factory_424' ), $activate_plugin_url, $cancel_license_url )
775
+ ];
776
+
777
+ if ( isset( $texts[ $type ] ) ) {
778
+
779
+ /**
780
+ * @since 4.1.1
781
+ *
782
+ * @param string $type
783
+ * @param string $plugin_name
784
+ *
785
+ * @param array $messages
786
+ */
787
+ return apply_filters( 'wbcr/factory/premium/notice_text', $texts[ $type ], $type, $this->plugin->getPluginName() );
788
+ }
789
+
790
+ return null;
791
+ }
792
+ }
libs/factory/core/includes/updates/class-factory-upgrader.php ADDED
@@ -0,0 +1,313 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424\Updates;
4
+
5
+ use Exception;
6
+ use stdClass;
7
+ use Wbcr_Factory424_Plugin;
8
+
9
+ // Exit if accessed directly
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ /**
15
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
16
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
17
+ * @copyright (c) 2018 Webraftic Ltd
18
+ * @version 1.0
19
+ */
20
+ class Upgrader {
21
+
22
+ const CHECK_UPDATES_INTERVAL = "43200";
23
+
24
+ /**
25
+ * Список доступных классов для работы с репозиториями
26
+ *
27
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
28
+ * @since 4.1.7
29
+ * @var array хранит имя репозитория и его имя класса
30
+ * [
31
+ * 'wordpress' => 'WBCR\Factory_Freemius_112\Updates\Freemius_Repository',
32
+ * 'freemius' => '\WBCR\Factory_424\Updates\Wordpress_Repository'
33
+ * ]
34
+ */
35
+ public static $repositories = [];
36
+
37
+ /**
38
+ * Тип апгрейдера, может быть default, premium
39
+ *
40
+ * @var string
41
+ */
42
+ protected $type = 'default';
43
+
44
+ /**
45
+ * @var Wbcr_Factory424_Plugin
46
+ */
47
+ protected $plugin;
48
+
49
+ /**
50
+ * @var string
51
+ */
52
+ protected $plugin_basename;
53
+
54
+ /**
55
+ * @var string
56
+ */
57
+ protected $plugin_main_file;
58
+
59
+ /**
60
+ * @var string
61
+ */
62
+ protected $plugin_absolute_path;
63
+
64
+ /**
65
+ * Имя плагина, для которого нужно проверять обновления
66
+ *
67
+ * @var string
68
+ */
69
+ protected $plugin_slug;
70
+
71
+ /**
72
+ * @var Repository
73
+ */
74
+ protected $repository;
75
+
76
+ /**
77
+ * @var array
78
+ */
79
+ protected $rollback = [
80
+ 'prev_stable_version' => null
81
+ ];
82
+
83
+ /**
84
+ * @var bool
85
+ */
86
+ protected $is_debug = false;
87
+
88
+ /**
89
+ * Manager constructor.
90
+ *
91
+ * @since 4.1.1
92
+ *
93
+ * @param Wbcr_Factory424_Plugin $plugin
94
+ * @param $args
95
+ * @param bool $is_premium
96
+ *
97
+ * @throws Exception
98
+ */
99
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
100
+
101
+ $this->plugin = $plugin;
102
+
103
+ $this->plugin_basename = $plugin->get_paths()->basename;
104
+ $this->plugin_main_file = $plugin->get_paths()->main_file;
105
+ $this->plugin_absolute_path = $plugin->get_paths()->absolute;
106
+ $this->is_debug = defined( 'FACTORY_UPDATES_DEBUG' ) && FACTORY_UPDATES_DEBUG;
107
+
108
+ # Добавляем Wordpress репозиторий в список доступных репозиториев по умолчанию
109
+ self::$repositories['wordpress'] = '\WBCR\Factory_424\Updates\Wordpress_Repository';
110
+
111
+ $settings = $this->get_settings();
112
+
113
+ $this->plugin_slug = $settings['slug'];
114
+ $this->rollback = $settings['rollback_settings'];
115
+
116
+ if ( empty( $this->plugin_slug ) || ! is_string( $this->plugin_slug ) ) {
117
+ throw new Exception( 'Argument {slug} can not be empty and must be of type string.' );
118
+ }
119
+
120
+ $this->set_repository();
121
+
122
+ if ( $this->repository->need_check_updates() ) {
123
+ $this->init_hooks();
124
+ }
125
+ }
126
+
127
+ /**
128
+ * @throws Exception
129
+ */
130
+ protected function set_repository() {
131
+ $settings = $this->get_settings();
132
+ $this->repository = $this->get_repository( $settings['repository'] );
133
+ $this->repository->init();
134
+ }
135
+
136
+ /**
137
+ * @return array
138
+ */
139
+ protected function get_settings() {
140
+ $settings = $this->plugin->getPluginInfoAttr( 'updates_settings' );
141
+
142
+ return wp_parse_args( $settings, [
143
+ 'repository' => 'wordpress',
144
+ 'slug' => '',
145
+ 'maybe_rollback' => false,
146
+ 'rollback_settings' => [
147
+ 'prev_stable_version' => '0.0.0'
148
+ ]
149
+ ] );
150
+ }
151
+
152
+ /**
153
+ * @since 4.1.1
154
+ * @throws Exception
155
+ */
156
+ protected function init_hooks() {
157
+ add_filter( 'site_transient_update_plugins', [
158
+ $this,
159
+ 'site_transient_update_plugins_hook'
160
+ ] );
161
+
162
+ add_action( 'wp_update_plugins', [ $this, 'reset_check_update_timer' ], 9 ); // WP Cron.
163
+ add_action( 'deleted_site_transient', [ $this, 'reset_check_update_timer' ] );
164
+ add_action( 'setted_site_transient', [ $this, 'reset_check_update_timer' ] );
165
+ }
166
+
167
+
168
+ /**
169
+ * When WP sets the update_plugins site transient, we set our own transient
170
+ *
171
+ * @since 4.1.1
172
+ *
173
+ * @param Object $transient Site transient object.
174
+ *
175
+ * @throws Exception
176
+ */
177
+ public function site_transient_update_plugins_hook( $transient ) {
178
+
179
+ if ( ! $transient || ! is_object( $transient ) ) {
180
+ return $transient;
181
+ }
182
+
183
+ $temp_object = $this->check_updates();
184
+
185
+ if ( ! empty( $temp_object ) && is_object( $temp_object ) && version_compare( $this->get_plugin_version(), $temp_object->new_version, '<' ) ) {
186
+ $transient->response[ $temp_object->plugin ] = $temp_object;
187
+
188
+ return $transient;
189
+ }
190
+
191
+ return $transient;
192
+ }
193
+
194
+ /**
195
+ * When WP deletes the update_plugins site transient or updates the plugins, we delete our own transients to avoid another 12 hours waiting
196
+ *
197
+ * @since 4.1.1
198
+ *
199
+ * @param string $transient Transient name.
200
+ * @param object $value Transient object.
201
+ */
202
+ public function reset_check_update_timer( $transient = 'update_plugins', $value = null ) {
203
+ $options_prefix = $this->type == "default" ? "" : "_" . $this->type;
204
+
205
+ // $value used by setted.
206
+ if ( 'update_plugins' === $transient ) {
207
+ if ( is_null( $value ) || is_object( $value ) && ! isset( $value->response ) ) {
208
+
209
+ $last_check_time = (int) $this->plugin->getPopulateOption( "last_check{$options_prefix}_update_time", 0 );
210
+
211
+ if ( 0 !== $last_check_time && time() > ( $last_check_time + MINUTE_IN_SECONDS ) ) {
212
+ $this->plugin->deletePopulateOption( "last_check{$options_prefix}_update_time" );
213
+ $this->plugin->deletePopulateOption( "last_check{$options_prefix}_update" );
214
+ }
215
+ }
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Проверяет последние обновления для текущего или премиум плагина.
221
+ *
222
+ * @since 4.1.1
223
+ * @return object|null
224
+ * @throws Exception
225
+ */
226
+ protected function check_updates( $force = false ) {
227
+
228
+ $options_prefix = $this->type == "default" ? "" : "_" . $this->type;
229
+ $check_updates_interval = self::CHECK_UPDATES_INTERVAL;
230
+ $last_check_time = (int) $this->plugin->getPopulateOption( "last_check{$options_prefix}_update_time", 0 );
231
+
232
+ if ( $this->is_debug && defined( 'FACTORY_CHECK_UPDATES_INTERVAL' ) ) {
233
+ $check_updates_interval = FACTORY_CHECK_UPDATES_INTERVAL;
234
+ if ( empty( $check_updates_interval ) || ! is_numeric( $check_updates_interval ) ) {
235
+ $check_updates_interval = MINUTE_IN_SECONDS;
236
+ }
237
+ }
238
+
239
+ if ( $force || ( time() > ( $last_check_time + $check_updates_interval ) ) ) {
240
+
241
+ $this->plugin->updatePopulateOption( "last_check{$options_prefix}_update_time", time() );
242
+
243
+ $last_version = $this->repository->get_last_version();
244
+
245
+ if ( ! empty( $last_version ) ) {
246
+ $temp_object = new stdClass();
247
+ $temp_object->slug = $this->plugin_slug;
248
+ $temp_object->plugin = $this->plugin_basename;
249
+ $temp_object->new_version = $last_version;
250
+ $temp_object->package = $this->repository->get_download_url();
251
+
252
+ $this->plugin->updatePopulateOption( "last_check{$options_prefix}_update", $temp_object );
253
+
254
+ return $temp_object;
255
+ }
256
+ }
257
+
258
+ return $this->plugin->getPopulateOption( "last_check{$options_prefix}_update" );
259
+ }
260
+
261
+ /**
262
+ * @since 4.1.1
263
+ *
264
+ * @param $args
265
+ *
266
+ * @return string
267
+ */
268
+ protected function get_admin_url( $args ) {
269
+ $url = admin_url( 'plugins.php', $args );
270
+
271
+ if ( $this->plugin->isNetworkActive() ) {
272
+ $url = network_admin_url( 'plugins.php', $args );
273
+ }
274
+
275
+ return add_query_arg( $args, $url );
276
+ }
277
+
278
+ /**
279
+ * @since 4.1.1
280
+ *
281
+ * @param $repository_name
282
+ *
283
+ * @return Repository
284
+ * @throws Exception
285
+ */
286
+ protected function get_repository( $repository_name ) {
287
+
288
+ if ( isset( self::$repositories[ $repository_name ] ) && class_exists( self::$repositories[ $repository_name ] ) ) {
289
+ if ( self::$repositories[ $repository_name ] instanceof Repository ) {
290
+ throw new Exception( "Repository {$repository_name} must extend the class WBCR\Factory_424\Updates\Repository interface!" );
291
+ }
292
+
293
+ return new self::$repositories[ $repository_name ]( $this->plugin );
294
+ }
295
+
296
+ throw new Exception( "Repository {$repository_name} is not supported!" );
297
+ }
298
+
299
+ /**
300
+ * @since 4.1.1
301
+ * @return string
302
+ */
303
+ protected function get_plugin_version() {
304
+ return $this->plugin->getPluginVersion();
305
+ }
306
+
307
+ /**
308
+ * @since 4.1.1
309
+ */
310
+ protected function rollback() {
311
+
312
+ }
313
+ }
libs/factory/core/includes/updates/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/core/includes/updates/repositories/class-factory-repository-abstract.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424\Updates;
4
+
5
+ // Exit if accessed directly
6
+ use Wbcr_Factory424_Plugin;
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
14
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
15
+ * @copyright (c) 2018 Webraftic Ltd
16
+ * @version 1.0
17
+ */
18
+ abstract class Repository {
19
+
20
+ /**
21
+ * @var bool
22
+ */
23
+ protected $initialized = false;
24
+
25
+ /**
26
+ * @var Wbcr_Factory424_Plugin
27
+ */
28
+ protected $plugin;
29
+
30
+ /**
31
+ * Repository constructor.
32
+ *
33
+ * @param Wbcr_Factory424_Plugin $plugin
34
+ * @param bool $is_premium
35
+ */
36
+ abstract public function __construct( Wbcr_Factory424_Plugin $plugin );
37
+
38
+ /**
39
+ * @return void
40
+ */
41
+ abstract public function init();
42
+
43
+ /**
44
+ * @return bool
45
+ */
46
+ abstract public function need_check_updates();
47
+
48
+ /**
49
+ * @return mixed
50
+ */
51
+ abstract public function is_support_premium();
52
+
53
+ /**
54
+ * @return string
55
+ */
56
+ abstract public function get_download_url();
57
+
58
+ /**
59
+ * @return string
60
+ */
61
+ abstract public function get_last_version();
62
+ }
libs/factory/core/includes/updates/repositories/class-factory-wordpress.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_424\Updates;
4
+
5
+ // Exit if accessed directly
6
+ use Wbcr_Factory424_Plugin;
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, repo: https://github.com/alexkovalevv
14
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, site: https://webcraftic.com
15
+ * @copyright (c) 2018 Webraftic Ltd
16
+ * @version 1.0
17
+ */
18
+ class Wordpress_Repository extends Repository {
19
+
20
+ /**
21
+ * Wordpress constructor.
22
+ *
23
+ * @param Wbcr_Factory424_Plugin $plugin
24
+ * @param bool $is_premium
25
+ */
26
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
27
+ $this->plugin = $plugin;
28
+ }
29
+
30
+ public function init() {
31
+ // TODO: Implement init() method.
32
+ }
33
+
34
+ /**
35
+ * @return bool
36
+ */
37
+ public function need_check_updates() {
38
+ return false;
39
+ }
40
+
41
+ /**
42
+ * @return bool
43
+ */
44
+ public function is_support_premium() {
45
+ return false;
46
+ }
47
+
48
+ /**
49
+ * @return string
50
+ */
51
+ public function get_download_url() {
52
+ return '';
53
+ }
54
+
55
+ /**
56
+ * @return string
57
+ */
58
+ public function get_last_version() {
59
+ return '0.0.0';
60
+ }
61
+
62
+ public function check_updates() {
63
+
64
+ }
65
+
66
+ /**
67
+ * @return bool
68
+ */
69
+ public function need_update() {
70
+ return false;
71
+ }
72
+ }
libs/factory/core/includes/updates/repositories/index.php ADDED
File without changes
libs/factory/core/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/core/langs/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/core/langs/wbcr_factory_424-ru_RU.mo ADDED
Binary file
libs/factory/core/langs/wbcr_factory_424-ru_RU.po ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: factory_forms\n"
4
+ "POT-Creation-Date: 2018-10-16 22:44+0300\n"
5
+ "PO-Revision-Date: 2018-10-16 22:45+0300\n"
6
+ "Last-Translator: \n"
7
+ "Language-Team: Alex Kovalev <alex.kovalevv@gmail.com>\n"
8
+ "Language: ru_RU\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 2.1.1\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
15
+ "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
16
+ "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c\n"
18
+ "X-Poedit-SearchPath-0: .\n"
19
+
20
+ #: includes/check-compatibility.php:80
21
+ msgid "warning"
22
+ msgstr "предупреждение"
23
+
24
+ #: includes/check-compatibility.php:82
25
+ #, php-format
26
+ msgid "The %s plugin has stopped."
27
+ msgstr "Работа плагина %s была остановлена."
28
+
29
+ #: includes/check-compatibility.php:83
30
+ msgid "Possible reasons:"
31
+ msgstr "Возможные причины:"
32
+
33
+ #: includes/check-compatibility.php:89
34
+ #, php-format
35
+ msgid "You need to update the PHP version to %s or higher!"
36
+ msgstr "Вам нужно обновить версию PHP до %s или выше!"
37
+
38
+ #: includes/check-compatibility.php:94
39
+ #, php-format
40
+ msgid "You need to update WordPress to %s or higher!"
41
+ msgstr "Вам нужно обновить WordPress до %s или выше!"
42
+
43
+ #: includes/functions.php:132
44
+ #, php-format
45
+ msgid ""
46
+ "%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead."
47
+ msgstr ""
48
+ "%1$s является <strong>устаревшим,</strong> начиная с версии %2$s в "
49
+ "Wordpress! Используйте %3$s."
50
+
51
+ #: includes/functions.php:134
52
+ #, php-format
53
+ msgid ""
54
+ "%1$s is <strong>deprecated</strong> since version %2$s with no alternative "
55
+ "available."
56
+ msgstr ""
57
+ "%1$s был вызван с параметром, который является <strong>устаревшими</strong> "
58
+ "начиная с версии %2$s , в настоящее время доступных альтернатив нет."
59
+
60
+ #: includes/plugin.class.php:202 includes/plugin.class.php:237
61
+ msgid ""
62
+ "You are trying to call this earlier than the plugin menu will be registered."
63
+ msgstr ""
64
+ "Вы пытаетесь вызвать это раньше, чем будет зарегистрировано меню плагина."
65
+
66
+ #: includes/plugin.class.php:220
67
+ msgid ""
68
+ "You are trying to get a link to a page that does not have multisite mode. "
69
+ "Clicking this link will lead the user to a non-existent page."
70
+ msgstr ""
71
+ "Вы пытаетесь получить ссылку на страницу, которая не имеет "
72
+ "многопользовательского режима. Щелчок по этой ссылке приведет пользователя "
73
+ "к несуществующей странице."
74
+
75
+ #: includes/plugin.class.php:222
76
+ msgid ""
77
+ "Trying to get a link to an unregistered page. You are trying to call this "
78
+ "earlier than the plugin menu will be registered."
79
+ msgstr ""
80
+ "Попытка получить ссылку на незарегистрированную страницу. Вы пытаетесь "
81
+ "вызвать это раньше, чем будет зарегистрировано меню плагина."
82
+
83
+ #~ msgid "On"
84
+ #~ msgstr "Вкл"
85
+
86
+ #~ msgid "Off"
87
+ #~ msgstr "Выкл"
88
+
89
+ #~ msgid "(use default website font)"
90
+ #~ msgstr "(шрифт сайта по умолчанию)"
91
+
92
+ #~ msgid "Sans Serif:"
93
+ #~ msgstr "Группа Sans Serif:"
94
+
95
+ #~ msgid "Serif:"
96
+ #~ msgstr "Группа Serif:"
97
+
98
+ #~ msgid "Monospaced:"
99
+ #~ msgstr "Группа Monospaced:"
100
+
101
+ #~ msgid "vertical"
102
+ #~ msgstr "вертикальный"
103
+
104
+ #~ msgid "horizontal"
105
+ #~ msgstr "горизонтальный"
106
+
107
+ #~ msgid "hide extra options"
108
+ #~ msgstr "скрыть дополнительные настроки"
109
+
110
+ #~ msgid "Select a side and move the slider to set up:"
111
+ #~ msgstr "Выберите сторону и переместите ползунок:"
112
+
113
+ #~ msgid "Change color"
114
+ #~ msgstr "Выбрать цвет"
115
+
116
+ #~ msgid "re-color"
117
+ #~ msgstr "Перекрасить"
118
+
119
+ #~ msgid "Select color:"
120
+ #~ msgstr "Выберите цвет:"
121
+
122
+ #~ msgid "Changing the color may takes a minute or more. Please be patient."
123
+ #~ msgstr ""
124
+ #~ "В некоторых случаях изменение цвета может занять около минуты. "
125
+ #~ "Пожалуйста, будьте терпеливы."
126
+
127
+ #~ msgid "Upload Pattern"
128
+ #~ msgstr "Добавить шаблон"
libs/factory/forms/assets/css/editor.css ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ font-family: Arial;
3
+ font-size: 14px;
4
+ background-color: #fff;
5
+ }
6
+ p {
7
+ margin: 0px;
8
+ }
9
+
10
+ p + p {
11
+ margin-top: 5px;
12
+ }
libs/factory/forms/assets/standard-controls.js ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function($){
2
+
3
+ if ( !$.factory ) $.factory = {}
4
+ if ( $.factory.widget ) return;
5
+
6
+ /**
7
+ * OnePress Widget Factory.
8
+ */
9
+ $.factory.widget = function (pluginName, pluginObject) {
10
+
11
+ var factory = {
12
+
13
+ createWidget: function (element, options) {
14
+ var widget = $.extend(true, {}, pluginObject);
15
+
16
+ widget.element = $(element);
17
+ widget.options = $.extend(true, widget.options, options);
18
+
19
+ if (widget._init) widget._init();
20
+ if (widget._create) widget._create();
21
+
22
+ $.data(element, 'plugin_' + pluginName, widget);
23
+ },
24
+
25
+ callMethod: function (widget, methodName) {
26
+ widget[methodName] && widget[methodName]();
27
+ }
28
+ };
29
+
30
+ $.fn[pluginName] = function () {
31
+ var args = arguments;
32
+ var argsCount = arguments.length;
33
+
34
+ this.each(function () {
35
+
36
+ var widget = $.data(this, 'plugin_' + pluginName);
37
+
38
+ // a widget is not created yet
39
+ if (!widget && argsCount <= 1) {
40
+ factory.createWidget(this, argsCount ? args[0] : false);
41
+
42
+ // a widget is created, the public method with no args is being called
43
+ } else if (argsCount == 1) {
44
+ factory.callMethod(widget, args[0]);
45
+ }
46
+ });
47
+ };
48
+ };
49
+
50
+ /**
51
+ * Radio #1
52
+ */
53
+
54
+ $.fn.onpRadioCircles = function( options ) {
55
+ if ( !options ) options = {};
56
+ options.theme = 'circles';
57
+ $(this).onpRadio(options);
58
+ };
59
+
60
+ $.fn.onpRadioSquares = function( options ) {
61
+ if ( !options ) options = {};
62
+ options.theme = 'squares';
63
+ $(this).onpRadio(options);
64
+ };
65
+
66
+ $.factory.widget('onpRadio', {
67
+ options: {
68
+ theme: 'squares',
69
+ selected: null
70
+ },
71
+ _create: function() {
72
+ var self = this;
73
+ this._createMarkup();
74
+
75
+ this.radio.find('.onp-radio-option').click(function(){
76
+ if ( $(this).is(".disabled") ) return;
77
+ var selected = self.radio.find('.onp-radio-option.selected');
78
+ if ( selected.data('value') == $(this).data('value')) return;
79
+
80
+ selected.removeClass('selected');
81
+ $(this).addClass("selected");
82
+
83
+ var value = $(this).data('value');
84
+ self.element.val(value);
85
+ self.element.trigger( "change", $(this).data('value') );
86
+ });
87
+ },
88
+ _createMarkup: function() {
89
+
90
+ var wrap = $("<ul class='onp-radio-wrap'></ul>").addClass('onp-radio-' + this.options.theme);
91
+ this.element.find("option").each(function(){
92
+ var $this = $(this);
93
+
94
+ var value = $this.attr('value');
95
+ var text = $this.html();
96
+ var icon = $this.data('icon');
97
+ var disabled = $this.attr('disabled');
98
+
99
+ var option = $("<li class='onp-radio-option' data-value='" + value + "'></li>");
100
+ var innerOptionWrap = $("<span class='onp-radio-option-inner-wrap'></span>").appendTo(option);
101
+ option.addClass('onp-radio-option-' + value);
102
+
103
+ if ( icon ) innerOptionWrap.append("<i class='" + icon + "'></i>");
104
+ if ( disabled ) option.addClass('disabled');
105
+
106
+ wrap.append(option);
107
+ });
108
+
109
+ this.options.selected = this.options.selected || this.element.find("option:selected").attr('value');
110
+ wrap.find('.onp-radio-option-' + this.options.selected).addClass("selected");
111
+
112
+ this.element.hide();
113
+ this.element.after(wrap);
114
+ this.radio = wrap;
115
+ }
116
+ });
117
+
118
+ var factoryForms = {
119
+
120
+ collapsedGroups: function( $target ) {
121
+ if ( !$target ) $target = $("body");
122
+
123
+ $target.find(".fy-collapsed-show").click(function(){
124
+ $( $(this).attr('href') ).fadeIn();
125
+ $(this).hide();
126
+ return false;
127
+ });
128
+
129
+ $target.find(".fy-collapsed-hide").click(function(){
130
+ var content = $( $(this).attr('href') );
131
+ content.fadeOut(300, function(){
132
+ content.prev().show();
133
+ });
134
+ return false;
135
+ });
136
+ }
137
+ }
138
+
139
+ $(function(){
140
+ $(".onp-radio-circles.auto").onpRadioCircles();
141
+ $(".onp-radio-squares.auto").onpRadioSquares();
142
+ factoryForms.collapsedGroups();
143
+ });
144
+
145
+ })(jQuery)
146
+
libs/factory/forms/boot.php ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Factory Forms
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @since 1.0.1
7
+ * @package factory-forms
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ // the module provides function for the admin area only
18
+
19
+ if ( ! is_admin() ) {
20
+ return;
21
+ }
22
+
23
+ // checks if the module is already loaded in order to
24
+ // prevent loading the same version of the module twice.
25
+ if ( defined( 'FACTORY_FORMS_422_LOADED' ) ) {
26
+ return;
27
+ }
28
+
29
+ define( 'FACTORY_FORMS_422_LOADED', true );
30
+
31
+ define( 'FACTORY_FORMS_422_VERSION', '4.2.2' );
32
+
33
+ // absolute path and URL to the files and resources of the module.
34
+ define( 'FACTORY_FORMS_422_DIR', dirname( __FILE__ ) );
35
+ define( 'FACTORY_FORMS_422_URL', plugins_url( null, __FILE__ ) );
36
+
37
+ #comp merge
38
+ require_once( FACTORY_FORMS_422_DIR . '/includes/providers/value-provider.interface.php' );
39
+ require_once( FACTORY_FORMS_422_DIR . '/includes/providers/meta-value-provider.class.php' );
40
+ require_once( FACTORY_FORMS_422_DIR . '/includes/providers/options-value-provider.class.php' );
41
+
42
+ require_once( FACTORY_FORMS_422_DIR . '/includes/form.class.php' );
43
+ #endcomp
44
+
45
+ load_plugin_textdomain( 'wbcr_factory_forms_422', false, dirname( plugin_basename( __FILE__ ) ) . '/langs' );
46
+
47
+ /**
48
+ * We add this code into the hook because all these controls quite heavy. So in order to get better perfomance,
49
+ * we load the form controls only on pages where the forms are created.
50
+ *
51
+ * @since 3.0.7
52
+ * @see the 'wbcr_factory_forms_422_register_controls' hook
53
+ *
54
+ */
55
+ if ( ! function_exists( 'wbcr_factory_forms_422_register_default_controls' ) ) {
56
+
57
+ /**
58
+ * @param Wbcr_Factory424_Plugin $plugin
59
+ *
60
+ * @throws Exception
61
+ */
62
+ function wbcr_factory_forms_422_register_default_controls( Wbcr_Factory424_Plugin $plugin ) {
63
+
64
+ if ( $plugin && ! isset( $plugin->forms ) ) {
65
+ throw new Exception( "The module Factory Forms is not loaded for the plugin '{$plugin->getPluginName()}'." );
66
+ }
67
+
68
+ require_once( FACTORY_FORMS_422_DIR . '/includes/html-builder.class.php' );
69
+ require_once( FACTORY_FORMS_422_DIR . '/includes/form-element.class.php' );
70
+ require_once( FACTORY_FORMS_422_DIR . '/includes/control.class.php' );
71
+ require_once( FACTORY_FORMS_422_DIR . '/includes/complex-control.class.php' );
72
+ require_once( FACTORY_FORMS_422_DIR . '/includes/holder.class.php' );
73
+ require_once( FACTORY_FORMS_422_DIR . '/includes/control-holder.class.php' );
74
+ require_once( FACTORY_FORMS_422_DIR . '/includes/custom-element.class.php' );
75
+ require_once( FACTORY_FORMS_422_DIR . '/includes/form-layout.class.php' );
76
+
77
+ // registration of controls
78
+ $plugin->forms->registerControls( [
79
+ [
80
+ 'type' => 'checkbox',
81
+ 'class' => 'Wbcr_FactoryForms422_CheckboxControl',
82
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/checkbox.php'
83
+ ],
84
+ [
85
+ 'type' => 'list',
86
+ 'class' => 'Wbcr_FactoryForms422_ListControl',
87
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/list.php'
88
+ ],
89
+ [
90
+ 'type' => 'dropdown',
91
+ 'class' => 'Wbcr_FactoryForms422_DropdownControl',
92
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/dropdown.php'
93
+ ],
94
+ [
95
+ 'type' => 'dropdown-and-colors',
96
+ 'class' => 'Wbcr_FactoryForms422_DropdownAndColorsControl',
97
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/dropdown-and-colors.php'
98
+ ],
99
+ [
100
+ 'type' => 'hidden',
101
+ 'class' => 'Wbcr_FactoryForms422_HiddenControl',
102
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/hidden.php'
103
+ ],
104
+ [
105
+ 'type' => 'hidden',
106
+ 'class' => 'Wbcr_FactoryForms422_HiddenControl',
107
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/hidden.php'
108
+ ],
109
+ [
110
+ 'type' => 'radio',
111
+ 'class' => 'Wbcr_FactoryForms422_RadioControl',
112
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/radio.php'
113
+ ],
114
+ [
115
+ 'type' => 'radio-colors',
116
+ 'class' => 'Wbcr_FactoryForms422_RadioColorsControl',
117
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/radio-colors.php'
118
+ ],
119
+ [
120
+ 'type' => 'textarea',
121
+ 'class' => 'Wbcr_FactoryForms422_TextareaControl',
122
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/textarea.php'
123
+ ],
124
+ [
125
+ 'type' => 'textbox',
126
+ 'class' => 'Wbcr_FactoryForms422_TextboxControl',
127
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/textbox.php'
128
+ ],
129
+ [
130
+ 'type' => 'multiple-textbox',
131
+ 'class' => 'Wbcr_FactoryForms422_MultipleTextboxControl',
132
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/multiple-textbox.php'
133
+ ],
134
+ [
135
+ 'type' => 'datetimepicker-range',
136
+ 'class' => 'Wbcr_FactoryForms422_DatepickerRangeControl',
137
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/datepicker-range.php'
138
+ ],
139
+ [
140
+ 'type' => 'url',
141
+ 'class' => 'Wbcr_FactoryForms422_UrlControl',
142
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/url.php'
143
+ ],
144
+ [
145
+ 'type' => 'wp-editor',
146
+ 'class' => 'Wbcr_FactoryForms422_WpEditorControl',
147
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/wp-editor.php'
148
+ ],
149
+ [
150
+ 'type' => 'color',
151
+ 'class' => 'Wbcr_FactoryForms422_ColorControl',
152
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/color.php'
153
+ ],
154
+ [
155
+ 'type' => 'color-and-opacity',
156
+ 'class' => 'Wbcr_FactoryForms422_ColorAndOpacityControl',
157
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/color-and-opacity.php'
158
+ ],
159
+ [
160
+ 'type' => 'gradient',
161
+ 'class' => 'Wbcr_FactoryForms422_GradientControl',
162
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/gradient.php'
163
+ ],
164
+ [
165
+ 'type' => 'font',
166
+ 'class' => 'Wbcr_FactoryForms422_FontControl',
167
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/font.php'
168
+ ],
169
+ [
170
+ 'type' => 'google-font',
171
+ 'class' => 'Wbcr_FactoryForms422_GoogleFontControl',
172
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/google-font.php'
173
+ ],
174
+ [
175
+ 'type' => 'pattern',
176
+ 'class' => 'Wbcr_FactoryForms422_PatternControl',
177
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/pattern.php'
178
+ ],
179
+ [
180
+ 'type' => 'integer',
181
+ 'class' => 'Wbcr_FactoryForms422_IntegerControl',
182
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/integer.php'
183
+ ],
184
+ [
185
+ 'type' => 'control-group',
186
+ 'class' => 'Wbcr_FactoryForms422_ControlGroupHolder',
187
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/control-group.php'
188
+ ],
189
+ [
190
+ 'type' => 'paddings-editor',
191
+ 'class' => 'Wbcr_FactoryForms422_PaddingsEditorControl',
192
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/paddings-editor.php'
193
+ ],
194
+ ] );
195
+
196
+ // registration of control holders
197
+ $plugin->forms->registerHolders( [
198
+ [
199
+ 'type' => 'tab',
200
+ 'class' => 'Wbcr_FactoryForms422_TabHolder',
201
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/tab.php'
202
+ ],
203
+ [
204
+ 'type' => 'tab-item',
205
+ 'class' => 'Wbcr_FactoryForms422_TabItemHolder',
206
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/tab-item.php'
207
+ ],
208
+ [
209
+ 'type' => 'accordion',
210
+ 'class' => 'Wbcr_FactoryForms422_AccordionHolder',
211
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/accordion.php'
212
+ ],
213
+ [
214
+ 'type' => 'accordion-item',
215
+ 'class' => 'Wbcr_FactoryForms422_AccordionItemHolder',
216
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/accordion-item.php'
217
+ ],
218
+ [
219
+ 'type' => 'control-group',
220
+ 'class' => 'Wbcr_FactoryForms422_ControlGroupHolder',
221
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/control-group.php'
222
+ ],
223
+ [
224
+ 'type' => 'control-group-item',
225
+ 'class' => 'Wbcr_FactoryForms422_ControlGroupItem',
226
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/control-group-item.php'
227
+ ],
228
+ [
229
+ 'type' => 'form-group',
230
+ 'class' => 'Wbcr_FactoryForms422_FormGroupHolder',
231
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/form-group.php'
232
+ ],
233
+ [
234
+ 'type' => 'more-link',
235
+ 'class' => 'Wbcr_FactoryForms422_MoreLinkHolder',
236
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/more-link.php'
237
+ ],
238
+ [
239
+ 'type' => 'div',
240
+ 'class' => 'Wbcr_FactoryForms422_DivHolder',
241
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/div.php'
242
+ ],
243
+ [
244
+ 'type' => 'columns',
245
+ 'class' => 'Wbcr_FactoryForms422_ColumnsHolder',
246
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/holders/columns.php'
247
+ ]
248
+ ] );
249
+
250
+ // registration custom form elements
251
+ $plugin->forms->registerCustomElements( [
252
+ [
253
+ 'type' => 'html',
254
+ 'class' => 'Wbcr_FactoryForms422_Html',
255
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/customs/html.php',
256
+ ],
257
+ [
258
+ 'type' => 'separator',
259
+ 'class' => 'Wbcr_FactoryForms422_Separator',
260
+ 'include' => FACTORY_FORMS_422_DIR . '/controls/customs/separator.php',
261
+ ],
262
+ ] );
263
+
264
+ // registration of form layouts
265
+ $plugin->forms->registerFormLayout( [
266
+ 'name' => 'bootstrap-3',
267
+ 'class' => 'Wbcr_FactoryForms422_Bootstrap3FormLayout',
268
+ 'include' => FACTORY_FORMS_422_DIR . '/layouts/bootstrap-3/bootstrap-3.php'
269
+ ] );
270
+ }
271
+
272
+ add_action( 'wbcr_factory_forms_422_register_controls', 'wbcr_factory_forms_422_register_default_controls' );
273
+ }
libs/factory/forms/controls/checkbox.php ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Checkbox Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ *
11
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
12
+ * @copyright (c) 2018, Webcraftic Ltd
13
+ *
14
+ * @package factory-forms
15
+ * @since 1.0.0
16
+ */
17
+
18
+ // Exit if accessed directly
19
+ if( !defined('ABSPATH') ) {
20
+ exit;
21
+ }
22
+
23
+ if( !class_exists('Wbcr_FactoryForms422_CheckboxControl') ) {
24
+
25
+ class Wbcr_FactoryForms422_CheckboxControl extends Wbcr_FactoryForms422_Control {
26
+
27
+ public $type = 'checkbox';
28
+
29
+ public function getSubmitValue($name, $sub_name)
30
+ {
31
+ $name_on_form = $this->getNameOnForm($name);
32
+
33
+ return isset($_POST[$name_on_form]) && $_POST[$name_on_form] != 0
34
+ ? 1
35
+ : 0;
36
+ }
37
+
38
+ /**
39
+ * Shows the html markup of the control.
40
+ *
41
+ * @since 1.0.0
42
+ * @return void
43
+ */
44
+ public function html()
45
+ {
46
+
47
+ $events_on_data = $this->getOption('eventsOn', array());
48
+ $events_off_data = $this->getOption('eventsOff', array());
49
+
50
+ if( !empty($events_on_data) || !empty($events_off_data) ) {
51
+
52
+ $events_on_string_data = json_encode($events_on_data);
53
+ $events_off_string_data = json_encode($events_off_data);
54
+
55
+ $name_on_form = $this->getNameOnForm();
56
+ $value = $this->getValue();
57
+
58
+ $print_styles = '';
59
+
60
+ if( $value ) {
61
+ $current_events_data = $events_on_data;
62
+ } else {
63
+ $current_events_data = $events_off_data;
64
+ }
65
+
66
+ foreach($current_events_data as $event_name => $selectors) {
67
+ if( $event_name == 'hide' ) {
68
+ $print_styles .= $selectors . '{display:none;}';
69
+ } else if( $event_name == 'show' ) {
70
+ $print_styles .= $selectors . '{display:block;}';
71
+ }
72
+ }
73
+
74
+ echo '<style>' . $print_styles . '</style>';
75
+ ?>
76
+
77
+ <script>
78
+ // Onepress factory checkbox control events
79
+ if( void 0 === window.__factory_checkbox_control_events_on_data ) {
80
+ window.__factory_checkbox_control_events_on_data = {};
81
+ }
82
+ if( void 0 === window.__factory_checkbox_control_events_off_data ) {
83
+ window.__factory_checkbox_control_events_off_data = {};
84
+ }
85
+ window.__factory_checkbox_control_events_on_data['<?php echo $name_on_form ?>'] = <?= $events_on_string_data ?>;
86
+ window.__factory_checkbox_control_events_off_data['<?php echo $name_on_form ?>'] = <?= $events_off_string_data ?>;
87
+ </script>
88
+ <?php
89
+ }
90
+
91
+ if( 'buttons' == $this->getOption('way') ) {
92
+ $this->buttonsHtml();
93
+ } else {
94
+ $this->defaultHtml();
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Shows the Buttons Checkbox.
100
+ *
101
+ * @since 1.0.0
102
+ * @return void
103
+ */
104
+ protected function buttonsHtml()
105
+ {
106
+ $value = esc_attr($this->getValue());
107
+ $name_on_form = $this->getNameOnForm();
108
+
109
+ $this->addCssClass('factory-buttons-way');
110
+ $this->addCssClass('btn-group');
111
+
112
+ if( $this->getOption('tumbler', false) ) {
113
+ $this->addCssClass('factory-tumbler');
114
+ }
115
+
116
+ $tumbler_function = $this->getOption('tumblerFunction', false);
117
+ if( $tumbler_function ) {
118
+ $this->addHtmlData('tumbler-function', $tumbler_function);
119
+ }
120
+
121
+ if( $this->getOption('tumblerHint', false) ) {
122
+ $this->addCssClass('factory-has-tumbler-hint');
123
+
124
+ $delay = $this->getOption('tumblerDelay', 3000);
125
+ $this->addHtmlData('tumbler-delay', $delay);
126
+ }
127
+
128
+
129
+ ?>
130
+ <div <?php $this->attrs() ?>>
131
+ <button type="button" class="btn btn-default btn-small btn-sm factory-on <?php if( $value ) {
132
+ echo 'active';
133
+ } ?>"><?php _e('On', 'wbcr_factory_forms_422') ?></button>
134
+ <button type="button" class="btn btn-default btn-small btn-sm factory-off <?php if( !$value ) {
135
+ echo 'active';
136
+ } ?>" data-value="0"><?php _e('Off', 'wbcr_factory_forms_422') ?></button>
137
+ <input type="checkbox" style="display: none" id="<?php echo $name_on_form ?>" class="factory-result" name="<?php echo $name_on_form ?>" value="<?= $value ?>" <?php if( $value ) {
138
+ echo 'checked="checked"';
139
+ } ?>" />
140
+ </div>
141
+ <?php if( $this->getOption('tumblerHint', false) ) { ?>
142
+ <div class="factory-checkbox-tumbler-hint factory-tumbler-hint" style="display: none;">
143
+ <div class="factory-tumbler-content">
144
+ <?php echo $this->getOption('tumblerHint') ?>
145
+ </div>
146
+ </div>
147
+ <?php } ?>
148
+ <?php
149
+ }
150
+
151
+ /**
152
+ * Shows the standart checkbox.
153
+ *
154
+ * @since 1.0.0
155
+ * @return void
156
+ */
157
+ protected function defaultHtml()
158
+ {
159
+ $value = esc_attr($this->getValue());
160
+ $name_on_form = $this->getNameOnForm();
161
+
162
+ $this->addHtmlAttr('type', 'checkbox');
163
+ $this->addHtmlAttr('id', $name_on_form);
164
+ $this->addHtmlAttr('name', $name_on_form);
165
+ $this->addHtmlAttr('value', $value);
166
+
167
+ if( $value ) {
168
+ $this->addHtmlAttr('checked', 'checked');
169
+ }
170
+ $this->addCssClass('factory-default-way');
171
+
172
+ ?>
173
+ <input <?php $this->attrs() ?>/>
174
+ <?php
175
+ }
176
+ }
177
+ }
libs/factory/forms/controls/color-and-opacity.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Color and Opacity
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ *
11
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
12
+ * @copyright (c) 2018, Webcraftic Ltd
13
+ *
14
+ * @package core
15
+ * @since 1.0.0
16
+ */
17
+
18
+ // Exit if accessed directly
19
+ if( !defined('ABSPATH') ) {
20
+ exit;
21
+ }
22
+
23
+ if( !class_exists('Wbcr_FactoryForms422_ColorAndOpacityControl') ) {
24
+ }
25
+
26
+ class Wbcr_FactoryForms422_ColorAndOpacityControl extends Wbcr_FactoryForms422_ComplexControl {
27
+
28
+ public $type = 'color-and-opacity';
29
+
30
+ public function __construct($options, $form, $provider = null)
31
+ {
32
+ parent::__construct($options, $form, $provider);
33
+
34
+ if( !isset($options['color']) ) {
35
+ $options['color'] = array();
36
+ }
37
+
38
+ $options['color'] = array_merge($options['color'], array(
39
+ 'name' => $this->options['name'] . '__color',
40
+ 'default' => isset($this->options['default'])
41
+ ? $this->options['default']['color']
42
+ : '#1e8cbe',
43
+ 'pickerTarget' => '.factory-control-' . $this->options['name'] . ' .factory-picker-target'
44
+ ));
45
+
46
+ if( !isset($options['opacity']) ) {
47
+ $options['opacity'] = array();
48
+ }
49
+
50
+ $options['opacity'] = array_merge($options['opacity'], array(
51
+ 'name' => $this->options['name'] . '__opacity',
52
+ 'default' => isset($this->options['default'])
53
+ ? $this->options['default']['opacity']
54
+ : 100,
55
+ 'units' => '%',
56
+ 'range' => array(0, 100),
57
+ 'way' => 'slider'
58
+ ));
59
+
60
+ $this->color = new Wbcr_FactoryForms422_ColorControl($options['color'], $form, $provider);
61
+ $this->opacity = new Wbcr_FactoryForms422_IntegerControl($options['opacity'], $form, $provider);
62
+
63
+ $this->innerControls = array($this->color, $this->opacity);
64
+ }
65
+
66
+ /**
67
+ * Shows the html markup of the control.
68
+ *
69
+ * @since 1.0.0
70
+ * @return void
71
+ */
72
+ public function html()
73
+ {
74
+ ?>
75
+ <div <?php $this->attrs() ?>>
76
+ <div class="factory-control-row">
77
+ <div class="factory-color-wrap">
78
+ <?php $this->color->html() ?>
79
+ </div>
80
+ <div class="factory-opacity-wrap">
81
+ <?php $this->opacity->html() ?>
82
+ </div>
83
+ </div>
84
+ <div class="factory-picker-target"></div>
85
+ </div>
86
+ <?php
87
+ }
88
+ }
libs/factory/forms/controls/color.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Color
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ *
11
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
12
+ * @copyright (c) 2018, Webcraftic Ltd
13
+ *
14
+ * @package core
15
+ * @since 1.0.0
16
+ */
17
+
18
+ // Exit if accessed directly
19
+ if( !defined('ABSPATH') ) {
20
+ exit;
21
+ }
22
+
23
+ if( !class_exists('Wbcr_FactoryForms422_ColorControl') ) {
24
+
25
+ class Wbcr_FactoryForms422_ColorControl extends Wbcr_FactoryForms422_Control {
26
+
27
+ public $type = 'color';
28
+
29
+ /**
30
+ * Shows the html markup of the control.
31
+ *
32
+ * @since 1.0.0
33
+ * @return void
34
+ */
35
+ public function html()
36
+ {
37
+ $name = $this->getNameOnForm();
38
+ $value = esc_attr($this->getValue());
39
+
40
+ if( !$value ) {
41
+ $value = '#1e8cbe';
42
+ }
43
+
44
+ // the "pickerTarget" options allows to select element where the palette will be shown
45
+ $picker_target = $this->getOption('pickerTarget');
46
+
47
+ if( !empty($picker_target) ) {
48
+ $this->addHtmlData('picker-target', $picker_target);
49
+ }
50
+
51
+ ?>
52
+ <div <?php $this->attrs() ?>>
53
+ <div class="factory-background" <?php echo(!empty($value)
54
+ ? 'style="background:' . $value . ';"'
55
+ : ''); ?>></div>
56
+ <div class="factory-pattern"></div>
57
+ <input type="text" id="<?php echo $name; ?>" name="<?php echo $name; ?>" class="factory-input-text factory-color-hex" value="<?php echo $value; ?>">
58
+ </div>
59
+ <?php
60
+ }
61
+ }
62
+ }
libs/factory/forms/controls/customs/html.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Html Markup
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_Html') ) {
18
+
19
+ class Wbcr_FactoryForms422_Html extends Wbcr_FactoryForms422_CustomElement {
20
+
21
+ public $type = 'html';
22
+
23
+ /**
24
+ * Shows the html markup of the element.
25
+ *
26
+ * @since 1.0.0
27
+ * @return void
28
+ */
29
+ public function html()
30
+ {
31
+ $html = $this->getOption('html', '');
32
+
33
+ // if the data options is a valid callback for an object method
34
+ if( (is_array($html) && count($html) == 2 && gettype($html[0]) == 'object') || function_exists($html) ) {
35
+
36
+ call_user_func($html, $this);
37
+
38
+ return;
39
+ }
40
+
41
+ // if the data options is an array of values
42
+ echo $html;
43
+ }
44
+ }
45
+ }
libs/factory/forms/controls/customs/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/forms/controls/customs/separator.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Separator Markup
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_Separator') ) {
18
+ class Wbcr_FactoryForms422_Separator extends Wbcr_FactoryForms422_CustomElement {
19
+
20
+ public $type = 'separator';
21
+
22
+ /**
23
+ * Shows the html markup of the element.
24
+ *
25
+ * @since 1.0.0
26
+ * @return void
27
+ */
28
+ public function html()
29
+ {
30
+ ?>
31
+ <div <?php $this->attrs() ?>></div>
32
+ <?php
33
+ }
34
+ }
35
+ }
libs/factory/forms/controls/datepicker-range.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Datepicker range control
5
+ *
6
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
7
+ * @copyright (c) 2018, Webcraftic Ltd
8
+ *
9
+ * Example:
10
+ * 'type' => 'datetimepicker-range',
11
+ * 'name' => 'facebook_start_date_filter',
12
+ * 'range_1' => array(
13
+ * 'format' => 'YYYY/MM/DD HH:mm',
14
+ * 'default' => date('Y/m/d H:i', strtotime('-1 week'))
15
+ * ),
16
+ * 'range_2' => array(
17
+ * 'format' => 'YYYY/MM/DD HH:mm',
18
+ * 'default' => date('Y/m/d H:i')
19
+ * ),
20
+ * 'title' => __('Выберите период', 'wpcr-scrapes'),
21
+ * 'hint' => __('Если Вкл., вы сможете установить настройки выбора записей за установленный период времени.', 'wpcr-scrapes')
22
+ *
23
+ * @package factory-forms
24
+ * @since 1.0.0
25
+ */
26
+
27
+ // Exit if accessed directly
28
+ if( !defined('ABSPATH') ) {
29
+ exit;
30
+ }
31
+
32
+ if( !class_exists('Wbcr_FactoryForms422_DatepickerRangeControl') ) {
33
+
34
+ class Wbcr_FactoryForms422_DatepickerRangeControl extends Wbcr_FactoryForms422_ComplexControl {
35
+
36
+ public $type = 'datetimepicker-range';
37
+
38
+ public function __construct($options, $form, $provider = null)
39
+ {
40
+ parent::__construct($options, $form, $provider);
41
+
42
+ if( !isset($options['range_1']) ) {
43
+ $options['range_1'] = array();
44
+ }
45
+
46
+ $options['range_1'] = array_merge(array(
47
+ 'scope' => isset($options['scope'])
48
+ ? $options['scope']
49
+ : 'factory',
50
+ 'name' => $this->options['name'] . '__range_1',
51
+ 'format' => 'YYYY/MM/DD HH:mm',
52
+ 'default' => date('Y/m/d H:i')
53
+ ), $options['range_1']);
54
+
55
+ if( !isset($options['range_2']) ) {
56
+ $options['range_2'] = array();
57
+ }
58
+
59
+ $options['range_2'] = array_merge(array(
60
+ 'scope' => isset($options['scope'])
61
+ ? $options['scope']
62
+ : 'factory',
63
+ 'name' => $this->options['name'] . '__range_2',
64
+ 'format' => 'YYYY/MM/DD HH:mm',
65
+ 'default' => date('Y/m/d H:i', strtotime("+1 month"))
66
+ ), $options['range_2']);
67
+
68
+ $this->range_1 = new Wbcr_FactoryForms422_TextboxControl($options['range_1'], $form, $provider);
69
+ $this->range_2 = new Wbcr_FactoryForms422_TextboxControl($options['range_2'], $form, $provider);
70
+ $this->inner_controls = array($this->range_1, $this->range_2);
71
+
72
+ foreach($this->inner_controls as $key => $control) {
73
+ $control->addCssClass('factory-datetimepicker-range-' . $key);
74
+ $control->addHtmlAttr('data-date-show-today-button', 'true');
75
+ $control->addHtmlAttr('data-date-show-clear', 'true');
76
+
77
+ $format = $control->getOption('format');
78
+
79
+ if( !empty($format) ) {
80
+ //'YYYY/MM/DD HH:mm'
81
+ $control->addHtmlAttr('data-date-format', $format);
82
+ }
83
+
84
+ $locale_parts = explode('_', get_locale());
85
+
86
+ $locale = isset($locale_parts[0])
87
+ ? $locale_parts[0]
88
+ : 'en';
89
+
90
+ $control->addHtmlAttr('data-date-locale', $locale);
91
+ }
92
+ }
93
+
94
+ public function render()
95
+ {
96
+ ?>
97
+ <div class='input-group date factory-datetimepicker-input-group' style="display:inline-block; width: 200px">
98
+ <?php $this->range_1->render(); ?>
99
+ </div>
100
+ <div class='input-group date factory-datetimepicker-input-group' style="display:inline-block; width: 200px">
101
+ <?php $this->range_2->render(); ?>
102
+ </div>
103
+ <?php
104
+ }
105
+ }
106
+ }
libs/factory/forms/controls/dropdown-and-colors.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Dropdown and Colors List Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * // see FactoryForms422_DropdownControl
9
+ * 'dropdown' => array(
10
+ * // a callback to return items or an array of items to select
11
+ * 'data' => OPanda_ThemeManager::getThemes(OPanda_Items::getCurrentItemName(), 'dropdown'),
12
+ * 'default' => 'default',
13
+ * 'value' => 'value' // a value to show in the control
14
+ * ),
15
+ * // see FactoryForms422_RadioColorsControl
16
+ * 'colors' => array(
17
+ * // a callback to return items or an array of items to select
18
+ * 'data' => array(
19
+ * array('default', '#75649b'),
20
+ * array('black', '#222'),
21
+ * array('light', '#fff3ce'),
22
+ * array('forest', '#c9d4be'),
23
+ * ),
24
+ * 'value' => 'value' // a value to show in the control
25
+ * 'default' => 'default', // a default value of the control if the "value" option is not specified
26
+ * ),
27
+ *
28
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
29
+ * @copyright (c) 2018, Webcraftic Ltd
30
+ *
31
+ * @package factory-forms
32
+ * @since 1.0.0
33
+ */
34
+
35
+ // Exit if accessed directly
36
+ if( !defined('ABSPATH') ) {
37
+ exit;
38
+ }
39
+
40
+ if( !class_exists('Wbcr_FactoryForms422_DropdownAndColorsControl') ) {
41
+
42
+ class Wbcr_FactoryForms422_DropdownAndColorsControl extends Wbcr_FactoryForms422_ComplexControl {
43
+
44
+ public $type = 'dropdown-and-colors';
45
+
46
+ public function __construct($options, $form, $provider = null)
47
+ {
48
+ parent::__construct($options, $form, $provider);
49
+
50
+ if( !isset($options['dropdown']) ) {
51
+ $options['dropdown'] = array();
52
+ }
53
+
54
+ $options['dropdown'] = array_merge($options['dropdown'], array(
55
+ 'scope' => isset($options['scope'])
56
+ ? $options['scope']
57
+ : 'opanda',
58
+ 'name' => $this->options['name'] . '__dropdown',
59
+ ));
60
+
61
+ if( !isset($options['colors']) ) {
62
+ $options['colors'] = array();
63
+ }
64
+
65
+ $options['colors'] = array_merge($options['colors'], array(
66
+ 'scope' => isset($options['scope'])
67
+ ? $options['scope']
68
+ : 'opanda',
69
+ 'name' => $this->options['name'] . '__colors',
70
+ ));
71
+
72
+ $this->dropdown = new Wbcr_FactoryForms422_DropdownControl($options['dropdown'], $form, $provider);
73
+ $this->colors = new Wbcr_FactoryForms422_RadioColorsControl($options['colors'], $form, $provider);
74
+ $this->inner_controls = array($this->dropdown, $this->colors);
75
+
76
+ $colors = $this->colors->getOption('data');
77
+
78
+ if( empty($colors) ) {
79
+ $dropdown_value = $this->dropdown->getValue();
80
+ $dOptions = $this->dropdown->getOption('data', array());
81
+
82
+ foreach($dOptions as $option) {
83
+ if( $option['value'] == $dropdown_value && isset($option['data']['colors']) ) {
84
+ $colors_options = json_decode(htmlspecialchars_decode($option['data']['colors']));
85
+ $this->colors->setOption('data', $colors_options);
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Shows the html markup of the control.
93
+ *
94
+ * @since 1.0.0
95
+ * @return void
96
+ */
97
+ public function html()
98
+ {
99
+ ?>
100
+ <script>
101
+ </script>
102
+ <div <?php $this->attrs() ?>>
103
+ <div class="factory-control-row">
104
+ <div class="factory-dropdown-wrap">
105
+ <?php $this->dropdown->render(); ?>
106
+ </div>
107
+ <div class="factory-colors-wrap">
108
+ <?php $this->colors->render(); ?>
109
+ </div>
110
+ </div>
111
+ <div class="factory-picker-target"></div>
112
+ </div>
113
+ <?php
114
+ }
115
+ }
116
+ }
libs/factory/forms/controls/dropdown.php ADDED
@@ -0,0 +1,393 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Dropdown List Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ * items => a callback to return items or an array of items to select
11
+ *
12
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
13
+ * @copyright (c) 2018, Webcraftic Ltd
14
+ *
15
+ * @package factory-forms
16
+ * @since 1.0.0
17
+ */
18
+
19
+ // Exit if accessed directly
20
+ if ( ! defined( 'ABSPATH' ) ) {
21
+ exit;
22
+ }
23
+
24
+ if ( ! class_exists( 'Wbcr_FactoryForms422_DropdownControl' ) ) {
25
+
26
+ class Wbcr_FactoryForms422_DropdownControl extends Wbcr_FactoryForms422_Control {
27
+
28
+ public $type = 'dropdown';
29
+
30
+ /**
31
+ * Returns a set of available items for the list.
32
+ *
33
+ * @since 1.0.0
34
+ * @return mixed[]
35
+ */
36
+ private function getItems() {
37
+ $data = $this->getOption( 'data', array() );
38
+
39
+ // if the data options is a valid callback for an object method
40
+ if ( ( is_array( $data ) && count( $data ) == 2 && is_object( $data[0] ) ) || is_string( $data ) ) {
41
+
42
+ return call_user_func( $data );
43
+ }
44
+
45
+ // if the data options is an array of values
46
+ return $data;
47
+ }
48
+
49
+ /**
50
+ * Returns true, if the data should be loaded via ajax.
51
+ *
52
+ * @since 1.0.0
53
+ * @return bool
54
+ */
55
+ protected function isAjax() {
56
+
57
+ $data = $this->getOption( 'data', array() );
58
+
59
+ return is_array( $data ) && isset( $data['ajax'] );
60
+ }
61
+
62
+ /**
63
+ * Shows the html markup of the control.
64
+ *
65
+ * @since 1.0.0
66
+ * @return void
67
+ */
68
+ public function html() {
69
+
70
+ $way = $this->getOption( 'way', 'default' );
71
+ $this->addHtmlData( 'way', $way );
72
+
73
+ $events_data = $this->getOption( 'events', array() );
74
+
75
+ if ( ! empty( $events_data ) ) {
76
+ $events_string_data = json_encode( $events_data );
77
+ $name_on_form = $this->getNameOnForm();
78
+
79
+ $value = $this->getValue();
80
+
81
+ if ( empty( $value ) || ( is_array( $value ) && empty( $value[0] ) ) ) {
82
+ $value = null;
83
+ }
84
+
85
+ if ( ! empty( $value ) && isset( $events_data[ $value ] ) && is_array( $events_data[ $value ] ) ) {
86
+ $print_styles = '';
87
+ foreach ( $events_data[ $value ] as $eventName => $selectors ) {
88
+ if ( $eventName == 'hide' ) {
89
+ $print_styles .= $selectors . '{display:none;}';
90
+ } else if ( $eventName == 'show' ) {
91
+ $print_styles .= $selectors . '{display:block;}';
92
+ }
93
+ }
94
+
95
+ echo '<style>' . $print_styles . '</style>';
96
+ }
97
+ ?>
98
+ <script>
99
+ // Onepress factory dropdown control events
100
+ if( void 0 === window.factory_dropdown_control_events_data ) {
101
+ window.factory_dropdown_control_events_data = {};
102
+ }
103
+ window.factory_dropdown_control_events_data['<?php echo $name_on_form ?>'] = <?= $events_string_data ?>;
104
+ </script>
105
+ <?php
106
+ }
107
+ if ( $this->isAjax() ) {
108
+
109
+ $data = $this->getOption( 'data', array() );
110
+ $ajax_id = 'factory-dropdown-' . rand( 1000000, 9999999 );
111
+
112
+ $value = $this->getValue();
113
+
114
+ if ( empty( $value ) || ( is_array( $value ) && empty( $value[0] ) ) ) {
115
+ $value = null;
116
+ }
117
+
118
+ ?>
119
+ <div class="factory-ajax-loader <?php echo $ajax_id . '-loader'; ?>"></div>
120
+ <script>
121
+ window['<?php echo $ajax_id ?>'] = {
122
+ 'loader': '.<?php echo $ajax_id . '-loader' ?>',
123
+ 'url': '<?php echo $data['url'] ?>',
124
+ 'data': <?php echo json_encode( $data['data'] ) ?>,
125
+ 'selected': '<?php echo $value ?>',
126
+ 'empty_list': '<?php echo $this->getOption( 'empty', __( 'The list is empty.', 'wbcr_factory_forms_422' ) ) ?>'
127
+ };
128
+ </script>
129
+ <?php
130
+
131
+ $this->addHtmlData( 'ajax', true );
132
+ $this->addHtmlData( 'ajax-data-id', $ajax_id );
133
+ $this->addCssClass( 'factory-hidden' );
134
+ }
135
+
136
+ if ( 'buttons' == $way ) {
137
+ $this->buttonsHtml();
138
+ } elseif ( 'ddslick' == $way ) {
139
+ $this->ddslickHtml();
140
+ } else {
141
+ $this->defaultHtml();
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Shows the Buttons Dropdown.
147
+ *
148
+ * @since 1.0.0
149
+ * @return void
150
+ */
151
+ protected function buttonsHtml() {
152
+ $items = $this->getItems();
153
+ $value = $this->getValue();
154
+
155
+ $name_on_form = $this->getNameOnForm();
156
+
157
+ $this->addCssClass( 'factory-buttons-way' );
158
+
159
+ ?>
160
+ <div <?php $this->attrs() ?>>
161
+ <div class="btn-group factory-buttons-group">
162
+ <?php foreach ( $items as $item ) { ?>
163
+ <button type="button" class="btn btn-default btn-small factory-<?php echo $item[0] ?> <?php if ( $value == $item[0] ) {
164
+ echo 'active';
165
+ } ?>" data-value="<?php echo $item[0] ?>"><?php echo $item[1] ?></button>
166
+ <?php } ?>
167
+ <input type="hidden" id="<?php echo $name_on_form ?>" class="factory-result" name="<?php echo $name_on_form ?>" value="<?php echo $value ?>"/>
168
+ </div>
169
+ <div class="factory-hints">
170
+ <?php foreach ( $items as $item ) { ?>
171
+ <?php if ( isset( $item[2] ) ) { ?>
172
+ <div class="factory-hint factory-hint-<?php echo $item[0] ?>" <?php if ( $value !== $item[0] ) {
173
+ echo 'style="display: none;"';
174
+ } ?>><?php echo $item[2] ?></div>
175
+ <?php } ?>
176
+ <?php } ?>
177
+ </div>
178
+ </div>
179
+ <?php
180
+ }
181
+
182
+ /**
183
+ * Shows the ddSlick dropbox.
184
+ *
185
+ * @since 3.2.8
186
+ * @return void
187
+ */
188
+ protected function ddslickHtml() {
189
+ $items = $this->getItems();
190
+ $value = $this->getValue();
191
+
192
+ $name_on_form = $this->getNameOnForm();
193
+
194
+ $this->addCssClass( 'factory-ddslick-way' );
195
+ $this->addHtmlData( 'name', $name_on_form );
196
+
197
+ $this->addHtmlData( 'width', $this->getOption( 'width', 300 ) );
198
+ $this->addHtmlData( 'align', $this->getOption( 'imagePosition', 'right' ) );
199
+
200
+ ?>
201
+ <div <?php $this->attrs() ?>>
202
+ <script>
203
+ //Dropdown plugin data
204
+ var factory_<?php echo $name_on_form ?>_data = [
205
+ <?php foreach ( $items as $item ) { ?>
206
+ {
207
+ text: "<?php echo $item['title'] ?>",
208
+ value: "<?php echo $item['value'] ?>",
209
+ selected: <?php if ( $value == $item['value'] ) {
210
+ echo 'true';
211
+ } else {
212
+ echo 'false';
213
+ } ?>,
214
+ description: "<?php echo( isset( $item['hint'] ) ? $item['hint'] : '' ); ?>",
215
+ imageSrc: "<?php echo( isset( $item['image'] ) ? $item['image'] : '' ); ?>",
216
+ imageHoverSrc: "<?php echo( isset( $item['hover'] ) ? $item['hover'] : '' ); ?>"
217
+ },
218
+ <?php } ?>
219
+ ];
220
+ </script>
221
+ <div class="factory-ddslick"></div>
222
+ <input type="hidden" class="factory-result" id="<?php echo $name_on_form ?>" name="<?php echo $name_on_form ?>" value="<?php echo $value ?>"/>
223
+ </div>
224
+ <?php
225
+ }
226
+
227
+ /**
228
+ * Shows the standart dropdown.
229
+ *
230
+ * @since 1.3.1
231
+ * @return void
232
+ */
233
+ protected function defaultHtml() {
234
+
235
+ $items = $this->getItems();
236
+ $value = esc_attr( $this->getValue() );
237
+
238
+ $name_on_form = $this->getNameOnForm();
239
+
240
+ $this->addHtmlAttr( 'id', $name_on_form );
241
+ $this->addHtmlAttr( 'name', $name_on_form );
242
+ $this->addCssClass( 'form-control' );
243
+
244
+ $hasGroups = $this->getOption( 'hasGroups', true );
245
+ $has_hints = $this->getOption( 'hasHints', false );
246
+
247
+ foreach ( $items as $item ) {
248
+ if ( isset( $item['type'] ) && $item['type'] == 'group' && ! empty( $item['items'] ) ) {
249
+ foreach ( (array) $item['items'] as $group_item ) {
250
+ $is_hint = ( isset( $group_item['hint'] ) && ! empty( $group_item['hint'] ) ) || ( isset( $group_item[2] ) && ! empty( $group_item[2] ) );
251
+ if ( ! $is_hint ) {
252
+ continue;
253
+ }
254
+ $has_hints = true;
255
+ break;
256
+ }
257
+ if ( $has_hints ) {
258
+ break;
259
+ }
260
+ } else {
261
+ $is_hint = ( isset( $item['hint'] ) && ! empty( $item['hint'] ) ) || ( isset( $item[2] ) && ! $item[2] );
262
+ if ( ! $is_hint ) {
263
+ continue;
264
+ }
265
+ $has_hints = true;
266
+ break;
267
+ }
268
+ }
269
+
270
+ $is_empty = $this->isAjax() || empty( $items );
271
+ $empty_list = $this->getOption( 'empty', __( '- empty -', 'wbcr_factory_forms_422' ) );
272
+
273
+ ?>
274
+ <select <?php $this->attrs() ?>>
275
+ <?php if ( $is_empty ) { ?>
276
+ <option value='' class="factory-empty-option">
277
+ <?php echo $empty_list ?>
278
+ </option>
279
+ <?php } else { ?>
280
+ <?php $this->printItems( $items, $value ) ?>
281
+ <?php } ?>
282
+ </select>
283
+ <?php if ( $has_hints ) { ?>
284
+ <div class="factory-hints">
285
+ <?php foreach ( $items as $item ) {
286
+ if ( isset( $item['type'] ) && $item['type'] == 'group' && ! empty( $item['items'] ) ) {
287
+ foreach ( (array) $item['items'] as $group_item ) {
288
+
289
+ $hint = isset( $group_item[2] ) ? esc_attr( $group_item[2] ) : null;
290
+ $hint = isset( $group_item['hint'] ) ? esc_attr( $group_item['hint'] ) : $hint;
291
+
292
+ $value = isset( $group_item[0] ) ? esc_attr( $group_item[0] ) : null;
293
+ $value = isset( $group_item['value'] ) ? esc_attr( $group_item['value'] ) : $value;
294
+
295
+ $this->printHint( $hint, $value, $value !== $value );
296
+ }
297
+ } else {
298
+ $hint = isset( $item[2] ) ? esc_attr( $item[2] ) : null;
299
+ $hint = isset( $item['hint'] ) ? esc_attr( $item['hint'] ) : $hint;
300
+
301
+ $value = isset( $item[0] ) ? esc_attr( $item[0] ) : null;
302
+ $value = isset( $item['value'] ) ? esc_attr( $item['value'] ) : $value;
303
+
304
+ $this->printHint( $hint, $value, $value !== $value );
305
+ }
306
+ } ?>
307
+ </div>
308
+ <?php } ?>
309
+ <?php
310
+ }
311
+
312
+ /**
313
+ * Print single hint markup
314
+ * @since 4.1.0
315
+ *
316
+ * @param string $hint
317
+ *
318
+ * @return void
319
+ */
320
+ protected function printHint( $hint, $name, $is_visible = false ) {
321
+
322
+ if ( ! empty( $hint ) ) {
323
+ $styles = ( $is_visible ) ? 'style="display: none;"' : '';
324
+
325
+ ?>
326
+ <div style="display: none;" class="factory-hint factory-hint-<?= esc_attr( $name ) ?>"<?= $styles ?>><?php echo $hint ?></div>
327
+ <?php
328
+ }
329
+ }
330
+
331
+ /**
332
+ * @param array $items
333
+ * @param null $selected
334
+ */
335
+ protected function printItems( $items, $selected = null ) {
336
+
337
+ foreach ( (array) $items as $item ) {
338
+
339
+ $subitems = array();
340
+ $data = null;
341
+
342
+ // this item is an associative array
343
+ if ( isset( $item['type'] ) || isset( $item['value'] ) ) {
344
+
345
+ $type = isset( $item['type'] ) ? $item['type'] : 'option';
346
+
347
+ if ( 'group' === $type ) {
348
+ $subitems = isset( $item['items'] ) ? $item['items'] : array();
349
+ }
350
+
351
+ $value = isset( $item['value'] ) ? $item['value'] : '';
352
+ $title = isset( $item['title'] ) ? $item['title'] : __( '- empty -', 'wbcr_factory_forms_422' );
353
+
354
+ $data = isset( $item['data'] ) ? $item['data'] : null;
355
+ } else {
356
+
357
+ $type = ( count( $item ) == 3 && $item[0] === 'group' ) ? 'group' : 'option';
358
+ if ( 'group' === $type ) {
359
+ $subitems = $item[2];
360
+ }
361
+
362
+ $title = $item[1];
363
+ $value = esc_attr( $item[0] );
364
+ }
365
+
366
+ if ( 'group' === $type ) {
367
+ ?>
368
+ <optgroup label="<?php echo $title ?>">
369
+ <?php $this->printItems( $subitems, $selected ); ?>
370
+ </optgroup>
371
+ <?php
372
+ } else {
373
+
374
+ $attr = ( $selected == $value ) ? 'selected="selected"' : '';
375
+
376
+ $strData = '';
377
+ if ( ! empty( $data ) ) {
378
+
379
+ foreach ( $data as $key => $values ) {
380
+ $strData = $strData . ' data-' . $key . '="' . ( is_array( $values ) ? implode( ',', $values ) : $values ) . '"';
381
+ }
382
+ }
383
+
384
+ ?>
385
+ <option value='<?php echo $value ?>' <?php echo $attr ?> <?php echo $strData ?>>
386
+ <?php echo $title ?>
387
+ </option>
388
+ <?php
389
+ }
390
+ }
391
+ }
392
+ }
393
+ }
libs/factory/forms/controls/font.php ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Dropdown List Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ * items => a callback to return items or an array of items to select
11
+ *
12
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
13
+ * @copyright (c) 2018, Webcraftic Ltd
14
+ *
15
+ * @package core
16
+ * @since 1.0.0
17
+ */
18
+ // Exit if accessed directly
19
+ if( !defined('ABSPATH') ) {
20
+ exit;
21
+ }
22
+
23
+ if( !class_exists('Wbcr_FactoryForms422_FontControl') ) {
24
+
25
+ class Wbcr_FactoryForms422_FontControl extends Wbcr_FactoryForms422_ComplexControl {
26
+
27
+ public $type = 'font';
28
+
29
+ public function __construct($options, $form, $provider = null)
30
+ {
31
+ parent::__construct($options, $form, $provider);
32
+
33
+ $option_font_size = array(
34
+ 'name' => $this->options['name'] . '__size',
35
+ 'units' => $this->options['units'],
36
+ 'default' => isset($this->options['default'])
37
+ ? $this->options['default']['size']
38
+ : null
39
+ );
40
+
41
+ $option_font_family = array(
42
+ 'name' => $this->options['name'] . '__family',
43
+ 'data' => $this->getFonts(),
44
+ 'default' => isset($this->options['default'])
45
+ ? $this->options['default']['family']
46
+ : null
47
+ );
48
+
49
+ $optionFontColor = array(
50
+ 'name' => $this->options['name'] . '__color',
51
+ 'default' => isset($this->options['default'])
52
+ ? $this->options['default']['color']
53
+ : null,
54
+ 'pickerTarget' => '.factory-control-' . $this->options['name'] . ' .factory-picker-target'
55
+ );
56
+
57
+ $this->size = new Wbcr_FactoryForms422_IntegerControl($option_font_size, $form, $provider);
58
+ $this->family = new Wbcr_FactoryForms422_DropdownControl($option_font_family, $form, $provider);
59
+ $this->color = new Wbcr_FactoryForms422_ColorControl($optionFontColor, $form, $provider);
60
+
61
+ $this->innerControls = array($this->family, $this->size, $this->color);
62
+ }
63
+
64
+ public function getFonts()
65
+ {
66
+
67
+ $fonts = $this->getDefaultFonts();
68
+
69
+ $fonts = apply_filters('wbcr_factory_forms_422_fonts', $fonts);
70
+ $fonts = apply_filters('wbcr_factory_forms_422_fonts-' . $this->options['name'], $fonts);
71
+
72
+ return $fonts;
73
+ }
74
+
75
+ public function getDefaultFonts()
76
+ {
77
+
78
+ $fonts = array(
79
+
80
+ array('inherit', __('(use default website font)', 'wbcr_factory_forms_422')),
81
+ array(
82
+ 'group',
83
+ __('Sans Serif:', 'wbcr_factory_forms_422'),
84
+ array(
85
+ array('Arial, "Helvetica Neue", Helvetica, sans-serif', 'Arial'),
86
+ array('"Arial Black", "Arial Bold", Gadget, sans-serif', 'Arial Black'),
87
+ array('"Arial Narrow", Arial, sans-serif', 'Arial Narrow'),
88
+ array(
89
+ '"Arial Rounded MT Bold", "Helvetica Rounded", Arial, sans-serif',
90
+ 'Arial Rounded MT Bold'
91
+ ),
92
+ array(
93
+ '"Avant Garde", Avantgarde, "Century Gothic", CenturyGothic, "AppleGothic", sans-serif',
94
+ 'Avant Garde'
95
+ ),
96
+ array('Calibri, Candara, Segoe, "Segoe UI", Optima, Arial, sans-serif', 'Calibri'),
97
+ array('Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif', 'Candara'),
98
+ array('"Century Gothic", CenturyGothic, AppleGothic, sans-serif', 'Century Gothic'),
99
+ array(
100
+ '"Franklin Gothic Medium", "Franklin Gothic", "ITC Franklin Gothic", Arial, sans-serif',
101
+ 'Franklin Gothic Medium'
102
+ ),
103
+ array('Futura, "Trebuchet MS", Arial, sans-serif', 'Futura'),
104
+ array('Geneva, Tahoma, Verdana, sans-serif', 'Geneva'),
105
+ array('"Gill Sans", "Gill Sans MT", Calibri, sans-serif', 'Gill Sans'),
106
+ array('"Helvetica Neue", Helvetica, Arial, sans-serif', 'Helvetica'),
107
+ array(
108
+ 'Impact, Haettenschweiler, "Franklin Gothic Bold", Charcoal, "Helvetica Inserat", "Bitstream Vera Sans Bold", "Arial Black", sans serif',
109
+ 'Impact'
110
+ ),
111
+ array(
112
+ '"Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif',
113
+ 'Lucida Grande'
114
+ ),
115
+ array('Optima, Segoe, "Segoe UI", Candara, Calibri, Arial, sans-serif', 'Optima'),
116
+ array(
117
+ '"Segoe UI", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif',
118
+ 'Segoe UI'
119
+ ),
120
+ array(
121
+ 'Montserrat, "Segoe UI", "Helvetica Neue", Arial, sans-serif',
122
+ 'Montserrat'
123
+ ),
124
+ array('Tahoma, Verdana, Segoe, sans-serif', 'Tahoma'),
125
+ array(
126
+ '"Trebuchet MS", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Tahoma, sans-serif',
127
+ 'Trebuchet MS'
128
+ ),
129
+ array('Verdana, Geneva, sans-serif', 'Verdana'),
130
+ )
131
+ ),
132
+ array(
133
+ 'group',
134
+ __('Serif:', 'wbcr_factory_forms_422'),
135
+ array(
136
+ array(
137
+ 'Baskerville, "Baskerville Old Face", "Hoefler Text", Garamond, "Times New Roman", serif',
138
+ 'Baskerville'
139
+ ),
140
+ array('"Big Caslon", "Book Antiqua", "Palatino Linotype", Georgia, serif', 'Big Caslon'),
141
+ array(
142
+ '"Bodoni MT", Didot, "Didot LT STD", "Hoefler Text", Garamond, "Times New Roman", serif',
143
+ 'Bodoni MT'
144
+ ),
145
+ array(
146
+ '"Book Antiqua", Palatino, "Palatino Linotype", "Palatino LT STD", Georgia, serif',
147
+ 'Book Antiqua'
148
+ ),
149
+ array(
150
+ '"Calisto MT", "Bookman Old Style", Bookman, "Goudy Old Style", Garamond, "Hoefler Text", "Bitstream Charter", Georgia, serif',
151
+ 'Calisto MT'
152
+ ),
153
+ array('Cambria, Georgia, serif', 'Cambria'),
154
+ array('Didot, "Didot LT STD", "Hoefler Text", Garamond, "Times New Roman", serif', 'Didot'),
155
+ array(
156
+ 'Garamond, Baskerville, "Baskerville Old Face", "Hoefler Text", "Times New Roman", serif',
157
+ 'Garamond'
158
+ ),
159
+ array('Georgia, Times, "Times New Roman", serif', 'Georgia'),
160
+ array(
161
+ '"Goudy Old Style", Garamond, "Big Caslon", "Times New Roman", serif',
162
+ 'Goudy Old Style'
163
+ ),
164
+ array(
165
+ '"Hoefler Text", "Baskerville old face", Garamond, "Times New Roman", serif',
166
+ 'Hoefler Text'
167
+ ),
168
+ array('"Lucida Bright", Georgia, serif', 'Lucida Bright'),
169
+ array(
170
+ 'Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif',
171
+ 'Palatino'
172
+ ),
173
+ array(
174
+ 'Perpetua, Baskerville, "Big Caslon", "Palatino Linotype", Palatino, "URW Palladio L", "Nimbus Roman No9 L", serif',
175
+ 'Perpetua'
176
+ ),
177
+ array(
178
+ 'Rockwell, "Courier Bold", Courier, Georgia, Times, "Times New Roman", serif',
179
+ 'Rockwell'
180
+ ),
181
+ array('"Rockwell Extra Bold", "Rockwell Bold", monospace', 'Rockwell Extra Bold'),
182
+ array(
183
+ 'TimesNewRoman, "Times New Roman", Times, Baskerville, Georgia, serif',
184
+ 'Times New Roman'
185
+ )
186
+ )
187
+ ),
188
+ array(
189
+ 'group',
190
+ __('Monospaced:', 'wbcr_factory_forms_422'),
191
+ array(
192
+ array('"Andale Mono", AndaleMono, monospace', 'Andale Mono'),
193
+ array('Consolas, monaco, monospace', 'Consolas'),
194
+ array(
195
+ '"Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace',
196
+ 'Courier New'
197
+ ),
198
+ array(
199
+ '"Lucida Console", "Lucida Sans Typewriter", Monaco, "Bitstream Vera Sans Mono", monospace',
200
+ 'Lucida Console'
201
+ ),
202
+ array(
203
+ '"Lucida Sans Typewriter", "Lucida Console", Monaco, "Bitstream Vera Sans Mono", monospace',
204
+ 'Lucida Sans Typewriter'
205
+ ),
206
+ array('Monaco, Consolas, "Lucida Console", monospace', 'Monaco')
207
+ )
208
+ )
209
+
210
+ );
211
+
212
+ return $fonts;
213
+ }
214
+
215
+ /**
216
+ * Removes \" in the font family value.
217
+ *
218
+ * @since 3.1.0
219
+ * @return mixed[]
220
+ */
221
+ public function getValuesToSave()
222
+ {
223
+ $values = parent::getValuesToSave();
224
+
225
+ $family_key = $this->options['name'] . '__family';
226
+ $values[$family_key] = sanitize_text_field($values[$family_key]);
227
+
228
+ return $values;
229
+ }
230
+
231
+ public function beforeControlsHtml()
232
+ {
233
+ }
234
+
235
+ public function afterControlsHtml()
236
+ {
237
+ }
238
+
239
+ /**
240
+ * Shows the html markup of the control.
241
+ *
242
+ * @since 1.0.0
243
+ * @return void
244
+ */
245
+ public function html()
246
+ {
247
+ ?>
248
+ <div <?php $this->attrs() ?>>
249
+ <div class="factory-control-row">
250
+ <?php $this->beforeControlsHtml() ?>
251
+
252
+ <div class="factory-family-wrap">
253
+ <?php $this->family->html() ?>
254
+ </div>
255
+ <div class="factory-size-wrap">
256
+ <?php $this->size->html() ?>
257
+ </div>
258
+ <div class="factory-color-wrap">
259
+ <?php $this->color->html() ?>
260
+ </div>
261
+
262
+ <?php $this->afterControlsHtml() ?>
263
+ </div>
264
+ <div class="factory-picker-target"></div>
265
+ </div>
266
+ <?php
267
+ }
268
+ }
269
+ }
270
+
libs/factory/forms/controls/google-font.php ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Dropdown List Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ * items => a callback to return items or an array of items to select
11
+ *
12
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
13
+ * @copyright (c) 2018, Webcraftic Ltd
14
+ *
15
+ * @package core
16
+ * @since 1.0.0
17
+ */
18
+ class Wbcr_FactoryForms422_GoogleFontControl extends Wbcr_FactoryForms422_FontControl {
19
+
20
+ public $type = 'google-font';
21
+ const APIKEY = 'AIzaSyB-3vazYv7Q-5QZA04bmSKFrWcw_VhC40w';
22
+
23
+ public function __construct($options, $form, $provider = null)
24
+ {
25
+ parent::__construct($options, $form, $provider);
26
+ $this->addCssClass('factory-font');
27
+
28
+ $option_google_font_data = array(
29
+ 'name' => $this->options['name'] . '__google_font_data',
30
+ 'cssClass' => 'factory-google-font-data'
31
+ );
32
+
33
+ $this->google_font_data = new Wbcr_FactoryForms422_HiddenControl($option_google_font_data, $form, $provider);
34
+ $this->inner_controls[] = $this->google_font_data;
35
+ }
36
+
37
+ /**
38
+ * @return array|mixed
39
+ */
40
+ public function getDefaultFonts()
41
+ {
42
+
43
+ $cache_fonts = get_transient('wbcr_factory_google_fonts');
44
+
45
+ if( !empty($cache_fonts) ) {
46
+ return $cache_fonts;
47
+ }
48
+
49
+ $google_fonts = $this->getGoogleFonts();
50
+
51
+ $fonts = array(
52
+ array('inherit', __('(use default website font)', 'wbcr_factory_forms_422'))
53
+ );
54
+
55
+ $fontsCommon = array(
56
+ 'group',
57
+ __('Standard:', 'wbcr_factory_forms_422'),
58
+ array(
59
+
60
+ array('Arial, "Helvetica Neue", Helvetica, sans-serif', 'Arial'),
61
+ array('"Helvetica Neue", Helvetica, Arial, sans-serif', 'Helvetica'),
62
+ array('Tahoma, Verdana, Segoe, sans-serif', 'Tahoma'),
63
+ array('Verdana, Geneva, sans-serif', 'Verdana'),
64
+
65
+ )
66
+ );
67
+
68
+ $fontsGoogleFonts = array('group', __('Google Fonts:', 'wbcr_factory_forms_422'), array());
69
+
70
+ foreach($google_fonts->items as $item) {
71
+
72
+ $alt_font = $item->category;
73
+ if( in_array($alt_font, array('handwriting', 'display')) ) {
74
+ $alt_font = 'serif';
75
+ }
76
+
77
+ $listItem = array(
78
+ 'title' => $item->family,
79
+ 'value' => $item->family . ', ' . $item->category,
80
+ 'hint' => '<em>Google Font</em>',
81
+ 'data' => array(
82
+ 'google-font' => true,
83
+ 'family' => $item->family,
84
+ 'variants' => $item->variants,
85
+ 'subsets' => $item->subsets
86
+ )
87
+ );
88
+
89
+ $fontsGoogleFonts[2][] = $listItem;
90
+ }
91
+
92
+ $fonts[] = $fontsCommon;
93
+ $fonts[] = $fontsGoogleFonts;
94
+
95
+ set_transient('wbcr_factory_google_fonts', $fonts, 60 * 60 * 6);
96
+
97
+ return $fonts;
98
+ }
99
+
100
+ /**
101
+ * @return array|mixed|object
102
+ */
103
+ protected function getGoogleFonts()
104
+ {
105
+
106
+ $body = get_transient('wbcr_factory_google_fonts_raw');
107
+ if( !empty($body) ) {
108
+ return $body;
109
+ }
110
+
111
+ $response = wp_remote_get(sprintf('https://www.googleapis.com/webfonts/v1/webfonts?key=%s', self::APIKEY));
112
+
113
+ $this->error = false;
114
+ $this->defailed_error = false;
115
+
116
+ if( is_wp_error($response) ) {
117
+
118
+ $this->error = __('Unable to retrieve the list of Google Fonts.', 'wbcr_factory_forms_422');
119
+ $this->defailed_error = $response->get_error_message();
120
+
121
+ return $body;
122
+ }
123
+
124
+ if( !isset($response['body']) ) {
125
+
126
+ $this->error = __('Invalide response from the Google Fonts API.', 'wbcr_factory_forms_422');
127
+ $this->defailed_error = $response['body'];
128
+
129
+ return $body;
130
+ }
131
+
132
+ $body = json_decode($response['body']);
133
+
134
+ if( empty($body->items) ) {
135
+
136
+ $this->error = __('Unexpected error. The list of Google Fonts are empty.', 'wbcr_factory_forms_422');
137
+
138
+ return $body;
139
+ }
140
+
141
+ set_transient('wbcr_factory_google_fonts_raw', $body, 60 * 60 * 6);
142
+
143
+ return $body;
144
+ }
145
+
146
+ public function afterControlsHtml()
147
+ {
148
+ ?>
149
+ <?php $this->google_font_data->html() ?>
150
+ <?php
151
+ }
152
+ }
libs/factory/forms/controls/gradient.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Gradient picker Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * title => Заголовок
9
+ * colors => массив цветов для градиента
10
+ * Пример: array("#000 0% 0.5", "#e70303 100% 1")
11
+ * filldirection => Направление градиента(top, left)
12
+ * Пример: 90deg
13
+ * value => a value to show in the control
14
+ * default => a default value of the control if the "value" option is not specified
15
+ *
16
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
17
+ * @copyright (c) 2018, Webcraftic Ltd
18
+ *
19
+ * @package core
20
+ * @since 1.0.0
21
+ */
22
+
23
+ // Exit if accessed directly
24
+ if( !defined('ABSPATH') ) {
25
+ exit;
26
+ }
27
+
28
+ if( !class_exists('Wbcr_FactoryForms422_GradientControl') ) {
29
+ class Wbcr_FactoryForms422_GradientControl extends Wbcr_FactoryForms422_Control {
30
+
31
+ public $type = 'gradient';
32
+
33
+ /**
34
+ * Shows the html markup of the control.
35
+ *
36
+ * @since 1.0.0
37
+ * @return void
38
+ */
39
+ public function html()
40
+ {
41
+ $name = $this->getNameOnForm();
42
+ $value = esc_attr($this->getValue());
43
+
44
+ if( !empty($value) ) {
45
+
46
+ $values = json_decode(stripcslashes(htmlspecialchars_decode($value)));
47
+
48
+ $points = '';
49
+
50
+ foreach($values->color_points as $split_values) {
51
+ $points .= $split_values . ',';
52
+ }
53
+
54
+ $points = rtrim($points, ',');
55
+
56
+ $this->addHtmlData('points', $points);
57
+ $this->addHtmlData('directions', $values->filldirection);
58
+ } else {
59
+ $this->addHtmlData('directions', 'top');
60
+ }
61
+ ?>
62
+ <script>
63
+ if( !window.factory ) {
64
+ window.factory = {};
65
+ }
66
+ if( !window.factory.res ) {
67
+ window.factory.res = {};
68
+ }
69
+ factory.res.resVertical = '<?php _e( 'vertical', 'wbcr_factory_forms_422' ) ?>';
70
+ factory.res.resHorizontal = '<?php _e( 'horizontal', 'wbcr_factory_forms_422' ) ?>';
71
+ </script>
72
+ <div <?php $this->attrs() ?>>
73
+ <div class="factory-gradient-picker">
74
+ <ul class="gradientPicker-pallets">
75
+ <li class="factory-preset-gradient factory-primary-gradient" data-primary="#1bbc9d" data-secondary="#16a086"></li>
76
+ <li class="factory-preset-gradient factory-primary-gradient" data-primary="#2fcc71" data-secondary="#27ae61"></li>
77
+ <li class="factory-preset-gradient factory-primary-gradient" data-primary="#3598dc" data-secondary="#2a80b9"></li>
78
+ <li class="factory-preset-gradient factory-primary-gradient" data-primary="#9c59b8" data-secondary="#8f44ad"></li>
79
+ <li class="factory-preset-gradient factory-primary-gradient" data-primary="#34495e" data-secondary="#2d3e50"></li>
80
+ <li class="factory-preset-gradient factory-primary-gradient" data-primary="#f1c40f" data-secondary="#f49c14"></li>
81
+ <li class="factory-preset-gradient factory-primary-gradient" data-primary="#e84c3d" data-secondary="#c1392b"></li>
82
+ <li class="factory-preset-gradient factory-primary-gradient" data-primary="#ecf0f1" data-secondary="#bec3c7"></li>
83
+ </ul>
84
+ <canvas class='gradientPicker-preview'></canvas>
85
+ <div class='factory-points'></div>
86
+ <div class='factory-color-picker-container'>
87
+ <div class="factory-slider-container">
88
+ <div class="factory-slider">
89
+ <input type="text" class="factory-input-text factory-color-hex"/>
90
+
91
+ <div class="factory-bar"></div>
92
+ <div class="factory-visible-value">100%</div>
93
+ </div>
94
+ </div>
95
+ <div class="factory-color-picker"></div>
96
+ </div>
97
+ </div>
98
+ <input type="hidden" id="<?php echo $name; ?>" class="factory-result" name="<?php echo $name; ?>" value="<?php echo $value; ?>">
99
+ </div>
100
+ <?php
101
+ }
102
+ }
103
+ }
libs/factory/forms/controls/hidden.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Hidden Input Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ *
11
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
12
+ * @copyright (c) 2018, Webcraftic Ltd
13
+ *
14
+ * @package factory-forms
15
+ * @since 1.0.0
16
+ */
17
+
18
+ // Exit if accessed directly
19
+ if( !defined('ABSPATH') ) {
20
+ exit;
21
+ }
22
+
23
+ if( !class_exists('Wbcr_FactoryForms422_HiddenControl') ) {
24
+
25
+ class Wbcr_FactoryForms422_HiddenControl extends Wbcr_FactoryForms422_Control {
26
+
27
+ public $type = 'hidden';
28
+
29
+ /**
30
+ * Shows the html markup of the control.
31
+ *
32
+ * @since 1.0.0
33
+ * @return void
34
+ */
35
+ public function html()
36
+ {
37
+ $value = esc_attr($this->getValue());
38
+ $name_on_form = $this->getNameOnForm();
39
+
40
+ $this->addHtmlAttr('id', $name_on_form);
41
+ $this->addHtmlAttr('name', $name_on_form);
42
+ $this->addHtmlAttr('value', $value);
43
+ $this->addHtmlAttr('type', 'hidden');
44
+
45
+ ?>
46
+ <input <?php $this->attrs() ?>/>
47
+ <?php
48
+ }
49
+ }
50
+ }
libs/factory/forms/controls/holders/accordion-item.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Tab Control Holder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package core
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_AccordionItemHolder') ) {
18
+
19
+ /**
20
+ * Tab Control Holder
21
+ *
22
+ * @since 1.0.0
23
+ */
24
+ class Wbcr_FactoryForms422_AccordionItemHolder extends Wbcr_FactoryForms422_Holder {
25
+
26
+ /**
27
+ * A holder type.
28
+ *
29
+ * @since 1.0.0
30
+ * @var string
31
+ */
32
+ public $type = 'accordion-item';
33
+
34
+ /**
35
+ * Here we should render a beginning html of the tab.
36
+ *
37
+ * @since 1.0.0
38
+ * @return void
39
+ */
40
+ public function beforeRendering()
41
+ {
42
+ ?>
43
+ <h3><?php echo $this->options['title']; ?></h3>
44
+ <div class="factory-accordion-item">
45
+ <div class="inner-factory-accordion-item">
46
+ <?php
47
+ }
48
+
49
+ /**
50
+ * Here we should render an end html of the tab.
51
+ *
52
+ * @since 1.0.0
53
+ * @return void
54
+ */
55
+ public function afterRendering()
56
+ {
57
+ ?>
58
+ </div>
59
+ </div>
60
+ <?php
61
+ }
62
+ }
63
+ }
libs/factory/forms/controls/holders/accordion.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Tab Control Holder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package core
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+ if( !class_exists('Wbcr_FactoryForms422_AccordionHolder') ) {
17
+ /**
18
+ * Tab Control Holder
19
+ *
20
+ * @since 1.0.0
21
+ */
22
+ class Wbcr_FactoryForms422_AccordionHolder extends Wbcr_FactoryForms422_Holder {
23
+
24
+ /**
25
+ * A holder type.
26
+ *
27
+ * @since 1.0.0
28
+ * @var string
29
+ */
30
+ public $type = 'accordion';
31
+
32
+ /**
33
+ * Here we should render a beginning html of the tab.
34
+ *
35
+ * @since 1.0.0
36
+ * @return void
37
+ */
38
+ public function beforeRendering()
39
+ {
40
+ ?>
41
+ <div <?php $this->attrs() ?>>
42
+ <?php
43
+ }
44
+
45
+ /**
46
+ * Here we should render an end html of the tab.
47
+ *
48
+ * @since 1.0.0
49
+ * @return void
50
+ */
51
+ public function afterRendering()
52
+ {
53
+ ?>
54
+ </div>
55
+ <?php
56
+ }
57
+ }
58
+ }
libs/factory/forms/controls/holders/columns.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Columns Holder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_ColumnsHolder') ) {
18
+ /**
19
+ * Columns Holder
20
+ *
21
+ * @since 1.0.0
22
+ */
23
+ class Wbcr_FactoryForms422_ColumnsHolder extends Wbcr_FactoryForms422_Holder {
24
+
25
+ /**
26
+ * A holder type.
27
+ *
28
+ * @since 1.0.0
29
+ * @var string
30
+ */
31
+ public $type = 'columns';
32
+
33
+ public function __construct($options, $form)
34
+ {
35
+ $columns_items = array();
36
+
37
+ // calculates the number of columns
38
+
39
+ $this->columns_count = 0;
40
+
41
+ foreach($options['items'] as $item) {
42
+ $i = (!isset($item['column'])
43
+ ? 1
44
+ : intval($item['column'])) - 1;
45
+ $columns_items[$i][] = $item;
46
+
47
+ if( $i > $this->columns_count ) {
48
+ $this->columns_count = $i + 1;
49
+ }
50
+ }
51
+ // calculates the number of rows
52
+
53
+ $this->rows_count = 0;
54
+ foreach($columns_items as $items) {
55
+ $count = count($items);
56
+ if( $count > $this->rows_count ) {
57
+ $this->rows_count = $count;
58
+ }
59
+ }
60
+
61
+ // creates elements
62
+
63
+ parent::__construct($options, $form);
64
+
65
+ // groups the created by columns
66
+
67
+ $element_index = 0;
68
+ $this->columns = array();
69
+
70
+ foreach($columns_items as $column_index => $columnItems) {
71
+ $count = count($columnItems);
72
+ for($k = 0; $k < $count; $k++) {
73
+ $this->columns[$column_index][] = $this->elements[$element_index];
74
+ $element_index++;
75
+ }
76
+ }
77
+ }
78
+
79
+
80
+ public function render()
81
+ {
82
+ $this->beforeRendering();
83
+
84
+ for($n = 0; $n < $this->rows_count; $n++) {
85
+
86
+ $this->form->layout->startRow($n, $this->rows_count);
87
+
88
+ for($i = 0; $i < $this->columns_count; $i++) {
89
+ $control = $this->columns[$i][$n];
90
+ $this->form->layout->startColumn($control, $i, $this->columns_count);
91
+ $this->columns[$i][$n]->render();
92
+ $this->form->layout->endColumn($control, $i, $this->columns_count);
93
+ }
94
+
95
+ $this->form->layout->endRow($n, $this->rows_count);
96
+ }
97
+ }
98
+ }
99
+ }
libs/factory/forms/controls/holders/control-group-item.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Tab Control Holder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_ControlGroupItem') ) {
18
+
19
+ /**
20
+ * Tab Control Holder
21
+ *
22
+ * @since 1.0.0
23
+ */
24
+ class Wbcr_FactoryForms422_ControlGroupItem extends Wbcr_FactoryForms422_Holder {
25
+
26
+ /**
27
+ * A holder type.
28
+ *
29
+ * @since 1.0.0
30
+ * @var string
31
+ */
32
+ public $type = 'control-group-item';
33
+
34
+
35
+ /**
36
+ * Here we should render a beginning html of the tab.
37
+ *
38
+ * @since 1.0.0
39
+ * @return void
40
+ */
41
+ public function beforeRendering()
42
+ {
43
+ $this->addCssClass('control-group-item');
44
+ $this->addCssClass('factory-control-group-item-' . $this->options['name']);
45
+
46
+ if( $this->parent->getValue() == $this->options['name'] ) {
47
+ $this->addCssClass('current');
48
+
49
+ foreach($this->elements as $val) {
50
+ $val->setOption('isActive', 1);
51
+ }
52
+ } else {
53
+ foreach($this->elements as $val) {
54
+ $val->setOption('isActive', 0);
55
+ }
56
+ }
57
+
58
+ ?>
59
+ <div <?php $this->attrs() ?>>
60
+ <?php
61
+ }
62
+
63
+ /**
64
+ * Here we should render an end html of the tab.
65
+ *
66
+ * @since 1.0.0
67
+ * @return void
68
+ */
69
+ public function afterRendering()
70
+ {
71
+ ?>
72
+ </div>
73
+ <?php
74
+ }
75
+ }
76
+ }
libs/factory/forms/controls/holders/control-group.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Tab Control Holder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_ControlGroupHolder') ) {
18
+
19
+ /**
20
+ * Tab Control Holder
21
+ *
22
+ * @since 1.0.0
23
+ */
24
+ class Wbcr_FactoryForms422_ControlGroupHolder extends Wbcr_FactoryForms422_ControlHolder {
25
+
26
+ /**
27
+ * A holder type.
28
+ *
29
+ * @since 1.0.0
30
+ * @var string
31
+ */
32
+ public $type = 'control-group';
33
+
34
+
35
+ /**
36
+ * Here we should render a beginning html of the tab.
37
+ *
38
+ * @since 1.0.0
39
+ * @return void
40
+ */
41
+ public function beforeRendering()
42
+ {
43
+ $name = $this->getNameOnForm();
44
+ $value = $this->getValue();
45
+
46
+ $title = $this->getOption('title', null);
47
+
48
+ ?>
49
+ <div <?php $this->attrs() ?>>
50
+ <input type="hidden" name="<?php echo $name ?>" id="<?php echo $name ?>" class="factory-ui-control-group" value="<?php echo $value ?>"/>
51
+
52
+ <?php if( $title ) { ?>
53
+ <strong class="factory-header"><?php echo $title; ?></strong>
54
+ <?php } ?>
55
+
56
+ <ul class="factory-control-group-nav">
57
+ <?php
58
+ foreach($this->elements as $element):
59
+
60
+ if( $element->options['type'] !== 'control-group-item' ) {
61
+ continue;
62
+ }
63
+
64
+ $builder = new Wbcr_FactoryForms422_HtmlAttributeBuilder();
65
+
66
+ $builder->addCssClass('factory-control-group-nav-label');
67
+ $builder->addCssClass('factory-control-group-nav-label-' . $element->getOption('name'));
68
+ $builder->addHtmlData('control-id', 'factory-control-group-item-' . $element->getOption('name'));
69
+ $builder->addHtmlData('control-name', $element->getOption('name'));
70
+
71
+ if( $value == $element->getOption('name') ) {
72
+ $builder->addCssClass('current');
73
+ }
74
+
75
+ ?>
76
+ <li <?php $builder->printAttrs(); ?>><?php $element->title(); ?></li>
77
+ <?php endforeach; ?>
78
+ </ul>
79
+ <div class="factory-control-group-body">
80
+ <?php
81
+ }
82
+
83
+ /**
84
+ * Here we should render an end html of the tab.
85
+ *
86
+ * @since 1.0.0
87
+ * @return void
88
+ */
89
+ public function afterRendering()
90
+ {
91
+ ?>
92
+ </div>
93
+ </div>
94
+ <?php
95
+ }
96
+ }
97
+ }
libs/factory/forms/controls/holders/div.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Div Control Holder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_DivHolder') ) {
18
+ /**
19
+ * Div Control Holder
20
+ *
21
+ * @since 1.0.0
22
+ */
23
+ class Wbcr_FactoryForms422_DivHolder extends Wbcr_FactoryForms422_Holder {
24
+
25
+ /**
26
+ * A holder type.
27
+ *
28
+ * @since 1.0.0
29
+ * @var string
30
+ */
31
+ public $type = 'div';
32
+
33
+ /**
34
+ * Here we should render a beginning html of the tab.
35
+ *
36
+ * @since 1.0.0
37
+ * @return void
38
+ */
39
+ public function beforeRendering()
40
+ {
41
+
42
+ if( isset($this->options['class']) ) {
43
+ $this->addCssClass($this->options['class']);
44
+ }
45
+ if( isset($this->options['id']) ) {
46
+ $this->addHtmlAttr('id', $this->options['id']);
47
+ }
48
+
49
+ ?>
50
+ <div <?php $this->attrs() ?>>
51
+ <?php
52
+ }
53
+
54
+ /**
55
+ * Here we should render an end html of the tab.
56
+ *
57
+ * @since 1.0.0
58
+ * @return void
59
+ */
60
+ public function afterRendering()
61
+ {
62
+ ?>
63
+ </div>
64
+ <?php
65
+ }
66
+ }
67
+ }
libs/factory/forms/controls/holders/form-group.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Group Holder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_FormGroupHolder') ) {
18
+ /**
19
+ * Group Holder
20
+ *
21
+ * @since 1.0.0
22
+ */
23
+ class Wbcr_FactoryForms422_FormGroupHolder extends Wbcr_FactoryForms422_Holder {
24
+
25
+ /**
26
+ * A holder type.
27
+ *
28
+ * @since 1.0.0
29
+ * @var string
30
+ */
31
+ public $type = 'form-group';
32
+
33
+ /**
34
+ * Here we should render a beginning html of the tab.
35
+ *
36
+ * @since 1.0.0
37
+ * @return void
38
+ */
39
+ public function beforeRendering()
40
+ {
41
+
42
+ $this->addCssClass('factory-form-group-' . $this->getName());
43
+ $this->addHtmlAttr('id', 'factory-form-group-' . $this->getName());
44
+
45
+ ?>
46
+ <fieldset <?php $this->attrs() ?>>
47
+ <?php if( $this->hasTitle() ) { ?>
48
+ <legend class='factory-legend'>
49
+ <p class='factory-title'><?php $this->title() ?></p>
50
+ <?php if( $this->hasHint() ) { ?>
51
+ <p class='factory-hint'><?php echo $this->hint() ?></p>
52
+ <?php } ?>
53
+ </legend>
54
+ <?php } ?>
55
+ <?php
56
+ }
57
+
58
+ /**
59
+ * Here we should render an end html of the tab.
60
+ *
61
+ * @since 1.0.0
62
+ * @return void
63
+ */
64
+ public function afterRendering()
65
+ {
66
+ ?>
67
+ </fieldset>
68
+ <?php
69
+ }
70
+ }
71
+ }
libs/factory/forms/controls/holders/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/forms/controls/holders/more-link.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of More Link Holder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_MoreLinkHolder') ) {
18
+
19
+ /**
20
+ * Collapsed Group Holder
21
+ *
22
+ * @since 1.0.0
23
+ */
24
+ class Wbcr_FactoryForms422_MoreLinkHolder extends Wbcr_FactoryForms422_Holder {
25
+
26
+ /**
27
+ * A holder type.
28
+ *
29
+ * @since 1.0.0
30
+ * @var string
31
+ */
32
+ public $type = 'more-link';
33
+
34
+ /**
35
+ * Here we should render a beginning html of the tab.
36
+ *
37
+ * @since 1.0.0
38
+ * @return void
39
+ */
40
+ public function beforeRendering()
41
+ {
42
+ $count = isset($this->options['count'])
43
+ ? $this->options['count']
44
+ : 0;
45
+
46
+ $id = 'factory-more-link-' . $this->getName();
47
+
48
+ ?>
49
+ <div <?php $this->attrs() ?>>
50
+ <div class="form-group">
51
+ <div class="control-label col-sm-2"></div>
52
+ <div class="control-group col-sm-10">
53
+ <a href="#<?php echo $id ?>" class="factory-more-link-show"><?php $this->title() ?>
54
+ (<?php echo $count ?>)</a>
55
+ </div>
56
+ </div>
57
+ <div class='factory-more-link-content' id="<?php echo $id ?>" style="display: none;">
58
+ <a href="#<?php echo $id ?>" class='factory-more-link-hide'><?php _e('hide extra options', 'factory'); ?></a>
59
+ <?php
60
+ }
61
+
62
+ /**
63
+ * Here we should render an end html of the tab.
64
+ *
65
+ * @since 1.0.0
66
+ * @return void
67
+ */
68
+ public function afterRendering()
69
+ {
70
+ ?>
71
+ </div></div>
72
+ <?php
73
+ }
74
+ }
75
+ }
libs/factory/forms/controls/holders/tab-item.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Tab Item Control Holder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+ // Exit if accessed directly
12
+ if( !defined('ABSPATH') ) {
13
+ exit;
14
+ }
15
+
16
+ if( !class_exists('Wbcr_FactoryForms422_TabItemHolder') ) {
17
+ /**
18
+ * Tab Item Control Holder
19
+ *
20
+ * @since 1.0.0
21
+ */
22
+ class Wbcr_FactoryForms422_TabItemHolder extends Wbcr_FactoryForms422_Holder {
23
+
24
+ /**
25
+ * A holder type.
26
+ *
27
+ * @since 1.0.0
28
+ * @var string
29
+ */
30
+ public $type = 'tab-item';
31
+
32
+ /**
33
+ * Here we should render a beginning html of the tab.
34
+ *
35
+ * @since 1.0.0
36
+ * @return void
37
+ */
38
+ public function beforeRendering()
39
+ {
40
+
41
+ $this->addCssClass('tab-' . $this->getName());
42
+ $this->addHtmlAttr('id', $this->getName());
43
+
44
+ $this->addCssClass('tab-pane');
45
+
46
+ if( isset($this->options['isFirst']) && $this->options['isFirst'] ) {
47
+ $this->addCssClass('active');
48
+ }
49
+
50
+ ?>
51
+ <div <?php $this->attrs() ?>>
52
+ <?php
53
+ }
54
+
55
+ /**
56
+ * Here we should render an end html of the tab.
57
+ *
58
+ * @since 1.0.0
59
+ * @return void
60
+ */
61
+ public function afterRendering()
62
+ {
63
+ ?>
64
+ </div>
65
+ <?php
66
+ }
67
+ }
68
+ }
libs/factory/forms/controls/holders/tab.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Tab Control Holder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_TabHolder') ) {
18
+
19
+ /**
20
+ * Tab Control Holder
21
+ *
22
+ * @since 1.0.0
23
+ */
24
+ class Wbcr_FactoryForms422_TabHolder extends Wbcr_FactoryForms422_Holder {
25
+
26
+ /**
27
+ * A holder type.
28
+ *
29
+ * @since 1.0.0
30
+ * @var string
31
+ */
32
+ public $type = 'tab';
33
+
34
+ /**
35
+ * An align of a tab (horizontal or vertical).
36
+ *
37
+ * @since 1.0.0
38
+ * @var string
39
+ */
40
+ public $align = 'horizontal';
41
+
42
+ /**
43
+ * Creates a new instance of control holder.
44
+ *
45
+ * @since 1.0.0
46
+ * @param mixed[] $options A holder options.
47
+ * @param FactoryForms422_Form $form A parent form.
48
+ */
49
+ public function __construct($options, $form)
50
+ {
51
+ parent::__construct($options, $form);
52
+ $this->align = isset($options['align'])
53
+ ? $options['align']
54
+ : 'horizontal';
55
+ }
56
+
57
+ /**
58
+ * Here we should render a beginning html of the tab.
59
+ *
60
+ * @since 1.0.0
61
+ * @return void
62
+ */
63
+ public function beforeRendering()
64
+ {
65
+
66
+ $is_first_tab = true;
67
+ $tab_class = $this->getOption('class');
68
+
69
+ if( !empty($tab_class) ) {
70
+ $this->addCssClass($tab_class);
71
+ }
72
+
73
+ $this->addCssClass('factory-align-' . $this->align);
74
+
75
+ ?>
76
+ <div <?php $this->attrs() ?>>
77
+ <div class="factory-headers">
78
+ <ul class="nav nav-tabs">
79
+ <?php foreach($this->elements as $element) {
80
+ if( $element->options['type'] !== 'tab-item' ) {
81
+ continue;
82
+ }
83
+
84
+ $tab_icon = '';
85
+ $has_icon = isset($element->options['icon']);
86
+
87
+ if( $has_icon ) {
88
+ $tab_icon = $element->options['icon'];
89
+ }
90
+
91
+ $builder = new Wbcr_FactoryForms422_HtmlAttributeBuilder();
92
+
93
+ $builder->addCssClass('factory-tab-item-header');
94
+ $builder->addCssClass('factory-tab-item-header-' . $element->getName());
95
+
96
+ if( $has_icon ) {
97
+ $builder->addCssClass('factory-tab-item-header-with-icon');
98
+ }
99
+ if( $is_first_tab ) {
100
+ $builder->addCssClass('active');
101
+ }
102
+
103
+ $builder->addHtmlData('tab-id', $element->getName());
104
+ $is_first_tab = false;
105
+
106
+ if( $has_icon ) { ?>
107
+ <style>
108
+ .factory-form-tab-item-header-<?php $element->name() ?> a {
109
+ background-image: url("<?php echo $tab_icon ?>");
110
+ }
111
+ </style>
112
+ <?php } ?>
113
+ <li <?php $builder->printAttrs() ?>>
114
+ <a href="#<?php $element->name() ?>" data-toggle="tab">
115
+ <?php $element->title() ?>
116
+ </a>
117
+ </li>
118
+ <?php } ?>
119
+ </ul>
120
+ </div>
121
+ <div class='tab-content factory-bodies'>
122
+ <?php
123
+ }
124
+
125
+ /**
126
+ * Here we should render an end html of the tab.
127
+ *
128
+ * @since 1.0.0
129
+ * @return void
130
+ */
131
+ public function afterRendering()
132
+ {
133
+ ?>
134
+ </div>
135
+ </div>
136
+ <?php
137
+ }
138
+ }
139
+ }
libs/factory/forms/controls/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/forms/controls/integer.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Integer Control
5
+ * Main options:
6
+ * name => a name of the control
7
+ * way => Тип значения 'slider' - слайдер, 'checkbox-slider' - чекбокс активирует слайдер, по умолчанию input
8
+ * checkbox => Указывается если, 'way' имеет значение 'checkbox-slider'
9
+ * Пример:
10
+ * array(
11
+ * 'on' => __('Show shadow', 'bizpanda'),
12
+ * 'off' => __('Hide shadow', 'bizpanda'),
13
+ * )
14
+ * title => Заголовок контрола
15
+ * slider-title => Заголовок слайдера( Только если 'way' имеет значение 'checkbox-slider' )
16
+ * range => Диапазон значений, указывается если 'way' имеет значение 'slider' или 'checkbox-slider'
17
+ * Пример: array(0,100)
18
+ * units => Единицы измерения(px,pt,em,%)
19
+ * isActive => Включение, отключение поля
20
+ * value => a value to show in the control
21
+ * default => a default value of the control if the "value" option is not specified
22
+ *
23
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
24
+ * @copyright (c) 2018, Webcraftic Ltd
25
+ *
26
+ * @package factory-forms
27
+ * @since 1.0.0
28
+ */
29
+
30
+ // Exit if accessed directly
31
+ if( !defined('ABSPATH') ) {
32
+ exit;
33
+ }
34
+
35
+ if( !class_exists('Wbcr_FactoryForms422_IntegerControl') ) {
36
+
37
+ class Wbcr_FactoryForms422_IntegerControl extends Wbcr_FactoryForms422_Control {
38
+
39
+ public $type = 'integer';
40
+
41
+ /**
42
+ * Converting string to integer.
43
+ *
44
+ * @since 1.0.0
45
+ * @return integer
46
+ */
47
+ public function html()
48
+ {
49
+
50
+ $name = $this->getNameOnForm();
51
+ $value = esc_attr($this->getValue());
52
+ $step = 1;
53
+ $range = $checkbox = array();
54
+ $is_active = $this->getOption('isActive', 1);
55
+ $unit = esc_attr($this->getOption('units'));
56
+
57
+ $way = $this->getOption('way');
58
+
59
+ if( empty($way) ) {
60
+ $way = 'text';
61
+ }
62
+
63
+ $has_slider = false;
64
+
65
+ if( in_array($way, array('slider', 'checkbox-slider')) ) {
66
+ $range = $this->getOption('range', array(0, 99));
67
+ $slider_title = $this->getOption('slider-title');
68
+ $checkbox = $this->getOption('checkbox');
69
+ $step = $this->getOption('step', 1);
70
+ $has_slider = true;
71
+ }
72
+
73
+ $this->addCssClass('factory-way-' . $way);
74
+
75
+ if( $has_slider ) {
76
+ $this->addCssClass('factory-has-slider');
77
+ }
78
+ ?>
79
+
80
+ <div <?php $this->attrs() ?>>
81
+ <?php if( $has_slider ) { ?>
82
+
83
+ <?php if( 'checkbox-slider' == $way ) { ?>
84
+
85
+ <div>
86
+ <label for="<?php echo $name; ?>_checker"><?php echo $is_active
87
+ ? $checkbox['off']
88
+ : $checkbox['on']; ?></label><br>
89
+ <input type="checkbox" id="<?php echo $name; ?>_checker" class="factory-checkbox" name="<?php echo $name; ?>_checker" <?php echo $is_active
90
+ ? 'checked'
91
+ : '' ?>>
92
+ </div>
93
+
94
+ <?php } ?>
95
+
96
+ <div
97
+ data-units="<?php echo $unit ?>"
98
+ data-range-start="<?php echo $range[0] ?>"
99
+ data-range-end="<?php echo $range[1] ?>"
100
+ data-step="<?php echo $step ?>"
101
+ <?php echo !$is_active
102
+ ? ' style="display:none;"'
103
+ : '' ?>
104
+ class="factory-slider-container factory-slider-container-<?php echo $name; ?>">
105
+ <?php if( !empty($slider_title) ): ?>
106
+ <label class="factory-title">
107
+ <?php echo $this->getOption('slider-title'); ?>
108
+ </label>
109
+ <?php endif; ?>
110
+
111
+ <div class="factory-slider">
112
+ <div class="factory-bar"></div>
113
+ <span class="factory-visible-value">
114
+ <?php echo $value ?><?php echo $unit ?>
115
+ </span>
116
+ </div>
117
+ <input type="hidden" name="<?php echo $name; ?>" class="factory-result" value="<?php echo $value; ?>"/>
118
+ </div>
119
+
120
+ <?php } else { ?>
121
+
122
+ <input type="number" id="<?php echo $name; ?>" name="<?php echo $name; ?>" value="<?php echo $value; ?>" class="factory-input-text"/>
123
+ <span class="factory-units"><?php echo $unit ?></span>
124
+
125
+ <?php } ?>
126
+ </div><!-- .factory-integer -->
127
+ <?php
128
+ }
129
+
130
+ /**
131
+ * Форматирует значение без единиц измерения
132
+ * @param string $values
133
+ * @param string $unit
134
+ * @return string
135
+ */
136
+ public function valueFormatWithoutUnit($values, $unit)
137
+ {
138
+ if( !is_numeric($values) ) {
139
+ return str_replace($unit, '', $values);
140
+ } else {
141
+ return $values;
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Форматирует значение c единицами измерения
147
+ * @param string $values
148
+ * @param string $unit
149
+ * @return string
150
+ */
151
+ public function valueFormatWithUnit($values, $unit)
152
+ {
153
+ if( is_numeric($values) ) {
154
+ return $values . $unit;
155
+ } else {
156
+ return $values;
157
+ }
158
+ }
159
+ }
160
+ }
libs/factory/forms/controls/list.php ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Multiselect List Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ * items => a callback to return items or an array of items to select
11
+ *
12
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
13
+ * @copyright (c) 2018, Webcraftic Ltd
14
+ *
15
+ * @package factory-forms
16
+ * @since 1.0.0
17
+ */
18
+
19
+ // Exit if accessed directly
20
+ if( !defined('ABSPATH') ) {
21
+ exit;
22
+ }
23
+
24
+ if( !class_exists('Wbcr_FactoryForms422_ListControl') ) {
25
+
26
+ class Wbcr_FactoryForms422_ListControl extends Wbcr_FactoryForms422_Control {
27
+
28
+ public $type = 'list';
29
+
30
+ /**
31
+ * Returns a set of available items for the list.
32
+ *
33
+ * @since 1.0.0
34
+ * @return mixed[]
35
+ */
36
+ private function getItems()
37
+ {
38
+
39
+ $data = $this->getOption('data', array());
40
+
41
+ // if the data options is a valid callback for an object method
42
+ if( (is_array($data) && count($data) == 2 && is_object($data[0])) || is_string($data) ) {
43
+
44
+ return call_user_func($data);
45
+ }
46
+
47
+ // if the data options is an array of values
48
+ return $data;
49
+ }
50
+
51
+ /**
52
+ * Returns true, if the data should be loaded via ajax.
53
+ *
54
+ * @since 1.0.0
55
+ * @return bool
56
+ */
57
+ protected function isAjax()
58
+ {
59
+
60
+ $data = $this->getOption('data', array());
61
+
62
+ return is_array($data) && isset($data['ajax']);
63
+ }
64
+
65
+ /**
66
+ * Shows the html markup of the control.
67
+ *
68
+ * @since 1.0.0
69
+ * @return void
70
+ */
71
+ public function html()
72
+ {
73
+
74
+ $way = $this->getOption('way', 'default');
75
+ $this->addHtmlData('way', $way);
76
+
77
+ if( $this->isAjax() ) {
78
+
79
+ $data = $this->getOption('data', array());
80
+ $ajax_id = 'factory-list-' . rand(1000000, 9999999);
81
+
82
+ $value = $this->getValue(null, true);
83
+
84
+ if( empty($value) || empty($value[0]) ) {
85
+ $value = array();
86
+ }
87
+
88
+ ?>
89
+ <div class="factory-ajax-loader <?php echo $ajax_id . '-loader'; ?>"></div>
90
+ <script>
91
+ window['<?php echo $ajax_id ?>'] = {
92
+ 'loader': '.<?php echo $ajax_id . '-loader' ?>',
93
+ 'url': '<?php echo $data['url'] ?>',
94
+ 'data': <?php echo json_encode( $data['data'] ) ?>,
95
+ 'selected': <?php echo json_encode( $value ) ?>,
96
+ 'emptyList': '<?php echo $this->getOption('empty', __('The list is empty.', 'wbcr_factory_forms_422') ) ?>'
97
+ };
98
+ </script>
99
+ <?php
100
+
101
+ $this->addHtmlData('ajax', true);
102
+ $this->addHtmlData('ajax-data-id', $ajax_id);
103
+ $this->addCssClass('factory-hidden');
104
+ }
105
+
106
+ if( 'checklist' == $way ) {
107
+ $this->checklistHtml();
108
+ } else {
109
+ $this->defaultHtml();
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Shows the Buttons Dropdown.
115
+ *
116
+ * @since 1.0.0
117
+ * @return void
118
+ */
119
+ protected function checklistHtml()
120
+ {
121
+ $items = $this->getItems();
122
+
123
+ $value = explode(',', $this->getValue());
124
+ if( empty($value) || empty($value[0]) ) {
125
+ $value = array();
126
+ }
127
+
128
+ $name_on_form = $this->getNameOnForm();
129
+
130
+ $this->addCssClass('factory-checklist-way');
131
+ $this->addHtmlData('name', $name_on_form);
132
+
133
+ $errors_callback = $this->getOption('errors');
134
+ $errors = !empty($errors_callback)
135
+ ? call_user_func($errors_callback)
136
+ : array();
137
+
138
+ $is_empty = $this->isAjax() || empty($items);
139
+ $emptyList = $this->getOption('empty', __('The list is empty.', 'wbcr_factory_forms_422'));
140
+
141
+ if( $is_empty ) {
142
+ $this->addCssClass('factory-empty');
143
+ }
144
+
145
+ ?>
146
+ <ul <?php $this->attrs() ?>>
147
+ <?php if( $is_empty ) { ?>
148
+ <li><?php echo $emptyList ?></li>
149
+ <?php } else { ?>
150
+ <?php foreach($items as $item) { ?>
151
+ <li>
152
+ <label for="factory-checklist-<?php echo $name_on_form ?>-<?php echo $item[0] ?>" class="<?php if( !empty($errors[$item[0]]) ) {
153
+ echo 'factory-has-error';
154
+ } ?>">
155
+ <?php if( !empty($errors[$item[0]]) ) { ?>
156
+ <span class="factory-error">
157
+ <i class="fa fa-exclamation-triangle"></i>
158
+ <div class='factory-error-text'><?php echo $errors[$item[0]] ?></div>
159
+ </span>
160
+ <?php } else { ?>
161
+ <span>
162
+ <input
163
+ type="checkbox"
164
+ name="<?php echo $name_on_form ?>[]"
165
+ value="<?php echo $item[0] ?>"
166
+ id="factory-checklist-<?php echo $name_on_form ?>-<?php echo $item[0] ?>"
167
+ <?php if( in_array($item[0], $value) ) {
168
+ echo 'checked="checked"';
169
+ } ?> />
170
+ </span>
171
+ <?php } ?>
172
+
173
+ <span><?php echo $item[1] ?></span>
174
+ </label>
175
+ </li>
176
+ <?php } ?>
177
+ <?php } ?>
178
+ </ul>
179
+ <?php
180
+ }
181
+
182
+ /**
183
+ * Shows the standart dropdown.
184
+ *
185
+ * @since 1.3.1
186
+ * @return void
187
+ */
188
+ protected function defaultHtml()
189
+ {
190
+
191
+ $items = $this->getItems();
192
+ $value = $this->getValue();
193
+
194
+ $name_on_form = $this->getNameOnForm();
195
+
196
+ $this->addHtmlAttr('id', $name_on_form);
197
+ $this->addHtmlAttr('name', $name_on_form);
198
+ $this->addCssClass('form-control');
199
+
200
+ ?>
201
+ <select multiple="multiple" <?php $this->attrs() ?>/>
202
+ <?php foreach($items as $item) {
203
+ if( count($item) == 3 ) {
204
+ ?>
205
+ <optgroup label="<?php echo $item[1] ?>">
206
+ <?php foreach($item[2] as $subitem) { ?>
207
+ <?php $selected = ($subitem[0] == $value)
208
+ ? 'selected="selected"'
209
+ : ''; ?>
210
+ <option value='<?php echo $subitem[0] ?>' <?php echo $selected ?>>
211
+ <?php echo $subitem[1] ?>
212
+ </option>
213
+ <?php } ?>
214
+ </optgroup>
215
+ <?php
216
+ } else {
217
+ $selected = ($item[0] == $value)
218
+ ? 'selected="selected"'
219
+ : '';
220
+ ?>
221
+ <option value='<?php echo $item[0] ?>' <?php echo $selected ?>>
222
+ <?php echo $item[1] ?>
223
+ </option>
224
+ <?php } ?>
225
+ <?php } ?>
226
+ </select>
227
+ <?php
228
+ }
229
+ }
230
+ }
libs/factory/forms/controls/multiple-textbox.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Control multiple textbox
5
+ *
6
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
7
+ * @copyright (c) 2018, Webcraftic Ltd
8
+ *
9
+ * @package factory-forms
10
+ * @since 1.0.0
11
+ */
12
+
13
+ // Exit if accessed directly
14
+ if( !defined('ABSPATH') ) {
15
+ exit;
16
+ }
17
+
18
+ if( !class_exists('Wbcr_FactoryForms422_MultipleTextboxControl') ) {
19
+
20
+ class Wbcr_FactoryForms422_MultipleTextboxControl extends Wbcr_FactoryForms422_Control {
21
+
22
+ public $type = 'multiple-textbox';
23
+
24
+ /**
25
+ * Preparing html attributes before rendering html of the control.
26
+ *
27
+ * @since 1.0.0
28
+ * @return void
29
+ */
30
+ protected function beforeHtml()
31
+ {
32
+
33
+ $name_on_form = $this->getNameOnForm();
34
+
35
+ if( $this->getOption('maxLength', false) ) {
36
+ $this->addHtmlAttr('maxlength', intval($this->getOption('maxLength')));
37
+ }
38
+
39
+ if( $this->getOption('placeholder', false) ) {
40
+ $this->addHtmlAttr('placeholder', $this->getOption('placeholder'));
41
+ }
42
+
43
+ $this->addCssClass('form-control');
44
+ $this->addHtmlAttr('type', 'text');
45
+ //$this->addHtmlAttr('id', $name_on_form);
46
+ $this->addCssClass(str_replace('_', '-', $name_on_form));
47
+ $this->addHtmlAttr('name', $name_on_form . '[]');
48
+ }
49
+
50
+ /**
51
+ * Shows the html markup of the control.
52
+ *
53
+ * @since 1.0.0
54
+ * @return void
55
+ */
56
+ public function html()
57
+ {
58
+
59
+ $values = $this->getValue();
60
+
61
+ if( !empty($values) ) {
62
+ $values = explode('{%spr%}', $values);
63
+ } else {
64
+ $values = array();
65
+ }
66
+
67
+ ?>
68
+ <div class="factory-multiple-textbox-group">
69
+ <div class="factory-mtextbox-items">
70
+ <?php if( empty($values) ): ?>
71
+ <div class="factory-mtextbox-item">
72
+ <input <?php $this->attrs() ?>/>
73
+ </div>
74
+ <?php else: ?>
75
+ <?php $counter = 0; ?>
76
+ <?php foreach($values as $value): ?>
77
+ <div class="factory-mtextbox-item">
78
+ <input value="<?= esc_attr($value) ?>"<?php $this->attrs() ?>/>
79
+ <?php if( $counter >= 1 ): ?>
80
+ <button class="btn btn-default btn-small factory-mtextbox-remove-item">
81
+ <i class="fa fa-times" aria-hidden="true"></i></button>
82
+ <?php endif; ?>
83
+ </div>
84
+ <?php $counter++; ?>
85
+ <?php endforeach; ?>
86
+ <?php endif; ?>
87
+ </div>
88
+ <button class="btn btn-default btn-small factory-mtextbox-add-item">
89
+ <i class="fa fa-plus" aria-hidden="true"></i> <?php _e('Add new', 'wbcr_factory_forms_422') ?>
90
+ </button>
91
+ </div>
92
+
93
+ <?php
94
+ }
95
+
96
+ /**
97
+ * Returns a submit value of the control by a given name.
98
+ *
99
+ * @since 1.0.0
100
+ * @return mixed
101
+ */
102
+ public function getSubmitValue($name, $subName)
103
+ {
104
+ $name_on_form = $this->getNameOnForm($name);
105
+
106
+ $value = isset($_POST[$name_on_form])
107
+ ? $_POST[$name_on_form]
108
+ : null;
109
+
110
+ if( is_array($value) ) {
111
+ $value = array_map('sanitize_text_field', $value);
112
+ $value = implode('{%spr%}', $value);
113
+ }
114
+
115
+ $value = sanitize_text_field($value);
116
+
117
+ return $value;
118
+ }
119
+ }
120
+ }
libs/factory/forms/controls/paddings-editor.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Paddings Control
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_PaddingsEditorControl') ) {
18
+
19
+ class Wbcr_FactoryForms422_PaddingsEditorControl extends Wbcr_FactoryForms422_Control {
20
+
21
+ public $type = 'paddings-editor';
22
+
23
+ /**
24
+ * Converting string to integer.
25
+ *
26
+ * @since 1.0.0
27
+ * @return integer
28
+ */
29
+ public function html()
30
+ {
31
+
32
+ $name = $this->getNameOnForm();
33
+ $raw_value = esc_attr($this->getValue());
34
+
35
+ $units = $this->getOption('units');
36
+ $values_with_units = explode(' ', $raw_value);
37
+
38
+ $values = array();
39
+ foreach($values_with_units as $value_with_unit) {
40
+ $values[] = intval($value_with_unit);
41
+ }
42
+
43
+ $unit = $this->getOption('units', 'px');
44
+ $range = $this->getOption('range', array(0, 99));
45
+ $step = $this->getOption('step', 1);
46
+
47
+ ?>
48
+ <div <?php $this->attrs() ?>
49
+ data-units="<?php echo $unit ?>"
50
+ data-range-start="<?php echo $range[0] ?>"
51
+ data-range-end="<?php echo $range[1] ?>"
52
+ data-step="<?php echo $step ?>">
53
+ <div class="factory-rectangle">
54
+ <div class="factory-side factory-side-top" data-value="<?php echo $values[0] ?>">
55
+ <span class="factory-visible-value"><?php echo $values[0] ?><?php echo $units ?></span>
56
+ </div>
57
+ <div class="factory-side factory-side-bottom" data-value="<?php echo $values[1] ?>">
58
+ <span class="factory-visible-value"><?php echo $values[1] ?><?php echo $units ?></span>
59
+ </div>
60
+ <div class="factory-side factory-side-left" data-value="<?php echo $values[2] ?>">
61
+ <span class="factory-visible-value"><?php echo $values[2] ?><?php echo $units ?></span>
62
+ </div>
63
+ <div class="factory-side factory-side-right" data-value="<?php echo $values[3] ?>">
64
+ <span class="factory-visible-value"><?php echo $values[3] ?><?php echo $units ?></span>
65
+ </div>
66
+ <div class="factory-side factory-side-center" data-value="<?php echo $values[0] ?>"></div>
67
+ </div>
68
+ <div class="factory-slider-container">
69
+ <label class="factory-title">
70
+ <?php _e('Select a side and move the slider to set up:', 'wbcr_factory_forms_422') ?>
71
+ </label>
72
+
73
+ <div class="factory-slider">
74
+ <div class="factory-bar"></div>
75
+ </div>
76
+ </div>
77
+ <input type="hidden" class="factory-result" name="<?php echo $name ?>" value="<?php echo $raw_value ?>"/>
78
+ </div>
79
+ <?php
80
+ }
81
+ }
82
+ }
libs/factory/forms/controls/pattern.php ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pattern Control
5
+ *
6
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
7
+ * @copyright (c) 2018, Webcraftic Ltd
8
+ *
9
+ * @package factory-forms
10
+ * @since 3.1.0
11
+ */
12
+
13
+ // Exit if accessed directly
14
+ if( !defined('ABSPATH') ) {
15
+ exit;
16
+ }
17
+
18
+ if( !class_exists('Wbcr_FactoryForms422_PatternControl') ) {
19
+
20
+ class Wbcr_FactoryForms422_PatternControl extends Wbcr_FactoryForms422_Control {
21
+
22
+ public $type = 'pattern';
23
+
24
+ public function getName()
25
+ {
26
+ return array(
27
+ $this->getOption('name') . '__url',
28
+ $this->getOption('name') . '__color'
29
+ );
30
+ }
31
+
32
+ public function __construct($options, $form, $provider = null)
33
+ {
34
+ parent::__construct($options, $form, $provider);
35
+
36
+ if( !isset($options['color']) ) {
37
+ $options['color'] = array();
38
+ }
39
+
40
+ $options['color'] = array_merge($options['color'], array(
41
+ 'name' => $this->options['name'] . '_color_picker',
42
+ 'default' => isset($this->options['default'])
43
+ ? $this->options['default']['color']
44
+ : null,
45
+ 'pickerTarget' => '.factory-control-' . $this->options['name'] . ' .factory-picker-target'
46
+ ));
47
+
48
+ if( !$options['color']['default'] ) {
49
+ $options['color']['default'] = '#1e8cbe';
50
+ }
51
+
52
+ $name = $this->getOption('name');
53
+
54
+ // filters to get available patterns for the given background contols
55
+ $this->patterns = apply_filters('wbcr_factory_forms_422_patterns', array());
56
+ $this->patterns = apply_filters('wbcr_factory_forms_422_patterns-' . $name, $this->patterns);
57
+
58
+ $this->custom_patterns = $this->getOption('patterns', array());
59
+
60
+ $this->color = new Wbcr_FactoryForms422_ColorControl($options['color'], $form, $provider);
61
+ }
62
+
63
+ /**
64
+ * Shows the html markup of the control.
65
+ *
66
+ * @since 1.0.0
67
+ * @return void
68
+ */
69
+ public function html()
70
+ {
71
+ $name = $this->getNameOnForm();
72
+ $values = $this->getValue();
73
+
74
+ // if a pattern is not set by defaut, sets the first available pattern
75
+ if( empty($values['url']) && !empty($this->patterns) ) {
76
+ foreach($this->patterns as $group_key => $groupValue) {
77
+ if( !empty($this->patterns[$group_key]['patterns']) ) {
78
+ $values['url'] = $this->patterns[$group_key]['patterns'][0]['pattern'];
79
+ break;
80
+ }
81
+ }
82
+ }
83
+
84
+ if( !empty($values['color']) ) {
85
+ $this->color->setOption('value', $values['color']);
86
+ }
87
+
88
+ $hasColor = !empty($values['color']);
89
+
90
+ if( $hasColor ) {
91
+ $this->addCssClass('factory-color-panel-active');
92
+ }
93
+
94
+ ?>
95
+ <div <?php $this->attrs() ?>>
96
+ <div class="factory-pattern-controls">
97
+ <div class="factory-preview-wrap">
98
+ <div <?php echo (!empty($values['url']))
99
+ ? 'style="background:url(' . esc_url($values['url']) . ') repeat; border:0; font-size:0;"'
100
+ : ''; ?> class="factory-preview <?php echo $this->getOption('name'); ?>"><span></span>
101
+ </div>
102
+ </div>
103
+ <a href="#" class="button button-default factory-button factory-change-color-btn <?php if( $hasColor ) {
104
+ echo 'button-active';
105
+ } ?>" title="<?php _e('Change color', 'wbcr_factory_forms_422') ?>">
106
+ <i class="fa fa-flask"></i>
107
+ <span><?php _e('re-color', 'wbcr_factory_forms_422') ?></span>
108
+ </a>
109
+ <input type="hidden" id="<?php echo $name[0]; ?>" name="<?php echo $name[0]; ?>" value="<?php echo esc_url($values['url']); ?>" class="factory-pattern-result">
110
+ <input type="hidden" id="<?php echo $name[1]; ?>" name="<?php echo $name[1]; ?>" value="<?php echo esc_attr($values['color']); ?>" class="factory-color-result">
111
+ </div>
112
+ <div class="factory-color-panel">
113
+ <div class="factory-color-wrap">
114
+ <span class="factory-color-label"><?php _e('Select color:', 'wbcr_factory_forms_422') ?></span>
115
+ <?php $this->color->html() ?>
116
+ <div class="factory-hint">
117
+ <i><?php _e('Changing the color may takes a minute or more. Please be patient.', 'wbcr_factory_forms_422') ?></i>
118
+ </div>
119
+ </div>
120
+ <div class="factory-picker-target"></div>
121
+ </div>
122
+ <div class="factory-patterns-panel">
123
+ <div class="factory-patterns-group factory-patterns-group-custom">
124
+ <?php $this->printPatterns($this->custom_patterns, 4, '<div class="factory-patterns-item factory-upload-btn factory-no-preview"><span class="fa fa-upload"></span></div>') ?>
125
+ </div>
126
+ <?php foreach($this->patterns as $key => $group): ?>
127
+ <?php if( !empty($group['patterns']) ): ?>
128
+ <div class="factory-patterns-group factory-patterns-group-<?php echo $key ?>">
129
+ <div class="factory-patterns-group-title"><?php echo $group['title'] ?></div>
130
+ <?php $this->printPatterns($group['patterns'], 4) ?>
131
+ </div>
132
+ <?php endif; ?>
133
+ <?php endforeach; ?>
134
+ </div>
135
+ <div class="clearfix"></div>
136
+ </div>
137
+ <?php
138
+ }
139
+
140
+ /**
141
+ * @param $patterns
142
+ * @param $perRow
143
+ * @param null $first_item
144
+ */
145
+ private function printPatterns($patterns, $perRow, $first_item = null)
146
+ {
147
+ $counter = 0;
148
+ $print_first_item = $first_item;
149
+
150
+ ?>
151
+ <div class="factory-patterns-row">
152
+ <?php
153
+
154
+ if( $print_first_item ) {
155
+ echo $print_first_item;
156
+ $print_first_item = null;
157
+ $counter++;
158
+ }
159
+
160
+ foreach($patterns as $pattern) {
161
+ $counter++;
162
+
163
+ ?>
164
+ <div class="factory-patterns-item" data-pattern="<?php echo $pattern['pattern']; ?>">
165
+ <div class="factory-pattern-holder" style="background:url(<?php echo $pattern['preview']; ?>) repeat;"></div>
166
+ </div>
167
+ <?php
168
+
169
+ if( $counter == 4 ) {
170
+ $counter = 0;
171
+ ?>
172
+ </div><div class="factory-patterns-row">
173
+ <?php
174
+ }
175
+ }
176
+ ?>
177
+ </div>
178
+ <?php
179
+ }
180
+ }
181
+ }
libs/factory/forms/controls/radio-colors.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Radio Colors Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ * data => a callback to return items or an array of items to select
11
+ * 'data' => array(
12
+ * array('default', '#75649b'),
13
+ * array('black', '#222'),
14
+ * array('light', '#fff3ce'),
15
+ * array('forest', '#c9d4be'),
16
+ *)
17
+ *
18
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
19
+ * @copyright (c) 2018, Webcraftic Ltd
20
+ *
21
+ * @package factory-forms
22
+ * @since 1.0.0
23
+ */
24
+
25
+ // Exit if accessed directly
26
+ if( !defined('ABSPATH') ) {
27
+ exit;
28
+ }
29
+
30
+ if( !class_exists('Wbcr_FactoryForms422_RadioColorsControl') ) {
31
+
32
+ class Wbcr_FactoryForms422_RadioColorsControl extends Wbcr_FactoryForms422_Control {
33
+
34
+ public $type = 'radio-color';
35
+
36
+ /**
37
+ * Returns a set of available items for the radio.
38
+ *
39
+ * @since 1.0.0
40
+ * @return mixed[]
41
+ */
42
+ private function getItems()
43
+ {
44
+ $data = $this->getOption('data', array());
45
+
46
+ // if the data options is a valid callback for an object method
47
+ if( (is_array($data) && count($data) == 2 && is_object($data[0])) || is_string($data) ) {
48
+
49
+ return call_user_func($data);
50
+ }
51
+
52
+ // if the data options is an array of values
53
+ return $data;
54
+ }
55
+
56
+ /**
57
+ * Preparing html attributes before rendering html of the control.
58
+ *
59
+ * @since 1.0.0
60
+ * @return void
61
+ */
62
+ protected function beforeHtml()
63
+ {
64
+ $name_on_form = $this->getNameOnForm();
65
+ $this->addHtmlAttr('name', $name_on_form);
66
+
67
+ echo '<div class="factory-colors-inner-wrap" data-radio-name="' . $name_on_form . '">';
68
+ }
69
+
70
+ /**
71
+ * Preparing html attributes afterHtml rendering html of the control.
72
+ *
73
+ * @since 1.0.0
74
+ * @return void
75
+ */
76
+ protected function afterHtml()
77
+ {
78
+ echo '</div>';
79
+ }
80
+
81
+ /**
82
+ * Shows the html markup of the control.
83
+ *
84
+ * @since 1.0.0
85
+ * @return void
86
+ */
87
+ public function html()
88
+ {
89
+ $items = $this->getItems();
90
+ $value = $this->getValue();
91
+
92
+ ?>
93
+ <?php foreach($items as $item) {
94
+ $checked = ($item[0] == $value)
95
+ ? 'checked="checked"'
96
+ : '';
97
+
98
+ if( empty($item[1]) || strpos($item[1], '#') === false ) {
99
+ $item[1] = '#fff';
100
+ }
101
+ ?>
102
+ <span class="factory-form-radio-item">
103
+ <lable class="factory-from-radio-label">
104
+ <input type="radio" <?php $this->attrs() ?> value="<?php echo esc_attr($item[0]) ?>" <?php echo $checked ?>/>
105
+ <span style="background-color:<?= esc_attr($item[1]) ?>"></span>
106
+ </lable>
107
+ </span>
108
+ <?php }
109
+ }
110
+ }
111
+ }
libs/factory/forms/controls/radio.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Radio Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ * items => a callback to return items or an array of items to select
11
+ *
12
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
13
+ * @copyright (c) 2018, Webcraftic Ltd
14
+ *
15
+ * @package factory-forms
16
+ * @since 1.0.0
17
+ */
18
+
19
+ // Exit if accessed directly
20
+ if( !defined('ABSPATH') ) {
21
+ exit;
22
+ }
23
+
24
+ if( !class_exists('Wbcr_FactoryForms422_RadioControl') ) {
25
+
26
+ class Wbcr_FactoryForms422_RadioControl extends Wbcr_FactoryForms422_Control {
27
+
28
+ public $type = 'radio';
29
+
30
+ /**
31
+ * Returns a set of available items for the radio.
32
+ *
33
+ * @since 1.0.0
34
+ * @return mixed[]
35
+ */
36
+ private function getItems()
37
+ {
38
+ $data = $this->getOption('data', array());
39
+
40
+ // if the data options is a valid callback for an object method
41
+ if( (is_array($data) && count($data) == 2 && is_object($data[0])) || is_string($data) ) {
42
+
43
+ return call_user_func($data);
44
+ }
45
+
46
+ // if the data options is an array of values
47
+ return $data;
48
+ }
49
+
50
+ /**
51
+ * Preparing html attributes before rendering html of the control.
52
+ *
53
+ * @since 1.0.0
54
+ * @return void
55
+ */
56
+ protected function beforeHtml()
57
+ {
58
+ $name_on_form = $this->getNameOnForm();
59
+ $this->addHtmlAttr('name', $name_on_form);
60
+ }
61
+
62
+ /**
63
+ * Shows the html markup of the control.
64
+ *
65
+ * @since 1.0.0
66
+ * @return void
67
+ */
68
+ public function html()
69
+ {
70
+ $items = $this->getItems();
71
+ $value = $this->getValue();
72
+ ?>
73
+ <?php foreach($items as $item) {
74
+ $checked = ($item[0] == $value)
75
+ ? 'checked="checked"'
76
+ : '';
77
+ ?>
78
+ <span class="factory-form-radio-item">
79
+ <lable class="factory-from-radio-label"><?= esc_html($item[1]); ?></lable>
80
+ <input type="radio" <?php $this->attrs() ?> value="<?php echo esc_attr($item[0]) ?>" <?php echo $checked ?>/>
81
+ </span>
82
+ <?php }
83
+ }
84
+ }
85
+ }
libs/factory/forms/controls/textarea.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Textarea Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ *
11
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
12
+ * @copyright (c) 2018, Webcraftic Ltd
13
+ *
14
+ * @package factory-forms
15
+ * @since 1.0.0
16
+ */
17
+
18
+ // Exit if accessed directly
19
+ if( !defined('ABSPATH') ) {
20
+ exit;
21
+ }
22
+
23
+ if( !class_exists('Wbcr_FactoryForms422_TextareaControl') ) {
24
+
25
+ class Wbcr_FactoryForms422_TextareaControl extends Wbcr_FactoryForms422_Control {
26
+
27
+ public $type = 'textarea';
28
+
29
+ /**
30
+ * Returns a submit value of the control by a given name.
31
+ *
32
+ * @since 1.0.0
33
+ * @return mixed
34
+ */
35
+ public function getSubmitValue($name, $subName)
36
+ {
37
+ $name_on_form = $this->getNameOnForm($name);
38
+
39
+ $raw_value = isset($_POST[$name_on_form])
40
+ ? $_POST[$name_on_form]
41
+ : null;
42
+
43
+ $value = $raw_value;
44
+
45
+ if( is_array($value) ) {
46
+ $value = array_map('sanitize_textarea_field', $value);
47
+ $value = implode(',', $value);
48
+ } else {
49
+ $value = sanitize_textarea_field($value);
50
+ }
51
+
52
+ return $this->filterValue($value, $raw_value);
53
+ }
54
+
55
+ /**
56
+ * Preparing html attributes before rendering html of the control.
57
+ *
58
+ * @since 1.0.0
59
+ * @return void
60
+ */
61
+ protected function beforeHtml()
62
+ {
63
+ $name_on_form = $this->getNameOnForm();
64
+ $height = (int)$this->getOption('height', 100);
65
+
66
+ $this->addCssClass('form-control');
67
+ $this->addHtmlAttr('name', $name_on_form);
68
+ $this->addHtmlAttr('id', $name_on_form);
69
+ $this->addHtmlAttr('style', 'min-height:' . $height . 'px');
70
+ }
71
+
72
+ /**
73
+ * Shows the html markup of the control.
74
+ *
75
+ * @since 1.0.0
76
+ * @return void
77
+ */
78
+ public function html()
79
+ {
80
+ ?>
81
+ <textarea <?php $this->attrs(); ?>><?php echo esc_textarea($this->getValue()); ?></textarea>
82
+ <?php
83
+ }
84
+ }
85
+ }
libs/factory/forms/controls/textbox.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Textbox Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ * maxLength => set the max length of text in the input control
11
+ * placeholder => a placeholder text for the control when the control value is empty
12
+ *
13
+ * Использование datepicker в текстовом поле (необходимо подключить bootstrap.datepicker)
14
+ * 'htmlAttrs' => array(
15
+ * 'data-provide' => 'datepicker-inline',
16
+ * 'data-date-language' => 'ru',
17
+ * 'data-date-autoclose' => 'true'
18
+ * )
19
+ *
20
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
21
+ * @copyright (c) 2018, Webcraftic Ltd
22
+ *
23
+ * @package factory-forms
24
+ * @since 1.0.0
25
+ */
26
+
27
+ // Exit if accessed directly
28
+ if( !defined('ABSPATH') ) {
29
+ exit;
30
+ }
31
+
32
+ if( !class_exists('Wbcr_FactoryForms422_TextboxControl') ) {
33
+
34
+ class Wbcr_FactoryForms422_TextboxControl extends Wbcr_FactoryForms422_Control {
35
+
36
+ public $type = 'textbox';
37
+
38
+ /**
39
+ * Preparing html attributes before rendering html of the control.
40
+ *
41
+ * @since 1.0.0
42
+ * @return void
43
+ */
44
+ protected function beforeHtml()
45
+ {
46
+ $value = esc_attr($this->getValue());
47
+ $name_on_form = $this->getNameOnForm();
48
+
49
+ if( $this->getOption('maxLength', false) ) {
50
+ $this->addHtmlAttr('maxlength', intval($this->getOption('maxLength')));
51
+ }
52
+
53
+ if( $this->getOption('placeholder', false) ) {
54
+ $this->addHtmlAttr('placeholder', $this->getOption('placeholder'));
55
+ }
56
+
57
+ $this->addCssClass('form-control');
58
+ $this->addHtmlAttr('type', 'text');
59
+ $this->addHtmlAttr('id', $name_on_form);
60
+ $this->addHtmlAttr('name', $name_on_form);
61
+ $this->addHtmlAttr('value', $value);
62
+ }
63
+
64
+ /**
65
+ * Shows the html markup of the control.
66
+ *
67
+ * @since 1.0.0
68
+ * @return void
69
+ */
70
+ public function html()
71
+ {
72
+ $units = $this->getOption('units', false);
73
+ ?>
74
+ <?php if( $units ) { ?><div class="input-group"><?php } ?>
75
+ <input <?php $this->attrs() ?>/>
76
+ <?php if( $units ) { ?>
77
+ <span class="input-group-addon"><?php echo $units; ?></span>
78
+ <?php } ?>
79
+ <?php if( $units ) { ?></div><?php } ?>
80
+ <?php
81
+ }
82
+ }
83
+ }
libs/factory/forms/controls/url.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Url Control
5
+ *
6
+ * Main options:
7
+ * @see FactoryForms422_TextboxControl
8
+ *
9
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
10
+ * @copyright (c) 2018, Webcraftic Ltd
11
+ *
12
+ * @package factory-forms
13
+ * @since 1.0.0
14
+ */
15
+
16
+ // Exit if accessed directly
17
+ if( !defined('ABSPATH') ) {
18
+ exit;
19
+ }
20
+
21
+ if( !class_exists('Wbcr_FactoryForms422_UrlControl') ) {
22
+
23
+ class Wbcr_FactoryForms422_UrlControl extends Wbcr_FactoryForms422_TextboxControl {
24
+
25
+ public $type = 'url';
26
+
27
+ /**
28
+ * Adding 'http://' to the url if it was missed.
29
+ *
30
+ * @since 1.0.0
31
+ * @return string
32
+ */
33
+ public function getSubmitValue($name, $sub_name)
34
+ {
35
+ $value = parent::getSubmitValue($name, $sub_name);
36
+ if( !empty($value) && substr($value, 0, 4) != 'http' ) {
37
+ $value = 'http://' . $value;
38
+ }
39
+
40
+ return $value;
41
+ }
42
+ }
43
+ }
libs/factory/forms/controls/wp-editor.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * WP Editor Control
5
+ *
6
+ * Main options:
7
+ * name => a name of the control
8
+ * value => a value to show in the control
9
+ * default => a default value of the control if the "value" option is not specified
10
+ * tinymce => an array of options for tinymce
11
+ * @link http://codex.wordpress.org/Function_Reference/wp_editor
12
+ *
13
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
14
+ * @copyright (c) 2018, Webcraftic Ltd
15
+ *
16
+ * @package factory-forms
17
+ * @since 1.0.0
18
+ */
19
+
20
+ // Exit if accessed directly
21
+ if( !defined('ABSPATH') ) {
22
+ exit;
23
+ }
24
+
25
+ if( !class_exists('Wbcr_FactoryForms422_WpEditorControl') ) {
26
+
27
+ class Wbcr_FactoryForms422_WpEditorControl extends Wbcr_FactoryForms422_Control {
28
+
29
+ public $type = 'wp-editor';
30
+
31
+ /**
32
+ * Preparing html attributes and options for tinymce.
33
+ *
34
+ * @since 1.0.0
35
+ * @return void
36
+ */
37
+ protected function beforeHtml()
38
+ {
39
+
40
+ if( empty($this->options['tinymce']) ) {
41
+ $this->options['tinymce'] = array();
42
+ }
43
+
44
+ if( !isset($this->options['tinymce']['content_css']) ) {
45
+ $this->options['tinymce']['content_css'] = FACTORY_FORMS_422_URL . '/assets/css/editor.css';
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Shows the html markup of the control.
51
+ *
52
+ * @since 1.0.0
53
+ * @return void
54
+ */
55
+ public function html()
56
+ {
57
+ $name_on_form = $this->getNameOnForm();
58
+
59
+ $value = $this->getValue();
60
+
61
+ ?>
62
+ <div class='factory-form-wp-editor'>
63
+ <?php wp_editor($value, $name_on_form, array(
64
+ 'textarea_name' => $name_on_form,
65
+ 'wpautop' => false,
66
+ 'teeny' => true,
67
+ 'tinymce' => $this->getOption('tinymce', array())
68
+ )); ?>
69
+ </div>
70
+ <?php
71
+ }
72
+
73
+ /**
74
+ * Returns a submit value of the control by a given name.
75
+ *
76
+ * @since 1.0.0
77
+ * @return mixed
78
+ */
79
+ public function getSubmitValue($name, $subName)
80
+ {
81
+ $name_on_form = $this->getNameOnForm($name);
82
+
83
+ $value = isset($_POST[$name_on_form])
84
+ ? $_POST[$name_on_form]
85
+ : null;
86
+
87
+ if( is_array($value) ) {
88
+ $value = implode(',', $value);
89
+ }
90
+
91
+ return wp_kses_post($value);
92
+ }
93
+ }
94
+ }
95
+
libs/factory/forms/includes/complex-control.class.php ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the base class for all complex controls.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+ if( !class_exists('Wbcr_FactoryForms422_ComplexControl') ) {
17
+ /**
18
+ * The base class for all controls.
19
+ *
20
+ * @since 1.0.0
21
+ */
22
+ abstract class Wbcr_FactoryForms422_ComplexControl extends Wbcr_FactoryForms422_Control {
23
+
24
+ /**
25
+ * Is this element a complex control?
26
+ *
27
+ * @since 1.0.0
28
+ * @var bool
29
+ */
30
+ public $is_complex_control = true;
31
+
32
+ /**
33
+ * Contains a set of internal controls.
34
+ *
35
+ * @since 1.0.0
36
+ * @var Wbcr_FactoryForms422_Control[]
37
+ */
38
+ public $inner_controls = array();
39
+
40
+ /**
41
+ * Sets a provider for the control.
42
+ *
43
+ * @since 1.0.0
44
+ * @param Wbcr_IFactoryForms422_ValueProvider $provider
45
+ * @return void
46
+ */
47
+ public function setProvider($provider)
48
+ {
49
+ $this->provider = $provider;
50
+
51
+ foreach($this->inner_controls as $control) {
52
+ $control->setProvider($provider);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Returns a control name used to save data with a provider.
58
+ *
59
+ * The method can return if the control have several elements.
60
+ *
61
+ * @since 1.0.0
62
+ * @return array|string|null A control name.
63
+ */
64
+ public function getName()
65
+ {
66
+ $names = array();
67
+
68
+ foreach($this->inner_controls as $control) {
69
+ $inner_names = $control->getName();
70
+ if( is_array($inner_names) ) {
71
+ $names = array_merge($names, $inner_names);
72
+ } else $names[] = $inner_names;
73
+ }
74
+
75
+ return $names;
76
+ }
77
+
78
+ /**
79
+ * Returns an array of value to save received after submission of a form.
80
+ *
81
+ * @see getSubmitValue
82
+ *
83
+ * The array has the following format:
84
+ * array(
85
+ * 'control-name1' => 'value1',
86
+ * 'control-name2__sub-name1' => 'value2'
87
+ * 'control-name2__sub-name2' => 'value3'
88
+ * )
89
+ *
90
+ * @since 1.0.0
91
+ * @return array
92
+ */
93
+ public function getValuesToSave()
94
+ {
95
+ $values = array();
96
+
97
+ foreach($this->inner_controls as $control) {
98
+ $inner_values = $control->getValuesToSave();
99
+ if( is_array($inner_values) ) {
100
+ $values = array_merge($values, $inner_values);
101
+ } else $values[] = $inner_values;
102
+ }
103
+
104
+ return $values;
105
+ }
106
+
107
+ /**
108
+ * Returns an initial value of control that is used to render the control first time.
109
+ *
110
+ * @since 1.0.0
111
+ * @param null $index
112
+ * @param bool $multiple
113
+ * @return array
114
+ */
115
+ public function getValue($index = null, $multiple = false)
116
+ {
117
+
118
+ $values = array();
119
+ foreach($this->inner_controls as $control) {
120
+ $inner_values = array_merge($values, $control->getValue());
121
+ if( is_array($inner_values) ) {
122
+ $values = array_merge($values, $inner_values);
123
+ } else $values[] = $inner_values;
124
+ }
125
+
126
+ if( $index !== null ) {
127
+ return $values[$index];
128
+ } else {
129
+ return $values;
130
+ }
131
+ }
132
+ }
133
+ }
libs/factory/forms/includes/control-holder.class.php ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the base class for all control holder
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_ControlHolder') ) {
18
+ /**
19
+ * The base class for control holders.
20
+ *
21
+ * @since 1.0.0
22
+ */
23
+ abstract class Wbcr_FactoryForms422_ControlHolder extends Wbcr_FactoryForms422_Control {
24
+
25
+ /**
26
+ * Holder Elements.
27
+ *
28
+ * @since 1.0.0
29
+ * @var Wbcr_FactoryForms422_Control[]
30
+ */
31
+ protected $elements = array();
32
+
33
+ /**
34
+ * Is this element a control holder?
35
+ *
36
+ * @since 1.0.0
37
+ * @var bool
38
+ */
39
+ public $is_holder = true;
40
+
41
+ /**
42
+ * Creates a new instance of control holder.
43
+ *
44
+ * @since 1.0.0
45
+ * @param mixed[] $options A holder options.
46
+ * @param Wbcr_FactoryForms422_Form $form A parent form.
47
+ */
48
+ public function __construct($options, $form)
49
+ {
50
+ parent::__construct($options, $form);
51
+
52
+ $this->elements = $form->createElements($options['items']);
53
+
54
+ foreach((array)$this->elements as $val) {
55
+ $val->parent = $this;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Returns holder elements.
61
+ *
62
+ * @since 1.0.0
63
+ * @return Wbcr_FactoryForms422_FormElement[].
64
+ */
65
+ public function getElements()
66
+ {
67
+ return $this->elements;
68
+ }
69
+
70
+ /**
71
+ * Renders the form or a given control holder.
72
+ *
73
+ * @since 1.0.0
74
+ * @return void
75
+ */
76
+ function render()
77
+ {
78
+ $this->beforeRendering();
79
+
80
+ $is_first_item = true;
81
+
82
+ foreach($this->elements as $element) {
83
+ $element->setOption('isFirst', $is_first_item);
84
+
85
+ if( $is_first_item ) {
86
+ $is_first_item = false;
87
+ }
88
+
89
+ do_action('wbcr_factory_form_before_element_' . $element->getName());
90
+
91
+ // if a current item is a control holder
92
+ if( $element->is_holder ) {
93
+
94
+ $this->form->layout->beforeHolder($element);
95
+ $element->render();
96
+ $this->form->layout->afterHolder($element);
97
+ // if a current item is an input control
98
+ } elseif( $element->is_control ) {
99
+
100
+ $this->form->layout->beforeControl($element);
101
+ $element->render();
102
+ $this->form->layout->afterControl($element);
103
+ // if a current item is a custom form element
104
+ } elseif( $element->is_custom ) {
105
+
106
+ $element->render();
107
+ // otherwise, show the error
108
+ } else {
109
+ echo('[ERROR] Invalid item.');
110
+ }
111
+
112
+ do_action('wbcr_factory_form_after_element_' . $element->getName());
113
+ }
114
+
115
+ $this->afterRendering();
116
+ }
117
+
118
+ /**
119
+ * Rendering a beginning of a holder.
120
+ *
121
+ * @since 1.0.0
122
+ * @return void
123
+ */
124
+ public function beforeRendering()
125
+ {
126
+ }
127
+
128
+ /**
129
+ * Rendering an end of a holder.
130
+ *
131
+ * @since 1.0.0
132
+ * @return void
133
+ */
134
+ public function afterRendering()
135
+ {
136
+ }
137
+
138
+ /**
139
+ * Rendering some html before an inner holder.
140
+ *
141
+ * @since 1.0.0
142
+ * @return void
143
+ */
144
+ public function beforeInnerHolder()
145
+ {
146
+ }
147
+
148
+ /**
149
+ * Rendering some html after an inner holder.
150
+ *
151
+ * @since 1.0.0
152
+ * @return void
153
+ */
154
+ public function afterInnerHolder()
155
+ {
156
+ }
157
+
158
+
159
+ public function beforeInnerElement()
160
+ {
161
+ }
162
+
163
+ /**
164
+ * Rendering some html after an inner element.
165
+ *
166
+ * @since 1.0.0
167
+ * @return void
168
+ */
169
+ public function afterInnerElement()
170
+ {
171
+ }
172
+ }
173
+ }
libs/factory/forms/includes/control.class.php ADDED
@@ -0,0 +1,422 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the base class for all controls.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_Control') ) {
18
+
19
+ /**
20
+ * The base class for all controls.
21
+ *
22
+ * @since 1.0.0
23
+ */
24
+ abstract class Wbcr_FactoryForms422_Control extends Wbcr_FactoryForms422_FormElement {
25
+
26
+ /**
27
+ * Is this element a control?
28
+ *
29
+ * @since 1.0.0
30
+ * @var bool
31
+ */
32
+ public $is_control = true;
33
+
34
+ /**
35
+ * Is this element a complex control?
36
+ *
37
+ * @since 1.0.0
38
+ * @var bool
39
+ */
40
+ public $is_complex_control = false;
41
+
42
+ /**
43
+ * A provider that is used to get values.
44
+ *
45
+ * @since 1.0.0
46
+ * @var Wbcr_IFactoryForms422_ValueProvider
47
+ */
48
+ protected $provider = null;
49
+
50
+ /**
51
+ * Create a new instance of the control.
52
+ *
53
+ * @param mixed[] $options
54
+ * @param FactoryForms422_Form $form
55
+ * @param null $provider
56
+ * @since 1.0.0
57
+ * @return void
58
+ */
59
+ public function __construct($options, $form, $provider = null)
60
+ {
61
+ parent::__construct($options, $form);
62
+ $this->provider = $provider;
63
+ }
64
+
65
+ /**
66
+ * Sets a provider for the control.
67
+ *
68
+ * @since 1.0.0
69
+ * @param IFactoryForms422_ValueProvider $provider
70
+ * @return void
71
+ */
72
+ public function setProvider($provider)
73
+ {
74
+ $this->provider = $provider;
75
+ }
76
+
77
+ /**
78
+ * Returns a control name used to save data with a provider.
79
+ *
80
+ * The method can return if the control have several elements.
81
+ *
82
+ * @since 1.0.0
83
+ * @return string[]|string|null A control name.
84
+ */
85
+ public function getName()
86
+ {
87
+ return isset($this->options['name'])
88
+ ? $this->options['name']
89
+ : null;
90
+ }
91
+
92
+ /**
93
+ * Prints a control name used to save data with a provider.
94
+ *
95
+ * @since 1.0.0
96
+ * @return void
97
+ */
98
+ protected function printName()
99
+ {
100
+ $name = $this->getName();
101
+ if( is_array($name) ) {
102
+ echo $name[0];
103
+ } else echo $name;
104
+ }
105
+
106
+ /**
107
+ * Returns a control scope.
108
+ *
109
+ * @since 1.0.0
110
+ * @return string|null A control scope.
111
+ */
112
+ public function getScope()
113
+ {
114
+ return isset($this->options['scope'])
115
+ ? $this->options['scope']
116
+ : null;
117
+ }
118
+
119
+ /**
120
+ * Prints a control scope.
121
+ *
122
+ * @since 1.0.0
123
+ * @return void
124
+ */
125
+ protected function printScope()
126
+ {
127
+ echo $this->getScope();
128
+ }
129
+
130
+ /**
131
+ * Returns a name of control on a form (scope + _ + name)
132
+ *
133
+ * @since 1.0.0
134
+ * @param null|string $name
135
+ * @return array|null|string|string[]
136
+ */
137
+ public function getNameOnForm($name = null)
138
+ {
139
+ $scope = $this->getScope();
140
+ $name = !$name
141
+ ? $this->getName()
142
+ : $name;
143
+
144
+ if( is_array($name) ) {
145
+ $names = array();
146
+ foreach($name as $item) {
147
+ $names[] = empty($scope)
148
+ ? $item
149
+ : $scope . '_' . $item;
150
+ }
151
+
152
+ return $names;
153
+ }
154
+
155
+ if( empty($scope) ) {
156
+ return $name;
157
+ }
158
+ if( empty($name) ) {
159
+ return null;
160
+ }
161
+
162
+ return $scope . '_' . $name;
163
+ }
164
+
165
+ /**
166
+ * Prints a control name on a form.
167
+ *
168
+ * @since 1.0.0
169
+ * @return void
170
+ */
171
+ public function printNameOnForm()
172
+ {
173
+ $name = $this->getNameOnForm();
174
+
175
+ if( is_array($name) ) {
176
+ echo $name[0];
177
+ } else {
178
+ echo $name;
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Returns a submit value of the control by a given name.
184
+ *
185
+ * @since 1.0.0
186
+ * @param string $name
187
+ * @param string $sub_name
188
+ * @return string
189
+ */
190
+ public function getSubmitValue($name, $sub_name)
191
+ {
192
+ $name_on_form = $this->getNameOnForm($name);
193
+
194
+ $raw_value = isset($_POST[$name_on_form])
195
+ ? $_POST[$name_on_form]
196
+ : null;
197
+
198
+ $value = $raw_value;
199
+
200
+ if( is_array($value) ) {
201
+ $value = array_map('sanitize_text_field', $value);
202
+ $value = implode(',', $value);
203
+ } else {
204
+ $value = sanitize_text_field($value);
205
+ }
206
+
207
+ return $this->filterValue($value, $raw_value);
208
+ }
209
+
210
+ /**
211
+ * @param $value
212
+ * @param $raw_value
213
+ * @return mixed
214
+ */
215
+ protected function filterValue($value, $raw_value)
216
+ {
217
+ $sanitize_func = $this->getOption('filter_value');
218
+
219
+ // if the data options is a valid callback for an object method
220
+ if( !empty($sanitize_func) && ((is_array($sanitize_func) && count($sanitize_func) == 2 && gettype($sanitize_func[0]) == 'object') || function_exists($sanitize_func)) ) {
221
+ return call_user_func_array($sanitize_func, array($value, $raw_value));
222
+ }
223
+
224
+ return $value;
225
+ }
226
+
227
+
228
+ /**
229
+ * Returns an array of value to save received after submission of a form.
230
+ *
231
+ * @see getSubmitValue
232
+ *
233
+ * The array has the following format:
234
+ * array(
235
+ * 'control-name1' => 'value1',
236
+ * 'control-name2__sub-name1' => 'value2'
237
+ * 'control-name2__sub-name2' => 'value3'
238
+ * )
239
+ *
240
+ * @since 3.1.0
241
+ * @return mixed[]
242
+ */
243
+ public function getValuesToSave()
244
+ {
245
+ $values = array();
246
+ $name = $this->getName();
247
+
248
+ if( is_array($name) ) {
249
+ $i = 0;
250
+
251
+ foreach($name as $single_name) {
252
+ $sub_name = $this->getSubName($single_name);
253
+ if( !$sub_name ) {
254
+ $sub_name = $i;
255
+ $i++;
256
+ }
257
+ $values[$single_name] = $this->getSubmitValue($single_name, $sub_name);
258
+ }
259
+
260
+ return $values;
261
+ }
262
+
263
+ $values[$name] = $this->getSubmitValue($name, null);
264
+
265
+ return $values;
266
+ }
267
+
268
+ /**
269
+ * Returns an initial value of control that is used to render the control first time.
270
+ *
271
+ * @since 1.0.0
272
+ * @return mixed;
273
+ */
274
+ public function getValue($index = null, $multiple = false)
275
+ {
276
+ if( isset($this->options['value']) ) {
277
+ if( is_array($this->options['value']) ) {
278
+ if( $index !== null ) {
279
+ return $this->options['value'][$index];
280
+ } else return $this->options['value'];
281
+ } else {
282
+ return $this->options['value'];
283
+ }
284
+ }
285
+
286
+ $default = null;
287
+ if( isset($this->options['default']) ) {
288
+ if( is_array($this->options['default']) ) {
289
+ if( $index !== null ) {
290
+ $default = $this->options['default'][$index];
291
+ } else $default = $this->options['default'];
292
+ } else {
293
+ $default = $this->options['default'];
294
+ }
295
+ }
296
+
297
+ if( $this->provider ) {
298
+ $name = $this->getName();
299
+
300
+ if( is_array($name) ) {
301
+
302
+ $values = array();
303
+ $i = 0;
304
+
305
+ foreach($name as $single_name) {
306
+ $sub_name = $this->getSubName($single_name);
307
+ if( !$sub_name ) {
308
+ $sub_name = $i;
309
+ $i++;
310
+ }
311
+ $values[$sub_name] = $this->provider->getValue($single_name, isset($default[$sub_name])
312
+ ? $default[$sub_name]
313
+ : null);
314
+ }
315
+
316
+ if( $index !== null ) {
317
+ return $values[$index];
318
+ }
319
+
320
+ return $values;
321
+ } else {
322
+ return $this->provider->getValue($this->getName(), $default, $multiple);
323
+ }
324
+ }
325
+
326
+ return $default;
327
+ }
328
+
329
+ /**
330
+ * Shows the control.
331
+ *
332
+ * @since 1.0.0
333
+ * @return void
334
+ */
335
+ public function render()
336
+ {
337
+ $this->addCssClass('factory-from-control-' . $this->type);
338
+
339
+ // if the control is off, then ignore it
340
+ $off = $this->getOption('off', false);
341
+
342
+ if( $off ) {
343
+ return;
344
+ }
345
+
346
+ $this->beforeHtml();
347
+ $this->html();
348
+ $this->afterHtml();
349
+ }
350
+
351
+ /**
352
+ * A virtual method that is executed before rendering html markup of the control.
353
+ *
354
+ * @since 1.0.0
355
+ * @return void
356
+ */
357
+ protected function beforeHtml()
358
+ {
359
+ }
360
+
361
+ /**
362
+ * A virtual method that is executed after rendering html markup of the control.
363
+ *
364
+ * @since 1.0.0
365
+ * @return void
366
+ */
367
+ protected function afterHtml()
368
+ {
369
+ }
370
+
371
+ /**
372
+ * Renders the html markup for the control.
373
+ *
374
+ * @since 1.0.0
375
+ * @return void
376
+ */
377
+ public function html()
378
+ {
379
+ }
380
+
381
+ /**
382
+ * Returns a layout option.
383
+ *
384
+ * @since 1.0.0
385
+ * @param string $option_name A layout option to return.
386
+ * @param mixed $default A default value to return if the option doesn't exist.
387
+ * @return mixed
388
+ */
389
+ public function getLayoutOption($option_name, $default)
390
+ {
391
+ if( !isset($this->options['layout']) ) {
392
+ return $default;
393
+ }
394
+ if( !isset($this->options['layout'][$option_name]) ) {
395
+ return $default;
396
+ }
397
+
398
+ return $this->options['layout'][$option_name];
399
+ }
400
+
401
+ /**
402
+ * Splits the control name by '__' and return the right part.
403
+ *
404
+ * For example, if the $control_name is 'control__color', then returns 'color'.
405
+ * Throws an error if the control name cannot be splitted.
406
+ *
407
+ * @since 3.1.0
408
+ * @param string $control_name
409
+ * @return string
410
+ */
411
+ protected function getSubName($control_name)
412
+ {
413
+
414
+ $parts = explode('__', $control_name, 2);
415
+ if( !isset($parts[1]) ) {
416
+ return null;
417
+ }
418
+
419
+ return $parts[1];
420
+ }
421
+ }
422
+ }
libs/factory/forms/includes/custom-element.class.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the base class for all custom elements.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_CustomElement') ) {
18
+ /**
19
+ * The base class for all controls.
20
+ *
21
+ * @since 1.0.0
22
+ */
23
+ abstract class Wbcr_FactoryForms422_CustomElement extends Wbcr_FactoryForms422_FormElement {
24
+
25
+ /**
26
+ * Is this element a custom form element?
27
+ *
28
+ * @since 1.0.0
29
+ * @var bool
30
+ */
31
+ public $is_custom = true;
32
+
33
+ public function render()
34
+ {
35
+
36
+ // if the control is off, then ignore it
37
+ $off = $this->getOption('off', false);
38
+
39
+ if( $off ) {
40
+ return;
41
+ }
42
+
43
+ $this->html();
44
+ }
45
+ }
46
+ }
libs/factory/forms/includes/form-element.class.php ADDED
@@ -0,0 +1,423 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the base class for all form element (controls, holders).
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_FormElement') ) {
18
+
19
+ /**
20
+ * The base class for all form element (controls, holders).
21
+ *
22
+ * Provides several methods to build html markup of an element.
23
+ *
24
+ * @since 1.0.0
25
+ */
26
+ abstract class Wbcr_FactoryForms422_FormElement {
27
+
28
+ /**
29
+ * A type of an elemnt.
30
+ *
31
+ * @since 1.0.0
32
+ * @var boolean
33
+ */
34
+ protected $type = null;
35
+
36
+ /**
37
+ * An html attribute builder.
38
+ *
39
+ * @since 1.0.0
40
+ * @var Wbcr_FactoryForms422_HtmlAttributeBuilder
41
+ */
42
+ private $html_builder;
43
+
44
+ /**
45
+ * Element options.
46
+ *
47
+ * @since 1.0.0
48
+ * @var array
49
+ */
50
+ public $options = array();
51
+
52
+ /**
53
+ * A parent form.
54
+ *
55
+ * @since 1.0.0
56
+ * @var Wbcr_FactoryForms422_Form
57
+ */
58
+ protected $form;
59
+
60
+ /**
61
+ * A form layout.
62
+ *
63
+ * @since 1.0.0
64
+ * @var Wbcr_FactoryForms422_FormLayout
65
+ */
66
+ protected $layout;
67
+
68
+ /**
69
+ * Is this element a control?
70
+ *
71
+ * @since 1.0.0
72
+ * @var bool
73
+ */
74
+ public $is_control = false;
75
+
76
+ /**
77
+ * Is this element a control holder?
78
+ *
79
+ * @since 1.0.0
80
+ * @var bool
81
+ */
82
+ public $is_holder = false;
83
+
84
+ /**
85
+ * Is this element a custom form element?
86
+ *
87
+ * @since 1.0.0
88
+ * @var bool
89
+ */
90
+ public $is_custom = false;
91
+
92
+ /**
93
+ * Creates a new instance of a form element.
94
+ *
95
+ * @since 1.0.0
96
+ * @param mixed[] $options A holder options.
97
+ * @param Wbcr_FactoryForms422_Form $form A parent form.
98
+ */
99
+ public function __construct($options, $form)
100
+ {
101
+ $this->options = $options;
102
+ $this->form = $form;
103
+ $this->layout = $form->layout;
104
+
105
+ $this->html_builder = new Wbcr_FactoryForms422_HtmlAttributeBuilder();
106
+
107
+ if( isset($this->options['cssClass']) ) {
108
+ $this->html_builder->addCssClass($this->options['cssClass']);
109
+ }
110
+
111
+ if( isset($this->options['htmlData']) ) {
112
+ foreach($this->options['htmlData'] as $data_key => $data_value) {
113
+ $this->html_builder->addHtmlData($data_key, $data_value);
114
+ }
115
+ }
116
+
117
+ if( isset($this->options['htmlAttrs']) ) {
118
+ foreach($this->options['htmlAttrs'] as $attr_key => $attr_value) {
119
+ $this->html_builder->addHtmlAttr($attr_key, $attr_value);
120
+ }
121
+ }
122
+
123
+ $this->addCssClass('factory-' . $this->type);
124
+ }
125
+
126
+
127
+ /**
128
+ * Sets options for the control.
129
+ *
130
+ * @since 1.0.0
131
+ * @param mixed[] $options
132
+ * @return void
133
+ */
134
+ public function setOptions($options)
135
+ {
136
+ $this->options = $options;
137
+ }
138
+
139
+ /**
140
+ * Gets options of the control.
141
+ *
142
+ * @since 1.0.0
143
+ * @return mixed[] $options
144
+ */
145
+ public function getOptions()
146
+ {
147
+ return $this->options;
148
+ }
149
+
150
+ /**
151
+ * Sets a new value for a given option.
152
+ *
153
+ * @since 1.0.0
154
+ * @param string $name An option name to set.
155
+ * @param mixed $value A value to set.
156
+ * @return void
157
+ */
158
+ public function setOption($name, $value)
159
+ {
160
+ $this->options[$name] = $value;
161
+ }
162
+
163
+ /**
164
+ * Gets an option value or default.
165
+ *
166
+ * @since 1.0.0
167
+ * @param string $name An option name to get.
168
+ * @param mixed $default A default value
169
+ * @return mixed|null
170
+ */
171
+ public function getOption($name, $default = null)
172
+ {
173
+ return isset($this->options[$name])
174
+ ? $this->options[$name]
175
+ : $default;
176
+ }
177
+
178
+ /**
179
+ * Prints an option value or default.
180
+ *
181
+ * @since 1.0.0
182
+ * @param string $name An option name to get.
183
+ * @param mixed $default A default value
184
+ * @return void
185
+ */
186
+ public function option($name, $default = null)
187
+ {
188
+ $value = $this->getOption($name, $default);
189
+ echo $value;
190
+ }
191
+
192
+ /**
193
+ * Adds a new CSS class for the element.
194
+ *
195
+ * @since 1.0.0
196
+ * @return void
197
+ */
198
+ public function addCssClass($class)
199
+ {
200
+ $this->html_builder->addCssClass($class);
201
+ }
202
+
203
+ /**
204
+ * Prints CSS classes of the element.
205
+ *
206
+ * @since 1.0.0
207
+ * @return void
208
+ */
209
+ protected function cssClass()
210
+ {
211
+ $this->html_builder->printCssClass();
212
+ }
213
+
214
+ /**
215
+ * Adds a new html attribute.
216
+ *
217
+ * @since 1.0.0
218
+ * @param string $data_key
219
+ * @param string $data_value
220
+ */
221
+ protected function addHtmlData($data_key, $data_value)
222
+ {
223
+ $this->html_builder->addHtmlData($data_key, $data_value);
224
+ }
225
+
226
+ /**
227
+ * Adds a new html attribute.
228
+ *
229
+ * @since 1.0.0
230
+ * @param string $attr_name
231
+ * @param string $attr_value
232
+ * @return void
233
+ */
234
+ protected function addHtmlAttr($attr_name, $attr_value)
235
+ {
236
+ $this->html_builder->addHtmlAttr($attr_name, $attr_value);
237
+ }
238
+
239
+ /**
240
+ * Prints all html attributes, including css classes and data.
241
+ *
242
+ * @since 1.0.0
243
+ * @return void
244
+ */
245
+ protected function attrs()
246
+ {
247
+ $this->html_builder->printAttrs();
248
+ }
249
+
250
+ /**
251
+ * Returns an element title.
252
+ *
253
+ * @since 1.0.0
254
+ * @return string|bool
255
+ */
256
+ public function getTitle()
257
+ {
258
+ if( isset($this->options['title']) ) {
259
+ return $this->options['title'];
260
+ }
261
+
262
+ return false;
263
+ }
264
+
265
+ /**
266
+ * Returns true if an element has title.
267
+ *
268
+ * @since 1.0.0
269
+ * @return bool
270
+ */
271
+ public function hasTitle()
272
+ {
273
+ $title = $this->getTitle();
274
+
275
+ return !empty($title);
276
+ }
277
+
278
+ /**
279
+ * Prints an element title.
280
+ *
281
+ * @since 1.0.0
282
+ * @return void
283
+ */
284
+ public function title()
285
+ {
286
+ echo $this->getTitle();
287
+ }
288
+
289
+ /**
290
+ * Returns an element hint.
291
+ *
292
+ * @since 1.0.0
293
+ * @return string
294
+ */
295
+ public function getHint()
296
+ {
297
+ if( isset($this->options['hint']) ) {
298
+ return $this->options['hint'];
299
+ }
300
+
301
+ return false;
302
+ }
303
+
304
+ /**
305
+ * Returns true if an element has hint.
306
+ *
307
+ * @since 1.0.0
308
+ * @return bool
309
+ */
310
+ public function hasHint()
311
+ {
312
+ $hint = $this->getHint();
313
+
314
+ return !empty($hint);
315
+ }
316
+
317
+ /**
318
+ * Prints an element hint.
319
+ *
320
+ * @since 1.0.0
321
+ * @return void
322
+ */
323
+ public function hint($esc = false)
324
+ {
325
+ echo $esc
326
+ ? esc_html($this->getHint())
327
+ : $this->getHint();
328
+ }
329
+
330
+ /**
331
+ * Returns an element name.
332
+ *
333
+ * @since 1.0.0
334
+ * @return string
335
+ */
336
+ public function getName()
337
+ {
338
+
339
+ if( empty($this->options['name']) && !empty($this->options['title']) ) {
340
+ $this->options['name'] = str_replace(' ', '-', $this->options['title']);
341
+ $this->options['name'] = strtolower($this->options['name']);
342
+ }
343
+
344
+ if( !isset($this->options['name']) ) {
345
+ $this->options['name'] = $this->type . '-' . rand();
346
+ }
347
+
348
+ return $this->options['name'];
349
+ }
350
+
351
+ /**
352
+ * Prints an element name.
353
+ *
354
+ * @since 1.0.0
355
+ * @return void
356
+ */
357
+ public function name()
358
+ {
359
+ echo $this->getName();
360
+ }
361
+
362
+ /**
363
+ * Returns a form name
364
+ *
365
+ * @since 1.0.0
366
+ * @return string
367
+ */
368
+ public function getFormName()
369
+ {
370
+ return $this->form->name;
371
+ }
372
+
373
+ /**
374
+ * Returns an element type.
375
+ *
376
+ * @since 1.0.0
377
+ * @return string
378
+ */
379
+ public function getType()
380
+ {
381
+ return $this->type;
382
+ }
383
+
384
+ /**
385
+ * Returns an element icon.
386
+ *
387
+ * @since 1.0.0
388
+ * @return string
389
+ */
390
+ public function getIcon()
391
+ {
392
+ if( isset($this->options['icon']) ) {
393
+ return $this->options['icon'];
394
+ }
395
+
396
+ return false;
397
+ }
398
+
399
+ /**
400
+ * Returns true if an element has a icon.
401
+ *
402
+ * @since 1.0.0
403
+ * @return bool
404
+ */
405
+ public function hasIcon()
406
+ {
407
+ $icon = $this->getIcon();
408
+
409
+ return !empty($icon);
410
+ }
411
+
412
+ /**
413
+ * Prints an element icon.
414
+ *
415
+ * @since 1.0.0
416
+ * @return void
417
+ */
418
+ public function icon()
419
+ {
420
+ echo $this->getIcon();
421
+ }
422
+ }
423
+ }
libs/factory/forms/includes/form-layout.class.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the base class for all form layouts.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_FormLayout') ) {
18
+
19
+ /**
20
+ * The base class for all form layouts.
21
+ */
22
+ abstract class Wbcr_FactoryForms422_FormLayout extends Wbcr_FactoryForms422_Holder {
23
+
24
+ /**
25
+ * A form layout name.
26
+ *
27
+ * @since 1.0.0
28
+ * @var string
29
+ */
30
+ protected $name = 'default';
31
+
32
+ /**
33
+ * A holder type.
34
+ *
35
+ * @since 1.0.0
36
+ * @var string
37
+ */
38
+ protected $type = 'form-layout';
39
+
40
+ /**
41
+ * Creates a new instance of a form layout.
42
+ *
43
+ * @since 1.0.0
44
+ * @param mixed[] $options A holder options.
45
+ * @param Wbcr_FactoryForms422_Form $form A parent form.
46
+ */
47
+ public function __construct($options, $form)
48
+ {
49
+
50
+ $options['name'] = $this->name;
51
+ $options['items'] = $form->getItems();
52
+
53
+ parent::__construct($options, $form);
54
+
55
+ $this->addCssClass('factory-forms-422-' . $this->type);
56
+ $this->addCssClass('factory-forms-422-' . $this->name);
57
+ }
58
+
59
+ /**
60
+ * Renders a beginning of a form.
61
+ *
62
+ * @since 1.0.0
63
+ * @return void
64
+ */
65
+ public function beforeRendering()
66
+ {
67
+ echo '<div ';
68
+ $this->attrs();
69
+ echo '>';
70
+ }
71
+
72
+ /**
73
+ * Renders the end of a form.
74
+ *
75
+ * @since 1.0.0
76
+ * @return void
77
+ */
78
+ public function afterRendering()
79
+ {
80
+ echo '</div>';
81
+ }
82
+
83
+ /**
84
+ * Rendering some html before a holder.
85
+ *
86
+ * @since 1.0.0
87
+ * @return void
88
+ */
89
+ public function beforeHolder($element)
90
+ {
91
+ }
92
+
93
+ /**
94
+ * Rendering some html after a holder.
95
+ *
96
+ * @since 1.0.0
97
+ * @return void
98
+ */
99
+ public function afterHolder($element)
100
+ {
101
+ }
102
+
103
+ /**
104
+ * Rendering some html before a contol.
105
+ *
106
+ * @since 1.0.0
107
+ * @return void
108
+ */
109
+ public function beforeControl($element)
110
+ {
111
+ }
112
+
113
+ /**
114
+ * Rendering some html after a contol.
115
+ *
116
+ * @since 1.0.0
117
+ * @return void
118
+ */
119
+ public function afterControl($element)
120
+ {
121
+ }
122
+ }
123
+ }
libs/factory/forms/includes/form.class.php ADDED
@@ -0,0 +1,690 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains a class that represnets an abstraction for forms.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ // creating a license manager for each plugin created via the factory
18
+ add_action('wbcr_factory_forms_422_plugin_created', 'wbcr_factory_forms_422_plugin_created');
19
+
20
+ function wbcr_factory_forms_422_plugin_created($plugin)
21
+ {
22
+ $plugin->forms = new Wbcr_FactoryForms422_Manager($plugin);
23
+ }
24
+
25
+ if( !class_exists('Wbcr_FactoryForms422_Manager') ) {
26
+
27
+ class Wbcr_FactoryForms422_Manager {
28
+
29
+ // ----------------------------------------------------
30
+ // Static fields and methods
31
+ // ----------------------------------------------------
32
+
33
+ /**
34
+ * This array contains data to use a respective control.
35
+ *
36
+ * @since 1.0.0
37
+ * @var array
38
+ */
39
+ public static $registered_controls = array();
40
+
41
+ /**
42
+ * Registers a new control.
43
+ *
44
+ * @since 1.0.0
45
+ * @param mixed[] $item Control data having the following format:
46
+ * type => a control type
47
+ * class => a control php class
48
+ * include => a path to include control code
49
+ * @return void
50
+ */
51
+ public function registerControl($item)
52
+ {
53
+ self::$registered_controls[$item['type']] = $item;
54
+ require_once $item['include'];
55
+ }
56
+
57
+ /**
58
+ * Registers a set of new controls.
59
+ *
60
+ * @see FactoryForms422_Form::registerControl()
61
+ *
62
+ * @since 1.0.0
63
+ * @return void
64
+ */
65
+ public function registerControls($data)
66
+ {
67
+ foreach($data as $item)
68
+ $this->registerControl($item);
69
+ }
70
+
71
+ /**
72
+ * This array contains holder data to use a respective control holder.
73
+ *
74
+ * @since 1.0.0
75
+ * @var array
76
+ */
77
+ public static $registered_holders = array();
78
+
79
+ /**
80
+ * Registers a new holder.
81
+ *
82
+ * @since 1.0.0
83
+ * @param mixed[] $item Holder data having the follwoin format:
84
+ * type => a control holder type
85
+ * class => a control holder php class
86
+ * include => a path to include control holder code
87
+ * @return void
88
+ */
89
+ public function registerHolder($item)
90
+ {
91
+ self::$registered_holders[$item['type']] = $item;
92
+ require_once $item['include'];
93
+ }
94
+
95
+ /**
96
+ * Registers a set of new holder controls.
97
+ *
98
+ * @see FactoryForms422_Form::registerHolder()
99
+ *
100
+ * @since 1.0.0
101
+ * @return void
102
+ */
103
+ public function registerHolders($data)
104
+ {
105
+ foreach($data as $item)
106
+ $this->registerHolder($item);
107
+ }
108
+
109
+ /**
110
+ * This array contains custom form element data to use a respective elements.
111
+ *
112
+ * @since 1.0.0
113
+ * @var array
114
+ */
115
+ public static $registered_custom_elements = array();
116
+
117
+ /**
118
+ * Registers a new custom form element.
119
+ *
120
+ * @since 1.0.0
121
+ * @return void
122
+ */
123
+ public function registerCustomElement($item)
124
+ {
125
+ self::$registered_custom_elements[$item['type']] = $item;
126
+ require_once $item['include'];
127
+ }
128
+
129
+ /**
130
+ * Registers a set of new custom form elements.
131
+ *
132
+ * @see FactoryForms422_Form::registerCustomElement()
133
+ *
134
+ * @since 1.0.0
135
+ * @return void
136
+ */
137
+ public function registerCustomElements($data)
138
+ {
139
+ foreach($data as $item)
140
+ $this->registerCustomElement($item);
141
+ }
142
+
143
+ /**
144
+ * Contains a set of layouts registered for forms.
145
+ *
146
+ * @since 1.0.0
147
+ * @var mixed[]
148
+ */
149
+ public static $form_layouts = array();
150
+
151
+ /**
152
+ * Registers a new layout for forms.
153
+ *
154
+ * @since 1.0.0
155
+ * @param array $data A layout data. Has the following format:
156
+ * name => a name of the layout
157
+ * class => a layout php class
158
+ * include => a path to include layout code
159
+ * @return void
160
+ */
161
+ public function registerFormLayout($data)
162
+ {
163
+ self::$form_layouts[$data['name']] = $data;
164
+ }
165
+
166
+ /**
167
+ * Extra propery that determines which UI is used in the admin panel.
168
+ *
169
+ * @since 1.0.0
170
+ * @var string
171
+ */
172
+ public static $temper;
173
+
174
+ /**
175
+ * A flat to register control only once.
176
+ *
177
+ * @since 3.0.7
178
+ * @var bool
179
+ */
180
+ public static $controls_registered = false;
181
+ }
182
+ }
183
+ if( !class_exists('Wbcr_FactoryForms422_Form') ) {
184
+ /**
185
+ * An abstraction for forms.
186
+ */
187
+ class Wbcr_FactoryForms422_Form {
188
+
189
+ // ----------------------------------------------------
190
+ // Object fields and methods
191
+ // ----------------------------------------------------
192
+
193
+ /**
194
+ * A value provider of the form that is used to save and load values.
195
+ *
196
+ * @since 1.0.0
197
+ * @var Wbcr_IFactoryForms422_ValueProvider
198
+ */
199
+ private $provider;
200
+
201
+ /**
202
+ * A prefix that will be used for names of input fields in the form.
203
+ *
204
+ * @since 1.0.0
205
+ * @var string
206
+ */
207
+ public $scope;
208
+
209
+ /**
210
+ * A form name that is used to call hooks and filter data.
211
+ *
212
+ * @since 1.0.0
213
+ * @var string
214
+ */
215
+ public $name = 'default';
216
+
217
+ /**
218
+ * It's not yet input controls. The array contains names of input controls and their
219
+ * options that are used to render and process input controls.
220
+ *
221
+ * @since 1.0.0
222
+ * @var mixed[]
223
+ */
224
+ protected $items = array();
225
+
226
+ /**
227
+ * Full set of input controls available after building the form.
228
+ *
229
+ * The array contains objects.
230
+ *
231
+ * @since 1.0.0
232
+ * @var array
233
+ */
234
+ private $controls = array();
235
+
236
+ /**
237
+ * A layout for the form.
238
+ *
239
+ * @since 1.0.0
240
+ * @var string
241
+ */
242
+ public $form_layout;
243
+
244
+ /**
245
+ * A current form layout used to render a form.
246
+ *
247
+ * @since 1.0.0
248
+ * @var Wbcr_FactoryForms422_FormLayout
249
+ */
250
+ public $layout;
251
+
252
+ /**
253
+ * Creates a new instance of a form.
254
+ *
255
+ * @since 1.0.0
256
+ * @param string $options Contains form options to setup.
257
+ */
258
+
259
+ /**
260
+ * Creates a new instance of a form.
261
+ *
262
+ * @since 1.0.0
263
+ * @param array $options
264
+ * @param Wbcr_Factory424_Plugin $plugin
265
+ */
266
+ public function __construct(array $options = array(), Wbcr_Factory424_Plugin $plugin)
267
+ {
268
+ // register controls once, when the first form is created
269
+ if( !Wbcr_FactoryForms422_Manager::$controls_registered ) {
270
+
271
+ do_action('wbcr_factory_forms_422_register_controls', $plugin);
272
+
273
+ //if( !empty($plugin) ) {
274
+ do_action('wbcr_factory_forms_422_register_controls_' . $plugin->getPluginName(), $plugin);
275
+ //}
276
+
277
+ Wbcr_FactoryForms422_Manager::$controls_registered = true;
278
+ }
279
+
280
+ $this->scope = isset($options['scope']) ? $options['scope'] : null;
281
+ $this->name = isset($options['name']) ? $options['name'] : $this->name;
282
+ /*$this->all_sites = isset($options['all_sites'])
283
+ ? $options['all_sites']
284
+ : false;*/
285
+
286
+ if( isset($options['formLayout']) ) {
287
+ $this->form_layout = $options['formLayout'];
288
+ } else {
289
+ $this->form_layout = 'bootstrap-3';
290
+ }
291
+
292
+ Wbcr_FactoryForms422_Manager::$temper = 'flat';
293
+ }
294
+
295
+ /**
296
+ * Sets a provider for the control.
297
+ *
298
+ * @since 1.0.0
299
+ * @param Wbcr_IFactoryForms422_ValueProvider $provider
300
+ * @return void
301
+ */
302
+ public function setProvider($provider)
303
+ {
304
+ $this->provider = $provider;
305
+ }
306
+
307
+ /**
308
+ * Adds items into the form.
309
+ *
310
+ * It's base method to use during configuration form.
311
+ *
312
+ * @since 1.0.0
313
+ * @param array $array An array of items.
314
+ */
315
+ public function add($array)
316
+ {
317
+ if( (bool)count(array_filter(array_keys($array), 'is_string')) ) {
318
+ $this->items[] = $array;
319
+ } else {
320
+ $this->items = array_merge($this->items, $array);
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Returns items to render.
326
+ *
327
+ * Has the follwoing hooks:
328
+ * 'factory_form_items' ( $formName, $items ) to filter form controls before building.
329
+ *
330
+ * @since 1.0.0
331
+ * @return mixed[] Items to render.
332
+ */
333
+ public function getItems()
334
+ {
335
+ return apply_filters('wbcr_factory_424_form_items', $this->items, $this->name);
336
+ }
337
+
338
+ /**
339
+ * Returns form controls (control objects).
340
+ *
341
+ * @since 1.0.0
342
+ * @return Wbcr_FactoryForms422_Control[]
343
+ */
344
+ public function getControls()
345
+ {
346
+ if( !empty($this->controls) ) {
347
+ return $this->controls;
348
+ }
349
+ $this->createControls();
350
+
351
+ return $this->controls;
352
+ }
353
+
354
+ /**
355
+ * Builds a form items to the control objects ready to use.
356
+ *
357
+ * @param null $holder
358
+ * @return Wbcr_FactoryForms422_Control[]
359
+ */
360
+
361
+ public function createControls($holder = null)
362
+ {
363
+ $items = ($holder == null) ? $this->getItems() : $holder['items'];
364
+
365
+ foreach($items as $item) {
366
+
367
+ if( $this->isControlHolder($item) && $this->isControl($item) ) {
368
+
369
+ $this->controls[] = $this->createControl($item);
370
+ $this->createControls($item);
371
+ // if a current item is a control holder
372
+ } elseif( $this->isControlHolder($item) ) {
373
+
374
+ $this->createControls($item);
375
+ // if a current item is an input control
376
+ } elseif( $this->isControl($item) ) {
377
+
378
+ $this->controls[] = $this->createControl($item);
379
+ // if a current item is an input control
380
+ } elseif( $this->isCustomElement($item) ) {
381
+
382
+ // nothing
383
+
384
+ // otherwise, show the error
385
+ } else {
386
+ die('[ERROR] Invalid item.');
387
+ }
388
+ }
389
+
390
+ return $this->controls;
391
+ }
392
+
393
+ /**
394
+ * Create an element.
395
+ *
396
+ * @since 1.0.0
397
+ * @param array $item Item data.
398
+ * @return Wbcr_FactoryForms422_FormElement|null A form element.
399
+ */
400
+ public function createElement($item)
401
+ {
402
+
403
+ if( $this->isControl($item) ) {
404
+ return $this->createControl($item);
405
+ } elseif( $this->isControlHolder($item) ) {
406
+ return $this->createHolder($item);
407
+ } elseif( $this->isCustomElement($item) ) {
408
+ return $this->createCustomElement($item);
409
+ } else {
410
+ printf('[ERROR] The element with the type <strong>%s</strong> was not found.', $item['type']);
411
+ exit;
412
+ }
413
+ }
414
+
415
+ /**
416
+ * Creates a set of elements.
417
+ *
418
+ * @since 1.0.0
419
+ * @param mixed[] $item Data of items.
420
+ * @return Wbcr_FactoryForms422_FormElement[] Created elements.
421
+ */
422
+ public function createElements($items = array())
423
+ {
424
+ $objects = array();
425
+ foreach($items as $item)
426
+ $objects[] = $this->createElement($item);
427
+
428
+ return $objects;
429
+ }
430
+
431
+ /**
432
+ * Create a control.
433
+ *
434
+ * @since 1.0.0
435
+ * @param array $item Item data.
436
+ * @return Wbcr_FactoryForms422_Control A control object.
437
+ */
438
+ public function createControl($item)
439
+ {
440
+ $object = null;
441
+
442
+ if( is_array($item) ) {
443
+
444
+ $control_data = Wbcr_FactoryForms422_Manager::$registered_controls[$item['type']];
445
+
446
+ require_once($control_data['include']);
447
+
448
+ $options = $item;
449
+ $options['scope'] = $this->scope;
450
+
451
+ $object = new $control_data['class']($options, $this);
452
+ } elseif( gettype($item) == 'object' ) {
453
+ $object = $item;
454
+ } else {
455
+ die('[ERROR] Invalid input control.');
456
+ }
457
+
458
+ $object->setProvider($this->provider);
459
+
460
+ return $object;
461
+ }
462
+
463
+ /**
464
+ * Create a control holder.
465
+ *
466
+ * @since 1.0.0
467
+ * @param array $item Item data.
468
+ * @return Wbcr_FactoryForms422_Holder A control holder object.
469
+ */
470
+ public function createHolder($item)
471
+ {
472
+ $object = null;
473
+
474
+ if( is_array($item) ) {
475
+
476
+ $holderData = Wbcr_FactoryForms422_Manager::$registered_holders[$item['type']];
477
+ require_once($holderData['include']);
478
+
479
+ $object = new $holderData['class']($item, $this);
480
+ } elseif( gettype($item) == 'object' ) {
481
+ $object = $item;
482
+ } else {
483
+ die('[ERROR] Invalid control holder.');
484
+ }
485
+
486
+ return $object;
487
+ }
488
+
489
+ /**
490
+ * Create a custom form element.
491
+ *
492
+ * @since 1.0.0
493
+ * @param mixed $item Item data.
494
+ * @return Wbcr_FactoryForms422_FormElement A custom form element object.
495
+ */
496
+ public function createCustomElement($item)
497
+ {
498
+ $object = null;
499
+
500
+ if( is_array($item) ) {
501
+
502
+ $data = Wbcr_FactoryForms422_Manager::$registered_custom_elements[$item['type']];
503
+ require_once($data['include']);
504
+
505
+ $options = $item;
506
+ $object = new $data['class']($options, $this);
507
+ } elseif( gettype($item) == 'object' ) {
508
+ $object = $item;
509
+ } else {
510
+ die('[ERROR] Invalid custom form element.');
511
+ }
512
+
513
+ return $object;
514
+ }
515
+
516
+ /**
517
+ * Renders a form.
518
+ *
519
+ * @since 1.0.0
520
+ * @param mixed[] $options Options for a form layout.
521
+ * @return void
522
+ */
523
+ public function html($options = array())
524
+ {
525
+
526
+ if( !isset(Wbcr_FactoryForms422_Manager::$form_layouts[$this->form_layout]) ) {
527
+ die(sprintf('[ERROR] The form layout %s was not found.', $this->form_layout));
528
+ }
529
+
530
+ // include a render code
531
+ $layout_data = Wbcr_FactoryForms422_Manager::$form_layouts[$this->form_layout];
532
+ require_once($layout_data['include']);
533
+
534
+ $this->connectAssets();
535
+
536
+ if( $this->provider ) {
537
+ $this->provider->init();
538
+ }
539
+ $layout = new $layout_data['class']($options, $this);
540
+ $this->layout = $layout;
541
+ $this->layout->render();
542
+ }
543
+
544
+ /**
545
+ * Connects assets (css and js).
546
+ *
547
+ * @since 1.0.0
548
+ * @param mixed[] $options Options for a form layout.
549
+ * @return void
550
+ */
551
+ private function connectAssets()
552
+ {
553
+
554
+ $this->connectAssetsForItems();
555
+ $layout_data = Wbcr_FactoryForms422_Manager::$form_layouts[$this->form_layout];
556
+
557
+ if( $layout_data['name'] == 'default' ) {
558
+ if( isset($layout_data['style']) ) {
559
+ wp_enqueue_style('wbcr-factory-form-000-default-layout', $layout_data['style']);
560
+ }
561
+ if( isset($layout_data['script']) ) {
562
+ wp_enqueue_script('wbcr-factory-form-000-default-layout-', $layout_data['script']);
563
+ }
564
+ } else {
565
+ if( isset($layout_data['style']) ) {
566
+ wp_enqueue_style('wbcr-factory-form-layout-' . $layout_data['name'], $layout_data['style']);
567
+ }
568
+ if( isset($layout_data['script']) ) {
569
+ wp_enqueue_script('wbcr-factory-form-layout-' . $layout_data['name'], $layout_data['script']);
570
+ }
571
+ }
572
+ }
573
+
574
+
575
+ /**
576
+ * Connects scripts and styles of form items.
577
+ *
578
+ * @since 1.0.0
579
+ * @param mixed[] $items Items for which it's nessesary to connect scripts and styles.
580
+ * @return void
581
+ */
582
+ public static function connectAssetsForItems($items = array())
583
+ {
584
+ foreach($items as $item)
585
+ self::connectAssetsForItem($item);
586
+ }
587
+
588
+ /**
589
+ * Connects scripts and styles of form item.
590
+ *
591
+ * @since 1.0.0
592
+ * @param mixed[] $item Item for which it's nessesary to connect scripts and styles.
593
+ * @return void
594
+ */
595
+ public static function connectAssetsForItem($item)
596
+ {
597
+ if( !is_array($item) ) {
598
+ return;
599
+ }
600
+
601
+ $type = $item['type'];
602
+
603
+ $haystack = array();
604
+ if( self::isControl($type) ) {
605
+ $haystack = Wbcr_FactoryForms422_Manager::$registered_controls;
606
+ } elseif( self::isControlHolder($type) ) {
607
+ $haystack = Wbcr_FactoryForms422_Manager::$registered_holders;
608
+ }
609
+
610
+ if( isset($haystack[$type]) ) {
611
+ if( isset($haystack[$type]['style']) ) {
612
+ $style = $haystack[$type]['style'];
613
+ if( !wp_style_is($style) ) {
614
+ wp_enqueue_style('factory-form-control-' . $type, $style);
615
+ }
616
+ }
617
+ if( isset($haystack[$type]['script']) ) {
618
+ $script = $haystack[$type]['script'];
619
+ if( !wp_script_is($script) ) {
620
+ wp_enqueue_script('factory-form-control-' . $type, $script, array('jquery'));
621
+ }
622
+ }
623
+ }
624
+
625
+ if( isset($item['items']) ) {
626
+ self::connectAssetsForItem($item['items']);
627
+ }
628
+ }
629
+
630
+ /**
631
+ * Saves form data by using a specified value provider.
632
+ *
633
+ * @since 1.0.0
634
+ */
635
+ public function save()
636
+ {
637
+ if( !$this->provider ) {
638
+ return null;
639
+ }
640
+
641
+ $controls = $this->getControls();
642
+
643
+ foreach($controls as $control) {
644
+ $values = $control->getValuesToSave();
645
+
646
+ foreach($values as $key_to_save => $value_to_save) {
647
+ $this->provider->setValue($key_to_save, $value_to_save);
648
+ }
649
+ }
650
+
651
+ $this->provider->saveChanges();
652
+ }
653
+
654
+ /**
655
+ * Returns true if a given item is an input control item.
656
+ *
657
+ * @since 1.0.0
658
+ * @param mixed[] $item
659
+ * @return bool
660
+ */
661
+ public static function isControl($item)
662
+ {
663
+ return isset(Wbcr_FactoryForms422_Manager::$registered_controls[$item['type']]);
664
+ }
665
+
666
+ /**
667
+ * Returns true if a given item is an control holder item.
668
+ *
669
+ * @since 1.0.0
670
+ * @param mixed[] $item
671
+ * @return bool
672
+ */
673
+ public static function isControlHolder($item)
674
+ {
675
+ return isset(Wbcr_FactoryForms422_Manager::$registered_holders[$item['type']]);
676
+ }
677
+
678
+ /**
679
+ * Returns true if a given item is html markup.
680
+ *
681
+ * @since 1.0.0
682
+ * @param mixed[] $item
683
+ * @return bool
684
+ */
685
+ public static function isCustomElement($item)
686
+ {
687
+ return isset(Wbcr_FactoryForms422_Manager::$registered_custom_elements[$item['type']]);
688
+ }
689
+ }
690
+ }
libs/factory/forms/includes/holder.class.php ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the base class for all control holder
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_Holder') ) {
18
+
19
+ /**
20
+ * The base class for control holders.
21
+ *
22
+ * @since 1.0.0
23
+ */
24
+ abstract class Wbcr_FactoryForms422_Holder extends Wbcr_FactoryForms422_FormElement {
25
+
26
+ /**
27
+ * Holder Elements.
28
+ *
29
+ * @since 1.0.0
30
+ * @var Wbcr_FactoryForms422_Control[]
31
+ */
32
+ protected $elements = array();
33
+
34
+ /**
35
+ * Is this element a control holder?
36
+ *
37
+ * @since 1.0.0
38
+ * @var bool
39
+ */
40
+ public $is_holder = true;
41
+
42
+ /**
43
+ * Creates a new instance of control holder.
44
+ *
45
+ * @since 1.0.0
46
+ * @param mixed[] $options A holder options.
47
+ * @param Wbcr_FactoryForms422_Form $form A parent form.
48
+ */
49
+ public function __construct($options, $form)
50
+ {
51
+ parent::__construct($options, $form);
52
+ $this->elements = $form->createElements($options['items']);
53
+ }
54
+
55
+ /**
56
+ * Returns holder elements.
57
+ *
58
+ * @since 1.0.0
59
+ * @return Wbcr_FactoryForms422_Control[].
60
+ */
61
+ public function getElements()
62
+ {
63
+ return $this->elements;
64
+ }
65
+
66
+ /**
67
+ * Renders the form or a given control holder.
68
+ *
69
+ * @since 1.0.0
70
+ * @return void
71
+ */
72
+ function render()
73
+ {
74
+
75
+ $this->beforeRendering();
76
+
77
+ $is_first_item = true;
78
+
79
+ foreach($this->elements as $element) {
80
+
81
+ $element->setOption('isFirst', $is_first_item);
82
+
83
+ if( $is_first_item ) {
84
+ $is_first_item = false;
85
+ }
86
+
87
+ do_action('wbcr_factory_424_form_before_element_' . $element->getOption('name'));
88
+
89
+ // if a current item is a control holder
90
+ if( $element->is_holder ) {
91
+
92
+ $this->form->layout->beforeHolder($element);
93
+ $element->render();
94
+ $this->form->layout->afterHolder($element);
95
+ // if a current item is an input control
96
+ } elseif( $element->is_control ) {
97
+ $this->form->layout->beforeControl($element);
98
+ $element->render();
99
+ $this->form->layout->afterControl($element);
100
+ // if a current item is a custom form element
101
+ } elseif( $element->is_custom ) {
102
+
103
+ $element->render();
104
+ // otherwise, show the error
105
+ } else {
106
+ echo('[ERROR] Invalid item.');
107
+ }
108
+
109
+ do_action('wbcr_factory_form_after_element_' . $element->getOption('name'));
110
+ }
111
+
112
+ $this->afterRendering();
113
+ }
114
+
115
+ /**
116
+ * Rendering a beginning of a holder.
117
+ *
118
+ * @since 1.0.0
119
+ * @return void
120
+ */
121
+ protected function beforeRendering()
122
+ {
123
+ }
124
+
125
+ /**
126
+ * Rendering an end of a holder.
127
+ *
128
+ * @since 1.0.0
129
+ * @return void
130
+ */
131
+ protected function afterRendering()
132
+ {
133
+ }
134
+
135
+ /**
136
+ * Rendering some html before an inner holder.
137
+ *
138
+ * @since 1.0.0
139
+ * @return void
140
+ */
141
+ protected function beforeInnerHolder()
142
+ {
143
+ }
144
+
145
+ /**
146
+ * Rendering some html after an inner holder.
147
+ *
148
+ * @since 1.0.0
149
+ * @return void
150
+ */
151
+ protected function afterInnerHolder()
152
+ {
153
+ }
154
+
155
+
156
+ protected function beforeInnerElement()
157
+ {
158
+ }
159
+
160
+ /**
161
+ * Rendering some html after an inner element.
162
+ *
163
+ * @since 1.0.0
164
+ * @return void
165
+ */
166
+ protected function afterInnerElement()
167
+ {
168
+ }
169
+ }
170
+ }
libs/factory/forms/includes/html-builder.class.php ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains Html Attribute Builder.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_HtmlAttributeBuilder') ) {
18
+ /**
19
+ * Html Attribute Builder
20
+ *
21
+ * @since 1.0.0
22
+ */
23
+ class Wbcr_FactoryForms422_HtmlAttributeBuilder {
24
+
25
+ /**
26
+ * An array to store css classes.
27
+ *
28
+ * @since 1.0.0
29
+ * @var string[]
30
+ */
31
+ protected $css_classes = array();
32
+
33
+ /**
34
+ * An array to store html attributes.
35
+ *
36
+ * @since 1.0.0
37
+ * @var string[]
38
+ */
39
+ protected $html_attrs = array();
40
+
41
+ /**
42
+ * An array to store html data.
43
+ *
44
+ * @since 1.0.0
45
+ * @var string[]
46
+ */
47
+ protected $html_data = array();
48
+
49
+ /**
50
+ * Adds a new CSS class.
51
+ *
52
+ * @since 1.0.0
53
+ * @return void
54
+ */
55
+ public function addCssClass($class)
56
+ {
57
+ if( !is_array($class) ) {
58
+ $this->css_classes[] = $class;
59
+ } else {
60
+ $this->css_classes = array_merge($this->css_classes, $class);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Prints CSS classes.
66
+ *
67
+ * @since 1.0.0
68
+ * @return void
69
+ */
70
+ public function printCssClass()
71
+ {
72
+ echo implode(' ', $this->css_classes);
73
+ }
74
+
75
+ /**
76
+ * Adds a new html data item.
77
+ *
78
+ * @since 1.0.0
79
+ * @param string $dataKey
80
+ * @param string $dataValue
81
+ * @return void
82
+ */
83
+ public function addHtmlData($dataKey, $dataValue)
84
+ {
85
+ $this->html_data[$dataKey] = $dataValue;
86
+ }
87
+
88
+ /**
89
+ * Prints html data items.
90
+ *
91
+ * @since 1.0.0
92
+ * @return void
93
+ */
94
+ public function printHtmlData()
95
+ {
96
+ foreach($this->html_data as $key => $value) {
97
+ echo 'data-' . $key . '="' . $value . '" ';
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Adds a new html attribute.
103
+ *
104
+ * @since 1.0.0
105
+ * @param string $attr_name
106
+ * @param string $attr_value
107
+ * @return void
108
+ */
109
+ public function addHtmlAttr($attr_name, $attr_value)
110
+ {
111
+ $this->html_attrs[$attr_name] = $attr_value;
112
+ }
113
+
114
+ /**
115
+ * Prints all html attributes, including css classes and data.
116
+ *
117
+ * @since 1.0.0
118
+ * @return void
119
+ */
120
+ public function printAttrs()
121
+ {
122
+ $attrs = $this->html_attrs;
123
+
124
+ if( !empty($this->css_classes) ) {
125
+ $attrs['class'] = implode(' ', $this->css_classes);
126
+ }
127
+
128
+ foreach($this->html_data as $data_key => $data_value) {
129
+ $attrs['data-' . $data_key] = $data_value;
130
+ }
131
+
132
+ foreach($attrs as $key => $value) {
133
+ echo $key . '="' . $value . '" ';
134
+ }
135
+ }
136
+ }
137
+ }
libs/factory/forms/includes/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/forms/includes/providers/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/forms/includes/providers/meta-value-provider.class.php ADDED
@@ -0,0 +1,303 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Factory Meta Value Provider.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_OptionsValueProvider') ) {
18
+
19
+ /**
20
+ * Factory Meta Value Provider
21
+ *
22
+ * This provide works with meta values like a lazy key-value storage and
23
+ * provides methods to commit changes on demand. It increases perfomance on form saving.
24
+ *
25
+ * @since 1.0.0
26
+ */
27
+ class Wbcr_FactoryForms422_MetaValueProvider implements Wbcr_IFactoryForms422_ValueProvider {
28
+
29
+
30
+ public $scope;
31
+
32
+ protected $post_id;
33
+
34
+ /**
35
+ * Values to save $metaName => $metaValue
36
+ * @var array
37
+ */
38
+ private $values = array();
39
+
40
+ /**
41
+ * Chanched meta keys (indexed array)
42
+ * @var array
43
+ */
44
+ private $keys = array();
45
+
46
+ private $meta = array();
47
+
48
+
49
+ /**
50
+ * Creates a new instance of a meta value provider.
51
+ *
52
+ * @param array $options
53
+ */
54
+ public function __construct($options = array())
55
+ {
56
+ global $post;
57
+
58
+ $this->scope = (isset($options['scope']))
59
+ ? $options['scope']
60
+ : null;
61
+
62
+ $this->scope = preg_replace('/\_meta\_box$/', '', $this->formatCamelCase($this->scope));
63
+
64
+ /*$this->post_id = (isset($options['post_id']))
65
+ ? $options['post_id']
66
+ : $post->ID;
67
+
68
+ // the second parameter for compatibility with wordpress 3.0
69
+ $temp = get_post_meta($this->post_id, '', true);
70
+
71
+ foreach($temp as $key => &$content) {
72
+ if( strpos($key, $this->scope) === 0 ) {
73
+ $this->meta[$key] = $content;
74
+ }
75
+ }*/
76
+
77
+ $this->init();
78
+ }
79
+
80
+ /**
81
+ * Initizalize an instance of the provider.
82
+ * This method should be invoked before the provider usage.
83
+ *
84
+ * @param bool $post_id
85
+ */
86
+ public function init($post_id = false)
87
+ {
88
+ global $post;
89
+
90
+ $this->post_id = $post_id
91
+ ? $post_id
92
+ : $post->ID;
93
+
94
+ // the second parameter for compatibility with wordpress 3.0
95
+ $temp = get_post_meta($this->post_id, '', true);
96
+
97
+ foreach($temp as $key => &$content) {
98
+ if( strpos($key, $this->scope) === 0 ) {
99
+ $this->meta[$key] = $content;
100
+ }
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Saves changes into a database.
106
+ * The method is optimized for bulk updates.
107
+ */
108
+ public function saveChanges()
109
+ {
110
+
111
+ $this->deleteValues();
112
+ $this->insertValues();
113
+ /**
114
+ * foreach ($this->values as $key => $value) {
115
+ * update_post_meta($this->postId, $key, $value);
116
+ * }
117
+ */
118
+ }
119
+
120
+ /**
121
+ * Removes all actual values from a database.
122
+ */
123
+ private function deleteValues()
124
+ {
125
+ if( count($this->keys) == 0 ) {
126
+ return;
127
+ }
128
+
129
+ global $wpdb;
130
+
131
+ $values = array();
132
+ $keys[] = $this->post_id;
133
+
134
+ for($i = 0; $i < count($this->keys); $i++) {
135
+ $values[] = '%s';
136
+ $keys[] = $this->keys[$i];
137
+ }
138
+
139
+ $clause = implode(',', $values);
140
+ $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->postmeta} WHERE post_id='%d' AND meta_key IN ($clause)", $keys));
141
+ }
142
+
143
+ /**
144
+ * /**
145
+ * Inserts new values by using bulk insert directly into a database.
146
+ *
147
+ * @return bool|false|int
148
+ */
149
+ private function insertValues()
150
+ {
151
+ global $wpdb;
152
+
153
+ $sql = "INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) VALUES ";
154
+ $rows = array();
155
+
156
+ foreach($this->values as $meta_key => $meta_value) {
157
+ if( is_array($meta_value) ) {
158
+ foreach($meta_value as $value) {
159
+ $rows[] = $wpdb->prepare('(%d,%s,%s)', $this->post_id, $meta_key, $value);
160
+ }
161
+ } else {
162
+ $rows[] = $wpdb->prepare('(%d,%s,%s)', $this->post_id, $meta_key, $meta_value);
163
+ }
164
+ }
165
+
166
+ if( empty($rows) ) {
167
+ return false;
168
+ }
169
+
170
+ $sql = $sql . implode(',', $rows);
171
+
172
+ return $wpdb->query($sql);
173
+ }
174
+
175
+ /**
176
+ * @param string $name
177
+ * @param null $default
178
+ * @param bool $multiple
179
+ * @return array|int|null
180
+ */
181
+ public function getValue($name, $default = null, $multiple = false)
182
+ {
183
+ if( is_array($name) ) {
184
+
185
+ $values = array();
186
+ $index = 0;
187
+
188
+ foreach($name as $item) {
189
+ $item_default = ($default && is_array($default) && isset($default[$index]))
190
+ ? $default[$index]
191
+ : null;
192
+
193
+ $values[] = $this->getValueBySingleName($item, $item_default, $multiple);
194
+ $index++;
195
+ }
196
+
197
+ return $values;
198
+ }
199
+
200
+ $value = $this->getValueBySingleName($name, $default, $multiple);
201
+
202
+ return $value;
203
+ }
204
+
205
+ /**
206
+ * @param $single_name
207
+ * @param null $default
208
+ * @param bool $multiple
209
+ * @return int|null
210
+ */
211
+ protected function getValueBySingleName($single_name, $default = null, $multiple = false)
212
+ {
213
+
214
+ $value = isset($this->meta[$this->scope . '_' . $single_name])
215
+ ? ($multiple)
216
+ ? $this->meta[$this->scope . '_' . $single_name]
217
+ : $this->meta[$this->scope . '_' . $single_name][0]
218
+ : $default;
219
+
220
+ if( $value === 'true' ) {
221
+ $value = 1;
222
+ }
223
+ if( $value === 'false' ) {
224
+ $value = 0;
225
+ }
226
+
227
+ return $value;
228
+ }
229
+
230
+ /**
231
+ * @param string $name
232
+ * @param mixed $value
233
+ */
234
+ public function setValue($name, $value)
235
+ {
236
+
237
+ if( is_array($name) ) {
238
+ $index = 0;
239
+
240
+ foreach($name as $item) {
241
+ $itemValue = ($value && is_array($value) && isset($value[$index]))
242
+ ? $value[$index]
243
+ : null;
244
+
245
+ $this->setValueBySingleName($item, $itemValue);
246
+ $index++;
247
+ }
248
+
249
+ return;
250
+ }
251
+
252
+ $this->setValueBySingleName($name, $value);
253
+
254
+ return;
255
+ }
256
+
257
+ /**
258
+ * @param string $single_name
259
+ * @param mixed $singe_value
260
+ */
261
+ protected function setValueBySingleName($single_name, $singe_value)
262
+ {
263
+ $name = $this->scope . '_' . $single_name;
264
+
265
+ if( is_array($singe_value) ) {
266
+
267
+ foreach($singe_value as $index => $value) {
268
+
269
+ $singe_value[$index] = empty($singe_value[$index])
270
+ ? $singe_value[$index]
271
+ : stripslashes($singe_value[$index]);
272
+ }
273
+
274
+ $value = $singe_value;
275
+ } else {
276
+ $value = empty($singe_value)
277
+ ? $singe_value
278
+ : stripslashes($singe_value);
279
+ }
280
+
281
+ $this->values[$name] = $value;
282
+ $this->keys[] = $name;
283
+ }
284
+
285
+ /**
286
+ * @param string $string
287
+ * @return string
288
+ */
289
+ private function formatCamelCase($string)
290
+ {
291
+ $output = "";
292
+ foreach(str_split($string) as $char) {
293
+ if( strtoupper($char) == $char && !in_array($char, array('_', '-')) ) {
294
+ $output .= "_";
295
+ }
296
+ $output .= $char;
297
+ }
298
+ $output = strtolower($output);
299
+
300
+ return $output;
301
+ }
302
+ }
303
+ }
libs/factory/forms/includes/providers/options-value-provider.class.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains the class of Factory Option Value Provider.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+ // Exit if accessed directly
12
+ if( !defined('ABSPATH') ) {
13
+ exit;
14
+ }
15
+
16
+ if( !class_exists('Wbcr_FactoryForms422_OptionsValueProvider') ) {
17
+
18
+ /**
19
+ * Factory Options Value Provider
20
+ *
21
+ * This provide stores form values in the wordpress options.
22
+ *
23
+ * @since 1.0.0
24
+ */
25
+ class Wbcr_FactoryForms422_OptionsValueProvider implements Wbcr_IFactoryForms422_ValueProvider {
26
+
27
+ /**
28
+ * A prefix that will be added to all option names.
29
+ *
30
+ * @since 1.0.0
31
+ * @var string
32
+ */
33
+ public $scope;
34
+
35
+ /**
36
+ * Values to save $optionName => $optionValue
37
+ *
38
+ * @since 1.0.0
39
+ * @var mixed[]
40
+ */
41
+ private $values = array();
42
+
43
+ /**
44
+ * Creates a new instance of an options value provider.
45
+ */
46
+ public function __construct(Wbcr_Factory424_Plugin $plugin)
47
+ {
48
+ $this->plugin = $plugin;
49
+ }
50
+
51
+ /**
52
+ * @since 1.0.0
53
+ */
54
+ public function init()
55
+ {
56
+ // nothing to do
57
+ }
58
+
59
+ /**
60
+ * @since 1.0.0
61
+ */
62
+ public function saveChanges()
63
+ {
64
+ foreach((array)$this->values as $option_name => $option_value) {
65
+ $this->plugin->updatePopulateOption($option_name, $option_value);
66
+ }
67
+ }
68
+
69
+ public function getValue($name, $default = null, $multiple = false)
70
+ {
71
+ $value = $this->plugin->getPopulateOption($name, $default);
72
+
73
+ if( $value === 'true' || $value === true ) {
74
+ $value = 1;
75
+ }
76
+ if( $value === 'false' || $value === false ) {
77
+ $value = 0;
78
+ }
79
+
80
+ return $value;
81
+ }
82
+
83
+ /**
84
+ * @param string $name
85
+ * @param mixed $value
86
+ */
87
+ public function setValue($name, $value)
88
+ {
89
+ $value = empty($value)
90
+ ? $value
91
+ : stripslashes($value);
92
+
93
+ $this->values[$name] = $value;
94
+ }
95
+ }
96
+ }
libs/factory/forms/includes/providers/value-provider.interface.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains an interface for all value provides.
4
+ *
5
+ * A value provider is a provide to get and save values to some stores (database, metadata and so on).
6
+ *
7
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ * @package factory-forms
11
+ * @since 1.0.0
12
+ */
13
+ // Exit if accessed directly
14
+ if( !defined('ABSPATH') ) {
15
+ exit;
16
+ }
17
+ if( !class_exists('Wbcr_IFactoryForms422_ValueProvider') ) {
18
+ /**
19
+ * The interface for all value provides.
20
+ *
21
+ * @since 1.0.0
22
+ */
23
+ interface Wbcr_IFactoryForms422_ValueProvider {
24
+
25
+ /**
26
+ * Inits a form a provider to get data from a storage.
27
+ *
28
+ * @since 1.0.0
29
+ * @return void
30
+ */
31
+ public function init();
32
+
33
+ /**
34
+ * Commits all changes.
35
+ *
36
+ * @since 1.0.0
37
+ * @return void
38
+ */
39
+ public function saveChanges();
40
+
41
+ /**
42
+ * Gets a value by its name.
43
+ *
44
+ * @since 1.0.0
45
+ * @param string $name A value name to get.
46
+ * @param mixed|null $default A default to return if a given name doesn't exist.
47
+ * @param string $name A value name to get.
48
+ * @return mixed
49
+ */
50
+ public function getValue($name, $default = null, $multiple = false);
51
+
52
+ /**
53
+ * Sets a value by its name.
54
+ *
55
+ * @since 1.0.0
56
+ * @param string $name A value name to set.
57
+ * @param mixed $value A value to set.
58
+ * @return void
59
+ */
60
+ public function setValue($name, $value);
61
+ }
62
+ }
libs/factory/forms/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/forms/langs/wbcr_factory_forms_422-ru_RU.mo ADDED
Binary file
libs/factory/forms/langs/wbcr_factory_forms_422-ru_RU.po ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: factory_forms\n"
4
+ "POT-Creation-Date: 2014-08-24 17:39+0400\n"
5
+ "PO-Revision-Date: 2014-08-24 17:49+0400\n"
6
+ "Last-Translator: \n"
7
+ "Language-Team: Alex Kovalev <alex.kovalevv@gmail.com>\n"
8
+ "Language: ru_RU\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 1.6.8\n"
13
+ "X-Poedit-Basepath: .\n"
14
+ "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
15
+ "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
16
+ "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c\n"
18
+ "X-Poedit-SearchPath-0: E:\\cloud\\Dropbox\\OnePress\\Products\\Topic\\Plugin "
19
+ "- Opt-In Panda for Wordpress\\wp-content\\plugins\\optinpanda-next\\libs"
20
+ "\\factory\\forms\n"
21
+
22
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
23
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/checkbox.php:55
24
+ msgid "On"
25
+ msgstr "Вкл"
26
+
27
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
28
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/checkbox.php:56
29
+ msgid "Off"
30
+ msgstr "Выкл"
31
+
32
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
33
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/font.php:33
34
+ msgid "(use default website font)"
35
+ msgstr "(шрифт сайта по умолчанию)"
36
+
37
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
38
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/font.php:35
39
+ msgid "Sans Serif:"
40
+ msgstr "Группа Sans Serif:"
41
+
42
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
43
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/font.php:58
44
+ msgid "Serif:"
45
+ msgstr "Группа Serif:"
46
+
47
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
48
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/font.php:78
49
+ msgid "Monospaced:"
50
+ msgstr "Группа Monospaced:"
51
+
52
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
53
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/gradient.php:54
54
+ msgid "vertical"
55
+ msgstr "вертикальный"
56
+
57
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
58
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/gradient.php:55
59
+ msgid "horizontal"
60
+ msgstr "горизонтальный"
61
+
62
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
63
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/holders/more-link.php:47
64
+ msgid "hide extra options"
65
+ msgstr "скрыть дополнительные настроки"
66
+
67
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
68
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/paddings-editor.php:51
69
+ msgid "Select a side and move the slider to set up:"
70
+ msgstr "Выберите сторону и переместите ползунок:"
71
+
72
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
73
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/pattern.php:78
74
+ msgid "Change color"
75
+ msgstr "Выбрать цвет"
76
+
77
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
78
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/pattern.php:80
79
+ msgid "re-color"
80
+ msgstr "Перекрасить"
81
+
82
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
83
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/pattern.php:89
84
+ msgid "Select color:"
85
+ msgstr "Выберите цвет:"
86
+
87
+ #: E:\cloud\Dropbox\OnePress\Products\Topic\Plugin - Opt-In Panda for
88
+ #: Wordpress\wp-content\plugins\optinpanda-next\libs\factory\forms/controls/pattern.php:91
89
+ msgid "Changing the color may takes a minute or more. Please be patient."
90
+ msgstr ""
91
+ "В некоторых случаях изменение цвета может занять около минуты. Пожалуйста, "
92
+ "будьте терпеливы."
93
+
94
+ #~ msgid "Upload Pattern"
95
+ #~ msgstr "Добавить шаблон"
libs/factory/forms/layouts/bootstrap-3/bootstrap-3.php ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The file contains a form layout based on Twitter Bootstrap 3
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package factory-forms
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ if( !class_exists('Wbcr_FactoryForms422_Bootstrap3FormLayout') ) {
18
+ /**
19
+ * A form layout based on Twitter Bootstrap 3
20
+ */
21
+ class Wbcr_FactoryForms422_Bootstrap3FormLayout extends Wbcr_FactoryForms422_FormLayout {
22
+
23
+ public $name = 'default';
24
+
25
+ /**
26
+ * Creates a new instance of a bootstrap3 form layout.
27
+ *
28
+ * @since 1.0.0
29
+ * @param array $options A holder options.
30
+ * @param Wbcr_FactoryForms422_Form $form A parent form.
31
+ */
32
+ public function __construct($options, $form)
33
+ {
34
+ parent::__construct($options, $form);
35
+
36
+ $this->addCssClass('factory-bootstrap');
37
+ if( isset($options['cssClass']) ) {
38
+ $this->addCssClass($options['cssClass']);
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Renders a beginning of a form.
44
+ *
45
+ * @since 1.0.0
46
+ * @return void
47
+ */
48
+ public function beforeRendering()
49
+ {
50
+ ?>
51
+ <div <?php $this->attrs() ?>>
52
+ <div class="form-horizontal">
53
+ <?php
54
+ }
55
+
56
+ /**
57
+ * Renders the end of a form.
58
+ *
59
+ * @since 1.0.0
60
+ * @return void
61
+ */
62
+ public function afterRendering()
63
+ {
64
+ ?>
65
+ </div>
66
+ </div>
67
+ <?php
68
+ }
69
+
70
+ /**
71
+ * @param Wbcr_FactoryForms422_Control $control
72
+ */
73
+ public function beforeControl($control)
74
+ {
75
+ if( $control->getType() == 'hidden' ) {
76
+ return;
77
+ }
78
+
79
+ $theme_class = '';
80
+ if( isset($control->options['theme']) ) {
81
+ $theme_class = $control->options['theme'];
82
+ }
83
+
84
+ $control_name = $control->getOption('name');
85
+ $control_name_class = $control_name
86
+ ? 'factory-control-' . $control_name
87
+ : '';
88
+
89
+ $col_left = $control->getLayoutOption('column-left', '2');
90
+ $col_right = $control->getLayoutOption('column-right', '10');
91
+ ?>
92
+ <div class="form-group form-group-<?php echo $control->getType() ?> <?php echo $theme_class ?> <?php echo $control_name_class ?>">
93
+ <label for="<?php $control->printNameOnForm() ?>" class="col-sm-<?= $col_left ?> control-label">
94
+ <?php if( $control->hasIcon() ) { ?>
95
+ <img class="control-icon" src="<?php $control->icon() ?>"/>
96
+ <?php } ?>
97
+ <?php
98
+ $hint_type = $control->getLayoutOption('hint-type', 'default');
99
+
100
+ $control->title();
101
+ if( $control->hasHint() ) {
102
+ if( $hint_type == 'icon' ): ?>
103
+ <?php $hint_icon_color = $control->getLayoutOption('hint-icon-color', 'green'); ?>
104
+ <span class="factory-hint-icon factory-hint-icon-<?= $hint_icon_color ?>" data-toggle="factory-tooltip" data-placement="right" title="<?php $control->hint(true) ?>">
105
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAQAAABKmM6bAAAAUUlEQVQIHU3BsQ1AQABA0X/komIrnQHYwyhqQ1hBo9KZRKL9CBfeAwy2ri42JA4mPQ9rJ6OVt0BisFM3Po7qbEliru7m/FkY+TN64ZVxEzh4ndrMN7+Z+jXCAAAAAElFTkSuQmCC" alt=""/>
106
+
107
+ </span>
108
+ <?php endif; ?>
109
+ <?php if( $control->getLayoutOption('hint-position', 'bottom') == 'left' ): ?>
110
+ <div class="help-block"><?php $control->hint() ?></div>
111
+ <?php endif; ?>
112
+ <?php } ?>
113
+ </label>
114
+ <div class="control-group col-sm-<?= $col_right ?>">
115
+ <?php
116
+ }
117
+
118
+ /**
119
+ * @param Wbcr_FactoryForms422_Control $control
120
+ */
121
+ public function afterControl($control)
122
+ {
123
+ if( $control->getType() == 'hidden' ) {
124
+ return;
125
+ }
126
+ ?>
127
+ <?php if( $control->getOption('after', false) ) { ?>
128
+ <span class="factory-after">
129
+ <?php $control->option('after') ?>
130
+ </span>
131
+ <?php } ?>
132
+
133
+ <?php
134
+ $hint_type = $control->getLayoutOption('hint-type', 'default');
135
+ if( $control->hasHint() && $hint_type == 'default' && $control->getLayoutOption('hint-position', 'bottom') == 'bottom' ):
136
+ ?>
137
+ <div class="help-block">
138
+ <?php $control->hint() ?>
139
+ </div>
140
+ <?php endif; ?>
141
+ </div>
142
+ </div>
143
+ <?php
144
+ }
145
+
146
+ /**
147
+ * @param int $index
148
+ * @param int $total
149
+ */
150
+ public function startRow($index, $total)
151
+ {
152
+ ?>
153
+ <div class='factory-row factory-row-<?php echo $index ?> factory-row-<?php echo $index ?>-of-<?php echo $total ?>'>
154
+ <div class="form-group form-group">
155
+ <?php
156
+ }
157
+
158
+ /**
159
+ * @param int $index
160
+ * @param int $total
161
+ */
162
+ public function endRow($index, $total)
163
+ {
164
+ ?>
165
+ </div>
166
+ </div>
167
+ <?php
168
+ }
169
+
170
+ /**
171
+ * @param Wbcr_FactoryForms422_Control $control
172
+ * @param int $index
173
+ * @param int $total
174
+ */
175
+ public function startColumn($control, $index, $total)
176
+ {
177
+ $index = $total == 2
178
+ ? 4
179
+ : 3;
180
+ $name = $control->getNameOnForm();
181
+ ?>
182
+ <label for="<?php echo $name ?>" class="col-sm-2 control-label control-label-<?php echo $name ?>">
183
+ <?php if( $control->hasIcon() ) { ?>
184
+ <img class="control-icon" src="<?php $control->icon() ?>"/>
185
+ <?php } ?>
186
+ <?php $control->title() ?>
187
+ <?php if( $control->hasHint() && $control->getLayoutOption('hint-position', 'bottom') == 'left' ) { ?>
188
+ <div class="help-block"><?php $control->hint() ?></div>
189
+ <?php } ?>
190
+ </label>
191
+ <div class="control-group control-group-<?php echo $name ?> col-sm-<?php echo $index ?>">
192
+ <?php
193
+ }
194
+
195
+ /**
196
+ * @param Wbcr_FactoryForms422_Control $control
197
+ * @param int $index
198
+ * @param int $total
199
+ */
200
+ public function endColumn($control, $index, $total)
201
+ {
202
+ ?>
203
+ <?php if( $control->getOption('after', false) ) { ?>
204
+ <span class="factory-after">
205
+ <?php $control->option('after') ?>
206
+ </span>
207
+ <?php } ?>
208
+ <?php if( $control->hasHint() && $control->getLayoutOption('hint-position', 'bottom') == 'bottom' ) { ?>
209
+ <div class="help-block">
210
+ <?php $control->hint() ?>
211
+ </div>
212
+ <?php } ?>
213
+ </div>
214
+ <?php
215
+ }
216
+ }
217
+ }
libs/factory/forms/layouts/bootstrap-3/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/forms/layouts/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/freemius/boot.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Load Freemius module.
4
+ *
5
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @since 1.0.0
7
+ * @package core
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ if ( defined( 'FACTORY_FREEMIUS_112_LOADED' ) ) {
18
+ return;
19
+ }
20
+
21
+ define( 'FACTORY_FREEMIUS_112_VERSION', '1.1.2' );
22
+
23
+ define( 'FACTORY_FREEMIUS_112_LOADED', true );
24
+ define( 'FACTORY_FREEMIUS_112_DIR', dirname( __FILE__ ) );
25
+ define( 'FACTORY_FREEMIUS_112_URL', plugins_url( null, __FILE__ ) );
26
+
27
+ #comp merge
28
+ // Freemius
29
+ require_once( FACTORY_FREEMIUS_112_DIR . '/includes/entities/class-freemius-entity.php' );
30
+ require_once( FACTORY_FREEMIUS_112_DIR . '/includes/entities/class-freemius-scope.php' );
31
+ require_once( FACTORY_FREEMIUS_112_DIR . '/includes/entities/class-freemius-user.php' );
32
+ require_once( FACTORY_FREEMIUS_112_DIR . '/includes/entities/class-freemius-site.php' );
33
+ require_once( FACTORY_FREEMIUS_112_DIR . '/includes/entities/class-freemius-license.php' );
34
+ require_once( FACTORY_FREEMIUS_112_DIR . '/includes/licensing/class-freemius-provider.php' );
35
+ require_once( FACTORY_FREEMIUS_112_DIR . '/includes/updates/class-freemius-repository.php' );
36
+
37
+ if ( ! class_exists( 'Freemius_Api_WordPress' ) ) {
38
+ require_once FACTORY_FREEMIUS_112_DIR . '/includes/sdk/FreemiusWordPress.php';
39
+ }
40
+
41
+ require_once( FACTORY_FREEMIUS_112_DIR . '/includes/class-freemius-api.php' );
42
+
43
+ /**
44
+ * @param Wbcr_Factory424_Plugin $plugin
45
+ */
46
+ add_action( 'wbcr_factory_freemius_112_plugin_created', function ( $plugin ) {
47
+ # Устанавливаем класс провайдера лицензий для премиум менеджера
48
+ $plugin->set_license_provider( 'freemius', 'WBCR\Factory_Freemius_112\Premium\Provider' );
49
+ # Устанавливаем класс репозитория обновлений для менеджера обновлений
50
+ $plugin->set_update_repository( 'freemius', 'WBCR\Factory_Freemius_112\Updates\Freemius_Repository' );
51
+ } );
52
+ #endcomp
libs/factory/freemius/includes/class-freemius-api.php ADDED
@@ -0,0 +1,416 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_Freemius_112;
4
+
5
+ use Freemius_Api_WordPress;
6
+ use Freemius_Exception;
7
+ use Wbcr_Factory424_Plugin;
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Class FS_Api
15
+ *
16
+ * Wraps Freemius API SDK to handle:
17
+ * 1. Clock sync.
18
+ * 2. Fallback to HTTP when HTTPS fails.
19
+ * 3. Adds caching layer to GET requests.
20
+ * 4. Adds consistency for failed requests by using last cached version.
21
+ *
22
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, Alex Kovalev <alex.kovalevv@gmail.com>
23
+ * @copyright (c) 2018, Webcraftic Ltd
24
+ *
25
+ * @package core
26
+ * @since 1.0.0
27
+ */
28
+ final class Api {
29
+
30
+ /**
31
+ * @var Freemius_Api_WordPress
32
+ */
33
+ private $api;
34
+
35
+ /**
36
+ * @var Wbcr_Factory424_Plugin
37
+ */
38
+ private $plugin;
39
+
40
+ /**
41
+ * @var Api[]
42
+ */
43
+ private static $instances = array();
44
+
45
+ /**
46
+ * @var int Clock diff in seconds between current server to API server.
47
+ */
48
+ private static $clock_diff;
49
+
50
+ /**
51
+ * @param Wbcr_Factory424_Plugin $slug
52
+ * @param string $scope 'app', 'developer', 'user' or 'install'.
53
+ * @param number $id Element's id.
54
+ * @param string $public_key Public key.
55
+ * @param bool|string $secret_key Element's secret key.
56
+ * @param bool $is_sandbox
57
+ */
58
+ private function __construct( Wbcr_Factory424_Plugin $plugin, $scope, $id, $public_key, $secret_key, $is_sandbox ) {
59
+ if ( ! class_exists( 'Freemius_Api_WordPress' ) ) {
60
+ require_once WP_FS__DIR_SDK . '/FreemiusWordPress.php';
61
+ }
62
+
63
+ $this->api = new Freemius_Api_WordPress( $scope, $id, $public_key, $secret_key, $is_sandbox );
64
+
65
+ $this->plugin = $plugin;
66
+
67
+ self::$clock_diff = $plugin->getPopulateOption( 'freemius_api_clock_diff', 0 );
68
+ Freemius_Api_WordPress::SetClockDiff( self::$clock_diff );
69
+
70
+ if ( $plugin->getPopulateOption( 'api_force_http', false ) ) {
71
+ Freemius_Api_WordPress::SetHttp();
72
+ }
73
+ }
74
+
75
+ /**
76
+ * @param Wbcr_Factory424_Plugin $plugin
77
+ * @param string $scope 'app', 'developer', 'user' or 'install'.
78
+ * @param number $id Element's id.
79
+ * @param string $public_key Public key.
80
+ * @param bool $is_sandbox
81
+ * @param bool|string $secret_key Element's secret key.
82
+ *
83
+ * @return Api
84
+ */
85
+ public static function instance( Wbcr_Factory424_Plugin $plugin, $scope, $id, $public_key, $is_sandbox, $secret_key = false ) {
86
+ $identifier = md5( $plugin->getPluginName() . $scope . $id . $public_key . ( is_string( $secret_key ) ? $secret_key : '' ) . json_encode( $is_sandbox ) );
87
+
88
+ if ( ! isset( self::$instances[ $identifier ] ) ) {
89
+ self::$instances[ $identifier ] = new self( $plugin, $scope, $id, $public_key, $secret_key, $is_sandbox );
90
+ }
91
+
92
+ return self::$instances[ $identifier ];
93
+ }
94
+
95
+ /**
96
+ * Check if valid ping request result.
97
+ *
98
+ * @author Vova Feldman (@svovaf)
99
+ * @since 1.1.1
100
+ *
101
+ * @param mixed $pong
102
+ *
103
+ * @return bool
104
+ */
105
+ public function is_valid_ping( $pong ) {
106
+ return Freemius_Api_WordPress::Test( $pong );
107
+ }
108
+
109
+ /**
110
+ * Override API call to wrap it in servers' clock sync method.
111
+ *
112
+ * @param string $path
113
+ * @param string $method
114
+ * @param array $params
115
+ *
116
+ * @return array|mixed|string
117
+ * @throws Freemius_Exception
118
+ */
119
+ public function call( $path, $method = 'GET', $params = array() ) {
120
+ return $this->_call( $path, $method, $params );
121
+ }
122
+
123
+ /**
124
+ * @param string $path
125
+ *
126
+ * @return string
127
+ */
128
+ public function get_url( $path = '' ) {
129
+ return Freemius_Api_WordPress::GetUrl( $path, $this->api->IsSandbox() );
130
+ }
131
+
132
+ /**
133
+ * Get API request URL signed via query string.
134
+ *
135
+ * @param string $path
136
+ *
137
+ * @return string
138
+ * @throws Freemius_Exception
139
+ */
140
+ public function get_signed_url( $path ) {
141
+ return $this->api->GetSignedUrl( $path );
142
+ }
143
+
144
+ #----------------------------------------------------------------------------------
145
+ #region Error Handling
146
+ #----------------------------------------------------------------------------------
147
+
148
+ /**
149
+ * @author Vova Feldman (@svovaf)
150
+ * @since 1.2.1.5
151
+ *
152
+ * @param mixed $result
153
+ *
154
+ * @return bool Is API result contains an error.
155
+ */
156
+ public static function is_api_error( $result ) {
157
+ return ( is_object( $result ) && isset( $result->error ) ) || is_string( $result );
158
+ }
159
+
160
+ /**
161
+ * @author Vova Feldman (@svovaf)
162
+ * @since 2.0.0
163
+ *
164
+ * @param mixed $result
165
+ *
166
+ * @return bool Is API result contains an error.
167
+ */
168
+ public static function is_api_error_object( $result ) {
169
+ return ( is_object( $result ) && isset( $result->error ) && isset( $result->error->message ) );
170
+ }
171
+
172
+ /**
173
+ * Checks if given API result is a non-empty and not an error object.
174
+ *
175
+ * @author Vova Feldman (@svovaf)
176
+ * @since 1.2.1.5
177
+ *
178
+ * @param mixed $result
179
+ * @param string|null $required_property Optional property we want to verify that is set.
180
+ *
181
+ * @return bool
182
+ */
183
+ public static function is_api_result_object( $result, $required_property = null ) {
184
+ return ( is_object( $result ) && ! isset( $result->error ) && ( empty( $required_property ) || isset( $result->{$required_property} ) ) );
185
+ }
186
+
187
+ /**
188
+ * Checks if given API result is a non-empty entity object with non-empty ID.
189
+ *
190
+ * @author Vova Feldman (@svovaf)
191
+ * @since 1.2.1.5
192
+ *
193
+ * @param mixed $result
194
+ *
195
+ * @return bool
196
+ */
197
+ /*static function is_api_result_entity( $result ) {
198
+ return self::is_api_result_object( $result, 'id' ) && FS_Entity::is_valid_id( $result->id );
199
+ }*/
200
+
201
+ /**
202
+ * Get API result error code. If failed to get code, returns an empty string.
203
+ *
204
+ * @author Vova Feldman (@svovaf)
205
+ * @since 2.0.0
206
+ *
207
+ * @param mixed $result
208
+ *
209
+ * @return string
210
+ */
211
+ public static function get_error_code( $result ) {
212
+ if ( is_object( $result ) && isset( $result->error ) && is_object( $result->error ) && ! empty( $result->error->code ) ) {
213
+ return $result->error->code;
214
+ }
215
+
216
+ return '';
217
+ }
218
+ #endregion
219
+
220
+ /**
221
+ * Find clock diff between server and API server, and store the diff locally.
222
+ *
223
+ * @param bool|int $diff
224
+ *
225
+ * @return bool|int False if clock diff didn't change, otherwise returns the clock diff in seconds.
226
+ */
227
+ private function sync_clock_diff( $diff = false ) {
228
+
229
+ // Sync clock and store.
230
+ $new_clock_diff = ( false === $diff ) ? Freemius_Api_WordPress::FindClockDiff() : $diff;
231
+
232
+ if ( $new_clock_diff === self::$clock_diff ) {
233
+ return false;
234
+ }
235
+
236
+ self::$clock_diff = $new_clock_diff;
237
+
238
+ // Update API clock's diff.
239
+ Freemius_Api_WordPress::SetClockDiff( self::$clock_diff );
240
+
241
+ // Store new clock diff in storage.
242
+ $this->plugin->updatePopulateOption( 'freemius_api_clock_diff', self::$clock_diff );
243
+
244
+ return $new_clock_diff;
245
+ }
246
+
247
+ /**
248
+ * Override API call to enable retry with servers' clock auto sync method.
249
+ *
250
+ * @param string $path
251
+ * @param string $method
252
+ * @param array $params
253
+ * @param bool $retry Is in retry or first call attempt.
254
+ *
255
+ * @return array|mixed|string
256
+ */
257
+ private function _call( $path, $method = 'GET', $params = array(), $retry = false ) {
258
+
259
+ $result = $this->api->Api( $path, $method, $params );
260
+
261
+ if ( null !== $result && isset( $result->error ) && isset( $result->error->code ) && 'request_expired' === $result->error->code ) {
262
+ if ( ! $retry ) {
263
+ $diff = isset( $result->error->timestamp ) ? ( time() - strtotime( $result->error->timestamp ) ) : false;
264
+
265
+ // Try to sync clock diff.
266
+ if ( false !== $this->sync_clock_diff( $diff ) ) {
267
+ // Retry call with new synced clock.
268
+ return $this->_call( $path, $method, $params, true );
269
+ }
270
+ }
271
+ }
272
+
273
+ return $result;
274
+ }
275
+
276
+ /**
277
+ * Test API connectivity.
278
+ *
279
+ * @author Vova Feldman (@svovaf)
280
+ * @since 1.0.9 If fails, try to fallback to HTTP.
281
+ * @since 1.1.6 Added a 5-min caching mechanism, to prevent from overloading the server if the API if
282
+ * temporary down.
283
+ *
284
+ * @return bool True if successful connectivity to the API.
285
+ */
286
+ /*public static function test( $plugin ) {
287
+ self::init( $plugin );
288
+
289
+ $cache_key = 'ping_test';
290
+
291
+ $test = self::$_cache->get_valid( $cache_key, null );
292
+
293
+ if ( is_null( $test ) ) {
294
+ $test = Freemius_Api_WordPress::Test();
295
+
296
+ if ( false === $test && Freemius_Api_WordPress::IsHttps() ) {
297
+ // Fallback to HTTP, since HTTPS fails.
298
+ Freemius_Api_WordPress::SetHttp();
299
+
300
+ self::$_options->set_option( 'api_force_http', true, true );
301
+
302
+ $test = Freemius_Api_WordPress::Test();
303
+
304
+ if ( false === $test ) {
305
+ /**
306
+ * API connectivity test fail also in HTTP request, therefore,
307
+ * fallback to HTTPS to keep connection secure.
308
+ *
309
+ * @since 1.1.6
310
+ */
311
+ /* self::$_options->set_option( 'api_force_http', false, true );
312
+ }
313
+ }
314
+
315
+ self::$_cache->set( $cache_key, $test, WP_FS__TIME_5_MIN_IN_SEC );
316
+ }
317
+
318
+ return $test;
319
+ }*/
320
+
321
+ /**
322
+ * Check if API is temporary down.
323
+ *
324
+ * @author Vova Feldman (@svovaf)
325
+ * @since 1.1.6
326
+ *
327
+ * @return bool
328
+ */
329
+ /*public static function is_temporary_down() {
330
+ self::init();
331
+
332
+ $test = self::$_cache->get_valid( 'ping_test', null );
333
+
334
+ return ( false === $test );
335
+ }*/
336
+
337
+ /**
338
+ * @author Vova Feldman (@svovaf)
339
+ * @since 1.1.6
340
+ *
341
+ * @return object
342
+ */
343
+ /*private function get_temporary_unavailable_error() {
344
+ return (object) array(
345
+ 'error' => (object) array(
346
+ 'type' => 'TemporaryUnavailable',
347
+ 'message' => 'API is temporary unavailable, please retry in ' . ( self::$_cache->get_record_expiration( 'ping_test' ) - WP_FS__SCRIPT_START_TIME ) . ' sec.',
348
+ 'code' => 'temporary_unavailable',
349
+ 'http' => 503
350
+ )
351
+ );
352
+ }*/
353
+
354
+ /**
355
+ * Ping API for connectivity test, and return result object.
356
+ *
357
+ * @author Vova Feldman (@svovaf)
358
+ * @since 1.0.9
359
+ *
360
+ * @param null|string $unique_anonymous_id
361
+ * @param array $params
362
+ *
363
+ * @return object
364
+ */
365
+ /*public function ping( $unique_anonymous_id = null, $params = array() ) {
366
+ if ( self::is_temporary_down() ) {
367
+ return $this->get_temporary_unavailable_error();
368
+ }
369
+
370
+ $pong = is_null( $unique_anonymous_id ) ? Freemius_Api_WordPress::Ping() : $this->_call( 'ping.json?' . http_build_query( array_merge( array( 'uid' => $unique_anonymous_id ), $params ) ) );
371
+
372
+ if ( $this->is_valid_ping( $pong ) ) {
373
+ return $pong;
374
+ }
375
+
376
+ if ( self::should_try_with_http( $pong ) ) {
377
+ // Fallback to HTTP, since HTTPS fails.
378
+ Freemius_Api_WordPress::SetHttp();
379
+
380
+ $this->plugin->updatePopulateOption( 'api_force_http', true );
381
+
382
+ $pong = is_null( $unique_anonymous_id ) ? Freemius_Api_WordPress::Ping() : $this->_call( 'ping.json?' . http_build_query( array_merge( array( 'uid' => $unique_anonymous_id ), $params ) ) );
383
+
384
+ if ( ! $this->is_valid_ping( $pong ) ) {
385
+ $this->plugin->updatePopulateOption( 'api_force_http', false );
386
+ }
387
+ }
388
+
389
+ return $pong;
390
+ }*/
391
+
392
+ /**
393
+ * Check if based on the API result we should try
394
+ * to re-run the same request with HTTP instead of HTTPS.
395
+ *
396
+ * @author Vova Feldman (@svovaf)
397
+ * @since 1.1.6
398
+ *
399
+ * @param $result
400
+ *
401
+ * @return bool
402
+ */
403
+ /*private static function should_try_with_http( $result ) {
404
+ if ( ! Freemius_Api_WordPress::IsHttps() ) {
405
+ return false;
406
+ }
407
+
408
+ return ( ! is_object( $result ) || ! isset( $result->error ) || ! isset( $result->error->code ) || ! in_array( $result->error->code, array(
409
+ 'curl_missing',
410
+ 'cloudflare_ddos_protection',
411
+ 'maintenance_mode',
412
+ 'squid_cache_block',
413
+ 'too_many_requests',
414
+ ) ) );
415
+ }*/
416
+ }
libs/factory/freemius/includes/entities/class-freemius-entity.php ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_Freemius_112\Entities;
4
+
5
+ use stdClass;
6
+
7
+ if ( ! defined( 'ABSPATH' ) ) {
8
+ exit;
9
+ }
10
+
11
+ /**
12
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, Alex Kovalev <alex.kovalevv@gmail.com>
13
+ * @link https://webcraftic.com
14
+ * @copyright (c) 2018 Webraftic Ltd, Freemius, Inc.
15
+ * @version 1.0
16
+ */
17
+ class Entity {
18
+
19
+ /**
20
+ * @var number
21
+ */
22
+ public $id;
23
+ /**
24
+ * @var string Datetime value in 'YYYY-MM-DD HH:MM:SS' format.
25
+ */
26
+ public $updated;
27
+ /**
28
+ * @var string Datetime value in 'YYYY-MM-DD HH:MM:SS' format.
29
+ */
30
+ public $created;
31
+
32
+ /**
33
+ * @var bool
34
+ */
35
+ private $is_updated = false;
36
+
37
+ /**
38
+ * @param bool|object|array $entity
39
+ */
40
+ public function __construct( $entity = false ) {
41
+ if ( ! ( $entity instanceof stdClass ) && ! is_array( $entity ) ) {
42
+ return;
43
+ }
44
+
45
+ $props = get_object_vars( $this );
46
+
47
+ foreach ( $props as $key => $def_value ) {
48
+ if ( is_object( $entity ) ) {
49
+ $this->{$key} = isset( $entity->{$key} ) ? $entity->{$key} : $def_value;
50
+ } else {
51
+ $this->{$key} = isset( $entity[ $key ] ) ? $entity[ $key ] : $def_value;
52
+ }
53
+ }
54
+ }
55
+
56
+ /**
57
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
58
+ * @since 1.1
59
+ *
60
+ * @param object|array $data
61
+ *
62
+ * @return bool
63
+ */
64
+ public function populate( $data ) {
65
+ if ( ! is_object( $data ) && ! is_array( $data ) ) {
66
+ return false;
67
+ }
68
+
69
+ $props = get_object_vars( $this );
70
+
71
+ foreach ( $props as $key => $def_value ) {
72
+ if ( is_array( $data ) ) {
73
+ $this->{$key} = isset( $data[ $key ] ) ? $data[ $key ] : $def_value;
74
+ } else {
75
+ $this->{$key} = isset( $data->{$key} ) ? $data->{$key} : $def_value;
76
+ }
77
+ }
78
+
79
+ return true;
80
+ }
81
+
82
+ /**
83
+ * @author Alexander Kovalev <alex.kovalevv@gmail.com>
84
+ * @since 1.0.0
85
+ * @return array
86
+ */
87
+ public function to_array() {
88
+ return get_object_vars( $this );
89
+ }
90
+
91
+ static function get_type() {
92
+ return 'type';
93
+ }
94
+
95
+ /**
96
+ * @author Vova Feldman (@svovaf)
97
+ * @since 1.0.6
98
+ *
99
+ * @param Entity $entity1
100
+ * @param Entity $entity2
101
+ *
102
+ * @return bool
103
+ */
104
+ static function equals( $entity1, $entity2 ) {
105
+ if ( is_null( $entity1 ) && is_null( $entity2 ) ) {
106
+ return true;
107
+ } else if ( is_object( $entity1 ) && is_object( $entity2 ) ) {
108
+ return ( $entity1->id == $entity2->id );
109
+ } else if ( is_object( $entity1 ) ) {
110
+ return is_null( $entity1->id );
111
+ } else {
112
+ return is_null( $entity2->id );
113
+ }
114
+ }
115
+
116
+
117
+ /**
118
+ * Update object property.
119
+ *
120
+ * @author Vova Feldman (@svovaf)
121
+ * @since 1.0.9
122
+ *
123
+ * @param string|array[string]mixed $key
124
+ * @param string|bool $val
125
+ *
126
+ * @return bool
127
+ */
128
+ function update( $key, $val = false ) {
129
+ if ( ! is_array( $key ) ) {
130
+ $key = [ $key => $val ];
131
+ }
132
+
133
+ $is_updated = false;
134
+
135
+ foreach ( $key as $k => $v ) {
136
+ if ( $this->{$k} === $v ) {
137
+ continue;
138
+ }
139
+
140
+ if ( ( is_string( $this->{$k} ) && is_numeric( $v ) || ( is_numeric( $this->{$k} ) && is_string( $v ) ) ) && $this->{$k} == $v ) {
141
+ continue;
142
+ }
143
+
144
+ // Update value.
145
+ $this->{$k} = $v;
146
+
147
+ $is_updated = true;
148
+ }
149
+
150
+ $this->is_updated = $is_updated;
151
+
152
+ return $is_updated;
153
+ }
154
+
155
+ /**
156
+ * Checks if entity was updated.
157
+ *
158
+ * @author Vova Feldman (@svovaf)
159
+ * @since 1.0.9
160
+ *
161
+ * @return bool
162
+ */
163
+ function is_updated() {
164
+ return $this->is_updated;
165
+ }
166
+
167
+ /**
168
+ * @author Vova Feldman (@svovaf)
169
+ * @since 1.1.2
170
+ *
171
+ * @param $id
172
+ *
173
+ * @return bool
174
+ */
175
+ static function is_valid_id( $id ) {
176
+ return is_numeric( $id );
177
+ }
178
+ }
libs/factory/freemius/includes/entities/class-freemius-license.php ADDED
@@ -0,0 +1,369 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_Freemius_112\Entities;
4
+
5
+ use stdClass;
6
+
7
+ if ( ! defined( 'ABSPATH' ) ) {
8
+ exit;
9
+ }
10
+
11
+ /**
12
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, Alex Kovalev <alex.kovalevv@gmail.com>
13
+ * @link https://webcraftic.com
14
+ * @copyright (c) 2018 Webraftic Ltd, Freemius, Inc.
15
+ * @version 1.0
16
+ */
17
+ class License extends Entity implements \WBCR\Factory_424\Premium\Interfaces\License {
18
+
19
+ /**
20
+ * @var number
21
+ */
22
+ public $plugin_id;
23
+
24
+ /**
25
+ * @var number
26
+ */
27
+ public $user_id;
28
+
29
+ /**
30
+ * @var number
31
+ */
32
+ public $plan_id;
33
+
34
+ /**
35
+ * @var
36
+ */
37
+ public $plan_title;
38
+
39
+ /**
40
+ * @var
41
+ */
42
+ public $billing_cycle;
43
+
44
+ /**
45
+ * @var number
46
+ */
47
+ public $pricing_id;
48
+
49
+ /**
50
+ * @var int|null
51
+ */
52
+ public $quota;
53
+
54
+ /**
55
+ * @var int
56
+ */
57
+ public $activated;
58
+
59
+ /**
60
+ * @var int
61
+ */
62
+ public $activated_local;
63
+
64
+ /**
65
+ * @var string
66
+ */
67
+ public $expiration;
68
+
69
+ /**
70
+ * @var string
71
+ */
72
+ public $secret_key;
73
+
74
+ /**
75
+ * @var bool $is_free_localhost Defaults to true. If true, allow unlimited localhost installs with the same
76
+ * license.
77
+ */
78
+ public $is_free_localhost;
79
+
80
+ /**
81
+ * @var bool $is_block_features Defaults to true. If false, don't block features after license expiry - only
82
+ * block updates and support.
83
+ */
84
+ public $is_block_features;
85
+
86
+ /**
87
+ * @var bool
88
+ */
89
+ public $is_cancelled;
90
+
91
+ /**
92
+ * @param stdClass|bool $license
93
+ */
94
+ public function __construct( $license = false ) {
95
+ parent::__construct( $license );
96
+ }
97
+
98
+ /**
99
+ * Get entity type.
100
+ *
101
+ * @return string
102
+ */
103
+ public static function get_type() {
104
+ return 'license';
105
+ }
106
+
107
+ /**
108
+ * Example: #sk_f=>}-5vuHp$3*wPQHxd(AD3<);1&i
109
+ *
110
+ * @return string|null
111
+ */
112
+ public function get_key() {
113
+ return $this->secret_key;
114
+ }
115
+
116
+ /**
117
+ * Example: #sk_f=>}-5vuHp$3******d(AD3<);1&i
118
+ *
119
+ * @return mixed
120
+ */
121
+ public function get_hidden_key() {
122
+ return substr_replace( $this->get_key(), '******', 15, 6 );
123
+ }
124
+
125
+ /**
126
+ * @return string|null
127
+ */
128
+ public function get_plan() {
129
+ return $this->plan_title;
130
+ }
131
+
132
+ /**
133
+ * @return mixed
134
+ */
135
+ public function get_billing_cycle() {
136
+ return $this->billing_cycle;
137
+ }
138
+
139
+ /**
140
+ * @return int
141
+ */
142
+ public function get_sites_quota() {
143
+ return $this->quota;
144
+ }
145
+
146
+ /**
147
+ * @return int
148
+ */
149
+ public function get_count_active_sites() {
150
+ return $this->activated;
151
+ }
152
+
153
+ /**
154
+ * Check how many site activations left.
155
+ *
156
+ * @author Vova Feldman (@svovaf)
157
+ * @since 1.0.5
158
+ *
159
+ * @return int
160
+ */
161
+ public function get_site_activations_left() {
162
+ if ( ! $this->is_active() || $this->is_expired() ) {
163
+ return 0;
164
+ }
165
+
166
+ if ( $this->is_unlimited() ) {
167
+ return 999;
168
+ }
169
+
170
+ return ( $this->quota - $this->activated - ( $this->is_free_localhost ? 0 : $this->activated_local ) );
171
+ }
172
+
173
+ /**
174
+ * @param string $format Return time in formats (time|days|date)
175
+ *
176
+ * @return float|int|string
177
+ */
178
+ public function get_expiration_time( $format = 'time' ) {
179
+ if ( $format == 'days' ) {
180
+ if ( $this->is_lifetime() ) {
181
+ return 999;
182
+ }
183
+
184
+ $remaining = strtotime( $this->expiration ) - date( 'U' );
185
+ $days_remaining = floor( $remaining / 86400 );
186
+
187
+ return $days_remaining;
188
+ } else if ( $format == 'date' ) {
189
+ return date( 'Y-m-d', strtotime( $this->expiration ) );
190
+ }
191
+
192
+ return $this->expiration;
193
+ }
194
+
195
+ /**
196
+ * @param $actual_license_data
197
+ */
198
+ /*public function sync( $actual_license_data ) {
199
+ $props = get_object_vars( $this );
200
+
201
+ foreach ( $props as $key => $def_value ) {
202
+ $this->{$key} = isset( $actual_license_data->{$key} ) ? $actual_license_data->{$key} : $def_value;
203
+ }
204
+ if ( isset( $actual_license_data->expiration ) and is_null( $actual_license_data->expiration ) ) {
205
+ $this->expiration = null;
206
+ }
207
+ }*/
208
+
209
+ /**
210
+ * Check if single site license.
211
+ *
212
+ * @author Vova Feldman (@svovaf)
213
+ * @since 1.1.8.1
214
+ *
215
+ * @return bool
216
+ */
217
+ public function is_single_site() {
218
+ return ( is_numeric( $this->quota ) && 1 == $this->quota );
219
+ }
220
+
221
+ /**
222
+ * @author Vova Feldman (@svovaf)
223
+ * @since 1.0.5
224
+ *
225
+ * @return bool
226
+ */
227
+ public function is_expired() {
228
+ return ! $this->is_lifetime() && ( strtotime( $this->expiration ) < date( 'U' ) );
229
+ }
230
+
231
+ /**
232
+ * Check if license is not expired.
233
+ *
234
+ * @author Vova Feldman (@svovaf)
235
+ * @since 1.2.1
236
+ *
237
+ * @return bool
238
+ */
239
+ public function is_valid() {
240
+ return ! $this->is_expired();
241
+ }
242
+
243
+ /**
244
+ * @author Vova Feldman (@svovaf)
245
+ * @since 1.0.6
246
+ *
247
+ * @return bool
248
+ */
249
+ public function is_lifetime() {
250
+ return is_null( $this->expiration );
251
+ }
252
+
253
+ /**
254
+ * @author Vova Feldman (@svovaf)
255
+ * @since 1.2.0
256
+ *
257
+ * @return bool
258
+ */
259
+ public function is_unlimited() {
260
+ return is_null( $this->quota );
261
+ }
262
+
263
+ /**
264
+ * Check if license is fully utilized.
265
+ *
266
+ * @author Vova Feldman (@svovaf)
267
+ * @since 1.0.6
268
+ *
269
+ * @param bool|null $is_localhost
270
+ *
271
+ * @return bool
272
+ */
273
+ public function is_utilized( $is_localhost = null ) {
274
+ if ( is_null( $is_localhost ) ) {
275
+ $is_localhost = false; // была WP_FS__IS_LOCALHOST_FOR_SERVER
276
+ }
277
+
278
+ if ( $this->is_unlimited() ) {
279
+ return false;
280
+ }
281
+
282
+ return ! ( $this->is_free_localhost && $is_localhost ) && ( $this->quota <= $this->activated + ( $this->is_free_localhost ? 0 : $this->activated_local ) );
283
+ }
284
+
285
+ /**
286
+ * Check if license can be activated.
287
+ *
288
+ * @author Vova Feldman (@svovaf)
289
+ * @since 2.0.0
290
+ *
291
+ * @param bool|null $is_localhost
292
+ *
293
+ * @return bool
294
+ */
295
+ public function can_activate( $is_localhost = null ) {
296
+ return ! $this->is_utilized( $is_localhost ) && $this->is_features_enabled();
297
+ }
298
+
299
+ /**
300
+ * Check if license can be activated on a given number of production and localhost sites.
301
+ *
302
+ * @author Vova Feldman (@svovaf)
303
+ * @since 2.0.0
304
+ *
305
+ * @param int $production_count
306
+ * @param int $localhost_count
307
+ *
308
+ * @return bool
309
+ */
310
+ //public function can_activate_bulk( $production_count, $localhost_count ) {
311
+ //if ( $this->is_unlimited() ) {
312
+ //return true;
313
+ //}
314
+
315
+ /**
316
+ * For simplicity, the logic will work as following: when given X sites to activate the license on, if it's
317
+ * possible to activate on ALL of them, do the activation. If it's not possible to activate on ALL of them,
318
+ * do NOT activate on any of them.
319
+ */
320
+ //return ( $this->quota >= $this->activated + $production_count + ( $this->is_free_localhost ? 0 : $this->activated_local + $localhost_count ) );
321
+ //}
322
+
323
+ /**
324
+ * @author Vova Feldman (@svovaf)
325
+ * @since 1.2.1
326
+ *
327
+ * @return bool
328
+ */
329
+ public function is_active() {
330
+ return ( ! $this->is_cancelled );
331
+ }
332
+
333
+ /**
334
+ * Check if license's plan features are enabled.
335
+ *
336
+ * - Either if plan not expired
337
+ * - If expired, based on the configuration to block features or not.
338
+ *
339
+ * @author Vova Feldman (@svovaf)
340
+ * @since 1.0.6
341
+ *
342
+ * @return bool
343
+ */
344
+ public function is_features_enabled() {
345
+ return $this->is_active() && ( ! $this->is_block_features || ! $this->is_expired() );
346
+ }
347
+
348
+ /**
349
+ * Subscription considered to be new without any payments
350
+ * if the license expires in less than 24 hours
351
+ * from the license creation.
352
+ *
353
+ * @author Vova Feldman (@svovaf)
354
+ * @since 1.0.9
355
+ *
356
+ * @return bool
357
+ */
358
+ public function is_first_payment_pending() {
359
+ return ( 86400 >= strtotime( $this->expiration ) - strtotime( $this->created ) );
360
+ }
361
+
362
+ /**
363
+ * @return int
364
+ */
365
+ public function total_activations() {
366
+ return ( $this->activated + $this->activated_local );
367
+ }
368
+
369
+ }
libs/factory/freemius/includes/entities/class-freemius-plugin.php ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_Freemius_112\Entities;
4
+
5
+ use stdClass;
6
+
7
+ if ( ! defined( 'ABSPATH' ) ) {
8
+ exit;
9
+ }
10
+
11
+ /**
12
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, Alex Kovalev <alex.kovalevv@gmail.com>
13
+ * @link https://webcraftic.com
14
+ * @copyright (c) 2018 Webraftic Ltd, Freemius, Inc.
15
+ * @version 1.0
16
+ */
17
+ class Plugin extends Scope {
18
+
19
+ /**
20
+ * @since 1.0.6
21
+ * @var null|number
22
+ */
23
+ public $parent_plugin_id;
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ public $title;
29
+ /**
30
+ * @var string
31
+ */
32
+ public $slug;
33
+
34
+ /**
35
+ * @var string
36
+ */
37
+ public $premium_slug;
38
+
39
+ /**
40
+ * @var string 'plugin' or 'theme'
41
+ */
42
+ public $type;
43
+
44
+ /**
45
+ * @var string|false false if the module doesn't have an affiliate program or one of the following: 'selected',
46
+ * 'customers', or 'all'.
47
+ */
48
+ public $affiliate_moderation;
49
+
50
+ /**
51
+ * @var bool Set to true if the free version of the module is hosted on WordPress.org. Defaults to true.
52
+ */
53
+ public $is_wp_org_compliant = true;
54
+
55
+ /**
56
+ * @var string
57
+ */
58
+ public $file;
59
+
60
+ /**
61
+ * @var string
62
+ */
63
+ public $version;
64
+
65
+ /**
66
+ * @var bool
67
+ */
68
+ public $auto_update;
69
+
70
+ /**
71
+ * @var bool
72
+ */
73
+ public $is_premium;
74
+
75
+ /**
76
+ * @var string
77
+ */
78
+ public $premium_suffix;
79
+
80
+ /**
81
+ * @var bool
82
+ */
83
+ public $is_live;
84
+
85
+ const AFFILIATE_MODERATION_CUSTOMERS = 'customers';
86
+
87
+ #endregion Install Specific Properties
88
+
89
+ /**
90
+ * @param stdClass|bool $plugin
91
+ */
92
+ function __construct( $plugin = false ) {
93
+ parent::__construct( $plugin );
94
+
95
+ $this->is_premium = false;
96
+ $this->is_live = true;
97
+ }
98
+
99
+ /**
100
+ * Check if plugin is an add-on (has parent).
101
+ *
102
+ * @author Vova Feldman (@svovaf)
103
+ * @since 1.0.6
104
+ *
105
+ * @return bool
106
+ */
107
+ function is_addon() {
108
+ return isset( $this->parent_plugin_id ) && is_numeric( $this->parent_plugin_id );
109
+ }
110
+
111
+ static function get_type() {
112
+ return 'plugin';
113
+ }
114
+ }
libs/factory/freemius/includes/entities/class-freemius-scope.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_Freemius_112\Entities;
4
+
5
+ use stdClass;
6
+
7
+ if ( ! defined( 'ABSPATH' ) ) {
8
+ exit;
9
+ }
10
+
11
+ /**
12
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, Alex Kovalev <alex.kovalevv@gmail.com>
13
+ * @link https://webcraftic.com
14
+ * @copyright (c) 2018 Webraftic Ltd, Freemius, Inc.
15
+ * @version 1.0
16
+ */
17
+ class Scope extends Entity {
18
+
19
+ /**
20
+ * @var string
21
+ */
22
+ public $public_key;
23
+ /**
24
+ * @var string
25
+ */
26
+ public $secret_key;
27
+
28
+ /**
29
+ * @param bool|stdClass $scope_entity
30
+ */
31
+ function __construct( $scope_entity = false ) {
32
+ parent::__construct( $scope_entity );
33
+ }
34
+ }
libs/factory/freemius/includes/entities/class-freemius-site.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_Freemius_112\Entities;
4
+
5
+ use stdClass;
6
+
7
+ if ( ! defined( 'ABSPATH' ) ) {
8
+ exit;
9
+ }
10
+
11
+ /**
12
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, Alex Kovalev <alex.kovalevv@gmail.com>
13
+ * @link https://webcraftic.com
14
+ * @copyright (c) 2018 Webraftic Ltd, Freemius, Inc.
15
+ * @version 1.0
16
+ */
17
+ class Site extends Scope {
18
+
19
+ /**
20
+ * @var number
21
+ */
22
+ public $site_id;
23
+
24
+ /**
25
+ * @var number
26
+ */
27
+ public $plugin_id;
28
+
29
+ /**
30
+ * @var number
31
+ */
32
+ public $user_id;
33
+
34
+ /**
35
+ * @var string
36
+ */
37
+ public $title;
38
+
39
+ /**
40
+ * @var string
41
+ */
42
+ public $url;
43
+
44
+ /**
45
+ * @var string
46
+ */
47
+ public $version;
48
+
49
+ /**
50
+ * @var string E.g. en-GB
51
+ */
52
+ public $language;
53
+
54
+ /**
55
+ * @var string E.g. UTF-8
56
+ */
57
+ public $charset;
58
+
59
+ /**
60
+ * @var string Platform version (e.g WordPress version).
61
+ */
62
+ public $platform_version;
63
+
64
+ /**
65
+ * Freemius SDK version
66
+ *
67
+ * @var string SDK version
68
+ */
69
+ public $sdk_version;
70
+
71
+ /**
72
+ * @var string Programming language version (e.g PHP version).
73
+ */
74
+ public $programming_language_version;
75
+
76
+ /**
77
+ * @var number|null
78
+ */
79
+ public $plan_id;
80
+
81
+ /**
82
+ * @var number|null
83
+ */
84
+ public $license_id;
85
+
86
+ /**
87
+ * @var number|null
88
+ */
89
+ public $trial_plan_id;
90
+
91
+ /**
92
+ * @var string|null
93
+ */
94
+ public $trial_ends;
95
+
96
+ /**
97
+ * @var bool
98
+ */
99
+ public $is_premium = false;
100
+
101
+ /**
102
+ * @var bool
103
+ */
104
+ public $is_disconnected = false;
105
+
106
+ /**
107
+ * @var bool
108
+ */
109
+ public $is_active = true;
110
+
111
+ /**
112
+ * @var bool
113
+ */
114
+ public $is_uninstalled = false;
115
+
116
+ /**
117
+ *
118
+ * @param stdClass|bool $site
119
+ */
120
+ public function __construct( $site = false ) {
121
+ parent::__construct( $site );
122
+
123
+ if ( is_object( $site ) and isset( $site->plan_id ) ) {
124
+ $this->plan_id = $site->plan_id;
125
+ }
126
+
127
+ if ( ! is_bool( $this->is_disconnected ) ) {
128
+ $this->is_disconnected = false;
129
+ }
130
+
131
+ $props = get_object_vars( $this );
132
+
133
+ foreach ( $props as $key => $def_value ) {
134
+ $this->{$key} = isset( $site->{'install_' . $key} ) ? $site->{'install_' . $key} : $def_value;
135
+ }
136
+ if ( isset ( $site->install_id ) ) {
137
+ $this->site_id = $site->install_id;
138
+ }
139
+ }
140
+
141
+ /**
142
+ * @return string
143
+ */
144
+ static function get_type() {
145
+ return 'install';
146
+ }
147
+ }
libs/factory/freemius/includes/entities/class-freemius-user.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_Freemius_112\Entities;
4
+
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
+ }
8
+
9
+ /**
10
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, Alex Kovalev <alex.kovalevv@gmail.com>
11
+ * @link https://webcraftic.com
12
+ * @copyright (c) 2018 Webraftic Ltd, Freemius, Inc.
13
+ * @version 1.0
14
+ */
15
+ class User extends Scope {
16
+
17
+ /**
18
+ * @var string
19
+ */
20
+ public $email;
21
+
22
+ /**
23
+ * @var string
24
+ */
25
+ public $first;
26
+
27
+ /**
28
+ * @var string
29
+ */
30
+ public $last;
31
+
32
+ /**
33
+ * @var bool
34
+ */
35
+ public $is_verified;
36
+
37
+ /**
38
+ * @var string|null
39
+ */
40
+ public $customer_id;
41
+
42
+ /**
43
+ * @var float
44
+ */
45
+ public $gross;
46
+
47
+ /**
48
+ * @param object|bool $user
49
+ */
50
+ public function __construct( $user = false ) {
51
+ parent::__construct( $user );
52
+ $props = get_object_vars( $this );
53
+
54
+ foreach ( $props as $key => $def_value ) {
55
+ $this->{$key} = isset( $user->{'user_' . $key} ) ? $user->{'user_' . $key} : $def_value;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * @return string
61
+ */
62
+ public function get_name() {
63
+ return trim( ucfirst( trim( is_string( $this->first ) ? $this->first : '' ) ) . ' ' . ucfirst( trim( is_string( $this->last ) ? $this->last : '' ) ) );
64
+ }
65
+
66
+ /**
67
+ * @return bool
68
+ */
69
+ public function is_verified() {
70
+ return ( isset( $this->is_verified ) && true === $this->is_verified );
71
+ }
72
+
73
+ /**
74
+ * @return string
75
+ */
76
+ static function get_type() {
77
+ return 'user';
78
+ }
79
+
80
+ }
libs/factory/freemius/includes/entities/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/freemius/includes/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/freemius/includes/licensing/class-freemius-provider.php ADDED
@@ -0,0 +1,739 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_Freemius_112\Premium;
4
+
5
+ use WBCR\Factory_Freemius_112\Entities\License;
6
+ use WBCR\Factory_Freemius_112\Entities\Plugin;
7
+ use WBCR\Factory_Freemius_112\Entities\Site;
8
+ use WBCR\Factory_Freemius_112\Entities\User;
9
+ use WBCR\Factory_424\Premium\Provider as License_Provider;
10
+ use Wbcr_Factory424_Plugin;
11
+ use WBCR\Factory_Freemius_112\Api;
12
+ use WP_Error;
13
+ use Exception;
14
+
15
+ // Exit if accessed directly
16
+ if ( ! defined( 'ABSPATH' ) ) {
17
+ exit;
18
+ }
19
+
20
+ /**
21
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>, Github: https://github.com/alexkovalevv
22
+ * @copyright (c) 2018 Webraftic Ltd, Freemius, Inc.
23
+ * @version 1.0
24
+ */
25
+ final class Provider extends License_Provider {
26
+
27
+ /**
28
+ * @var int
29
+ */
30
+ private $plugin_id;
31
+
32
+ /**
33
+ * @var string
34
+ */
35
+ private $public_key;
36
+
37
+ /**
38
+ * @var string
39
+ */
40
+ private $slug;
41
+
42
+ /**
43
+ * @var \WBCR\Factory_Freemius_112\Api
44
+ */
45
+ private $site_api;
46
+
47
+ /**
48
+ * @var \WBCR\Factory_Freemius_112\Api
49
+ */
50
+ private $plugin_api;
51
+
52
+ /**
53
+ * @var \WBCR\Factory_Freemius_112\Api
54
+ */
55
+ private $user_api;
56
+
57
+ /**
58
+ * @var bool
59
+ */
60
+ private $is_activate_license = false;
61
+
62
+ /**
63
+ * @var License|null
64
+ */
65
+ private $license;
66
+
67
+ /**
68
+ * @var Site|null
69
+ */
70
+ private $license_site;
71
+
72
+ /**
73
+ * @var User|null
74
+ */
75
+ private $license_user;
76
+
77
+ /**
78
+ * @var Plugin|null
79
+ */
80
+ private $license_plugin;
81
+
82
+ /**
83
+ * Manager constructor.
84
+ *
85
+ * @param Wbcr_Factory424_Plugin $plugin
86
+ *
87
+ * @throws Exception
88
+ */
89
+ public function __construct( Wbcr_Factory424_Plugin $plugin, array $settings ) {
90
+ parent::__construct( $plugin, $settings );
91
+
92
+ $this->plugin_id = $this->get_setting( 'plugin_id', null );
93
+ $this->public_key = $this->get_setting( 'public_key', null );
94
+ $this->slug = $this->get_setting( 'slug', null );
95
+
96
+ if ( empty( $this->plugin_id ) || empty( $this->public_key ) || empty( $this->slug ) ) {
97
+ throw new Exception( 'One of required (plugin_id, public_key, slug) attrs is empty.' );
98
+ }
99
+
100
+ $this->init_license();
101
+ }
102
+
103
+ /**
104
+ * @return bool
105
+ * @throws Exception
106
+ */
107
+ public function is_activate() {
108
+ return $this->is_activate_license;
109
+ }
110
+
111
+ /**
112
+ * @return bool
113
+ * @throws Exception
114
+ */
115
+ public function is_active() {
116
+ if ( ! $this->is_activate_license ) {
117
+ return false;
118
+ }
119
+
120
+ return $this->get_license()->is_valid();
121
+ }
122
+
123
+ /**
124
+ * @return string
125
+ * @throws Exception
126
+ */
127
+ public function get_plan() {
128
+ if ( ! $this->is_activate_license ) {
129
+ return null;
130
+ }
131
+
132
+ return $this->get_license()->get_plan();
133
+ }
134
+
135
+ /**
136
+ * @return string
137
+ * @throws Exception
138
+ */
139
+ public function get_billing_cycle() {
140
+ if ( ! $this->is_activate_license ) {
141
+ return null;
142
+ }
143
+
144
+ return $this->get_license()->get_billing_cycle();
145
+ }
146
+
147
+ /**
148
+ * @return \WBCR\Factory_Freemius_112\Entities\License|null
149
+ * @throws Exception
150
+ */
151
+ public function get_license() {
152
+ return $this->license;
153
+ }
154
+
155
+ /**
156
+ * @return string|null
157
+ * @throws \Freemius_Exception
158
+ * @throws Exception
159
+ */
160
+ public function get_package_download_url() {
161
+
162
+ if ( ! $this->is_activate_license ) {
163
+ return null;
164
+ }
165
+
166
+ $endpoint = "/updates/latest.zip";
167
+
168
+ $endpoint = add_query_arg( [
169
+ 'is_premium' => json_encode( true ),
170
+ //'type' => 'all'
171
+ ], $endpoint );
172
+
173
+ try {
174
+ return $this->get_api_site_scope( $this->license_site )->get_signed_url( $endpoint );
175
+ } catch( \Freemius_Exception $e ) {
176
+ throw new Exception( $e->getMessage(), $e->getCode() );
177
+ }
178
+ }
179
+
180
+ /**
181
+ * @return array|mixed|string
182
+ * @throws \Freemius_Exception
183
+ * @throws Exception
184
+ */
185
+ public function get_downloadable_package_info() {
186
+
187
+ if ( ! $this->is_activate_license ) {
188
+ return null;
189
+ }
190
+ try {
191
+ $latest = $this->get_api_site_scope( $this->license_site )->call( "/updates/latest.json" );
192
+
193
+ if ( isset( $latest->error ) ) {
194
+ $error = $latest->error;
195
+
196
+ if ( is_object( $error ) || is_array( $error ) ) {
197
+ $error = var_export( $error, true );
198
+ }
199
+
200
+ throw new Exception( "Freemius API ERROR:" . $error );
201
+ }
202
+ } catch( \Freemius_Exception $e ) {
203
+ throw new Exception( $e->getMessage(), $e->getCode() );
204
+ }
205
+
206
+ return $latest;
207
+ }
208
+
209
+ /**
210
+ * @param string $current_version
211
+ *
212
+ * @throws \Freemius_Exception
213
+ * @throws Exception
214
+ */
215
+ public function get_package_updates( $current_version ) {
216
+
217
+ if ( ! $this->is_activate_license ) {
218
+ return null;
219
+ }
220
+
221
+ try {
222
+ $updates = $this->get_api_site_scope( $this->license_site )->call( 'updates.json?version=' . $current_version, 'GET' );
223
+
224
+ if ( isset( $updates->error ) ) {
225
+ throw new Exception( $updates->error );
226
+ }
227
+ } catch( \Freemius_Exception $e ) {
228
+ throw new Exception( $e->getMessage(), $e->getCode() );
229
+ }
230
+
231
+ return $updates;
232
+ }
233
+
234
+ /**
235
+ * Активирует лицензицию
236
+ *
237
+ * @param string $key
238
+ *
239
+ * @return bool|mixed
240
+ * @throws \Freemius_Exception
241
+ * @throws Exception
242
+ */
243
+ public function activate( $key ) {
244
+
245
+ $license_key = trim( rtrim( $key ) );
246
+
247
+ if ( $this->is_activate_license ) {
248
+ if ( $this->license->id == $license_key ) {
249
+ $this->sync();
250
+
251
+ return true;
252
+ }
253
+
254
+ $this->deactivate();
255
+ }
256
+
257
+ $url = 'https://wp.freemius.com/action/service/user/install/';
258
+ $request_body = [
259
+ 'plugin_slug' => $this->slug,
260
+ 'plugin_id' => $this->plugin_id,
261
+ 'plugin_public_key' => $this->public_key,
262
+ 'plugin_version' => $this->plugin->getPluginVersion(),
263
+ 'is_active' => true,
264
+ 'is_premium' => true,
265
+ 'is_uninstalled' => false,
266
+ 'is_marketing_allowed' => false,
267
+ 'is_disconnected' => false,
268
+ 'user_ip' => $this->get_user_ip(),
269
+ 'format' => 'json',
270
+ 'license_key' => $license_key,
271
+ 'site_name' => get_bloginfo( 'name' ),
272
+ 'site_url' => get_home_url(), //site_uid
273
+ 'site_uid' => $this->get_unique_site_id(),
274
+ 'language' => get_bloginfo( 'language' ),
275
+ 'charset' => get_bloginfo( 'charset' ),
276
+ 'platform_version' => get_bloginfo( 'version' ),
277
+ 'sdk_version' => '2.2.3',
278
+ 'programming_language_version' => phpversion()
279
+ ];
280
+
281
+ $responce = wp_remote_post( $url, [
282
+ 'body' => $request_body,
283
+ 'timeout' => 15,
284
+ ] );
285
+
286
+ if ( is_wp_error( $responce ) ) {
287
+ throw new Exception( $responce->get_error_message() );
288
+ }
289
+
290
+ if ( isset( $responce['response']['code'] ) && $responce['response']['code'] == 403 ) {
291
+ return new WP_Error( 'alert-danger', 'http error' );
292
+ }
293
+
294
+ $responce_data = json_decode( $responce['body'] );
295
+
296
+ if ( isset( $responce_data->error ) ) {
297
+ throw new Exception( $responce_data->error );
298
+ }
299
+
300
+ $license_user = new User( $responce_data );
301
+ $license_site = new Site( $responce_data );
302
+
303
+ $user_api = $this->get_api_user_scope( $license_user );
304
+ $site_api = $this->get_api_site_scope( $license_site );
305
+
306
+ $user_licensies = $user_api->call( $this->get_plugin_endpoint() . '/licenses.json', 'GET' );
307
+
308
+ foreach ( $user_licensies->licenses as $user_license ) {
309
+ if ( $user_license->secret_key == $license_key ) {
310
+ $license = new License( $user_license );
311
+ }
312
+ }
313
+
314
+ $request_plan_path = $this->get_plugin_endpoint() . '/plans/' . $license->plan_id . '.json';
315
+ $request_plan = $user_api->call( $request_plan_path, 'GET' );
316
+
317
+ $license->plan_title = $request_plan->title;
318
+
319
+ $request_subscriptions_path = $this->get_license_endpoint( $license ) . '/subscriptions.json';
320
+ $request_subscriptions = $site_api->call( $request_subscriptions_path, 'GET' );
321
+
322
+ if ( isset( $request_subscriptions->subscriptions ) && isset( $request_subscriptions->subscriptions[0] ) ) {
323
+ $license->billing_cycle = $request_subscriptions->subscriptions[0]->billing_cycle;
324
+ }
325
+
326
+ $this->init_license( $license, $license_user, $license_site );
327
+ $this->save_license_data();
328
+
329
+ $plugin_name = $this->plugin->getPluginName();
330
+ $license_info = [
331
+ 'provider' => 'freemius',
332
+ 'is_active' => $this->is_active(),
333
+ 'license_key' => $this->get_license()->get_key(),
334
+ 'expiration_time' => $this->get_license()->get_expiration_time()
335
+ ];
336
+
337
+ /**
338
+ * Дейтсвие сработает после того, как лицензия будет успешно активирована
339
+ *
340
+ * @since 1.0.9 Изменил имя хука на {$plugin_name}/factory/premium/license_activate
341
+ * @since 1.0.0 Добавлен
342
+ *
343
+ * @param string $provider Провайдер лицензии
344
+ * @param string $license_info Дополнительная информация о лицензии
345
+ */
346
+ do_action( "{$plugin_name}/factory/premium/license_activate", 'freemius', $license_info );
347
+
348
+ return true;
349
+ }
350
+
351
+ /**
352
+ * Деактивирует лицензию
353
+ *
354
+ * @return bool
355
+ * @throws \Freemius_Exception
356
+ * @throws Exception
357
+ */
358
+ public function deactivate() {
359
+ if ( ! $this->is_activate_license ) {
360
+ return true;
361
+ }
362
+
363
+ $plugin_name = $this->plugin->getPluginName();
364
+ $license_info = [
365
+ 'provider' => 'freemius',
366
+ 'is_active' => $this->is_active(),
367
+ 'license_key' => $this->get_license()->get_key(),
368
+ 'expiration_time' => $this->get_license()->get_expiration_time()
369
+ ];
370
+
371
+ $site_api = $this->get_api_site_scope( $this->license_site );
372
+ $user_api = $this->get_api_user_scope( $this->license_user );
373
+
374
+ $site_api->call( $this->get_license_endpoint( $this->license ) . '.json?license_key=' . $this->license->get_key(), 'DELETE' );
375
+ $user_api->call( $this->get_plugin_endpoint() . '/installs.json?ids=' . $this->license_site->id, 'DELETE' );
376
+
377
+ // todo: добавить обработку ошибок
378
+
379
+ $this->delete_license_data();
380
+
381
+ /**
382
+ * Дейтсвие сработает после того, как лицензия будет успешно деактивирована
383
+ *
384
+ * @since 1.0.9 Изменил имя хука на {$plugin_name}/factory/premium/license_deactivate
385
+ * @since 1.0.0 Добавлен
386
+ *
387
+ * @param string $provider Провайдер лицензии
388
+ * @param string $license_info Дополнительная информация о лицензии
389
+ */
390
+ do_action( "{$plugin_name}/factory/premium/license_deactivate", 'freemius', $license_info );
391
+
392
+ return true;
393
+ }
394
+
395
+ /**
396
+ * Синхронизирует данные текущей лицензии.
397
+ *
398
+ * @return bool
399
+ * @throws Exception
400
+ */
401
+ public function sync() {
402
+ if ( ! $this->is_activate_license ) {
403
+ return false;
404
+ }
405
+
406
+ $site_api = $this->get_api_site_scope( $this->license_site );
407
+ $user_api = $this->get_api_user_scope( $this->license_user );
408
+
409
+ $request_install = $site_api->call( '/', 'GET' );
410
+
411
+ // Если установка не найдена или неактивна, деактивируем лицензию
412
+ if ( isset( $request_install->error ) || ! ( isset( $request_install->is_active ) && $request_install->is_active ) ) {
413
+ $this->deactivate();
414
+
415
+ return true;
416
+ }
417
+
418
+ $use_license_key = urlencode( $this->license->secret_key );
419
+ $request_license_path = $this->get_license_endpoint( $this->license ) . '.json?license_key=' . $use_license_key;
420
+ $request_license = $site_api->call( $request_license_path, 'GET' );
421
+
422
+ // Если лицензия не найдена или неактивна или тарифный план не совпадает с текущей установкой,
423
+ // деактивируем лицензию.
424
+ if ( isset( $request_license->error ) || ! ( isset( $request_license->plan_id ) && $request_license->plan_id == $request_install->plan_id ) ) {
425
+ $this->deactivate();
426
+
427
+ return true;
428
+ }
429
+
430
+ $request_subscriptions_path = $this->get_license_endpoint( $this->license ) . '/subscriptions.json';
431
+ $request_subscriptions = $site_api->call( $request_subscriptions_path, 'GET' );
432
+
433
+ $request_plan_path = $this->get_plugin_endpoint() . '/plans/' . $this->license->plan_id . '.json';
434
+ $request_plan = $user_api->call( $request_plan_path, 'GET' );
435
+
436
+ $this->license->plan_title = $request_plan->title;
437
+
438
+ if ( isset( $request_subscriptions->subscriptions ) && isset( $request_subscriptions->subscriptions[0] ) ) {
439
+ if ( ! is_null( $request_subscriptions->subscriptions[0]->next_payment ) ) {
440
+ $this->license->billing_cycle = $request_subscriptions->subscriptions[0]->billing_cycle;
441
+ }
442
+ }
443
+
444
+ $this->license->populate( $request_license );
445
+ $this->save_license_data();
446
+
447
+ // Обновляем информацию о сайте и сервере пользователя
448
+ $site_api->call( '/', 'put', [
449
+ 'id' => $this->license_site->id,
450
+ 'uid' => $this->get_unique_site_id(),
451
+ 'plugin_version' => $this->plugin->getPluginVersion(),
452
+ 'language' => get_bloginfo( 'language' ),
453
+ 'charset' => get_bloginfo( 'charset' ),
454
+ 'platform_version' => get_bloginfo( 'version' ),
455
+ 'sdk_version' => '2.2.3',
456
+ 'programming_language_version' => phpversion()
457
+ ] );
458
+
459
+ $plugin_name = $this->plugin->getPluginName();
460
+ $license_info = [
461
+ 'provider' => 'freemius',
462
+ 'is_active' => $this->is_active(),
463
+ 'license_key' => $this->get_license()->get_key(),
464
+ 'expiration_time' => $this->get_license()->get_expiration_time()
465
+ ];
466
+
467
+ /**
468
+ * Выполняется, когда синхронизация завершена успешно, без деактивации
469
+ *
470
+ * @since 1.0.9 Изменил имя хука на {$plugin_name}/factory/premium/license_sync
471
+ * @since 1.0.0 Добавлен
472
+ *
473
+ * @param string $license_info Дополнительная информация о лицензии
474
+ */
475
+ do_action( "{$plugin_name}/factory/premium/license_sync", $license_info );
476
+
477
+ return true;
478
+ }
479
+
480
+ /**
481
+ * Используется ли платная подписка на обновления плагина.
482
+ *
483
+ * @return bool
484
+ */
485
+ public function has_paid_subscription() {
486
+ if ( ! $this->is_activate_license ) {
487
+ return false;
488
+ }
489
+
490
+ return ! empty( $this->license->billing_cycle );
491
+ }
492
+
493
+ /**
494
+ * Отменяет платную подписку в freemius.com
495
+ *
496
+ * @return bool
497
+ * @throws Exception
498
+ */
499
+ public function cancel_paid_subscription() {
500
+ if ( ! $this->is_activate_license ) {
501
+ return false;
502
+ }
503
+
504
+ $site_api = $this->get_api_site_scope( $this->license_site );
505
+
506
+ $request_subscriptions = $site_api->call( $this->get_license_endpoint( $this->license ) . '/subscriptions.json', 'GET' );
507
+
508
+ if ( isset( $request_subscriptions->subscriptions ) && isset( $request_subscriptions->subscriptions[0] ) ) {
509
+ $site_api->call( 'downgrade.json', 'PUT' );
510
+ $this->license->billing_cycle = null;
511
+ $this->save_license_data();
512
+ }
513
+
514
+ return true;
515
+ }
516
+
517
+ /**
518
+ * Отписывается от платной подписики на обновления
519
+ *
520
+ * @return WP_Error
521
+ */
522
+ /*public function unsubscribe() {
523
+
524
+ }*/
525
+
526
+ // GETTERS SECTION
527
+ // -----------------------------------------------------------------------------------
528
+
529
+ /**
530
+ * Unique site identifier (Hash).
531
+ *
532
+ * @author Vova Feldman (@svovaf)
533
+ * @since 1.1.0
534
+ *
535
+ * @param null|int $blog_id Since 2.0.0
536
+ *
537
+ * @return string
538
+ */
539
+ protected function get_unique_site_id() {
540
+ $key = str_replace( [ 'http://', 'https://' ], '', get_site_url() );
541
+
542
+ $secure_auth = SECURE_AUTH_KEY;
543
+ if ( empty( $secure_auth ) || false !== strpos( $secure_auth, ' ' ) ) {
544
+ // Protect against default auth key.
545
+ $secure_auth = md5( microtime() );
546
+ }
547
+
548
+ /**
549
+ * Base the unique identifier on the WP secure authentication key. Which
550
+ * turns the key into a secret anonymous identifier. This will help us
551
+ * to avoid duplicate installs generation on the backend upon opt-in.
552
+ *
553
+ * @author Vova Feldman (@svovaf)
554
+ * @since 1.2.3
555
+ */
556
+ $unique_id = md5( $key . $secure_auth );
557
+
558
+ return $unique_id;
559
+ }
560
+
561
+ /**
562
+ * Get client IP.
563
+ *
564
+ * @author Vova Feldman (@svovaf)
565
+ * @since 1.1.2
566
+ *
567
+ * @return string|null
568
+ */
569
+ protected function get_user_ip() {
570
+ $fields = [
571
+ 'HTTP_CF_CONNECTING_IP',
572
+ 'HTTP_CLIENT_IP',
573
+ 'HTTP_X_FORWARDED_FOR',
574
+ 'HTTP_X_FORWARDED',
575
+ 'HTTP_FORWARDED_FOR',
576
+ 'HTTP_FORWARDED',
577
+ 'REMOTE_ADDR',
578
+ ];
579
+
580
+ foreach ( $fields as $ip_field ) {
581
+ if ( ! empty( $_SERVER[ $ip_field ] ) ) {
582
+ return $_SERVER[ $ip_field ];
583
+ }
584
+ }
585
+
586
+ return null;
587
+ }
588
+
589
+ /**
590
+ * @param bool $flush
591
+ *
592
+ * @return \WBCR\Factory_Freemius_112\Api
593
+ * @throws Exception
594
+ */
595
+ private function get_api_user_scope( User $user, $flush = false ) {
596
+ if ( ! isset( $this->user_api ) || $flush ) {
597
+ $this->user_api = Api::instance( $this->plugin, 'user', $user->id, $user->public_key, false, $user->secret_key );
598
+ }
599
+
600
+ return $this->user_api;
601
+ }
602
+
603
+ /**
604
+ * @param bool $flush
605
+ *
606
+ * @return \WBCR\Factory_Freemius_112\Api
607
+ * @throws Exception
608
+ */
609
+ private function get_api_site_scope( Site $site, $flush = false ) {
610
+ if ( ! isset( $this->site_api ) || $flush ) {
611
+ $this->site_api = Api::instance( $this->plugin, 'install', $site->id, $site->public_key, false, $site->secret_key );
612
+ }
613
+
614
+ return $this->site_api;
615
+ }
616
+
617
+ /**
618
+ * Get plugin public API scope.
619
+ *
620
+ * @return \WBCR\Factory_Freemius_112\Api
621
+ * @throws Exception
622
+ */
623
+ private function get_api_plugin_scope() {
624
+ if ( ! isset( $this->plugin_api ) ) {
625
+ $this->plugin_api = Api::instance( $this->plugin, 'plugin', $this->plugin_id, $this->public_key, false );
626
+ }
627
+
628
+ return $this->plugin_api;
629
+ }
630
+
631
+ /**
632
+ * @param License $license
633
+ *
634
+ * @return string
635
+ */
636
+ private function get_license_endpoint( License $license ) {
637
+ return '/licenses/' . $license->id;
638
+ }
639
+
640
+ /**
641
+ * @return string
642
+ * @throws Exception
643
+ */
644
+ private function get_plugin_endpoint() {
645
+ return '/plugins/' . $this->plugin_id;
646
+ }
647
+
648
+ // END GETTERS SECTION
649
+ // -----------------------------------------------------------------------------------
650
+
651
+ /**
652
+ * @return void
653
+ * @throws Exception
654
+ */
655
+ private function init_license( $license = null, $license_user = null, $license_site = null, $license_plugin = null ) {
656
+
657
+ if ( $this->is_activate_license ) {
658
+ return;
659
+ }
660
+
661
+ if ( $license instanceof License && $license_user instanceof User && $license_site instanceof Site ) {
662
+ $this->license = $license;
663
+ $this->license_site = $license_site;
664
+ $this->license_user = $license_user;
665
+ $this->license_plugin = $license_plugin;
666
+ } else {
667
+ $license_data = $this->plugin->getPopulateOption( 'license', [] );
668
+
669
+ if ( empty( $license_data ) || ! ( isset( $license_data['license'] ) && isset( $license_data['site'] ) && isset( $license_data['user'] ) ) ) {
670
+ return;
671
+ }
672
+
673
+ $this->license = new License( $license_data['license'] );
674
+ $this->license_site = new Site( $license_data['site'] );
675
+ $this->license_user = new User( $license_data['user'] );
676
+
677
+ if ( isset( $license_data['plugin'] ) ) {
678
+ $this->license_plugin = new Plugin( $license_data['plugin'] );
679
+ }
680
+ }
681
+
682
+ if ( $this->license->id && $this->license_site->id && $this->license_user->id ) {
683
+ $this->is_activate_license = true;
684
+ }
685
+ }
686
+
687
+ /**
688
+ * Сбрасывает всю объектную информацию о лицензии
689
+ *
690
+ * @since 1.0.0
691
+ * @return void
692
+ */
693
+ private function flush_license_data() {
694
+
695
+ $this->is_activate_license = false;
696
+ $this->license = null;
697
+ $this->license_site = null;
698
+ $this->license_user = null;
699
+ $this->license_plugin = null;
700
+
701
+ $this->user_api = null;
702
+ $this->site_api = null;
703
+ }
704
+
705
+ /**
706
+ * Сбрасывает всю объектную информацию о лицензии и удаляет
707
+ * данные о лицензии из базы данных.
708
+ *
709
+ * @since 1.0.0
710
+ * @return void
711
+ */
712
+ private function delete_license_data() {
713
+ $this->flush_license_data();
714
+
715
+ $this->plugin->deletePopulateOption( 'license' );
716
+ }
717
+
718
+ /**
719
+ * Сохраняет лицензионные данные в базе данных, если данные
720
+ * уже есть в базе данных, метод просто обновляет их.
721
+ */
722
+ private function save_license_data() {
723
+ if ( ! $this->license || ! $this->license_site || ! $this->license_user ) {
724
+ return;
725
+ }
726
+
727
+ $save_data = [
728
+ 'license' => $this->license->to_array(),
729
+ 'site' => $this->license_site->to_array(),
730
+ 'user' => $this->license_user->to_array()
731
+ ];
732
+
733
+ if ( ! empty( $this->license_plugin ) ) {
734
+ $save_data['plugin'] = $this->license_plugin->to_array();
735
+ }
736
+
737
+ $this->plugin->updatePopulateOption( 'license', $save_data );
738
+ }
739
+ }
libs/factory/freemius/includes/licensing/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/freemius/includes/sdk/Exceptions/ArgumentNotExistException.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! class_exists( 'Freemius_InvalidArgumentException' ) ) {
3
+ exit;
4
+ }
5
+
6
+ if ( ! class_exists( 'Freemius_ArgumentNotExistException' ) ) {
7
+ class Freemius_ArgumentNotExistException extends Freemius_InvalidArgumentException {
8
+ }
9
+ }
libs/factory/freemius/includes/sdk/Exceptions/EmptyArgumentException.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! class_exists( 'Freemius_InvalidArgumentException' ) ) {
3
+ exit;
4
+ }
5
+
6
+ if ( ! class_exists( 'Freemius_EmptyArgumentException' ) ) {
7
+ class Freemius_EmptyArgumentException extends Freemius_InvalidArgumentException {
8
+ }
9
+ }
libs/factory/freemius/includes/sdk/Exceptions/Exception.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! class_exists( 'Freemius_Exception' ) ) {
3
+ /**
4
+ * Thrown when an API call returns an exception.
5
+ *
6
+ */
7
+ class Freemius_Exception extends Exception {
8
+ protected $_result;
9
+ protected $_type;
10
+ protected $_code;
11
+
12
+ /**
13
+ * Make a new API Exception with the given result.
14
+ *
15
+ * @param array $result The result from the API server.
16
+ */
17
+ public function __construct( $result ) {
18
+ $this->_result = $result;
19
+
20
+ $code = 0;
21
+ $message = 'Unknown error, please check GetResult().';
22
+ $type = '';
23
+
24
+ if ( isset( $result['error'] ) && is_array( $result['error'] ) ) {
25
+ if ( isset( $result['error']['code'] ) ) {
26
+ $code = $result['error']['code'];
27
+ }
28
+ if ( isset( $result['error']['message'] ) ) {
29
+ $message = $result['error']['message'];
30
+ }
31
+ if ( isset( $result['error']['type'] ) ) {
32
+ $type = $result['error']['type'];
33
+ }
34
+ }
35
+
36
+ $this->_type = $type;
37
+ $this->_code = $code;
38
+
39
+ parent::__construct( $message, is_numeric( $code ) ? $code : 0 );
40
+ }
41
+
42
+ /**
43
+ * Return the associated result object returned by the API server.
44
+ *
45
+ * @return array The result from the API server
46
+ */
47
+ public function getResult() {
48
+ return $this->_result;
49
+ }
50
+
51
+ public function getStringCode() {
52
+ return $this->_code;
53
+ }
54
+
55
+ public function getType() {
56
+ return $this->_type;
57
+ }
58
+
59
+ /**
60
+ * To make debugging easier.
61
+ *
62
+ * @return string The string representation of the error
63
+ */
64
+ public function __toString() {
65
+ $str = $this->getType() . ': ';
66
+
67
+ if ( $this->code != 0 ) {
68
+ $str .= $this->getStringCode() . ': ';
69
+ }
70
+
71
+ return $str . $this->getMessage();
72
+ }
73
+ }
74
+ }
libs/factory/freemius/includes/sdk/Exceptions/InvalidArgumentException.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! class_exists( 'Freemius_Exception' ) ) {
3
+ exit;
4
+ }
5
+
6
+ if ( ! class_exists( 'Freemius_InvalidArgumentException' ) ) {
7
+ class Freemius_InvalidArgumentException extends Freemius_Exception { }
8
+ }
libs/factory/freemius/includes/sdk/Exceptions/OAuthException.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! class_exists( 'Freemius_Exception' ) ) {
3
+ exit;
4
+ }
5
+
6
+ if ( ! class_exists( 'Freemius_OAuthException' ) ) {
7
+ class Freemius_OAuthException extends Freemius_Exception {
8
+ public function __construct( $pResult ) {
9
+ parent::__construct( $pResult );
10
+ }
11
+ }
12
+ }
libs/factory/freemius/includes/sdk/Exceptions/index.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <?php
2
+ // Silence is golden.
3
+ // Hide file structure from users on unprotected servers.
libs/factory/freemius/includes/sdk/FreemiusBase.php ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright 2014 Freemius, Inc.
4
+ *
5
+ * Licensed under the GPL v2 (the "License"); you may
6
+ * not use this file except in compliance with the License. You may obtain
7
+ * a copy of the License at
8
+ *
9
+ * http://choosealicense.com/licenses/gpl-v2/
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ * License for the specific language governing permissions and limitations
15
+ * under the License.
16
+ */
17
+
18
+ if ( ! defined( 'FS_API__VERSION' ) ) {
19
+ define( 'FS_API__VERSION', '1' );
20
+ }
21
+ if ( ! defined( 'FS_SDK__PATH' ) ) {
22
+ define( 'FS_SDK__PATH', dirname( __FILE__ ) );
23
+ }
24
+ if ( ! defined( 'FS_SDK__EXCEPTIONS_PATH' ) ) {
25
+ define( 'FS_SDK__EXCEPTIONS_PATH', FS_SDK__PATH . '/Exceptions/' );
26
+ }
27
+
28
+ if ( ! function_exists( 'json_decode' ) ) {
29
+ throw new Exception( 'Freemius needs the JSON PHP extension.' );
30
+ }
31
+
32
+ // Include all exception files.
33
+ $exceptions = array(
34
+ 'Exception',
35
+ 'InvalidArgumentException',
36
+ 'ArgumentNotExistException',
37
+ 'EmptyArgumentException',
38
+ 'OAuthException'
39
+ );
40
+
41
+ foreach ( $exceptions as $e ) {
42
+ require_once FS_SDK__EXCEPTIONS_PATH . $e . '.php';
43
+ }
44
+
45
+ if ( class_exists( 'Freemius_Api_Base' ) ) {
46
+ return;
47
+ }
48
+
49
+ abstract class Freemius_Api_Base {
50
+ const VERSION = '1.0.4';
51
+ const FORMAT = 'json';
52
+
53
+ protected $_id;
54
+ protected $_public;
55
+ protected $_secret;
56
+ protected $_scope;
57
+ protected $_isSandbox;
58
+
59
+ /**
60
+ * @param string $pScope 'app', 'developer', 'plugin', 'user' or 'install'.
61
+ * @param number $pID Element's id.
62
+ * @param string $pPublic Public key.
63
+ * @param string $pSecret Element's secret key.
64
+ * @param bool $pIsSandbox Whether or not to run API in sandbox mode.
65
+ */
66
+ public function Init( $pScope, $pID, $pPublic, $pSecret, $pIsSandbox = false ) {
67
+ $this->_id = $pID;
68
+ $this->_public = $pPublic;
69
+ $this->_secret = $pSecret;
70
+ $this->_scope = $pScope;
71
+ $this->_isSandbox = $pIsSandbox;
72
+ }
73
+
74
+ public function IsSandbox() {
75
+ return $this->_isSandbox;
76
+ }
77
+
78
+ function CanonizePath( $pPath ) {
79
+ $pPath = trim( $pPath, '/' );
80
+ $query_pos = strpos( $pPath, '?' );
81
+ $query = '';
82
+
83
+ if ( false !== $query_pos ) {
84
+ $query = substr( $pPath, $query_pos );
85
+ $pPath = substr( $pPath, 0, $query_pos );
86
+ }
87
+
88
+ // Trim '.json' suffix.
89
+ $format_length = strlen( '.' . self::FORMAT );
90
+ $start = $format_length * ( - 1 ); //negative
91
+ if ( substr( strtolower( $pPath ), $start ) === ( '.' . self::FORMAT ) ) {
92
+ $pPath = substr( $pPath, 0, strlen( $pPath ) - $format_length );
93
+ }
94
+
95
+ switch ( $this->_scope ) {
96
+ case 'app':
97
+ $base = '/apps/' . $this->_id;
98
+ break;
99
+ case 'developer':
100
+ $base = '/developers/' . $this->_id;
101
+ break;
102
+ case 'user':
103
+ $base = '/users/' . $this->_id;
104
+ break;
105
+ case 'plugin':
106
+ $base = '/plugins/' . $this->_id;
107
+ break;
108
+ case 'install':
109
+ $base = '/installs/' . $this->_id;
110
+ break;
111
+ default:
112
+ throw new Freemius_Exception( 'Scope not implemented.' );
113
+ }
114
+
115
+ return '/v' . FS_API__VERSION . $base .
116
+ ( ! empty( $pPath ) ? '/' : '' ) . $pPath .
117
+ ( ( false === strpos( $pPath, '.' ) ) ? '.' . self::FORMAT : '' ) . $query;
118
+ }
119
+
120
+ abstract function MakeRequest( $pCanonizedPath, $pMethod = 'GET', $pParams = array() );
121
+
122
+ /**
123
+ * @param string $pPath
124
+ * @param string $pMethod
125
+ * @param array $pParams
126
+ *
127
+ * @return object[]|object|null
128
+ */
129
+ private function _Api( $pPath, $pMethod = 'GET', $pParams = array() ) {
130
+ $pMethod = strtoupper( $pMethod );
131
+
132
+ try {
133
+ $result = $this->MakeRequest( $pPath, $pMethod, $pParams );
134
+ } catch ( Freemius_Exception $e ) {
135
+ // Map to error object.
136
+ $result = (object) $e->getResult();
137
+ } catch ( Exception $e ) {
138
+ // Map to error object.
139
+ $result = (object) array(
140
+ 'error' => array(
141
+ 'type' => 'Unknown',
142
+ 'message' => $e->getMessage() . ' (' . $e->getFile() . ': ' . $e->getLine() . ')',
143
+ 'code' => 'unknown',
144
+ 'http' => 402
145
+ )
146
+ );
147
+ }
148
+
149
+ return $result;
150
+ }
151
+
152
+ public function Api( $pPath, $pMethod = 'GET', $pParams = array() ) {
153
+ return $this->_Api( $this->CanonizePath( $pPath ), $pMethod, $pParams );
154
+ }
155
+
156
+ /**
157
+ * Base64 decoding that does not need to be urldecode()-ed.
158
+ *
159
+ * Exactly the same as PHP base64 encode except it uses
160
+ * `-` instead of `+`
161
+ * `_` instead of `/`
162
+ * No padded =
163
+ *
164
+ * @param string $input Base64UrlEncoded() string
165
+ *
166
+ * @return string
167
+ */
168
+ protected static function Base64UrlDecode( $input ) {
169
+ /**
170
+ * IMPORTANT NOTE:
171
+ * This is a hack suggested by @otto42 and @greenshady from
172
+ * the theme's review team. The usage of base64 for API
173
+ * signature encoding was approved in a Slack meeting
174
+ * held on Tue (10/25 2016).
175
+ *
176
+ * @todo Remove this hack once the base64 error is removed from the Theme Check.
177
+ *
178
+ * @since 1.2.2
179
+ * @author Vova Feldman (@svovaf)
180
+ */
181
+ $fn = 'base64' . '_decode';
182
+ return $fn( strtr( $input, '-_', '+/' ) );
183
+ }
184
+
185
+ /**
186
+ * Base64 encoding that does not need to be urlencode()ed.
187
+ *
188
+ * Exactly the same as base64 encode except it uses
189
+ * `-` instead of `+
190
+ * `_` instead of `/`
191
+ *
192
+ * @param string $input string
193
+ *
194
+ * @return string Base64 encoded string
195
+ */
196
+ protected static function Base64UrlEncode( $input ) {
197
+ /**
198
+ * IMPORTANT NOTE:
199
+ * This is a hack suggested by @otto42 and @greenshady from
200
+ * the theme's review team. The usage of base64 for API
201
+ * signature encoding was approved in a Slack meeting
202
+ * held on Tue (10/25 2016).
203
+ *
204
+ * @todo Remove this hack once the base64 error is removed from the Theme Check.
205
+ *
206
+ * @since 1.2.2
207
+ * @author Vova Feldman (@svovaf)
208
+ */
209
+ $fn = 'base64' . '_encode';
210
+ $str = strtr( $fn( $input ), '+/', '-_' );
211
+ $str = str_replace( '=', '', $str );
212
+
213
+ return $str;
214
+ }
215
+ }
libs/factory/freemius/includes/sdk/FreemiusWordPress.php ADDED
@@ -0,0 +1,704 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright 2016 Freemius, Inc.
4
+ *
5
+ * Licensed under the GPL v2 (the "License"); you may
6
+ * not use this file except in compliance with the License. You may obtain
7
+ * a copy of the License at
8
+ *
9
+ * http://choosealicense.com/licenses/gpl-v2/
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ * License for the specific language governing permissions and limitations
15
+ * under the License.
16
+ */
17
+
18
+ require_once dirname( __FILE__ ) . '/FreemiusBase.php';
19
+
20
+ if ( ! defined( 'FS_SDK__USER_AGENT' ) ) {
21
+ define( 'FS_SDK__USER_AGENT', 'fs-php-' . Freemius_Api_Base::VERSION );
22
+ }
23
+
24
+ if ( ! defined( 'FS_SDK__SIMULATE_NO_CURL' ) ) {
25
+ define( 'FS_SDK__SIMULATE_NO_CURL', false );
26
+ }
27
+
28
+ if ( ! defined( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE' ) ) {
29
+ define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE', false );
30
+ }
31
+
32
+ if ( ! defined( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL' ) ) {
33
+ define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL', false );
34
+ }
35
+
36
+ if ( ! defined( 'FS_SDK__HAS_CURL' ) ) {
37
+ if ( FS_SDK__SIMULATE_NO_CURL ) {
38
+ define( 'FS_SDK__HAS_CURL', false );
39
+ } else {
40
+ $curl_required_methods = array(
41
+ 'curl_version',
42
+ 'curl_exec',
43
+ 'curl_init',
44
+ 'curl_close',
45
+ 'curl_setopt',
46
+ 'curl_setopt_array',
47
+ 'curl_error',
48
+ );
49
+
50
+ $has_curl = true;
51
+ foreach ( $curl_required_methods as $m ) {
52
+ if ( ! function_exists( $m ) ) {
53
+ $has_curl = false;
54
+ break;
55
+ }
56
+ }
57
+
58
+ define( 'FS_SDK__HAS_CURL', $has_curl );
59
+ }
60
+ }
61
+
62
+ $curl_version = FS_SDK__HAS_CURL ?
63
+ curl_version() :
64
+ array( 'version' => '7.37' );
65
+
66
+ if ( ! defined( 'FS_API__PROTOCOL' ) ) {
67
+ define( 'FS_API__PROTOCOL', version_compare( $curl_version['version'], '7.37', '>=' ) ? 'https' : 'http' );
68
+ }
69
+
70
+ if ( ! defined( 'FS_API__LOGGER_ON' ) ) {
71
+ define( 'FS_API__LOGGER_ON', false );
72
+ }
73
+
74
+ if ( ! defined( 'FS_API__ADDRESS' ) ) {
75
+ define( 'FS_API__ADDRESS', '://api.freemius.com' );
76
+ }
77
+ if ( ! defined( 'FS_API__SANDBOX_ADDRESS' ) ) {
78
+ define( 'FS_API__SANDBOX_ADDRESS', '://sandbox-api.freemius.com' );
79
+ }
80
+
81
+ if ( class_exists( 'Freemius_Api_WordPress' ) ) {
82
+ return;
83
+ }
84
+
85
+ class Freemius_Api_WordPress extends Freemius_Api_Base {
86
+ private static $_logger = array();
87
+
88
+ /**
89
+ * @param string $pScope 'app', 'developer', 'user' or 'install'.
90
+ * @param number $pID Element's id.
91
+ * @param string $pPublic Public key.
92
+ * @param string|bool $pSecret Element's secret key.
93
+ * @param bool $pSandbox Whether or not to run API in sandbox mode.
94
+ */
95
+ public function __construct( $pScope, $pID, $pPublic, $pSecret = false, $pSandbox = false ) {
96
+ // If secret key not provided, use public key encryption.
97
+ if ( is_bool( $pSecret ) ) {
98
+ $pSecret = $pPublic;
99
+ }
100
+
101
+ parent::Init( $pScope, $pID, $pPublic, $pSecret, $pSandbox );
102
+ }
103
+
104
+ public static function GetUrl( $pCanonizedPath = '', $pIsSandbox = false ) {
105
+ $address = ( $pIsSandbox ? FS_API__SANDBOX_ADDRESS : FS_API__ADDRESS );
106
+
107
+ if ( ':' === $address[0] ) {
108
+ $address = self::$_protocol . $address;
109
+ }
110
+
111
+ return $address . $pCanonizedPath;
112
+ }
113
+
114
+ #----------------------------------------------------------------------------------
115
+ #region Servers Clock Diff
116
+ #----------------------------------------------------------------------------------
117
+
118
+ /**
119
+ * @var int Clock diff in seconds between current server to API server.
120
+ */
121
+ private static $_clock_diff = 0;
122
+
123
+ /**
124
+ * Set clock diff for all API calls.
125
+ *
126
+ * @since 1.0.3
127
+ *
128
+ * @param $pSeconds
129
+ */
130
+ public static function SetClockDiff( $pSeconds ) {
131
+ self::$_clock_diff = $pSeconds;
132
+ }
133
+
134
+ /**
135
+ * Find clock diff between current server to API server.
136
+ *
137
+ * @since 1.0.2
138
+ * @return int Clock diff in seconds.
139
+ */
140
+ public static function FindClockDiff() {
141
+ $time = time();
142
+ $pong = self::Ping();
143
+
144
+ return ( $time - strtotime( $pong->timestamp ) );
145
+ }
146
+
147
+ #endregion
148
+
149
+ /**
150
+ * @var string http or https
151
+ */
152
+ private static $_protocol = FS_API__PROTOCOL;
153
+
154
+ /**
155
+ * Set API connection protocol.
156
+ *
157
+ * @since 1.0.4
158
+ */
159
+ public static function SetHttp() {
160
+ self::$_protocol = 'http';
161
+ }
162
+
163
+ /**
164
+ * @since 1.0.4
165
+ *
166
+ * @return bool
167
+ */
168
+ public static function IsHttps() {
169
+ return ( 'https' === self::$_protocol );
170
+ }
171
+
172
+ /**
173
+ * Sign request with the following HTTP headers:
174
+ * Content-MD5: MD5(HTTP Request body)
175
+ * Date: Current date (i.e Sat, 14 Feb 2016 20:24:46 +0000)
176
+ * Authorization: FS {scope_entity_id}:{scope_entity_public_key}:base64encode(sha256(string_to_sign,
177
+ * {scope_entity_secret_key}))
178
+ *
179
+ * @param string $pResourceUrl
180
+ * @param array $pWPRemoteArgs
181
+ *
182
+ * @return array
183
+ */
184
+ function SignRequest( $pResourceUrl, $pWPRemoteArgs ) {
185
+ $auth = $this->GenerateAuthorizationParams(
186
+ $pResourceUrl,
187
+ $pWPRemoteArgs['method'],
188
+ ! empty( $pWPRemoteArgs['body'] ) ? $pWPRemoteArgs['body'] : ''
189
+ );
190
+
191
+ $pWPRemoteArgs['headers']['Date'] = $auth['date'];
192
+ $pWPRemoteArgs['headers']['Authorization'] = $auth['authorization'];
193
+
194
+ if ( ! empty( $auth['content_md5'] ) ) {
195
+ $pWPRemoteArgs['headers']['Content-MD5'] = $auth['content_md5'];
196
+ }
197
+
198
+ return $pWPRemoteArgs;
199
+ }
200
+
201
+ /**
202
+ * Generate Authorization request headers:
203
+ *
204
+ * Content-MD5: MD5(HTTP Request body)
205
+ * Date: Current date (i.e Sat, 14 Feb 2016 20:24:46 +0000)
206
+ * Authorization: FS {scope_entity_id}:{scope_entity_public_key}:base64encode(sha256(string_to_sign,
207
+ * {scope_entity_secret_key}))
208
+ *
209
+ * @author Vova Feldman
210
+ *
211
+ * @param string $pResourceUrl
212
+ * @param string $pMethod
213
+ * @param string $pPostParams
214
+ *
215
+ * @return array
216
+ * @throws Freemius_Exception
217
+ */
218
+ function GenerateAuthorizationParams(
219
+ $pResourceUrl,
220
+ $pMethod = 'GET',
221
+ $pPostParams = ''
222
+ ) {
223
+ $pMethod = strtoupper( $pMethod );
224
+
225
+ $eol = "\n";
226
+ $content_md5 = '';
227
+ $content_type = '';
228
+ $now = ( time() - self::$_clock_diff );
229
+ $date = date( 'r', $now );
230
+
231
+ if ( in_array( $pMethod, array( 'POST', 'PUT' ) ) && ! empty( $pPostParams ) ) {
232
+ $content_md5 = md5( $pPostParams );
233
+ $content_type = 'application/json';
234
+ }
235
+
236
+ $string_to_sign = implode( $eol, array(
237
+ $pMethod,
238
+ $content_md5,
239
+ $content_type,
240
+ $date,
241
+ $pResourceUrl
242
+ ) );
243
+
244
+ // If secret and public keys are identical, it means that
245
+ // the signature uses public key hash encoding.
246
+ $auth_type = ( $this->_secret !== $this->_public ) ? 'FS' : 'FSP';
247
+
248
+ $auth = array(
249
+ 'date' => $date,
250
+ 'authorization' => $auth_type . ' ' . $this->_id . ':' .
251
+ $this->_public . ':' .
252
+ self::Base64UrlEncode( hash_hmac(
253
+ 'sha256', $string_to_sign, $this->_secret
254
+ ) )
255
+ );
256
+
257
+ if ( ! empty( $content_md5 ) ) {
258
+ $auth['content_md5'] = $content_md5;
259
+ }
260
+
261
+ return $auth;
262
+ }
263
+
264
+ /**
265
+ * Get API request URL signed via query string.
266
+ *
267
+ * @since 1.2.3 Stopped using http_build_query(). Instead, use urlencode(). In some environments the encoding of http_build_query() can generate a URL that once used with a redirect, the `&` querystring separator is escaped to `&amp;` which breaks the URL (Added by @svovaf).
268
+ *
269
+ * @param string $pPath
270
+ *
271
+ * @throws Freemius_Exception
272
+ *
273
+ * @return string
274
+ */
275
+ function GetSignedUrl( $pPath ) {
276
+ $resource = explode( '?', $this->CanonizePath( $pPath ) );
277
+ $pResourceUrl = $resource[0];
278
+
279
+ $auth = $this->GenerateAuthorizationParams( $pResourceUrl );
280
+
281
+ return Freemius_Api_WordPress::GetUrl(
282
+ $pResourceUrl . '?' .
283
+ ( 1 < count( $resource ) && ! empty( $resource[1] ) ? $resource[1] . '&' : '' ) .
284
+ 'authorization=' . urlencode( $auth['authorization'] ) .
285
+ '&auth_date=' . urlencode( $auth['date'] )
286
+ , $this->_isSandbox );
287
+ }
288
+
289
+ /**
290
+ * @author Vova Feldman
291
+ *
292
+ * @param string $pUrl
293
+ * @param array $pWPRemoteArgs
294
+ *
295
+ * @return mixed
296
+ */
297
+ private static function ExecuteRequest( $pUrl, &$pWPRemoteArgs ) {
298
+ $start = microtime( true );
299
+
300
+ $response = wp_remote_request( $pUrl, $pWPRemoteArgs );
301
+
302
+ if ( FS_API__LOGGER_ON ) {
303
+ $end = microtime( true );
304
+
305
+ $has_body = ( isset( $pWPRemoteArgs['body'] ) && ! empty( $pWPRemoteArgs['body'] ) );
306
+ $is_http_error = is_wp_error( $response );
307
+
308
+ self::$_logger[] = array(
309
+ 'id' => count( self::$_logger ),
310
+ 'start' => $start,
311
+ 'end' => $end,
312
+ 'total' => ( $end - $start ),
313
+ 'method' => $pWPRemoteArgs['method'],
314
+ 'path' => $pUrl,
315
+ 'body' => $has_body ? $pWPRemoteArgs['body'] : null,
316
+ 'result' => ! $is_http_error ?
317
+ $response['body'] :
318
+ json_encode( $response->get_error_messages() ),
319
+ 'code' => ! $is_http_error ? $response['response']['code'] : null,
320
+ 'backtrace' => debug_backtrace(),
321
+ );
322
+ }
323
+
324
+ return $response;
325
+ }
326
+
327
+ /**
328
+ * @return array
329
+ */
330
+ static function GetLogger() {
331
+ return self::$_logger;
332
+ }
333
+
334
+ /**
335
+ * @param string $pCanonizedPath
336
+ * @param string $pMethod
337
+ * @param array $pParams
338
+ * @param null|array $pWPRemoteArgs
339
+ * @param bool $pIsSandbox
340
+ * @param null|callable $pBeforeExecutionFunction
341
+ *
342
+ * @return object[]|object|null
343
+ *
344
+ * @throws \Freemius_Exception
345
+ */
346
+ private static function MakeStaticRequest(
347
+ $pCanonizedPath,
348
+ $pMethod = 'GET',
349
+ $pParams = array(),
350
+ $pWPRemoteArgs = null,
351
+ $pIsSandbox = false,
352
+ $pBeforeExecutionFunction = null
353
+ ) {
354
+ // Connectivity errors simulation.
355
+ if ( FS_SDK__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE ) {
356
+ self::ThrowCloudFlareDDoSException();
357
+ } else if ( FS_SDK__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL ) {
358
+ self::ThrowSquidAclException();
359
+ }
360
+
361
+ if ( empty( $pWPRemoteArgs ) ) {
362
+ $user_agent = 'Freemius/WordPress-SDK/' . Freemius_Api_Base::VERSION . '; ' .
363
+ home_url();
364
+
365
+ $pWPRemoteArgs = array(
366
+ 'method' => strtoupper( $pMethod ),
367
+ 'connect_timeout' => 10,
368
+ 'timeout' => 60,
369
+ 'follow_redirects' => true,
370
+ 'redirection' => 5,
371
+ 'user-agent' => $user_agent,
372
+ 'blocking' => true,
373
+ );
374
+ }
375
+
376
+ if ( ! isset( $pWPRemoteArgs['headers'] ) ||
377
+ ! is_array( $pWPRemoteArgs['headers'] )
378
+ ) {
379
+ $pWPRemoteArgs['headers'] = array();
380
+ }
381
+
382
+ if ( in_array( $pMethod, array( 'POST', 'PUT' ) ) ) {
383
+ if ( is_array( $pParams ) && 0 < count( $pParams ) ) {
384
+ $pWPRemoteArgs['headers']['Content-type'] = 'application/json';
385
+ $pWPRemoteArgs['body'] = json_encode( $pParams );
386
+ }
387
+ }
388
+
389
+ $request_url = self::GetUrl( $pCanonizedPath, $pIsSandbox );
390
+
391
+ $resource = explode( '?', $pCanonizedPath );
392
+
393
+ if ( FS_SDK__HAS_CURL ) {
394
+ // Disable the 'Expect: 100-continue' behaviour. This causes cURL to wait
395
+ // for 2 seconds if the server does not support this header.
396
+ $pWPRemoteArgs['headers']['Expect'] = '';
397
+ }
398
+
399
+ if ( 'https' === substr( strtolower( $request_url ), 0, 5 ) ) {
400
+ $pWPRemoteArgs['sslverify'] = false;
401
+ }
402
+
403
+ if ( false !== $pBeforeExecutionFunction &&
404
+ is_callable( $pBeforeExecutionFunction )
405
+ ) {
406
+ $pWPRemoteArgs = call_user_func( $pBeforeExecutionFunction, $resource[0], $pWPRemoteArgs );
407
+ }
408
+
409
+ $result = self::ExecuteRequest( $request_url, $pWPRemoteArgs );
410
+
411
+ if ( is_wp_error( $result ) ) {
412
+ /**
413
+ * @var WP_Error $result
414
+ */
415
+ if ( self::IsCurlError( $result ) ) {
416
+ /**
417
+ * With dual stacked DNS responses, it's possible for a server to
418
+ * have IPv6 enabled but not have IPv6 connectivity. If this is
419
+ * the case, cURL will try IPv4 first and if that fails, then it will
420
+ * fall back to IPv6 and the error EHOSTUNREACH is returned by the
421
+ * operating system.
422
+ */
423
+ $matches = array();
424
+ $regex = '/Failed to connect to ([^:].*): Network is unreachable/';
425
+ if ( preg_match( $regex, $result->get_error_message( 'http_request_failed' ), $matches ) ) {
426
+ /**
427
+ * Validate IP before calling `inet_pton()` to avoid PHP un-catchable warning.
428
+ * @author Vova Feldman (@svovaf)
429
+ */
430
+ if ( filter_var( $matches[1], FILTER_VALIDATE_IP ) ) {
431
+ if ( strlen( inet_pton( $matches[1] ) ) === 16 ) {
432
+ // error_log('Invalid IPv6 configuration on server, Please disable or get native IPv6 on your server.');
433
+ // Hook to an action triggered just before cURL is executed to resolve the IP version to v4.
434
+ add_action( 'http_api_curl', 'Freemius_Api_WordPress::CurlResolveToIPv4', 10, 1 );
435
+
436
+ // Re-run request.
437
+ $result = self::ExecuteRequest( $request_url, $pWPRemoteArgs );
438
+ }
439
+ }
440
+ }
441
+ }
442
+
443
+ if ( is_wp_error( $result ) ) {
444
+ self::ThrowWPRemoteException( $result );
445
+ }
446
+ }
447
+
448
+ $response_body = $result['body'];
449
+
450
+ if ( empty( $response_body ) ) {
451
+ return null;
452
+ }
453
+
454
+ $decoded = json_decode( $response_body );
455
+
456
+ if ( is_null( $decoded ) ) {
457
+ if ( preg_match( '/Please turn JavaScript on/i', $response_body ) &&
458
+ preg_match( '/text\/javascript/', $response_body )
459
+ ) {
460
+ self::ThrowCloudFlareDDoSException( $response_body );
461
+ } else if ( preg_match( '/Access control configuration prevents your request from being allowed at this time. Please contact your service provider if you feel this is incorrect./', $response_body ) &&
462
+ preg_match( '/squid/', $response_body )
463
+ ) {
464
+ self::ThrowSquidAclException( $response_body );
465
+ } else {
466
+ $decoded = (object) array(
467
+ 'error' => (object) array(
468
+ 'type' => 'Unknown',
469
+ 'message' => $response_body,
470
+ 'code' => 'unknown',
471
+ 'http' => 402
472
+ )
473
+ );
474
+ }
475
+ }
476
+
477
+ return $decoded;
478
+ }
479
+
480
+
481
+ /**
482
+ * Makes an HTTP request. This method can be overridden by subclasses if
483
+ * developers want to do fancier things or use something other than wp_remote_request()
484
+ * to make the request.
485
+ *
486
+ * @param string $pCanonizedPath The URL to make the request to
487
+ * @param string $pMethod HTTP method
488
+ * @param array $pParams The parameters to use for the POST body
489
+ * @param null|array $pWPRemoteArgs wp_remote_request options.
490
+ *
491
+ * @return object[]|object|null
492
+ *
493
+ * @throws Freemius_Exception
494
+ */
495
+ public function MakeRequest(
496
+ $pCanonizedPath,
497
+ $pMethod = 'GET',
498
+ $pParams = array(),
499
+ $pWPRemoteArgs = null
500
+ ) {
501
+ $resource = explode( '?', $pCanonizedPath );
502
+
503
+ // Only sign request if not ping.json connectivity test.
504
+ $sign_request = ( '/v1/ping.json' !== strtolower( substr( $resource[0], - strlen( '/v1/ping.json' ) ) ) );
505
+
506
+ return self::MakeStaticRequest(
507
+ $pCanonizedPath,
508
+ $pMethod,
509
+ $pParams,
510
+ $pWPRemoteArgs,
511
+ $this->_isSandbox,
512
+ $sign_request ? array( &$this, 'SignRequest' ) : null
513
+ );
514
+ }
515
+
516
+ /**
517
+ * Sets CURLOPT_IPRESOLVE to CURL_IPRESOLVE_V4 for cURL-Handle provided as parameter
518
+ *
519
+ * @param resource $handle A cURL handle returned by curl_init()
520
+ *
521
+ * @return resource $handle A cURL handle returned by curl_init() with CURLOPT_IPRESOLVE set to
522
+ * CURL_IPRESOLVE_V4
523
+ *
524
+ * @link https://gist.github.com/golderweb/3a2aaec2d56125cc004e
525
+ */
526
+ static function CurlResolveToIPv4( $handle ) {
527
+ curl_setopt( $handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
528
+
529
+ return $handle;
530
+ }
531
+
532
+ #----------------------------------------------------------------------------------
533
+ #region Connectivity Test
534
+ #----------------------------------------------------------------------------------
535
+
536
+ /**
537
+ * If successful connectivity to the API endpoint using ping.json endpoint.
538
+ *
539
+ * - OR -
540
+ *
541
+ * Validate if ping result object is valid.
542
+ *
543
+ * @param mixed $pPong
544
+ *
545
+ * @return bool
546
+ */
547
+ public static function Test( $pPong = null ) {
548
+ $pong = is_null( $pPong ) ?
549
+ self::Ping() :
550
+ $pPong;
551
+
552
+ return (
553
+ is_object( $pong ) &&
554
+ isset( $pong->api ) &&
555
+ 'pong' === $pong->api
556
+ );
557
+ }
558
+
559
+ /**
560
+ * Ping API to test connectivity.
561
+ *
562
+ * @return object
563
+ */
564
+ public static function Ping() {
565
+ try {
566
+ $result = self::MakeStaticRequest( '/v' . FS_API__VERSION . '/ping.json' );
567
+ } catch ( Freemius_Exception $e ) {
568
+ // Map to error object.
569
+ $result = (object) $e->getResult();
570
+ } catch ( Exception $e ) {
571
+ // Map to error object.
572
+ $result = (object) array(
573
+ 'error' => array(
574
+ 'type' => 'Unknown',
575
+ 'message' => $e->getMessage() . ' (' . $e->getFile() . ': ' . $e->getLine() . ')',
576
+ 'code' => 'unknown',
577
+ 'http' => 402
578
+ )
579
+ );
580
+ }
581
+
582
+ return $result;
583
+ }
584
+
585
+ #endregion
586
+
587
+ #----------------------------------------------------------------------------------
588
+ #region Connectivity Exceptions
589
+ #----------------------------------------------------------------------------------
590
+
591
+ /**
592
+ * @param \WP_Error $pError
593
+ *
594
+ * @return bool
595
+ */
596
+ private static function IsCurlError( WP_Error $pError ) {
597
+ $message = $pError->get_error_message( 'http_request_failed' );
598
+
599
+ return ( 0 === strpos( $message, 'cURL' ) );
600
+ }
601
+
602
+ /**
603
+ * @param WP_Error $pError
604
+ *
605
+ * @throws Freemius_Exception
606
+ */
607
+ private static function ThrowWPRemoteException( WP_Error $pError ) {
608
+ if ( self::IsCurlError( $pError ) ) {
609
+ $message = $pError->get_error_message( 'http_request_failed' );
610
+
611
+ #region Check if there are any missing cURL methods.
612
+
613
+ $curl_required_methods = array(
614
+ 'curl_version',
615
+ 'curl_exec',
616
+ 'curl_init',
617
+ 'curl_close',
618
+ 'curl_setopt',
619
+ 'curl_setopt_array',
620
+ 'curl_error',
621
+ );
622
+
623
+ // Find all missing methods.
624
+ $missing_methods = array();
625
+ foreach ( $curl_required_methods as $m ) {
626
+ if ( ! function_exists( $m ) ) {
627
+ $missing_methods[] = $m;
628
+ }
629
+ }
630
+
631
+ if ( ! empty( $missing_methods ) ) {
632
+ throw new Freemius_Exception( array(
633
+ 'error' => (object) array(
634
+ 'type' => 'cUrlMissing',
635
+ 'message' => $message,
636
+ 'code' => 'curl_missing',
637
+ 'http' => 402
638
+ ),
639
+ 'missing_methods' => $missing_methods,
640
+ ) );
641
+ }
642
+
643
+ #endregion
644
+
645
+ // cURL error - "cURL error {{errno}}: {{error}}".
646
+ $parts = explode( ':', substr( $message, strlen( 'cURL error ' ) ), 2 );
647
+
648
+ $code = ( 0 < count( $parts ) ) ? $parts[0] : 'http_request_failed';
649
+ $message = ( 1 < count( $parts ) ) ? $parts[1] : $message;
650
+
651
+ $e = new Freemius_Exception( array(
652
+ 'error' => array(
653
+ 'code' => $code,
654
+ 'message' => $message,
655
+ 'type' => 'CurlException',
656
+ ),
657
+ ) );
658
+ } else {
659
+ $e = new Freemius_Exception( array(
660
+ 'error' => array(
661
+ 'code' => $pError->get_error_code(),
662
+ 'message' => $pError->get_error_message(),
663
+ 'type' => 'WPRemoteException',
664
+ ),
665
+ ) );
666
+ }
667
+
668
+ throw $e;
669
+ }
670
+
671
+ /**
672
+ * @param string $pResult
673
+ *
674
+ * @throws Freemius_Exception
675
+ */
676
+ private static function ThrowCloudFlareDDoSException( $pResult = '' ) {
677
+ throw new Freemius_Exception( array(
678
+ 'error' => (object) array(
679
+ 'type' => 'CloudFlareDDoSProtection',
680
+ 'message' => $pResult,
681
+ 'code' => 'cloudflare_ddos_protection',
682
+ 'http' => 402
683
+ )
684
+ ) );
685
+ }
686
+
687
+ /**
688
+ * @param string $pResult
689
+ *
690
+ * @throws Freemius_Exception
691
+ */
692
+ private static function ThrowSquidAclException( $pResult = '' ) {
693
+ throw new Freemius_Exception( array(
694
+ 'error' => (object) array(
695
+ 'type' => 'SquidCacheBlock',
696
+ 'message' => $pResult,
697
+ 'code' => 'squid_cache_block',
698
+ 'http' => 402
699
+ )
700
+ ) );
701
+ }
702
+
703
+ #endregion
704
+ }
libs/factory/freemius/includes/sdk/LICENSE.txt ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 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
+
libs/factory/freemius/includes/sdk/index.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <?php
2
+ // Silence is golden.
3
+ // Hide file structure from users on unprotected servers.
libs/factory/freemius/includes/updates/class-freemius-repository.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WBCR\Factory_Freemius_112\Updates;
4
+
5
+ // Exit if accessed directly
6
+ use Exception;
7
+ use Wbcr_Factory424_Plugin;
8
+ use WBCR\Factory_424\Updates\Repository;
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
+ /**
15
+ * @author Webcraftic <wordpress.webraftic@gmail.com>, Alex Kovalev <alex.kovalevv@gmail.com>
16
+ * @link https://webcraftic.com
17
+ * @copyright (c) 2018 Webraftic Ltd
18
+ * @version 1.0
19
+ */
20
+ class Freemius_Repository extends Repository {
21
+
22
+ /**
23
+ * @var \WBCR\Factory_Freemius_112\Premium\Provider
24
+ */
25
+ private $premium;
26
+
27
+ /**
28
+ * Freemius constructor.
29
+ * @since 4.0.0
30
+ *
31
+ * @param Wbcr_Factory424_Plugin $plugin
32
+ *
33
+ * @throws Exception
34
+ */
35
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
36
+ $this->plugin = $plugin;
37
+ $this->premium = $this->plugin->premium;
38
+ }
39
+
40
+ /**
41
+ * @throws Exception
42
+ */
43
+ public function init() {
44
+ if ( ! $this->premium instanceof \WBCR\Factory_Freemius_112\Premium\Provider ) {
45
+ throw new Exception( "This repository type requires Freemius premium provider." );
46
+ }
47
+
48
+ if ( ! $this->premium->is_activate() ) {
49
+ throw new Exception( "Only premium plugins can check or receive updates via Freemius repository." );
50
+ }
51
+
52
+ $this->initialized = true;
53
+
54
+ add_filter( 'http_request_host_is_external', array(
55
+ $this,
56
+ 'http_request_host_is_external_filter'
57
+ ), 10, 3 );
58
+ }
59
+
60
+ /**
61
+ * @return bool
62
+ */
63
+ public function need_check_updates() {
64
+ return true;
65
+ }
66
+
67
+ /**
68
+ * @return bool|mixed
69
+ */
70
+ public function is_support_premium() {
71
+ return true;
72
+ }
73
+
74
+ /**
75
+ * @return string|null
76
+ * @throws Exception
77
+ */
78
+ public function get_download_url() {
79
+ return $this->premium->get_package_download_url();
80
+ }
81
+
82
+ /**
83
+ * @return string|null
84
+ * @throws Exception
85
+ */
86
+ public function get_last_version() {
87
+ try {
88
+ $last_package = $this->premium->get_downloadable_package_info();
89
+
90
+ if ( empty( $last_package->version ) ) {
91
+ return null;
92
+ }
93
+ } catch( Exception $e ) {
94
+ if ( defined( 'FACTORY_UPDATES_DEBUG' ) && FACTORY_UPDATES_DEBUG ) {
95
+ throw new Exception( $e->getMessage(), $e->getCode() );
96
+ }
97
+
98
+ return null;
99
+ }
100
+
101
+ return $last_package->version;
102
+ }
103
+
104
+ /**
105
+ * Since WP version 3.6, a new security feature was added that denies access to repository with a local ip.
106
+ * During development mode we want to be able updating plugin versions via our localhost repository. This
107
+ * filter white-list all domains including "api.freemius".
108
+ *
109
+ * @link http://www.emanueletessore.com/wordpress-download-failed-valid-url-provided/
110
+ *
111
+ * @author Vova Feldman (@svovaf)
112
+ * @since 1.0.4
113
+ *
114
+ * @param bool $allow
115
+ * @param string $host
116
+ * @param string $url
117
+ *
118
+ * @return bool
119
+ */
120
+ function http_request_host_is_external_filter( $allow, $host, $url ) {
121
+ return ( false !== strpos( $host, 'freemius' ) ) ? true : $allow;
122
+ }
123
+ }
libs/factory/freemius/includes/updates/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/freemius/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/pages/boot.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Factory Pages
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @since 1.0.1
7
+ * @package core
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ // module provides function only for the admin area
18
+ if ( ! is_admin() ) {
19
+ return;
20
+ }
21
+
22
+ if ( defined( 'FACTORY_PAGES_424_LOADED' ) ) {
23
+ return;
24
+ }
25
+
26
+ define( 'FACTORY_PAGES_424_LOADED', true );
27
+
28
+ define( 'FACTORY_PAGES_424_VERSION', '4.2.4' );
29
+
30
+ define( 'FACTORY_PAGES_424_DIR', dirname( __FILE__ ) );
31
+ define( 'FACTORY_PAGES_424_URL', plugins_url( null, __FILE__ ) );
32
+
33
+ if ( ! defined( 'FACTORY_FLAT_ADMIN' ) ) {
34
+ define( 'FACTORY_FLAT_ADMIN', true );
35
+ }
36
+
37
+ load_plugin_textdomain( 'wbcr_factory_pages_424', false, dirname( plugin_basename( __FILE__ ) ) . '/langs' );
38
+
39
+ require( FACTORY_PAGES_424_DIR . '/pages.php' );
40
+ require( FACTORY_PAGES_424_DIR . '/includes/page.class.php' );
41
+ require( FACTORY_PAGES_424_DIR . '/includes/admin-page.class.php' );
42
+ require( FACTORY_PAGES_424_DIR . '/templates/impressive-page.class.php' );
43
+
libs/factory/pages/includes/admin-page.class.php ADDED
@@ -0,0 +1,562 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Admin page class
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @since 1.0.0
7
+ * @package factory-core
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ if ( ! class_exists( 'Wbcr_FactoryPages424_AdminPage' ) ) {
18
+
19
+ class Wbcr_FactoryPages424_AdminPage extends Wbcr_FactoryPages424_Page {
20
+
21
+ /**
22
+ * Visible page title.
23
+ * For example: 'License Manager'
24
+ *
25
+ * @var string
26
+ */
27
+ public $page_title;
28
+
29
+ /**
30
+ * Visible title in menu.
31
+ * For example: 'License Manager'
32
+ *
33
+ * @var string
34
+ */
35
+ public $menu_title = null;
36
+
37
+ /**
38
+ * If set, an extra sub menu will be created with another title.
39
+ *
40
+ * @var string
41
+ */
42
+ public $menu_sub_title = null;
43
+
44
+ /**
45
+ * Иконка меню в главном меню админ панели
46
+ *
47
+ * Используется только в том случае, если ссылка на страницу отображается
48
+ * в главном меню админ панели (левый сайдбар) и не является элементом подменю.
49
+ *
50
+ * Пример: '~/assets/img/menu-icon.png', ~/ будет заменен ссылкой на корневую
51
+ * директорию плагина.
52
+ * Можно использовать dashicons: '\f321'
53
+ *
54
+ * @var string
55
+ */
56
+ public $menu_icon = null;
57
+
58
+ /**
59
+ * Позиция в главном меню админ панели
60
+ *
61
+ * Если эта страница была добавлена в главное меню админ панели (левый сайдбар).
62
+ * Вы можете установить позицию меню. Подробнее смотрите в Wordpress кодексе.
63
+ *
64
+ * @link http://codex.wordpress.org/Function_Reference/add_menu_page
65
+ *
66
+ * Позиция может быть установлена от 0 до 100 и чем больше цифра, тем ниже будет
67
+ * расположен пункт меню.
68
+ *
69
+ * Внимание! Если два пункта используют одинаковую цифру-позицию, один из пунктов
70
+ * меню может быть перезаписан и будет показан только один пункт из двух.
71
+ * Чтобы избежать конфликта, можно использовать десятичные значения, вместо целых
72
+ * чисел: 63.3 вместо 63. Используйте кавычки: "63.3".
73
+ *
74
+ * 2 Консоль
75
+ * 4 Разделитель
76
+ * 5 Посты
77
+ * 10 Медиа
78
+ * 15 Ссылки
79
+ * 20 Страницы
80
+ * 25 Комментарии
81
+ * 59 Разделитель
82
+ * 60 Внешний вид
83
+ * 65 Плагины
84
+ * 70 Пользователи
85
+ * 75 Инструменты
86
+ * 80 Настройки
87
+ * 99 Разделитель
88
+ *
89
+ * @var string
90
+ */
91
+ public $menu_position = null;
92
+
93
+ /**
94
+ * Тип записи к меню которой, нужно прикрепить ссылку на страницу
95
+ *
96
+ * К примеру, если вы установите тип записи "post". В меню "Записи" появится
97
+ * ссылка на эту страницу, как элемент подменю.
98
+ *
99
+ * Пример: 'post'
100
+ *
101
+ * @var string
102
+ */
103
+ public $menu_post_type = null;
104
+
105
+ /**
106
+ * Название (slug) элемента главного родительского меню в админ панели, в которое будет
107
+ * добавлен пункт меню этой страницы, как элемент подменю.
108
+ *
109
+ * Примеры:
110
+ * index.php - Консоль (Dashboard). Или спец. функция: add_dashboard_page();
111
+ * edit.php - Посты (Posts). Или спец. функция: add_posts_page();
112
+ * upload.php - Медиафайлы (Media). Или спец. функция: add_media_page();
113
+ * link-manager.php - Ссылки (Links). Или спец. функция: add_links_page();
114
+ * edit.php?post_type=page - Страницы (Pages). Или спец. функция: add_pages_page();
115
+ * edit-comments.php - Комментарии (Comments). Или спец. функция: add_comments_page();
116
+ * edit.php?post_type=your_post_type - Произвольные типы записей.
117
+ * themes.php - Внешний вид (Appearance). Или спец. функция: add_theme_page();
118
+ * plugins.php - Плагины (Plugins). Или спец. функция: add_plugins_page();
119
+ * users.php - Пользователи (Users). Или спец. функция: add_users_page();
120
+ * tools.php - Инструменты (Tools). Или спец. функция: add_management_page();
121
+ * options-general.php - Настройки (Settings). Или спец. функция: add_options_page()
122
+ * settings.php - Настройки (Settings) сети сайтов в MU режиме.
123
+ *
124
+ * @var string
125
+ */
126
+ public $menu_target = null;
127
+
128
+ /**
129
+ * if true, then admin.php is used as a base url.
130
+ *
131
+ * @var bool
132
+ */
133
+ public $custom_target = false;
134
+
135
+ /**
136
+ * Разрешения пользователя, чтобы иметь доступ к странице.
137
+ *
138
+ * Этот параметр отвечает и за доступ к странице этого пункта меню. Подробнее
139
+ * смотрите в кодексе Wordpress:
140
+ *
141
+ * @link http://codex.wordpress.org/Roles_and_Capabilities
142
+ *
143
+ * Указывать массив разрешений, например:
144
+ * ['manage_options', 'manage_network']
145
+ *
146
+ * @var array
147
+ */
148
+ public $capabilitiy = null;
149
+
150
+ /**
151
+ * Скрыть страницу из главного меню админ панели?
152
+ *
153
+ * Если true, то закладка на эту страницу не будет добавлена в главное меню
154
+ * админ панели.
155
+ *
156
+ * @var bool
157
+ */
158
+ public $internal = false;
159
+
160
+ /**
161
+ * If true, the page is for network
162
+ *
163
+ * @var bool
164
+ */
165
+ public $network = false;
166
+
167
+ /**
168
+ * Предотвратить создание страницы?
169
+ *
170
+ * Если true, то страница не будет создана. Может пригодиться в тех случаях,
171
+ * когда страница должна быть создана только при выполнении условий.
172
+ *
173
+ * @since 3.0.6
174
+ * @var bool
175
+ */
176
+ public $hidden = false;
177
+
178
+ /**
179
+ * Сделать доступной страницу в панели управлениям сайтами (панель суперадминистратора)
180
+ *
181
+ * Если установлено true, в панели управления сайтами появится закладка на эту страницу.
182
+ * Также эта страница получить разрешения на просмотр для группы суперадминистраторов.
183
+ *
184
+ * @var bool
185
+ */
186
+ public $available_for_multisite = false;
187
+
188
+ /**
189
+ * Задать текст ссылки на странице плагинов (рядом с активировать/деактивировать)
190
+ *
191
+ * Будет работать только, свойство $add_link_to_plugin_actions=true.
192
+ * По умолчанию, если текст ссылки не задан, используется заголовок элемента меню
193
+ * или заголовок страницы.
194
+ *
195
+ * @var string
196
+ */
197
+ public $title_plugin_action_link;
198
+
199
+ /**
200
+ * Добавлять ссылку на странице плагинов (рядом с активировать/деактивировать)?
201
+ *
202
+ * Если true, будет автоматически добавлена ссылка на эту страницу, внутри страницы
203
+ * wp-admin/plugins.php (рядом с активировать/деактивировать). Чаще всего требуется
204
+ * добавить ссылку на страницу настроек. Если эта страница у вас является главной,
205
+ * то вы можете сделать это свойство активным.
206
+ *
207
+ * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/plugin_action_links_(plugin_file_name)
208
+ * @var bool
209
+ */
210
+ public $add_link_to_plugin_actions = false;
211
+
212
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
213
+ parent::__construct( $plugin );
214
+ $this->configure();
215
+
216
+ $this->id = empty( $this->id ) ? str_replace( 'adminpage', '', strtolower( get_class( $this ) ) ) : $this->id;
217
+
218
+ if ( $this->add_link_to_plugin_actions ) {
219
+ if ( $plugin->isNetworkActive() ) {
220
+ // plugin settings link
221
+ add_filter( "network_admin_plugin_action_links_" . $this->plugin->get_paths()->basename, [
222
+ $this,
223
+ 'addLinkToPluginActions'
224
+ ] );
225
+ } else {
226
+ // plugin settings link
227
+ add_filter( "plugin_action_links_" . $this->plugin->get_paths()->basename, [
228
+ $this,
229
+ 'addLinkToPluginActions'
230
+ ] );
231
+ }
232
+ }
233
+ }
234
+
235
+ /**
236
+ * May be used to configure the page before uts usage.
237
+ */
238
+ public function configure() {
239
+ }
240
+
241
+ /**
242
+ * Includes the Factory Bootstrap assets for a current page.
243
+ *
244
+ * @param string $hook
245
+ *
246
+ * @return void
247
+ */
248
+ public function actionAdminBootstrapScripts( $hook ) {
249
+ $this->scripts->connect( 'bootstrap' );
250
+ $this->styles->connect( 'bootstrap' );
251
+ }
252
+
253
+ /**
254
+ * Includes the assets for a current page (all assets except Factory Bootstrap assets).
255
+ *
256
+ * @param string $hook
257
+ *
258
+ * @return void
259
+ */
260
+ public function actionAdminScripts( $hook ) {
261
+ $this->scripts->connect();
262
+ $this->styles->connect();
263
+ }
264
+
265
+ /**
266
+ * @return string
267
+ */
268
+ public function getMenuScope() {
269
+ return $this->plugin->getPluginName();
270
+ }
271
+
272
+
273
+ /**
274
+ * @return string
275
+ */
276
+ public function getMenuTitle() {
277
+ $menu_title = ! $this->menu_title ? $this->page_title : $this->menu_title;
278
+
279
+ /**
280
+ * @since 4.0.9 - добавлен
281
+ */
282
+ return apply_filters( 'wbcr/factory/pages/impressive/menu_title', $menu_title, $this->plugin->getPluginName(), $this->id );
283
+ }
284
+
285
+ /**
286
+ * @return string
287
+ */
288
+ public function getPageTitle() {
289
+
290
+ $page_title = ! $this->page_title ? $this->getMenuTitle() : $this->page_title;
291
+
292
+ /**
293
+ * @since 4.0.9 - добавлен
294
+ */
295
+ return apply_filters( 'wbcr/factory/pages/impressive/page_title', $page_title, $this->plugin->getPluginName(), $this->id );
296
+ }
297
+
298
+ /**
299
+ * @param null $id
300
+ *
301
+ * @return mixed|string
302
+ */
303
+ public function getResultId( $id = null ) {
304
+ $id = ! empty( $id ) ? $id : $this->id;
305
+
306
+ if ( $this->plugin ) {
307
+ return $id . '-' . $this->getMenuScope();
308
+ }
309
+
310
+ return $id;
311
+ }
312
+
313
+ /**
314
+ * Registers admin page for the admin menu.
315
+ */
316
+ public function connect() {
317
+ $result_id = $this->getResultId();
318
+
319
+ $this->hidden = apply_filters( 'wbcr_factory_424_page_is_hidden_' . $result_id, $this->hidden );
320
+
321
+ if ( $this->hidden ) {
322
+ return;
323
+ }
324
+
325
+ $this->internal = apply_filters( 'wbcr_factory_424_page_is_internal_' . $result_id, $this->internal );
326
+
327
+ if ( $this->internal ) {
328
+ $this->menu_target = null;
329
+ $this->menu_post_type = null;
330
+ }
331
+
332
+ // makes redirect to the page
333
+ $controller = $this->request->get( 'fy_page', null, true );
334
+
335
+ if ( $controller && $controller == $this->id ) {
336
+ $plugin = $this->request->get( 'fy_plugin', null, true );
337
+
338
+ if ( $this->plugin->getPluginName() == $plugin ) {
339
+
340
+ $action = $this->request->get( 'fy_action', 'index', true );
341
+ $is_ajax = $this->request->get( 'fy_ajax', false );
342
+
343
+ if ( $is_ajax ) {
344
+ $this->executeByName( $action );
345
+ exit;
346
+ } else {
347
+
348
+ $params = (array) $this->request->getAll( true );
349
+
350
+ unset( $params['fy_page'] );
351
+ unset( $params['fy_plugin'] );
352
+ unset( $params['fy_action'] );
353
+
354
+ $this->redirectToAction( $action, $params );
355
+ }
356
+ }
357
+ }
358
+
359
+ // calls scripts and styles, adds pages to menu
360
+ if ( $this->request->get( 'page', 'none' ) == $result_id ) {
361
+ $this->assets( $this->scripts, $this->styles );
362
+
363
+ if ( ! $this->scripts->isEmpty( 'bootstrap' ) || ! $this->styles->isEmpty( 'bootstrap' ) ) {
364
+ add_action( 'wbcr_factory_424_bootstrap_enqueue_scripts_' . $this->plugin->getPluginName(), [
365
+ $this,
366
+ 'actionAdminBootstrapScripts'
367
+ ] );
368
+ }
369
+
370
+ // includes styles and scripts
371
+ if ( ! $this->scripts->isEmpty() || ! $this->styles->isEmpty() ) {
372
+ add_action( 'admin_enqueue_scripts', [ $this, 'actionAdminScripts' ] );
373
+ }
374
+ }
375
+
376
+ // if this page for a custom menu page
377
+ if ( $this->menu_post_type ) {
378
+ $this->menu_target = 'edit.php?post_type=' . $this->menu_post_type;
379
+
380
+ if ( empty( $this->capabilitiy ) ) {
381
+ $this->capabilitiy = 'edit_' . $this->menu_post_type;
382
+ }
383
+ }
384
+
385
+ // sets default capabilities
386
+ if ( empty( $this->capabilitiy ) ) {
387
+ $this->capabilitiy = 'manage_options';
388
+ }
389
+
390
+ // submenu
391
+ if ( $this->menu_target ) {
392
+ add_submenu_page( $this->menu_target, $this->getPageTitle(), $this->getMenuTitle(), $this->capabilitiy, $result_id, [
393
+ $this,
394
+ 'show'
395
+ ] );
396
+ // global menu
397
+ } else {
398
+ add_menu_page( $this->getPageTitle(), $this->getMenuTitle(), $this->capabilitiy, $result_id, [
399
+ $this,
400
+ 'show'
401
+ ], null, $this->menu_position );
402
+
403
+ if ( ! empty( $this->menu_sub_title ) ) {
404
+
405
+ add_submenu_page( $result_id, $this->menu_sub_title, $this->menu_sub_title, $this->capabilitiy, $result_id, [
406
+ $this,
407
+ 'show'
408
+ ] );
409
+ }
410
+
411
+ add_action( 'admin_head', [ $this, 'actionAdminHead' ] );
412
+ }
413
+
414
+ // executes an action
415
+ if ( $this->current() ) {
416
+ ob_start();
417
+ $action = $this->request->get( 'action', 'index', true );
418
+ $this->executeByName( $action );
419
+ $this->result = ob_get_contents();
420
+ ob_end_clean();
421
+ }
422
+ }
423
+
424
+ protected function current() {
425
+ $result_id = $this->getResultId();
426
+
427
+ if ( $result_id == $this->request->get( 'page', 'none' ) ) {
428
+ return true;
429
+ }
430
+
431
+ return false;
432
+ }
433
+
434
+ /**
435
+ * @param string $action
436
+ * @param array $query_args
437
+ */
438
+ public function redirectToAction( $action, $query_args = [] ) {
439
+
440
+ wp_safe_redirect( $this->getActionUrl( $action, $query_args ) );
441
+ exit;
442
+ }
443
+
444
+ /**
445
+ * @param string $action
446
+ * @param array $query_args
447
+ */
448
+ public function actionUrl( $action = null, $query_args = [] ) {
449
+ echo $this->getActionUrl( $action, $query_args );
450
+ }
451
+
452
+ /**
453
+ * @param null $action
454
+ * @param array $query_args
455
+ *
456
+ * @return string
457
+ */
458
+ public function getActionUrl( $action = null, $query_args = [] ) {
459
+ $url = $this->getBaseUrl( null, $query_args );
460
+
461
+ if ( ! empty( $action ) ) {
462
+ $url = add_query_arg( 'action', $action, $url );
463
+ }
464
+
465
+ return $url;
466
+ }
467
+
468
+ /**
469
+ * @return string
470
+ */
471
+ public function getBaseUrl( $id = null, $query_args = [] ) {
472
+ $result_id = $this->getResultId( $id );
473
+
474
+ if ( $this->menu_target ) {
475
+ $url = $this->network ? network_admin_url( $this->menu_target ) : admin_url( $this->menu_target );
476
+
477
+ return add_query_arg( array_merge( [ 'page' => $result_id ], $query_args ), $url );
478
+ } else {
479
+ $url = $this->network ? network_admin_url( 'admin.php' ) : admin_url( 'admin.php' );
480
+
481
+ return add_query_arg( array_merge( [ 'page' => $result_id, $query_args ] ), $url );
482
+ }
483
+ }
484
+
485
+ public function actionAdminHead() {
486
+ $result_id = $this->getResultId();
487
+
488
+ if ( ! empty( $this->menu_icon ) ) {
489
+
490
+ if ( preg_match( '/\\\f\d{3}/', $this->menu_icon ) ) {
491
+ $icon_code = $this->menu_icon;
492
+ } else {
493
+ $icon_url = str_replace( '~/', $this->plugin->get_paths()->url . '/', $this->menu_icon );
494
+ }
495
+ }
496
+
497
+ global $wp_version;
498
+
499
+ if ( version_compare( $wp_version, '3.7.3', '>' ) ) {
500
+ ?>
501
+ <style type="text/css" media="screen">
502
+ <?php if ( !empty($icon_url) ) { ?>
503
+
504
+ a.toplevel_page_<?php echo $result_id ?> .wp-menu-image {
505
+ background: url('<?php echo $icon_url ?>') no-repeat 10px -30px !important;
506
+ }
507
+
508
+ <?php } ?>
509
+
510
+ a.toplevel_page_<?php echo $result_id ?> .wp-menu-image:before {
511
+ content: "<?php echo !empty($icon_code) ? $icon_code : ''; ?>" !important;
512
+ }
513
+
514
+ a.toplevel_page_<?php echo $result_id ?>:hover .wp-menu-image,
515
+ a.toplevel_page_<?php echo $result_id ?>.wp-has-current-submenu .wp-menu-image,
516
+ a.toplevel_page_<?php echo $result_id ?>.current .wp-menu-image {
517
+ background-position: 10px 2px !important;
518
+ }
519
+ </style>
520
+ <?php } else { ?>
521
+ <style type="text/css" media="screen">
522
+ a.toplevel_page_<?php echo $result_id ?> .wp-menu-image {
523
+ background: url('<?php echo $icon_url ?>') no-repeat 6px -33px !important;
524
+ }
525
+
526
+ a.toplevel_page_<?php echo $result_id ?>:hover .wp-menu-image,
527
+ a.toplevel_page_<?php echo $result_id ?>.current .wp-menu-image {
528
+ background-position: 6px -1px !important;
529
+ }
530
+ </style>
531
+ <?php
532
+ }
533
+
534
+ if ( $this->internal ) {
535
+ ?>
536
+ <style type="text/css" media="screen">
537
+ li.toplevel_page_<?php echo $result_id ?> {
538
+ display: none;
539
+ }
540
+ </style>
541
+ <?php
542
+ }
543
+ }
544
+
545
+
546
+ /**
547
+ * Add settings link in plugins list
548
+ *
549
+ * @param $links
550
+ *
551
+ * @return mixed
552
+ */
553
+ function addLinkToPluginActions( $links ) {
554
+ $link_title = ! empty( $this->title_plugin_action_link ) ? $this->title_plugin_action_link : $this->getMenuTitle();
555
+
556
+ $settings_link = '<a href="' . $this->getBaseUrl() . '">' . $link_title . '</a>';
557
+ array_unshift( $links, $settings_link );
558
+
559
+ return $links;
560
+ }
561
+ }
562
+ }
libs/factory/pages/includes/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/pages/includes/page.class.php ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Admin page class
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @since 1.0.0
7
+ * @package factory-core
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ if ( ! class_exists( 'Wbcr_FactoryPages424_Page' ) ) {
18
+
19
+ class Wbcr_FactoryPages424_Page {
20
+
21
+
22
+ /**
23
+ * Уникальный ID страницы
24
+ *
25
+ * ID страницы используется для формирования ссылки на страницу.
26
+ *
27
+ * Ссылки выглядят примерно так:
28
+ * http://clearfy-test.loc/wp-admin/admin.php?page=components-wbcr_clearfy
29
+ *
30
+ * Чтобы не было конфликтов с другими плагинами, используйте префиксы.
31
+ *
32
+ * @since 1.0.0
33
+ * @see FactoryPages424_AdminPage
34
+ *
35
+ * @var string
36
+ */
37
+ public $id;
38
+
39
+ /**
40
+ * Current Factory Plugin.
41
+ *
42
+ * @var Wbcr_Factory424_Plugin
43
+ */
44
+ public $plugin;
45
+
46
+ /**
47
+ * @var string
48
+ */
49
+ public $result;
50
+
51
+ //private $default_actions = array();
52
+
53
+ /**
54
+ * @param Wbcr_Factory424_Plugin $plugin
55
+ *
56
+ * @throws Exception
57
+ */
58
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
59
+ $this->plugin = $plugin;
60
+
61
+ if ( $plugin ) {
62
+ $this->scripts = $this->plugin->newScriptList();
63
+ $this->styles = $this->plugin->newStyleList();
64
+ $this->request = $plugin->request;
65
+ }
66
+ }
67
+
68
+ /*public function __call($name, $arguments) {
69
+
70
+
71
+ if(!empty($custom_action)) {
72
+
73
+ }
74
+
75
+ }*/
76
+
77
+ public function assets( $scripts, $styles ) {
78
+ }
79
+
80
+ /**
81
+ * Shows page.
82
+ */
83
+ public function show() {
84
+
85
+ if ( $this->result ) {
86
+ echo $this->result;
87
+ } else {
88
+ $action = isset( $_GET['action'] ) ? $_GET['action'] : 'index';
89
+ $this->executeByName( $action );
90
+ }
91
+ }
92
+
93
+ /**
94
+ * @param string $action
95
+ *
96
+ * @throws Exception
97
+ */
98
+ public function executeByName( $action ) {
99
+ $raw_action_name = $action;
100
+
101
+ if ( preg_match( '/[-_]+/', $action ) ) {
102
+ $action = $this->dashesToCamelCase( $action, false );
103
+ }
104
+ $actionFunction = $action . 'Action';
105
+
106
+ $cancel = $this->OnActionExecuting( $action );
107
+
108
+ if ( $cancel === false ) {
109
+ return;
110
+ }
111
+
112
+ if ( ! method_exists( $this, $actionFunction ) ) {
113
+ // todo: продумать и доработать выполнение произвольных и глобальных дейтсвия для всех страниц
114
+ /*$custom_actions = apply_filters('wbcr/factory_pages_424/custom_actions', array(), $raw_action_name);
115
+
116
+ if(isset($custom_actions[$raw_action_name])) {
117
+ $custom_actions[$raw_action_name]();
118
+ $this->OnActionExected($action);
119
+ return;
120
+ } else {*/
121
+ $actionFunction = 'indexAction';
122
+ //}
123
+ }
124
+
125
+ call_user_func_array( [ $this, $actionFunction ], [] );
126
+ $this->OnActionExected( $action );
127
+ }
128
+
129
+ /**
130
+ * @param string $string
131
+ * @param bool $capitalizeFirstCharacter
132
+ *
133
+ * @return mixed
134
+ * @throws Exception
135
+ */
136
+ protected function dashesToCamelCase( $string, $capitalizeFirstCharacter = false ) {
137
+ $str = str_replace( ' ', '', ucwords( preg_replace( '/[-_]/', ' ', $string ) ) );
138
+
139
+ if ( ! $capitalizeFirstCharacter ) {
140
+ $str[0] = strtolower( $str[0] );
141
+ }
142
+
143
+ if ( empty( $str ) ) {
144
+ throw new Exception( 'Dashed to camelcase parse error.' );
145
+ }
146
+
147
+ return $str;
148
+ }
149
+
150
+ /**
151
+ * @param $action
152
+ *
153
+ * @return bool
154
+ */
155
+ protected function OnActionExecuting( $action ) {
156
+ }
157
+
158
+ protected function OnActionExected( $action ) {
159
+ }
160
+
161
+ /**
162
+ * @param $path
163
+ */
164
+ protected function script( $path ) {
165
+ wp_enqueue_script( $path, $path, [ 'jquery' ], false, true );
166
+ }
167
+ }
168
+ }
libs/factory/pages/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
libs/factory/pages/langs/wbcr_factory_pages_424-fr_FR.mo ADDED
Binary file
libs/factory/pages/langs/wbcr_factory_pages_424-fr_FR.po ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: clearfy\n"
4
+ "POT-Creation-Date: 2017-11-09 10:33+0300\n"
5
+ "PO-Revision-Date: 2017-11-09 19:04+0300\n"
6
+ "Last-Translator: alex.kovalevv@gmail.com <alex.kovalevv@gmail.com>\n"
7
+ "Language-Team: Alex Kovalev <alex.kovalevv@gmail.com>\n"
8
+ "Language: fr\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 1.8.8\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
15
+ "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
16
+ "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c\n"
18
+ "X-Poedit-SearchPath-0: .\n"
19
+
20
+ #: templates/impressive-page.class.php:45
21
+ msgid "Settings"
22
+ msgstr "Paramètres"
23
+
24
+ #: templates/impressive-page.class.php:170
25
+ msgid ""
26
+ "It seems that a caching/performance plugin is active on this site. Please "
27
+ "manually invalidate that plugin's cache after making any changes to the "
28
+ "settings below."
29
+ msgstr ""
30
+ "Il semble qu'un plugin cache / performance soit actif sur ce site. Veuillez "
31
+ "invalider manuellement le cache de ce plugin après avoir apporté des "
32
+ "modifications aux paramètres ci-dessous."
33
+
34
+ #: templates/impressive-page.class.php:187
35
+ msgid "The settings have been updated successfully!"
36
+ msgstr "Les paramètres ont été mis à jour avec succès!"
37
+
38
+ #: templates/impressive-page.class.php:251
39
+ msgid "Page"
40
+ msgstr "Page"
41
+
42
+ #: templates/impressive-page.class.php:256
43
+ msgid "Save settings"
44
+ msgstr "Enregistrer les paramètres"
45
+
46
+ #: templates/impressive-page.class.php:328
47
+ msgid "You do not have permission to edit page."
48
+ msgstr "Vous n'êtes pas autorisé à modifier la page."
49
+
50
+ #: templates/impressive-page.class.php:403
51
+ msgid ""
52
+ "A neutral setting that can not harm your site, but you must be sure that you "
53
+ "need to use it."
54
+ msgstr ""
55
+ "Un paramètre neutre qui ne peut pas nuire à votre site, mais vous devez être "
56
+ "sûr que vous devez l'utiliser."
57
+
58
+ #: templates/impressive-page.class.php:407
59
+ msgid ""
60
+ "When set this option, you must be careful. Plugins and themes may depend on "
61
+ "this function. You must be sure that you can disable this feature for the "
62
+ "site."
63
+ msgstr ""
64
+ "Lorsque vous définissez cette option, vous devez faire attention. Les "
65
+ "plugins et les thèmes peuvent dépendre de cette fonction. Vous devez être "
66
+ "sûr que vous pouvez désactiver cette fonctionnalité pour le site."
67
+
68
+ #: templates/impressive-page.class.php:411
69
+ msgid "Absolutely safe setting, We recommend to use."
70
+ msgstr "Réglage absolument sûr, nous recommandons d'utiliser."
71
+
72
+ #: templates/impressive-page.class.php:416
73
+ msgid "Hover to the icon to get help for the feature you selected."
74
+ msgstr "Passez à l'icône pour obtenir de l'aide sur la fonction sélectionnée."
75
+
76
+ #: templates/impressive-page.class.php:432
77
+ msgid "Do you want the plugin to improved and update?"
78
+ msgstr "Voulez-vous que le plugin pour améliorer et mettre à jour?"
79
+
80
+ #: templates/impressive-page.class.php:435
81
+ msgid ""
82
+ "Help the author, leave a review on wordpress.org. Thanks to feedback, I will "
83
+ "know that the plugin is really useful to you and is needed."
84
+ msgstr ""
85
+ "Aidez l'auteur, laissez un commentaire sur wordpress.org. Grâce aux retours, "
86
+ "je saurai que le plugin est vraiment utile et nécessaire."
87
+
88
+ #: templates/impressive-page.class.php:437
89
+ msgid "And also write your ideas on how to extend or improve the plugin."
90
+ msgstr ""
91
+ "Et écrivez aussi vos idées sur la façon d'étendre ou d'améliorer le plugin."
92
+
93
+ #: templates/impressive-page.class.php:442
94
+ msgid "Go rate us and push ideas"
95
+ msgstr "Allez nous évaluer et pousser des idées"
96
+
97
+ #: templates/impressive-page.class.php:454
98
+ msgid "Donation for plug-in development"
99
+ msgstr "Don pour le développement du plug-in"
libs/factory/pages/langs/wbcr_factory_pages_424-ru_RU.mo ADDED
Binary file
libs/factory/pages/langs/wbcr_factory_pages_424-ru_RU.po ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: clearfy\n"
4
+ "POT-Creation-Date: 2018-10-16 22:44+0300\n"
5
+ "PO-Revision-Date: 2018-10-16 22:44+0300\n"
6
+ "Last-Translator: alex.kovalevv@gmail.com <alex.kovalevv@gmail.com>\n"
7
+ "Language-Team: Alex Kovalev <alex.kovalevv@gmail.com>\n"
8
+ "Language: ru_RU\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 2.1.1\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
15
+ "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
16
+ "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c\n"
18
+ "X-Poedit-SearchPath-0: .\n"
19
+
20
+ #: templates/impressive-page.class.php:128
21
+ msgid "Settings"
22
+ msgstr "Настройки"
23
+
24
+ #: templates/impressive-page.class.php:484
25
+ msgid "The settings have been updated successfully!"
26
+ msgstr "Настройки были успешно обновлены!"
27
+
28
+ #: templates/impressive-page.class.php:484
29
+ msgid ""
30
+ "It seems that a caching/performance plugin is active on this site. Please "
31
+ "manually invalidate that plugin's cache after making any changes to the "
32
+ "settings below."
33
+ msgstr ""
34
+ "Похоже, что Вы используете плагин кэширования или ускорения блога. Не "
35
+ "забудьте после изменения любых настроек, очистить кэш вручную!"
36
+
37
+ #: templates/impressive-page.class.php:659
38
+ msgid "Page"
39
+ msgstr "Страница"
40
+
41
+ #: templates/impressive-page.class.php:665
42
+ msgid "Clearfy settings"
43
+ msgstr "Настройки Clearfy"
44
+
45
+ #: templates/impressive-page.class.php:668
46
+ msgid "Save"
47
+ msgstr "Сохранить"
48
+
49
+ #: templates/impressive-page.class.php:783
50
+ msgid "You do not have permission to edit page."
51
+ msgstr "У вас недостаточно прав, для редактирования этой страницы."
52
+
53
+ #~ msgid "Save settings"
54
+ #~ msgstr "Сохранить настройки"
55
+
56
+ #~ msgid ""
57
+ #~ "A neutral setting that can not harm your site, but you must be sure that "
58
+ #~ "you need to use it."
59
+ #~ msgstr ""
60
+ #~ "Нейтральная настройка, которая не может нанести вред вашему сайту, но вы "
61
+ #~ "должны быть уверены, что вам нужно ее использовать."
62
+
63
+ #~ msgid ""
64
+ #~ "When set this option, you must be careful. Plugins and themes may depend "
65
+ #~ "on this function. You must be sure that you can disable this feature for "
66
+ #~ "the site."
67
+ #~ msgstr ""
68
+ #~ "При включении этой настройки, вы должны быть осторожны. Некоторые плагины "
69
+ #~ "и темы могут зависеть от этой функции. Вы должны быть уверены, что эту "
70
+ #~ "функцию можно отключить для сайта."
71
+
72
+ #~ msgid "Absolutely safe setting, We recommend to use."
73
+ #~ msgstr "Абсолютно безопасная настройка, рекомендуем использовать."
74
+
75
+ #~ msgid "Hover to the icon to get help for the feature you selected."
76
+ #~ msgstr ""
77
+ #~ "Наведите указатель мыши на значок, чтобы получить справку по выбранной "
78
+ #~ "функции."
79
+
80
+ #~ msgid "Do you want the plugin to improved and update?"
81
+ #~ msgstr "Вы хотите, чтобы плагин улучшался и обновлялся?"
82
+
83
+ #~ msgid ""
84
+ #~ "Help the author, leave a review on wordpress.org. Thanks to feedback, I "
85
+ #~ "will know that the plugin is really useful to you and is needed."
86
+ #~ msgstr ""
87
+ #~ "Помогите автору, оставьте отзыв на wordpress.org. Благодаря отзывам, я "
88
+ #~ "буду знать, что плагин действительно полезен для вас и необходим."
89
+
90
+ #~ msgid "And also write your ideas on how to extend or improve the plugin."
91
+ #~ msgstr ""
92
+ #~ "А также напишите свои идеи о том, как расширить или улучшить плагин."
93
+
94
+ #~ msgid "Go rate us and push ideas"
95
+ #~ msgstr "Оставить отзыв или поделиться идеей"
96
+
97
+ #~ msgid "Donation for plug-in development"
98
+ #~ msgstr "Пожертвования на развитие плагина"
libs/factory/pages/pages.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * A group of classes and methods to create and manage pages.
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @copyright (c) 2018, Webcraftic Ltd
7
+ *
8
+ * @package core
9
+ * @since 1.0.0
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if( !defined('ABSPATH') ) {
14
+ exit;
15
+ }
16
+
17
+ add_action('admin_menu', 'Wbcr_FactoryPages424::actionAdminMenu');
18
+ add_action('network_admin_menu', 'Wbcr_FactoryPages424::actionAdminMenu');
19
+
20
+ if( !class_exists('Wbcr_FactoryPages424') ) {
21
+ /**
22
+ * A base class to manage pages.
23
+ *
24
+ * @since 1.0.0
25
+ */
26
+ class Wbcr_FactoryPages424 {
27
+
28
+ /**
29
+ * @var Wbcr_FactoryPages424_Page[]
30
+ */
31
+ private static $pages = array();
32
+
33
+ /**
34
+ * @param Wbcr_Factory424_Plugin $plugin
35
+ * @param $class_name
36
+ */
37
+ public static function register($plugin, $class_name)
38
+ {
39
+ if( !isset(self::$pages[$plugin->getPluginName()]) ) {
40
+ self::$pages[$plugin->getPluginName()] = array();
41
+ }
42
+ $page = new $class_name($plugin);
43
+ if( is_multisite() && is_network_admin() && !$page->available_for_multisite ) {
44
+ return;
45
+ }
46
+ self::$pages[$plugin->getPluginName()][] = $page;
47
+ }
48
+
49
+ public static function actionAdminMenu()
50
+ {
51
+ if( empty(self::$pages) ) {
52
+ return;
53
+ }
54
+
55
+ foreach(self::$pages as $plugin_pages) {
56
+ foreach($plugin_pages as $page) {
57
+ $page->connect();
58
+ }
59
+ }
60
+ }
61
+
62
+ public static function getPageUrl(Wbcr_Factory424_Plugin $plugin, $page_id, $args = array())
63
+ {
64
+ if( isset(self::$pages[$plugin->getPluginName()]) ) {
65
+ $pages = self::$pages[$plugin->getPluginName()];
66
+
67
+ foreach($pages as $page) {
68
+ if( $page->id == $page_id ) {
69
+ return $page->getBaseUrl($page_id, $args);
70
+ }
71
+ }
72
+ } else {
73
+ _doing_it_wrong(__METHOD__, __('You are trying to call this earlier than the plugin menu will be registered.'), '4.0.8');
74
+ }
75
+ }
76
+
77
+ /**
78
+ * @param Wbcr_Factory424_Plugin $plugin
79
+ * @return array
80
+ */
81
+ public static function getIds($plugin)
82
+ {
83
+ if( !isset(self::$pages[$plugin->getPluginName()]) ) {
84
+ return array();
85
+ }
86
+
87
+ $result = array();
88
+ foreach(self::$pages[$plugin->getPluginName()] as $page)
89
+ $result[] = $page->getResultId();
90
+
91
+ return $result;
92
+ }
93
+ }
94
+ }
95
+
96
+ if( !function_exists('wbcr_factory_pages_424_get_page_id') ) {
97
+ /**
98
+ *
99
+ * @param Wbcr_Factory424_Plugin $plugin
100
+ * @param string $page_id
101
+ * @return string
102
+ */
103
+ function wbcr_factory_pages_424_get_page_id($plugin, $page_id)
104
+ {
105
+ return $page_id . '-' . $plugin->getPluginName();
106
+ }
107
+ }
libs/factory/pages/templates/assets/css/impressive.page.template.css ADDED
@@ -0,0 +1,508 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * General styles
3
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
4
+ * @copyright Alex Kovalev 23.08.2017
5
+ */
6
+ #WBCR .updated,
7
+ #WBCR .notice,
8
+ #WBCR .error {
9
+ display: none !important;
10
+ }
11
+ #WBCR .wbcr-factory-pages-424-impressive-page-template {
12
+ position: relative;
13
+ /**
14
+ Content sections
15
+ */
16
+ /**
17
+ Widget in the sidebar of the plugin
18
+ */
19
+ }
20
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-color-grey {
21
+ color: #9a9a9a;
22
+ }
23
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-orange-color {
24
+ color: #ffc107;
25
+ }
26
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-light-orange-color {
27
+ color: #ffeb3b;
28
+ }
29
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .form-group {
30
+ padding: 0 20px;
31
+ }
32
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .form-group label {
33
+ font-weight: normal;
34
+ }
35
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .form-horizontal .control-label {
36
+ max-width: 300px;
37
+ }
38
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .factory-control-buttons {
39
+ text-align: right;
40
+ padding-right: 20px;
41
+ }
42
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .factory-from-control-list label span {
43
+ display: inline-block;
44
+ vertical-align: bottom;
45
+ }
46
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .factory-from-control-list label span input[type="checkbox"],
47
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .factory-from-control-list label span input[type="checkbox"]:focus {
48
+ outline: none;
49
+ }
50
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .alert {
51
+ font-weight: bold;
52
+ margin: 0 !important;
53
+ border: 0;
54
+ border-radius: 0;
55
+ padding: 15px;
56
+ }
57
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .alert + .wbcr-factory-page-group-header {
58
+ margin-top: 0 !important;
59
+ }
60
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .alert.alert-warning {
61
+ background: #fff3d0;
62
+ }
63
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .alert.alert-warning:nth-child(2n+1) {
64
+ background: #fffde9;
65
+ }
66
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .alert.alert-danger {
67
+ background: #de716d;
68
+ }
69
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .alert.alert-danger:nth-child(2n+1) {
70
+ background: #ec8c89;
71
+ }
72
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .alert.alert-success {
73
+ background: #d0ecc4;
74
+ }
75
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .alert.alert-success:nth-child(2n+1) {
76
+ background: #e0eadb;
77
+ }
78
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-header {
79
+ padding: 20px 20px 40px;
80
+ }
81
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-recomended-text {
82
+ display: block;
83
+ font-size: 11px;
84
+ font-weight: lighter;
85
+ color: #179347;
86
+ }
87
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-options,
88
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page {
89
+ position: relative;
90
+ background: #e6e6e6;
91
+ overflow: hidden;
92
+ }
93
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-options:after,
94
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page:after {
95
+ display: block;
96
+ content: '';
97
+ clear: both;
98
+ }
99
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-group-header {
100
+ background: #efefef;
101
+ padding: 20px 0 10px 20px;
102
+ margin: 30px 0;
103
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
104
+ }
105
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-group-header:first-child {
106
+ margin-top: 0;
107
+ }
108
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-group-header strong {
109
+ font-size: 15px;
110
+ }
111
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-group-header p {
112
+ color: #8c8888;
113
+ font-size: 12px;
114
+ }
115
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap {
116
+ margin-left: 230px;
117
+ padding: 80px 0 0 0;
118
+ vertical-align: top;
119
+ background: #fff;
120
+ }
121
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap .nav-tab-wrapper,
122
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap h2.nav-tab-wrapper,
123
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap h1.nav-tab-wrapper {
124
+ border: 0;
125
+ }
126
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap .nav-tab-active {
127
+ background: #efefef !important;
128
+ margin-bottom: -2px !important;
129
+ border-bottom: 1px solid #efefef !important;
130
+ }
131
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap .nav-tab:first-child {
132
+ margin: 0;
133
+ }
134
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap .nav-tab:hover {
135
+ background: #f7f7f7;
136
+ }
137
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap .nav-tab {
138
+ border: 2px solid #dedede;
139
+ border-bottom: 0;
140
+ box-shadow: -1px 0 0 rgba(0, 0, 0, 0.1);
141
+ }
142
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap .nav-tab:active,
143
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap .nav-tab:focus {
144
+ box-shadow: none;
145
+ outline: none;
146
+ }
147
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header {
148
+ position: absolute;
149
+ z-index: 13;
150
+ top: 0;
151
+ left: 0;
152
+ right: 0;
153
+ overflow: hidden;
154
+ background-color: #32373c;
155
+ color: #fff;
156
+ border-radius: 5px 5px 0 0;
157
+ }
158
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-header-logo {
159
+ float: left;
160
+ padding: 25px 0;
161
+ font-size: 20px;
162
+ line-height: 30px;
163
+ font-weight: 400;
164
+ text-align: center;
165
+ background-color: #464b50;
166
+ color: #ccc;
167
+ padding-left: 25px;
168
+ margin-right: 10px;
169
+ background: none;
170
+ }
171
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-header-title {
172
+ display: inline-block;
173
+ vertical-align: middle;
174
+ }
175
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-header-title h2 {
176
+ font-size: 18px;
177
+ line-height: 30px;
178
+ font-weight: 300;
179
+ margin-top: 26px;
180
+ padding: 0 !important;
181
+ overflow: hidden;
182
+ white-space: nowrap;
183
+ text-overflow: ellipsis;
184
+ color: #fff;
185
+ }
186
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-control {
187
+ position: relative;
188
+ float: right;
189
+ margin: 12px;
190
+ }
191
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-button {
192
+ display: inline-block;
193
+ vertical-align: top;
194
+ font-size: 13px;
195
+ font-weight: 600;
196
+ line-height: 20px;
197
+ text-transform: uppercase;
198
+ margin: 10px 0 0;
199
+ padding: 8px 30px;
200
+ cursor: pointer;
201
+ position: relative;
202
+ overflow: hidden;
203
+ border: none;
204
+ border-radius: 50px;
205
+ box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.08) inset;
206
+ background-color: #f1f1f1;
207
+ color: inherit;
208
+ transition: background-color 0.3s, border-color 0.3s, color 0.3s, opacity 0.3s;
209
+ text-align: center;
210
+ outline: none;
211
+ text-decoration: none;
212
+ z-index: 3;
213
+ }
214
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-button.wbcr-factory-type-save {
215
+ box-shadow: none;
216
+ min-width: 100px;
217
+ background-color: #8bc34a;
218
+ color: #fff;
219
+ }
220
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-button.wbcr-factory-type-save:hover {
221
+ background: #9dbb7b;
222
+ color: #fff;
223
+ }
224
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-button.wbcr-factory-type-save:active {
225
+ box-shadow: inset -1px 1px 1px rgba(0, 0, 0, 0.3);
226
+ }
227
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-button.wbcr-factory-type-settings {
228
+ box-shadow: none;
229
+ min-width: 200px;
230
+ background-color: #9e9e9e;
231
+ color: #fff;
232
+ }
233
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-button.wbcr-factory-type-settings:hover {
234
+ background: #797979;
235
+ color: #fff;
236
+ }
237
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-header .wbcr-factory-button.wbcr-factory-type-settings:active {
238
+ box-shadow: inset -1px 1px 1px rgba(0, 0, 0, 0.3);
239
+ }
240
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar {
241
+ float: left;
242
+ vertical-align: top;
243
+ width: 230px;
244
+ background: #e6e6e6;
245
+ }
246
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul {
247
+ padding: 0;
248
+ margin-bottom: 0;
249
+ margin-top: 80px;
250
+ }
251
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab {
252
+ display: block;
253
+ background: #efefef;
254
+ margin: 1px 0;
255
+ }
256
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link {
257
+ display: block;
258
+ width: 100%;
259
+ padding: 20px 20px;
260
+ font-size: 12px;
261
+ color: #585858;
262
+ text-decoration: none;
263
+ text-transform: uppercase;
264
+ text-align: left;
265
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
266
+ }
267
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link .wbcr-factory-tab__title {
268
+ display: block;
269
+ font-weight: bold;
270
+ }
271
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link .wbcr-factory-tab__short-description {
272
+ display: block;
273
+ font-size: 13px;
274
+ font-weight: normal;
275
+ text-transform: none;
276
+ color: #9a9a9a;
277
+ }
278
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link .dashicons {
279
+ float: right;
280
+ color: #ccc;
281
+ }
282
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link::after {
283
+ clear: both;
284
+ }
285
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link:hover {
286
+ background: #f7f6f6;
287
+ }
288
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link:hover .dashicons {
289
+ color: #9a9a9a;
290
+ }
291
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link,
292
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link:active,
293
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link:hover,
294
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link:active,
295
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__link:focus {
296
+ outline: 0 !important;
297
+ box-shadow: none !important;
298
+ }
299
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab.wbcr-factory-active-tab {
300
+ background: #fff;
301
+ }
302
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab.wbcr-factory-active-tab a {
303
+ color: #ff5722;
304
+ font-weight: bold;
305
+ border-left: 5px solid #ff5722;
306
+ }
307
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab.wbcr-factory-active-tab a .dashicons {
308
+ color: #9a9a9a;
309
+ }
310
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-content-section,
311
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section {
312
+ display: inline-block;
313
+ vertical-align: top;
314
+ }
315
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-content-section {
316
+ width: 74.6%;
317
+ }
318
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-content-section.wbcr-fullwidth {
319
+ width: 100%;
320
+ }
321
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-content-section .nav-tab-wrapper {
322
+ margin-top: 15px;
323
+ }
324
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-content-section .wbcr-factory-content {
325
+ background: #f7f7f7;
326
+ padding: 0 0 20px 0;
327
+ border: 1px solid #dad8d8;
328
+ box-shadow: -1px 0px 1px rgba(0, 0, 0, 0.1);
329
+ }
330
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-content-section .wbcr-factory-content > form {
331
+ padding-top: 0 !important;
332
+ }
333
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section {
334
+ width: 25%;
335
+ padding: 10px;
336
+ margin: 0 0 -20px;
337
+ background-color: #f9f9f9;
338
+ box-shadow: -1px 1px 5px rgba(0, 0, 0, 0.1);
339
+ }
340
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section .wbcr-factory-sidebar-widget {
341
+ margin: 0 0 20px;
342
+ }
343
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget {
344
+ display: inline-block;
345
+ min-height: 230px;
346
+ width: 100%;
347
+ margin-top: 20px;
348
+ background-color: #fff;
349
+ padding: 20px 15px;
350
+ vertical-align: top;
351
+ }
352
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget.wbcr-factory-hide {
353
+ display: none;
354
+ }
355
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget.wbcr-factory-warning {
356
+ background: #fff4d0;
357
+ }
358
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget.wbcr-factory-danger {
359
+ background: #e2ffc0;
360
+ }
361
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget.wbcr-factory-success {
362
+ background: #ffebe9;
363
+ }
364
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget .wbcr-factory-hint-icon-simple {
365
+ display: inline-block;
366
+ width: 16px;
367
+ height: 16px;
368
+ line-height: 13px;
369
+ padding: 0;
370
+ font-size: 11px;
371
+ text-align: center;
372
+ color: #fff;
373
+ background: #E91E63;
374
+ border-radius: 3px;
375
+ }
376
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget .wbcr-factory-simple-grey {
377
+ background: #E91E63;
378
+ }
379
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget .wbcr-factory-simple-red {
380
+ background: #9e9e9e;
381
+ }
382
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget .wbcr-factory-simple-green {
383
+ background: #8bc34a;
384
+ }
385
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget .wbcr-factory-icon-5stars {
386
+ display: block;
387
+ width: 80px;
388
+ height: 17px;
389
+ background: url('../img/5-stars22.png') no-repeat;
390
+ vertical-align: middle;
391
+ margin-bottom: 5px;
392
+ }
393
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget #wbcr-factory-paypal-donation-form input[type="image"] {
394
+ display: block;
395
+ margin: 30px auto 0;
396
+ outline: none;
397
+ }
398
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget #wbcr-factory-paypal-donation-form input[type="image"] :focus,
399
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget #wbcr-factory-paypal-donation-form input[type="image"] :active {
400
+ box-shadow: none;
401
+ }
402
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-sidebar-widget #wbcr-factory-paypal-donation-form .wbcr-factory-donation-price {
403
+ font-size: 50px;
404
+ margin-top: 30px;
405
+ text-align: center;
406
+ font-weight: 600;
407
+ color: #8BC34A;
408
+ }
409
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-more_features .wbcr-factory-feature-box {
410
+ min-height: 240px;
411
+ margin-bottom: 20px;
412
+ text-align: center;
413
+ background: #fdfcf7;
414
+ padding: 30px;
415
+ border: 1px solid #f3f1e7;
416
+ }
417
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-more_features .wbcr-factory-feature-box .dashicons {
418
+ width: 50px;
419
+ height: 50px;
420
+ font-size: 50px;
421
+ color: #FFC107;
422
+ line-height: normal;
423
+ }
424
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-more_features .wbcr-factory-feature-box h3 {
425
+ color: #7b6111;
426
+ }
427
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-more_features .wbcr-factory-feature-box p {
428
+ color: #9e9e9e;
429
+ }
430
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-more_features .wbcr-factory-buttons-wrap {
431
+ margin-top: 20px;
432
+ text-align: center;
433
+ }
434
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-more_features .wbcr-factory-premium-button {
435
+ display: inline-block;
436
+ padding: 20px 60px;
437
+ background-color: #FFC107;
438
+ color: #866605;
439
+ text-decoration: none;
440
+ text-transform: uppercase;
441
+ font-weight: bold;
442
+ transition: background-color 0.3s, border-color 0.3s, color 0.3s, opacity 0.3s;
443
+ }
444
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-more_features .wbcr-factory-premium-button:hover {
445
+ background-color: #ffce3a;
446
+ }
447
+ #WBCR .wbcr-factory-pages-424-impressive-page-template #wbcr-factory-confirm-dialog {
448
+ padding: 20px;
449
+ background: #ffffff;
450
+ }
451
+ #WBCR .wbcr-factory-pages-424-impressive-page-template #wbcr-factory-confirm-dialog .updated,
452
+ #WBCR .wbcr-factory-pages-424-impressive-page-template #wbcr-factory-confirm-dialog .alert {
453
+ display: none;
454
+ }
455
+ #WBCR .wbcr-factory-pages-424-impressive-page-template #wbcr-factory-confirm-dialog h2 {
456
+ font-size: 18px;
457
+ margin-top: 10px;
458
+ }
459
+ #WBCR .wbcr-factory-pages-424-impressive-page-template #wbcr-factory-confirm-dialog .wbcr-factory-confirm-description {
460
+ padding: 10px;
461
+ background: #ffedeb;
462
+ border: 1px solid #ffdfdc;
463
+ margin: 15px 0;
464
+ }
465
+ #WBCR .wbcr-factory-pages-424-impressive-page-template #wbcr-factory-confirm-dialog .wbcr-factory-confirm-hint {
466
+ margin-bottom: 15px;
467
+ color: #7b7b7b;
468
+ }
469
+ @media screen and (max-width: 1367px) {
470
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-content-section {
471
+ width: 69.6%;
472
+ }
473
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section {
474
+ width: 30%;
475
+ }
476
+ }
477
+ @media screen and (max-width: 1320px) {
478
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-content-section {
479
+ width: 100%;
480
+ }
481
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-right-sidebar-section {
482
+ display: none !important;
483
+ }
484
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-header-logo .dash {
485
+ display: none !important;
486
+ }
487
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-header-title {
488
+ display: none !important;
489
+ }
490
+ }
491
+ @media screen and (max-width: 950px) {
492
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar {
493
+ width: 70px;
494
+ }
495
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab a {
496
+ font-size: 0;
497
+ }
498
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__title {
499
+ font-size: 0;
500
+ }
501
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-left-navigation-bar ul .wbcr-factory-nav-tab .wbcr-factory-tab__short-description {
502
+ display: none !important;
503
+ }
504
+ #WBCR .wbcr-factory-pages-424-impressive-page-template .wbcr-factory-page-inner-wrap {
505
+ margin-left: 70px;
506
+ }
507
+ }
508
+ /*# sourceMappingURL=impressive.page.template.css.map */
libs/factory/pages/templates/assets/css/impressive.page.template.css.map ADDED
@@ -0,0 +1 @@
 
1
+ {"version":3,"sources":["impressive.page.template.less"],"names":[],"mappings":";;;;;AAMA,KACE;AADF,KACY;AADZ,KACqB;EACjB,wBAAA;;AAFJ,KAKE;EACE,kBAAA;;;;;;;;AANJ,KAKE,iDAGE;EACE,cAAA;;AATN,KAKE,iDAOE;EACE,cAAA;;AAbN,KAKE,iDAWE;EACE,cAAA;;AAjBN,KAKE,iDAeE;EACE,eAAA;;AArBN,KAKE,iDAeE,YAEE;EACE,mBAAA;;AAvBR,KAKE,iDAsBE,iBAAiB;EACf,gBAAA;;AA5BN,KAKE,iDA0BE;EACE,iBAAA;EACA,mBAAA;;AAjCN,KAKE,iDA+BE,2BACE,MACE;EACE,qBAAA;EACA,sBAAA;;AAxCV,KAKE,iDA+BE,2BACE,MACE,KAGE,MAAK;AAzCf,KAKE,iDA+BE,2BACE,MACE,KAG0B,MAAK,iBAAiB;EAC5C,aAAA;;AA1CZ,KAKE,iDA2CE;EACE,iBAAA;EACA,oBAAA;EACA,SAAA;EACA,gBAAA;EACA,aAAA;;AAEA,KAlDJ,iDA2CE,OAOI;EACA,wBAAA;;AAGF,KAtDJ,iDA2CE,OAWG;EACC,mBAAA;;AAGF,KA1DJ,iDA2CE,OAeG,cAAc,UAAU;EACvB,mBAAA;;AAGF,KA9DJ,iDA2CE,OAmBG;EACC,mBAAA;;AAGF,KAlEJ,iDA2CE,OAuBG,aAAa,UAAU;EACtB,mBAAA;;AAGF,KAtEJ,iDA2CE,OA2BG;EACC,mBAAA;;AAGF,KA1EJ,iDA2CE,OA+BG,cAAc,UAAU;EACvB,mBAAA;;AAhFR,KAKE,iDA+EE;EACE,uBAAA;;AArFN,KAKE,iDAmFE;EACE,cAAA;EACA,eAAA;EACA,oBAAA;EACA,cAAA;;AA5FN,KAKE,iDA0FE;AA/FJ,KAKE,iDA0FyB;EACrB,kBAAA;EACA,mBAAA;EACA,gBAAA;;AASA,KAtGJ,iDA0FE,sBAYG;AAAD,KAtGJ,iDA0FyB,mBAYpB;EACC,cAAA;EACA,SAAS,EAAT;EACA,WAAA;;AA9GR,KAKE,iDA6GE;EACE,mBAAA;EACA,yBAAA;EACA,cAAA;EACA,sCAAA;;AACA,KAlHJ,iDA6GE,gCAKG;EACC,aAAA;;AAxHR,KAKE,iDA6GE,gCAQE;EACE,eAAA;;AA3HR,KAKE,iDA6GE,gCAWE;EACE,cAAA;EACA,eAAA;;AA/HR,KAKE,iDAmIE;EAIE,kBAAA;EAEA,mBAAA;EACA,mBAAA;EACA,gBAAA;;AAhJN,KAKE,iDAmIE,8BAUE;AAlJN,KAKE,iDAmIE,8BAUoB,GAAE;AAlJ1B,KAKE,iDAmIE,8BAUwC,GAAE;EACtC,SAAA;;AAnJR,KAKE,iDAmIE,8BAaE;EACE,mBAAA;EACA,mBAAA;EACA,gCAAA;;AAxJR,KAKE,iDAmIE,8BAkBE,SAAQ;EACN,SAAA;;AA3JR,KAKE,iDAmIE,8BAqBE,SAAQ;EACN,mBAAA;;AA9JR,KAKE,iDAmIE,8BAwBE;EACE,yBAAA;EACA,gBAAA;EACA,uCAAA;;AACA,KA/JN,iDAmIE,8BAwBE,SAIG;AAAS,KA/JhB,iDAmIE,8BAwBE,SAIa;EACT,gBAAA;EACA,aAAA;;AAtKV,KAKE,iDAsKE;EACE,kBAAA;EACA,WAAA;EACA,MAAA;EACA,OAAA;EACA,QAAA;EACA,gBAAA;EACA,yBAAA;EACA,WAAA;EACA,0BAAA;;AApLN,KAKE,iDAsKE,0BAWE;EACE,WAAA;EACA,eAAA;EACA,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,kBAAA;EAEA,yBAAA;EACA,WAAA;EACA,kBAAA;EACA,kBAAA;EACA,gBAAA;;AAlMR,KAKE,iDAsKE,0BA0BE;EACE,qBAAA;EACA,sBAAA;;AAvMR,KAKE,iDAsKE,0BA0BE,2BAGE;EACE,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,gBAAA;EACA,qBAAA;EAEA,gBAAA;EACA,mBAAA;EACA,uBAAA;EACA,WAAA;;AAlNV,KAKE,iDAsKE,0BA2CE;EACE,kBAAA;EACA,YAAA;EACA,YAAA;;AAzNR,KAKE,iDAsKE,0BAiDE;EACE,qBAAA;EACA,mBAAA;EACA,eAAA;EACA,gBAAA;EACA,iBAAA;EACA,yBAAA;EACA,gBAAA;EACA,iBAAA;EACA,eAAA;EACA,kBAAA;EACA,gBAAA;EACA,YAAA;EACA,mBAAA;EACA,8CAAA;EACA,yBAAA;EACA,cAAA;EACA,8EAAA;EACA,kBAAA;EACA,aAAA;EACA,qBAAA;EACA,UAAA;;AAEA,KA9ON,iDAsKE,0BAiDE,qBAuBG;EACC,gBAAA;EACA,gBAAA;EACA,yBAAA;EACA,WAAA;;AACA,KAnPR,iDAsKE,0BAiDE,qBAuBG,uBAKE;EACC,mBAAA;EACA,WAAA;;AAEF,KAvPR,iDAsKE,0BAiDE,qBAuBG,uBASE;EACC,iDAAA;;AAIJ,KA5PN,iDAsKE,0BAiDE,qBAqCG;EACC,gBAAA;EACA,gBAAA;EACA,yBAAA;EACA,WAAA;;AACA,KAjQR,iDAsKE,0BAiDE,qBAqCG,2BAKE;EACC,mBAAA;EACA,WAAA;;AAEF,KArQR,iDAsKE,0BAiDE,qBAqCG,2BASE;EACC,iDAAA;;AA3QZ,KAKE,iDA4QE;EAEE,WAAA;EACA,mBAAA;EACA,YAAA;EACA,mBAAA;;AAtRN,KAKE,iDA4QE,kCAOE;EACE,UAAA;EACA,gBAAA;EACA,gBAAA;;AA3RR,KAKE,iDA4QE,kCAOE,GAIE;EACE,cAAA;EACA,mBAAA;EAEA,aAAA;;AAhSV,KAKE,iDA4QE,kCAOE,GAIE,sBAKE;EACE,cAAA;EACA,WAAA;EACA,kBAAA;EACA,eAAA;EACA,cAAA;EACA,qBAAA;EACA,yBAAA;EACA,gBAAA;EACA,gDAAgD,oDAAoD,4BAApG;;AA1SZ,KAKE,iDA4QE,kCAOE,GAIE,sBAKE,wBAWE;EACE,cAAA;EACA,iBAAA;;AA9Sd,KAKE,iDA4QE,kCAOE,GAIE,sBAKE,wBAgBE;EACE,cAAA;EACA,eAAA;EACA,mBAAA;EACA,oBAAA;EACA,cAAA;;AAtTd,KAKE,iDA4QE,kCAOE,GAIE,sBAKE,wBAwBE;EACE,YAAA;EAEA,WAAA;;AAGF,KA1TV,iDA4QE,kCAOE,GAIE,sBAKE,wBA8BG;EACC,WAAA;;AAGF,KA9TV,iDA4QE,kCAOE,GAIE,sBAKE,wBAkCG;EACC,mBAAA;;AADF,KA9TV,iDA4QE,kCAOE,GAIE,sBAKE,wBAkCG,MAEC;EACE,cAAA;;AAGJ,KApUV,iDA4QE,kCAOE,GAIE,sBAKE;AAwCK,KApUb,iDA4QE,kCAOE,GAIE,sBAKE,wBAwCM;AAAS,KApUvB,iDA4QE,kCAOE,GAIE,sBAKE,wBAwCgB;AAAQ,KApUhC,iDA4QE,kCAOE,GAIE,sBAKE,wBAwCyB;AAAS,KApU1C,iDA4QE,kCAOE,GAIE,sBAKE,wBAwCmC;EAC/B,qBAAA;EACA,2BAAA;;AAIJ,KA1UR,iDA4QE,kCAOE,GAIE,sBAmDG;EACC,gBAAA;;AADF,KA1UR,iDA4QE,kCAOE,GAIE,sBAmDG,wBAEC;EACE,cAAA;EACA,iBAAA;EACA,8BAAA;;AALJ,KA1UR,iDA4QE,kCAOE,GAIE,sBAmDG,wBAEC,EAIE;EACE,cAAA;;AAtVhB,KAKE,iDA4VE;AAjWJ,KAKE,iDA4ViC;EAC7B,qBAAA;EACA,mBAAA;;AAnWN,KAKE,iDAiWE;EACE,YAAA;;AACA,KAnWJ,iDAiWE,8BAEG;EACC,WAAA;;AAzWR,KAKE,iDAiWE,8BAKE;EACE,gBAAA;;AA5WR,KAKE,iDAiWE,8BAQE;EACE,mBAAA;EACA,mBAAA;EACA,yBAAA;EACA,2CAAA;;AACA,KA9WN,iDAiWE,8BAQE,sBAKI;EACA,yBAAA;;AApXV,KAKE,iDAoXE;EACE,UAAA;EACA,aAAA;EACA,iBAAA;EACA,yBAAA;EACA,2CAAA;;AA9XN,KAKE,iDAoXE,oCAOE;EACE,gBAAA;;AAjYR,KAKE,iDAmYE;EACE,qBAAA;EACA,iBAAA;EACA,WAAA;EACA,gBAAA;EACA,sBAAA;EACA,kBAAA;EACA,mBAAA;;AAEA,KA5YJ,iDAmYE,6BASG;EACC,aAAA;;AAGF,KAhZJ,iDAmYE,6BAaG;EACC,mBAAA;;AAGF,KApZJ,iDAmYE,6BAiBG;EACC,mBAAA;;AAGF,KAxZJ,iDAmYE,6BAqBG;EACC,mBAAA;;AA9ZR,KAKE,iDAmYE,6BAyBE;EACE,qBAAA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;EACA,UAAA;EACA,eAAA;EACA,kBAAA;EACA,WAAA;EACA,mBAAA;EACA,kBAAA;;AA3aR,KAKE,iDAmYE,6BAqCE;EACE,mBAAA;;AA9aR,KAKE,iDAmYE,6BAwCE;EACE,mBAAA;;AAjbR,KAKE,iDAmYE,6BA2CE;EACE,mBAAA;;AApbR,KAKE,iDAmYE,6BA+CE;EACE,cAAA;EACA,WAAA;EACA,YAAA;EACA,gBAAgB,iCAAhB;EACA,sBAAA;EACA,kBAAA;;AA7bR,KAKE,iDAmYE,6BAwDE,mCACE,MAAK;EACH,cAAA;EACA,mBAAA;EACA,aAAA;;AApcV,KAKE,iDAmYE,6BAwDE,mCACE,MAAK,cAIH;AArcV,KAKE,iDAmYE,6BAwDE,mCACE,MAAK,cAIK;EACN,gBAAA;;AAtcZ,KAKE,iDAmYE,6BAwDE,mCASE;EACE,eAAA;EACA,gBAAA;EACA,kBAAA;EACA,gBAAA;EACA,cAAA;;AA9cV,KAKE,iDA8cE,iCACE;EAEE,iBAAA;EACA,mBAAA;EACA,kBAAA;EACA,mBAAA;EACA,aAAA;EACA,yBAAA;;AA3dR,KAKE,iDA8cE,iCACE,0BAQE;EACE,WAAA;EACA,YAAA;EACA,eAAA;EACA,cAAA;EACA,mBAAA;;AAjeV,KAKE,iDA8cE,iCACE,0BAeE;EACE,cAAA;;AApeV,KAKE,iDA8cE,iCACE,0BAkBE;EACE,cAAA;;AAveV,KAKE,iDA8cE,iCAwBE;EACE,gBAAA;EACA,kBAAA;;AA7eR,KAKE,iDA8cE,iCA6BE;EACE,qBAAA;EACA,kBAAA;EACA,yBAAA;EACA,cAAA;EACA,qBAAA;EACA,yBAAA;EACA,iBAAA;EACA,8EAAA;;AACA,KApfN,iDA8cE,iCA6BE,6BASG;EACC,yBAAA;;AA1fV,KAKE,iDA0fE;EACE,aAAA;EACA,mBAAA;;AAjgBN,KAKE,iDA0fE,6BAIE;AAngBN,KAKE,iDA0fE,6BAIY;EACR,aAAA;;AApgBR,KAKE,iDA0fE,6BAOE;EACE,eAAA;EACA,gBAAA;;AAxgBR,KAKE,iDA0fE,6BAWE;EACE,aAAA;EACA,mBAAA;EACA,yBAAA;EACA,cAAA;;AA9gBR,KAKE,iDA0fE,6BAiBE;EACE,mBAAA;EACA,cAAA;;AAMR,mBAAsC;EACpC,KACE,iDACE;IACE,YAAA;;EAHN,KACE,iDAKE;IACE,UAAA;;;AAMR,mBAAsC;EACpC,KACE,iDACE;IACE,WAAA;;EAHN,KACE,iDAIE;IACE,wBAAA;;EANN,KACE,iDAOE,0BACE;IACE,wBAAA;;EAVR,KACE,iDAYE;IACE,wBAAA;;;AAMR,mBAAqC;EACnC,KACE,iDACE;IACE,WAAA;;EAHN,KACE,iDACE,kCAGE,GACE,sBACE;IACE,YAAA;;EARZ,KACE,iDACE,kCAGE,GACE,sBAIE;IACE,YAAA;;EAXZ,KACE,iDACE,kCAGE,GACE,sBAOE;IACE,wBAAA;;EAdZ,KACE,iDAkBE;IACE,iBAAA","file":"impressive.page.template.css"}
libs/factory/pages/templates/assets/css/impressive.page.template.less ADDED
@@ -0,0 +1,604 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * General styles
3
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
4
+ * @copyright Alex Kovalev 23.08.2017
5
+ */
6
+
7
+ #WBCR {
8
+ .updated, .notice, .error {
9
+ display: none !important;
10
+ }
11
+
12
+ .wbcr-factory-pages-000-impressive-page-template {
13
+ position: relative;
14
+
15
+ .wbcr-factory-color-grey {
16
+ color: #9a9a9a;
17
+ }
18
+
19
+ .wbcr-factory-orange-color {
20
+ color: #ffc107;
21
+ }
22
+
23
+ .wbcr-factory-light-orange-color {
24
+ color: #ffeb3b;
25
+ }
26
+
27
+ .form-group {
28
+ padding: 0 20px;
29
+ label {
30
+ font-weight: normal;
31
+ }
32
+ }
33
+
34
+ .form-horizontal .control-label {
35
+ max-width: 300px;
36
+ }
37
+
38
+ .factory-control-buttons {
39
+ text-align: right;
40
+ padding-right: 20px;
41
+ }
42
+
43
+ .factory-from-control-list {
44
+ label {
45
+ span {
46
+ display: inline-block;
47
+ vertical-align: bottom;
48
+ input[type="checkbox"], input[type="checkbox"]:focus {
49
+ outline: none;
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ .alert {
56
+ font-weight: bold;
57
+ margin: 0 !important;
58
+ border: 0;
59
+ border-radius: 0;
60
+ padding: 15px;
61
+
62
+ & + .wbcr-factory-page-group-header {
63
+ margin-top: 0 !important;
64
+ }
65
+
66
+ &.alert-warning {
67
+ background: #fff3d0;
68
+ }
69
+
70
+ &.alert-warning:nth-child(2n+1) {
71
+ background: #fffde9;
72
+ }
73
+
74
+ &.alert-danger {
75
+ background: #de716d;
76
+ }
77
+
78
+ &.alert-danger:nth-child(2n+1) {
79
+ background: #ec8c89;
80
+ }
81
+
82
+ &.alert-success {
83
+ background: #d0ecc4;
84
+ }
85
+
86
+ &.alert-success:nth-child(2n+1) {
87
+ background: #e0eadb;
88
+ }
89
+ }
90
+
91
+ .wbcr-factory-header {
92
+ padding: 20px 20px 40px;
93
+ }
94
+
95
+ .wbcr-factory-recomended-text {
96
+ display: block;
97
+ font-size: 11px;
98
+ font-weight: lighter;
99
+ color: #179347;
100
+ }
101
+
102
+ .wbcr-factory-options, .wbcr-factory-page {
103
+ position: relative;
104
+ background: #e6e6e6;
105
+ overflow: hidden;
106
+ //padding-left: 230px;
107
+
108
+ form.form-horizontal {
109
+ //min-height: 500px;
110
+ //position: relative;
111
+ //padding: 0 0 50px 100px;
112
+ }
113
+
114
+ &:after {
115
+ display: block;
116
+ content: '';
117
+ clear: both;
118
+ }
119
+ }
120
+
121
+ .wbcr-factory-page-group-header {
122
+ background: #efefef;
123
+ padding: 20px 0 10px 20px;
124
+ margin: 30px 0;
125
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
126
+ &:first-child {
127
+ margin-top: 0;
128
+ }
129
+ strong {
130
+ font-size: 15px;
131
+ }
132
+ p {
133
+ color: #8c8888;
134
+ font-size: 12px;
135
+ }
136
+ }
137
+
138
+ .wbcr-factory-page {
139
+ //min-height: 500px;
140
+ // padding: 80px 20px 50px 230px;
141
+ }
142
+
143
+ .wbcr-factory-page-inner-wrap {
144
+ //float: left;
145
+ //display: inline-block;
146
+ //min-height: 800px;
147
+ margin-left: 230px;
148
+ //padding: 120px 0 20px 20px;
149
+ padding: 80px 0 0 0;
150
+ vertical-align: top;
151
+ background: #fff;
152
+ //min-height: 800px;
153
+ .nav-tab-wrapper, h2.nav-tab-wrapper, h1.nav-tab-wrapper {
154
+ border: 0;
155
+ }
156
+ .nav-tab-active {
157
+ background: #efefef !important;
158
+ margin-bottom: -2px !important;
159
+ border-bottom: 1px solid #efefef !important;
160
+ }
161
+ .nav-tab:first-child {
162
+ margin: 0;
163
+ }
164
+ .nav-tab:hover {
165
+ background: #f7f7f7;
166
+ }
167
+ .nav-tab {
168
+ border: 2px solid #dedede;
169
+ border-bottom: 0;
170
+ box-shadow: -1px 0 0 rgba(0, 0, 0, 0.1);
171
+ &:active, &:focus {
172
+ box-shadow: none;
173
+ outline: none;
174
+ }
175
+ }
176
+ }
177
+
178
+ .wbcr-factory-page-header {
179
+ position: absolute;
180
+ z-index: 13;
181
+ top: 0;
182
+ left: 0;
183
+ right: 0;
184
+ overflow: hidden;
185
+ background-color: #32373c;
186
+ color: #fff;
187
+ border-radius: 5px 5px 0 0;
188
+
189
+ .wbcr-factory-header-logo {
190
+ float: left;
191
+ padding: 25px 0;
192
+ font-size: 20px;
193
+ line-height: 30px;
194
+ font-weight: 400;
195
+ text-align: center;
196
+ //width: 170px;
197
+ background-color: #464b50;
198
+ color: #ccc;
199
+ padding-left: 25px;
200
+ margin-right: 10px;
201
+ background: none;
202
+ }
203
+
204
+ .wbcr-factory-header-title {
205
+ display: inline-block;
206
+ vertical-align: middle;
207
+ h2 {
208
+ font-size: 18px;
209
+ line-height: 30px;
210
+ font-weight: 300;
211
+ margin-top: 26px;
212
+ padding: 0 !important;
213
+ //margin: 0 !important;
214
+ overflow: hidden;
215
+ white-space: nowrap;
216
+ text-overflow: ellipsis;
217
+ color: #fff;
218
+ }
219
+ }
220
+
221
+ .wbcr-factory-control {
222
+ position: relative;
223
+ float: right;
224
+ margin: 12px;
225
+ }
226
+
227
+ .wbcr-factory-button {
228
+ display: inline-block;
229
+ vertical-align: top;
230
+ font-size: 13px;
231
+ font-weight: 600;
232
+ line-height: 20px;
233
+ text-transform: uppercase;
234
+ margin: 10px 0 0;
235
+ padding: 8px 30px;
236
+ cursor: pointer;
237
+ position: relative;
238
+ overflow: hidden;
239
+ border: none;
240
+ border-radius: 50px;
241
+ box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.08) inset;
242
+ background-color: #f1f1f1;
243
+ color: inherit;
244
+ transition: background-color 0.3s, border-color 0.3s, color 0.3s, opacity 0.3s;
245
+ text-align: center;
246
+ outline: none;
247
+ text-decoration: none;
248
+ z-index: 3;
249
+
250
+ &.wbcr-factory-type-save {
251
+ box-shadow: none;
252
+ min-width: 100px;
253
+ background-color: #8bc34a;
254
+ color: #fff;
255
+ &:hover {
256
+ background: #9dbb7b;
257
+ color: #fff;
258
+ }
259
+ &:active {
260
+ box-shadow: inset -1px 1px 1px rgba(0, 0, 0, 0.3);
261
+ }
262
+ }
263
+
264
+ &.wbcr-factory-type-settings {
265
+ box-shadow: none;
266
+ min-width: 200px;
267
+ background-color: #9e9e9e;
268
+ color: #fff;
269
+ &:hover {
270
+ background: #797979;
271
+ color: #fff;
272
+ }
273
+ &:active {
274
+ box-shadow: inset -1px 1px 1px rgba(0, 0, 0, 0.3);
275
+ }
276
+ }
277
+ }
278
+ }
279
+
280
+ .wbcr-factory-left-navigation-bar {
281
+ //display: inline-block;
282
+ float: left;
283
+ vertical-align: top;
284
+ width: 230px;
285
+ background: #e6e6e6;
286
+
287
+ ul {
288
+ padding: 0;
289
+ margin-bottom: 0;
290
+ margin-top: 80px;
291
+ .wbcr-factory-nav-tab {
292
+ display: block;
293
+ background: #efefef;
294
+ //padding: 15px 20px;
295
+ margin: 1px 0;
296
+ .wbcr-factory-tab__link {
297
+ display: block;
298
+ width: 100%;
299
+ padding: 20px 20px;
300
+ font-size: 12px;
301
+ color: #585858;
302
+ text-decoration: none;
303
+ text-transform: uppercase;
304
+ text-align: left;
305
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
306
+
307
+ .wbcr-factory-tab__title {
308
+ display: block;
309
+ font-weight: bold;
310
+ }
311
+
312
+ .wbcr-factory-tab__short-description {
313
+ display: block;
314
+ font-size: 13px;
315
+ font-weight: normal;
316
+ text-transform: none;
317
+ color: #9a9a9a;
318
+ }
319
+
320
+ .dashicons {
321
+ float: right;
322
+ //font-size: 22px;
323
+ color: #ccc;
324
+ }
325
+
326
+ &::after {
327
+ clear: both;
328
+ }
329
+
330
+ &:hover {
331
+ background: #f7f6f6;
332
+ .dashicons {
333
+ color: #9a9a9a;
334
+ }
335
+ }
336
+ &, &:active, &:hover, &:active, &:focus {
337
+ outline: 0 !important;
338
+ box-shadow: none !important;
339
+ }
340
+
341
+ }
342
+ &.wbcr-factory-active-tab {
343
+ background: #fff;
344
+ a {
345
+ color: #ff5722;
346
+ font-weight: bold;
347
+ border-left: 5px solid #ff5722;
348
+ .dashicons {
349
+ color: #9a9a9a;
350
+ }
351
+ }
352
+ }
353
+ }
354
+ }
355
+ }
356
+
357
+ /**
358
+ Content sections
359
+ */
360
+ .wbcr-factory-content-section, .wbcr-factory-right-sidebar-section {
361
+ display: inline-block;
362
+ vertical-align: top;
363
+ }
364
+
365
+ .wbcr-factory-content-section {
366
+ width: 74.6%;
367
+ &.wbcr-fullwidth {
368
+ width: 100%;
369
+ }
370
+ .nav-tab-wrapper {
371
+ margin-top: 15px;
372
+ }
373
+ .wbcr-factory-content {
374
+ background: #f7f7f7;
375
+ padding: 0 0 20px 0;
376
+ border: 1px solid #dad8d8;
377
+ box-shadow: -1px 0px 1px rgba(0, 0, 0, 0.1);
378
+ & > form {
379
+ padding-top: 0 !important;
380
+ }
381
+ }
382
+ }
383
+
384
+ .wbcr-factory-right-sidebar-section {
385
+ width: 25%;
386
+ padding: 10px;
387
+ margin: 0 0 -20px;
388
+ background-color: #f9f9f9;
389
+ box-shadow: -1px 1px 5px rgba(0, 0, 0, 0.1);
390
+
391
+ .wbcr-factory-sidebar-widget {
392
+ margin: 0 0 20px;
393
+ }
394
+ }
395
+
396
+ /**
397
+ Widget in the sidebar of the plugin
398
+ */
399
+ .wbcr-factory-sidebar-widget {
400
+ display: inline-block;
401
+ min-height: 230px;
402
+ width: 100%;
403
+ margin-top: 20px;
404
+ background-color: #fff;
405
+ padding: 20px 15px;
406
+ vertical-align: top;
407
+
408
+ &.wbcr-factory-hide {
409
+ display: none;
410
+ }
411
+
412
+ &.wbcr-factory-warning {
413
+ background: #fff4d0;
414
+ }
415
+
416
+ &.wbcr-factory-danger {
417
+ background: #e2ffc0;
418
+ }
419
+
420
+ &.wbcr-factory-success {
421
+ background: #ffebe9;
422
+ }
423
+
424
+ .wbcr-factory-hint-icon-simple {
425
+ display: inline-block;
426
+ width: 16px;
427
+ height: 16px;
428
+ line-height: 13px;
429
+ padding: 0;
430
+ font-size: 11px;
431
+ text-align: center;
432
+ color: #fff;
433
+ background: #E91E63;
434
+ border-radius: 3px;
435
+ }
436
+ .wbcr-factory-simple-grey {
437
+ background: #E91E63;
438
+ }
439
+ .wbcr-factory-simple-red {
440
+ background: #9e9e9e;
441
+ }
442
+ .wbcr-factory-simple-green {
443
+ background: #8bc34a;
444
+ }
445
+
446
+ .wbcr-factory-icon-5stars {
447
+ display: block;
448
+ width: 80px;
449
+ height: 17px;
450
+ background: url('../img/5-stars22.png') no-repeat;
451
+ vertical-align: middle;
452
+ margin-bottom: 5px;
453
+ }
454
+
455
+ #wbcr-factory-paypal-donation-form {
456
+ input[type="image"] {
457
+ display: block;
458
+ margin: 30px auto 0;
459
+ outline: none;
460
+ :focus, :active {
461
+ box-shadow: none;
462
+ }
463
+ }
464
+ .wbcr-factory-donation-price {
465
+ font-size: 50px;
466
+ margin-top: 30px;
467
+ text-align: center;
468
+ font-weight: 600;
469
+ color: #8BC34A;
470
+ }
471
+ }
472
+ }
473
+
474
+ .wbcr-factory-page-more_features {
475
+ .wbcr-factory-feature-box {
476
+ //margin: 20px 0 0 20px;
477
+ min-height: 240px;
478
+ margin-bottom: 20px;
479
+ text-align: center;
480
+ background: #fdfcf7;
481
+ padding: 30px;
482
+ border: 1px solid #f3f1e7;
483
+ .dashicons {
484
+ width: 50px;
485
+ height: 50px;
486
+ font-size: 50px;
487
+ color: #FFC107;
488
+ line-height: normal;
489
+ }
490
+ h3 {
491
+ color: #7b6111;
492
+ }
493
+ p {
494
+ color: #9e9e9e;
495
+ }
496
+ }
497
+
498
+ .wbcr-factory-buttons-wrap {
499
+ margin-top: 20px;
500
+ text-align: center;
501
+ }
502
+
503
+ .wbcr-factory-premium-button {
504
+ display: inline-block;
505
+ padding: 20px 60px;
506
+ background-color: #FFC107;
507
+ color: #866605;
508
+ text-decoration: none;
509
+ text-transform: uppercase;
510
+ font-weight: bold;
511
+ transition: background-color 0.3s, border-color 0.3s, color 0.3s, opacity 0.3s;
512
+ &:hover {
513
+ background-color: #ffce3a
514
+ }
515
+ }
516
+ }
517
+
518
+ #wbcr-factory-confirm-dialog {
519
+ padding: 20px;
520
+ background: #ffffff;
521
+
522
+ .updated, .alert {
523
+ display: none;
524
+ }
525
+ h2 {
526
+ font-size: 18px;
527
+ margin-top: 10px;
528
+ }
529
+ .wbcr-factory-confirm-description {
530
+ padding: 10px;
531
+ background: #ffedeb;
532
+ border: 1px solid #ffdfdc;
533
+ margin: 15px 0;
534
+ }
535
+ .wbcr-factory-confirm-hint {
536
+ margin-bottom: 15px;
537
+ color: #7b7b7b;
538
+ }
539
+ }
540
+ }
541
+ }
542
+
543
+ @media screen and (max-width: 1367px) {
544
+ #WBCR {
545
+ .wbcr-factory-pages-000-impressive-page-template {
546
+ .wbcr-factory-content-section {
547
+ width: 69.6%;
548
+ }
549
+
550
+ .wbcr-factory-right-sidebar-section {
551
+ width: 30%;
552
+ }
553
+ }
554
+ }
555
+ }
556
+
557
+ @media screen and (max-width: 1320px) {
558
+ #WBCR {
559
+ .wbcr-factory-pages-000-impressive-page-template {
560
+ .wbcr-factory-content-section {
561
+ width: 100%;
562
+ }
563
+ .wbcr-factory-right-sidebar-section {
564
+ display: none !important;
565
+ }
566
+ .wbcr-factory-header-logo {
567
+ .dash {
568
+ display: none !important;
569
+ }
570
+ }
571
+ .wbcr-factory-header-title {
572
+ display: none !important;
573
+ }
574
+ }
575
+ }
576
+ }
577
+
578
+ @media screen and (max-width: 950px) {
579
+ #WBCR {
580
+ .wbcr-factory-pages-000-impressive-page-template {
581
+ .wbcr-factory-left-navigation-bar {
582
+ width: 70px;
583
+
584
+ ul {
585
+ .wbcr-factory-nav-tab {
586
+ a {
587
+ font-size: 0;
588
+ }
589
+ .wbcr-factory-tab__title {
590
+ font-size: 0;
591
+ }
592
+ .wbcr-factory-tab__short-description {
593
+ display: none !important;
594
+ }
595
+ }
596
+ }
597
+ }
598
+ .wbcr-factory-page-inner-wrap {
599
+ margin-left: 70px;
600
+ }
601
+
602
+ }
603
+ }
604
+ }
libs/factory/pages/templates/assets/img/5-stars22.png ADDED
Binary file
libs/factory/pages/templates/assets/img/paypal-donate.png ADDED
Binary file
libs/factory/pages/templates/assets/img/webcraftic-plugin-icon.png ADDED
Binary file
libs/factory/pages/templates/impressive-page.class.php ADDED
@@ -0,0 +1,897 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Impressive page themplate class
4
+ *
5
+ * @author Alex Kovalev <alex.kovalevv@gmail.com>
6
+ * @since 1.0.0
7
+ * @package factory-pages
8
+ * @copyright (c) 2018, Webcraftic Ltd
9
+ *
10
+ */
11
+
12
+ // Exit if accessed directly
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ if ( ! class_exists( 'Wbcr_FactoryPages424_ImpressiveThemplate' ) ) {
18
+ /**
19
+ * Class Wbcr_FactoryPages424_ImpressiveThemplate
20
+ */
21
+ abstract class Wbcr_FactoryPages424_ImpressiveThemplate extends Wbcr_FactoryPages424_AdminPage {
22
+
23
+ /**
24
+ * Тип страницы:
25
+ *
26
+ * Существует только два типа страниц:
27
+ * options - предназначена для создании страниц с набором опций и настроек.
28
+ * page - предназначена для произвольного контента, любой html код.
29
+ *
30
+ * @var string
31
+ */
32
+ public $type = 'options';
33
+
34
+ /**
35
+ * ID родительской страницы, если указан, тогда эта страница будет внутренней странтцей
36
+ *
37
+ * @var string
38
+ */
39
+ public $page_parent_page;
40
+
41
+ /**
42
+ * Иконка меню в интерфейсе плагина
43
+ *
44
+ * Отображается в левом меню интерфейса плагина. Вы должны указать css класс dashicons.
45
+ * Иконки можно найти тут: https://developer.wordpress.org/resource/dashicons/#admin-site-alt
46
+ *
47
+ * @var string
48
+ */
49
+ public $page_menu_dashicon;
50
+
51
+ /**
52
+ * Короткое описание пункта меню в интерфейсе плагина
53
+ *
54
+ * Используется для справки, что содержится в разделе меню. По умолчанию
55
+ * описание не используется.
56
+ *
57
+ * @var string
58
+ */
59
+ public $page_menu_short_description;
60
+
61
+ /**
62
+ * Позиция закладки на страницу в главном меню плагина
63
+ *
64
+ * Может быть полезно, если вы хотите, что закладка на вашу страницу
65
+ * была выше всех остальных закладок.
66
+ * Вы должны установить число от 0 до 100, чем выше число, тем ниже
67
+ * будет расположена закладка в меню.
68
+ *
69
+ * Пример: 0 - в самом конце, 100 - в самом начале
70
+ *
71
+ * @var int
72
+ */
73
+ public $page_menu_position = 10;
74
+
75
+ /**
76
+ * Показывать заголовок страницы?
77
+ *
78
+ * Заголовок страницы печатается в шапке интерфейса плагина, по некоторым
79
+ * причинам вам может понадобиться его скрыть. Установите false, чтобы скрыть
80
+ * заголовок страницы.
81
+ *
82
+ * @var bool
83
+ */
84
+ public $show_page_title = true;
85
+
86
+ /**
87
+ * Показывать правый сайдбар в контенте страницы?
88
+ *
89
+ * Сайдбар для рекламы, уведомлений, виджетов. Если вы планируете
90
+ * например выводить рекламу для покупки премиум версии плагина,
91
+ * вы можете включить правый сайдбар и вставить в него виджет с рекламой.
92
+ *
93
+ * Внимание! Сайбар будет показан только на страницах с типом options.
94
+ *
95
+ * @var bool
96
+ */
97
+ public $show_right_sidebar_in_options = false;
98
+
99
+ /**
100
+ * Показывать нижний сайдбар в контенте страницы?
101
+ * Сайдбар для рекламы, уведомлений, виджетов. Если вы планируете
102
+ * например выводить рекламу для покупки премиум версии плагина,
103
+ * вы можете включить правый сайдбар и вставить в него виджет с рекламой.
104
+ *
105
+ * @var bool
106
+ */
107
+ public $show_bottom_sidebar = true;
108
+
109
+ /**
110
+ * @var array
111
+ */
112
+ public $page_menu = [];
113
+
114
+ /**
115
+ * @param Wbcr_Factory424_Plugin $plugin
116
+ */
117
+ public function __construct( Wbcr_Factory424_Plugin $plugin ) {
118
+ $this->menuIcon = FACTORY_PAGES_424_URL . '/templates/assets/img/webcraftic-plugin-icon.png';
119
+ //$allow_multisite = apply_filters('wbcr_factory_424_core_admin_allow_multisite', false);
120
+
121
+ if ( is_multisite() && $this->available_for_multisite && $plugin->isNetworkActive() ) {
122
+ $this->network = true;
123
+ $this->menu_target = 'settings.php';
124
+ $this->capabilitiy = 'manage_network';
125
+ }
126
+
127
+ parent::__construct( $plugin );
128
+
129
+ $this->title_plugin_action_link = __( 'Settings', 'wbcr_factory_pages_424' );
130
+
131
+ $this->setPageMenu();
132
+ }
133
+
134
+ /**
135
+ * Set page menu item
136
+ */
137
+ public function setPageMenu() {
138
+ global $factory_impressive_page_menu;
139
+
140
+ $dashicon = ( ! empty( $this->page_menu_dashicon ) ) ? ' ' . $this->page_menu_dashicon : '';
141
+ $short_description = ( ! empty( $this->page_menu_short_description ) ) ? ' ' . $this->page_menu_short_description : '';
142
+
143
+ if ( is_multisite() && is_network_admin() && ! $this->network ) {
144
+ return;
145
+ }
146
+
147
+ $factory_impressive_page_menu[ $this->getMenuScope() ][ $this->getResultId() ] = [
148
+ 'type' => $this->type, // page, options
149
+ 'url' => $this->getBaseUrl(),
150
+ 'title' => $this->getPageTitle() . ' <span class="dashicons' . $dashicon . '"></span>',
151
+ 'short_description' => $short_description,
152
+ 'position' => $this->page_menu_position,
153
+ 'parent' => $this->page_parent_page
154
+ ];
155
+ }
156
+
157
+ /**
158
+ * Get page menu items
159
+ *
160
+ * @return mixed
161
+ */
162
+ public function getPageMenu() {
163
+ global $factory_impressive_page_menu;
164
+
165
+ return $factory_impressive_page_menu[ $this->getMenuScope() ];
166
+ }
167
+
168
+ /**
169
+ * Requests assets (js and css) for the page.
170
+ *
171
+ * @since 1.0.0
172
+ * @return void
173
+ * @see FactoryPages424_AdminPage
174
+ *
175
+ */
176
+ public function assets( $scripts, $styles ) {
177
+
178
+ $this->scripts->request( 'jquery' );
179
+
180
+ $this->scripts->request( [
181
+ 'control.checkbox',
182
+ 'control.dropdown',
183
+ 'bootstrap.tooltip'
184
+ ], 'bootstrap' );
185
+
186
+ $this->styles->request( [
187
+ 'bootstrap.core',
188
+ 'bootstrap.form-group',
189
+ 'bootstrap.separator',
190
+ 'control.dropdown',
191
+ 'control.checkbox'
192
+ ], 'bootstrap' );
193
+
194
+ $this->styles->add( FACTORY_PAGES_424_URL . '/templates/assets/css/impressive.page.template.css' );
195
+ }
196
+
197
+ /**
198
+ * Получает заголовок плагина (обычно используется для брендинга)
199
+ *
200
+ * @return string
201
+ */
202
+ public function getPluginTitle() {
203
+ /**
204
+ * @since 4.0.8 - добавлен
205
+ * @since 4.0.9 - является устаревшим
206
+ */
207
+ $plugin_title = wbcr_factory_424_apply_filters_deprecated( 'wbcr/factory/imppage/plugin_title', [
208
+ $this->plugin->getPluginTitle(),
209
+ $this->plugin->getPluginName()
210
+ ], '4.0.9', 'wbcr/factory/pages/impressive/plugin_title' );
211
+
212
+ /**
213
+ * @since 4.0.9 - является устаревшим
214
+ */
215
+ $plugin_title = apply_filters( 'wbcr/factory/pages/impressive/plugin_title', $plugin_title, $this->plugin->getPluginName() );
216
+
217
+ return $plugin_title;
218
+ }
219
+
220
+ /**
221
+ * Получает полную ссылку текущей страницы
222
+ *
223
+ * @return string
224
+ */
225
+ public function getPageUrl() {
226
+ /**
227
+ * @since 4.0.9 - добавлен
228
+ */
229
+ return apply_filters( 'wbcr/factory/pages/impressive/base_url', $this->getBaseUrl(), $this->plugin->getPluginName(), $this->id );
230
+ }
231
+
232
+ /**
233
+ * Пространство имен для меню плагина
234
+ * Можно приклеить меню к другому плагину, просто перезаписав этот метод в дочернем классе
235
+ *
236
+ * @return string
237
+ */
238
+ public function getMenuScope() {
239
+ /**
240
+ * @since 4.0.9 - добавлен
241
+ */
242
+ return apply_filters( 'wbcr/factory/pages/impressive/menu_scope', $this->plugin->getPluginName(), $this->plugin->getPluginName(), $this->id );
243
+ }
244
+
245
+ /**
246
+ * Get options with namespace
247
+ *
248
+ * @param $option_name
249
+ * @param bool $default
250
+ *
251
+ * @return mixed|void
252
+ */
253
+ public function getOption( $option_name, $default = false ) {
254
+ _deprecated_function( __METHOD__, '4.0.9', '$this->plugin->getOption()' );
255
+
256
+ return $this->plugin->getOption( $option_name, $default );
257
+ }
258
+
259
+ /**
260
+ * Shows a page or options
261
+ *
262
+ * @sinve 1.0.0
263
+ * @return void
264
+ */
265
+ public function indexAction() {
266
+ $page_menu = $this->getPageMenu();
267
+ if ( 'options' === $page_menu[ $this->getResultId() ]['type'] ) {
268
+ $this->showOptions();
269
+ } else {
270
+ $this->showPage();
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Flush cache and rules
276
+ *
277
+ * @sinve 4.0.0
278
+ * @return void
279
+ */
280
+ public function flushCacheAndRulesAction() {
281
+ check_admin_referer( 'wbcr_factory_' . $this->getResultId() . '_flush_action' );
282
+
283
+ if ( class_exists( 'WbcrFactoryClearfy216_Helpers' ) ) {
284
+ WbcrFactoryClearfy216_Helpers::flushPageCache();
285
+ }
286
+
287
+ /**
288
+ * @since 4.0.1 - является устаревшим
289
+ */
290
+ wbcr_factory_424_do_action_deprecated( 'wbcr_factory_424_imppage_flush_cache', [
291
+ $this->plugin->getPluginName(),
292
+ $this->getResultId()
293
+ ], '4.0.1', 'wbcr_factory_424_imppage_after_form_save' );
294
+
295
+ /**
296
+ * @since 4.0.9 - является устаревшим
297
+ */
298
+ wbcr_factory_424_do_action_deprecated( 'wbcr_factory_424_imppage_after_form_save', [
299
+ $this->plugin,
300
+ $this
301
+ ], '4.0.9', 'wbcr/factory/pages/impressive/after_form_save' );
302
+
303
+ /**
304
+ * @since 4.0.1 - добавлен
305
+ * @since 4.0.9 - изменено название экшена, без привязки к версии фреймворка
306
+ */
307
+ do_action( 'wbcr/factory/pages/impressive/after_form_save', $this->plugin, $this );
308
+
309
+ $this->afterFormSave();
310
+
311
+ $redirect_args = [
312
+ $this->plugin->getPluginName() . '_saved' => 1
313
+ ];
314
+ /**
315
+ * @since 4.0.9 - является устаревшим
316
+ */
317
+ $redirect_args = wbcr_factory_424_apply_filters_deprecated( 'wbcr_factory_424_imppage_after_form_save_redirect_args', [ $redirect_args ], '4.0.9', 'wbcr/factory/pages/impressive/save_redirect_args' );
318
+
319
+ /**
320
+ * @since 4.0.1 - добавлен
321
+ * @since 4.0.9 - изменено название экшена, без привязки к версии фреймворка
322
+ */
323
+ $redirect_args = apply_filters( 'wbcr/factory/pages/impressive/save_redirect_args', $redirect_args );
324
+
325
+ $this->redirectToAction( 'index', $redirect_args );
326
+ }
327
+
328
+
329
+ /**
330
+ * Вызывается всегда при загрузке страницы, перед опциями формы с типом страницы options
331
+ */
332
+ protected function warningNotice() {
333
+ /*if( WP_CACHE ) {
334
+ $this->printWarningNotice(__("It seems that a caching/performance plugin is active on this site. Please manually invalidate that plugin's cache after making any changes to the settings below.", 'wbcr_factory_pages_424'));
335
+ }*/
336
+ // Метод предназначен для вызова в дочернем классе
337
+ }
338
+
339
+ /**
340
+ * Вызывается всегда при загрузке страницы, перед опциями формы с типом страницы options
341
+ *
342
+ * @since 4.0.0
343
+ *
344
+ * @param array $notices
345
+ *
346
+ * @return array
347
+ */
348
+ protected function getActionNotices( $notices ) {
349
+ // Метод предназначен для вызова в дочернем классе
350
+ return $notices;
351
+ }
352
+
353
+ /**
354
+ * Вызывается перед сохранением опций формы
355
+ *
356
+ * @since 4.0.0
357
+ * @return void
358
+ */
359
+ protected function beforeFormSave() {
360
+ // Метод предназначен для вызова в дочернем классе
361
+ }
362
+
363
+ /**
364
+ * Вызывается после сохранением опций формы, когда выполнен сброс кеша и совершен редирект
365
+ *
366
+ * @since 4.0.0
367
+ * @return void
368
+ */
369
+ protected function afterFormSave() {
370
+ // Метод предназначен для вызова в дочернем классе
371
+ }
372
+
373
+ /**
374
+ * Вызывается в процессе выполнения сохранения, но после сохранения всех опций
375
+ *
376
+ * @since 4.0.0
377
+ * @return void
378
+ */
379
+ protected function formSaved() {
380
+ // Метод предназначен для вызова в дочернем классе
381
+ }
382
+
383
+ public function printWarningNotice( $message ) {
384
+ echo '<div class="alert alert-warning wbcr-factory-warning-notice"><p><span class="dashicons dashicons-warning"></span> ' . $message . '</p></div>';
385
+ }
386
+
387
+ public function printErrorNotice( $message ) {
388
+ echo '<div class="alert alert-danger wbcr-factory-warning-notice"><p><span class="dashicons dashicons-dismiss"></span> ' . $message . '</p></div>';
389
+ }
390
+
391
+ public function printSuccessNotice( $message ) {
392
+ echo '<div class="alert alert-success wbcr-factory-warning-notice"><p><span class="dashicons dashicons-plus"></span> ' . $message . '</p></div>';
393
+ }
394
+
395
+ /**
396
+ * Печатает все зарегистрированные системные уведомления внутри интерфейса плагина
397
+ * Типы уведомлений: предупреждения, ошибки, успешные выполнения задач
398
+ */
399
+ protected function printAllNotices() {
400
+ $this->warningNotice();
401
+ $this->showActionsNotice();
402
+
403
+ /**
404
+ * @since 4.0.9 - является устаревшим
405
+ */
406
+ wbcr_factory_424_do_action_deprecated( 'wbcr_factory_pages_424_imppage_print_all_notices', [
407
+ $this->plugin,
408
+ $this
409
+ ], '4.0.9', 'wbcr/factory/pages/impressive/print_all_notices' );
410
+
411
+ /**
412
+ * @since 4.0.1 - добавлен
413
+ * @since 4.0.9 - изменено имя
414
+ */
415
+ do_action( 'wbcr/factory/pages/impressive/print_all_notices', $this->plugin, $this );
416
+ }
417
+
418
+ private function showActionsNotice() {
419
+ $notices = [
420
+ [
421
+ 'conditions' => [
422
+ $this->plugin->getPluginName() . '_saved' => '1'
423
+ ],
424
+ 'type' => 'success',
425
+ 'message' => __( 'The settings have been updated successfully!', 'wbcr_factory_pages_424' ) . ( WP_CACHE ? '<br>' . __( "It seems that a caching/performance plugin is active on this site. Please manually invalidate that plugin's ca