Toolset Types – Custom Post Types, Custom Fields and Taxonomies - Version 2.2.22

Version Description

  • First version of the public relationship API that will be sustainable also for many-to-many relationships.
  • Added a warning about dropping the PHP 5.2 support (which is no longer officially supported anyway) in the near future.
  • Fixed: Using the_title filter without the mandatory $id argument.
  • Fixed: Deprecated function notice in PHP 7.2.
Download this release

Release Info

Developer zaantar
Plugin Icon 128x128 Toolset Types – Custom Post Types, Custom Fields and Taxonomies
Version 2.2.22
Comparing to
See all releases

Code changes from version 2.2.21 to 2.2.22

Files changed (263) hide show
  1. application/autoload_classmap.php +8 -8
  2. application/controllers/{utils → admin_notice}/utils.php +0 -0
  3. application/controllers/ajax.php +42 -205
  4. application/controllers/asset/manager.php +9 -1
  5. application/models/field/{type/definition → gateway}/checkbox.php +0 -0
  6. application/models/field/{type/definition → gateway}/checkboxes.php +0 -0
  7. application/models/field/{type/definition → gateway}/date.php +0 -0
  8. application/models/field/{type/definition → gateway}/numeric.php +0 -0
  9. application/models/field/{type/definition → gateway}/radio.php +0 -0
  10. application/models/field/{type/definition → gateway}/select.php +0 -0
  11. application/models/field/{type/definition → gateway}/singular.php +0 -0
  12. readme.txt +8 -2
  13. vendor/autoload.php +1 -1
  14. vendor/composer/autoload_classmap.php +154 -61
  15. vendor/composer/autoload_real.php +7 -7
  16. vendor/composer/autoload_static.php +159 -66
  17. vendor/composer/installed.json +15 -9
  18. vendor/otgs/installer/changelog.txt +10 -0
  19. vendor/otgs/installer/includes/class-installer-theme.php +2 -2
  20. vendor/otgs/installer/includes/class-otgs-installer-filename-hooks.php +33 -0
  21. vendor/otgs/installer/includes/class-otgs-installer-php-functions.php +29 -0
  22. vendor/otgs/installer/includes/class-wp-installer.php +67 -46
  23. vendor/otgs/installer/installer.php +6 -2
  24. vendor/otgs/installer/loader.php +1 -1
  25. vendor/toolset/toolset-common/api.php +31 -0
  26. vendor/toolset/toolset-common/autoload_classmap.php +73 -7
  27. vendor/toolset/toolset-common/bootstrap.php +35 -2
  28. vendor/toolset/toolset-common/changelog.md +49 -19
  29. vendor/toolset/toolset-common/debug/main.js +4 -3
  30. vendor/toolset/toolset-common/debug/main.twig +2 -3
  31. vendor/toolset/toolset-common/functions.php +0 -9
  32. vendor/toolset/toolset-common/inc/autoloaded/admin.php +32 -0
  33. vendor/toolset/toolset-common/inc/{controller → autoloaded}/admin/notices.php +6 -1
  34. vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/get_ct_block_preview.php +50 -0
  35. vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/get_post_by_id.php +54 -0
  36. vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/get_term_by_id.php +54 -0
  37. vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/get_user_by_id.php +54 -0
  38. vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/get_view_block_preview.php +142 -0
  39. vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/intermediary_post_cleanup.php +85 -0
  40. vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/migrate_to_m2m.php +26 -14
  41. vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_posts_by_title.php +134 -0
  42. vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_terms.php +71 -0
  43. vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_users.php +75 -0
  44. vendor/toolset/toolset-common/inc/{controller → autoloaded}/asset_manager.php +0 -0
  45. vendor/toolset/toolset-common/inc/{controller → autoloaded}/constants.php +0 -0
  46. vendor/toolset/toolset-common/inc/autoloaded/cron/cron.php +182 -0
  47. vendor/toolset/toolset-common/inc/autoloaded/cron/event.php +37 -0
  48. vendor/toolset/toolset-common/inc/autoloaded/cron/event_interface.php +45 -0
  49. vendor/toolset/toolset-common/inc/autoloaded/element/element.php +28 -73
  50. vendor/toolset/toolset-common/inc/autoloaded/element/element_factory.php +92 -11
  51. vendor/toolset/toolset-common/inc/autoloaded/element/i_element.php +40 -12
  52. vendor/toolset/toolset-common/inc/autoloaded/element/i_post.php +29 -1
  53. vendor/toolset/toolset-common/inc/autoloaded/element/post.php +124 -8
  54. vendor/toolset/toolset-common/inc/autoloaded/element/post_translation_set.php +160 -20
  55. vendor/toolset/toolset-common/inc/autoloaded/field/definition.php +10 -1
  56. vendor/toolset/toolset-common/inc/autoloaded/field/definition_abstract.php +1 -1
  57. vendor/toolset/toolset-common/inc/autoloaded/field/definition_factory.php +9 -9
  58. vendor/toolset/toolset-common/inc/autoloaded/field/definition_factory_interface.php +212 -0
  59. vendor/toolset/toolset-common/inc/autoloaded/field/definition_factory_post.php +1 -1
  60. vendor/toolset/toolset-common/inc/autoloaded/field/definition_factory_term.php +1 -1
  61. vendor/toolset/toolset-common/inc/autoloaded/field/definition_factory_user.php +1 -1
  62. vendor/toolset/toolset-common/inc/autoloaded/field/definition_interface.php +71 -0
  63. vendor/toolset/toolset-common/inc/autoloaded/field/definition_post.php +9 -1
  64. vendor/toolset/toolset-common/inc/autoloaded/field/definition_term.php +8 -0
  65. vendor/toolset/toolset-common/inc/autoloaded/field/definition_user.php +8 -0
  66. vendor/toolset/toolset-common/inc/autoloaded/field/group.php +2 -2
  67. vendor/toolset/toolset-common/inc/autoloaded/files.php +54 -0
  68. vendor/toolset/toolset-common/inc/autoloaded/naming_helper.php +1 -1
  69. vendor/toolset/toolset-common/inc/autoloaded/post_type/abstract.php +125 -0
  70. vendor/toolset/toolset-common/inc/autoloaded/post_type/excluded_list.php +1 -0
  71. vendor/toolset/toolset-common/inc/autoloaded/post_type/from_types.php +40 -3
  72. vendor/toolset/toolset-common/inc/autoloaded/post_type/i_post_type.php +37 -0
  73. vendor/toolset/toolset-common/inc/autoloaded/post_type/i_post_type_from_types.php +22 -0
  74. vendor/toolset/toolset-common/inc/autoloaded/post_type/query.php +12 -1
  75. vendor/toolset/toolset-common/inc/autoloaded/post_type/registered.php +4 -2
  76. vendor/toolset/toolset-common/inc/autoloaded/post_type/repository.php +7 -3
  77. vendor/toolset/toolset-common/inc/autoloaded/relationship_service.php +27 -3
  78. vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template/abstract.php +48 -0
  79. vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template/interface.php +23 -0
  80. vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template/phtml.php +29 -0
  81. vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template/static.php +12 -0
  82. vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template/twig.php +70 -0
  83. vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template_factory.php +102 -0
  84. vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template_repository.php +63 -0
  85. vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template_repository_abstract.php +79 -0
  86. vendor/toolset/toolset-common/inc/autoloaded/renderer/renderer.php +228 -0
  87. vendor/toolset/toolset-common/inc/autoloaded/result_set.php +7 -2
  88. vendor/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/abstract.php +170 -0
  89. vendor/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/legacy_relationships.php +141 -0
  90. vendor/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/loader.php +25 -0
  91. vendor/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/m2m.php +251 -0
  92. vendor/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/table_join_manager.php +172 -0
  93. vendor/toolset/toolset-common/inc/autoloaded/wpdb_user.php +30 -0
  94. vendor/toolset/toolset-common/inc/autoloaded/wpml_utils.php +53 -28
  95. vendor/toolset/toolset-common/inc/m2m/association.php +0 -191
  96. vendor/toolset/toolset-common/inc/m2m/association/association.php +472 -0
  97. vendor/toolset/toolset-common/inc/m2m/association/cleanup/association.php +73 -0
  98. vendor/toolset/toolset-common/inc/m2m/association/cleanup/cron_event.php +45 -0
  99. vendor/toolset/toolset-common/inc/m2m/association/cleanup/cron_handler.php +57 -0
  100. vendor/toolset/toolset-common/inc/m2m/association/cleanup/dangling_intermediary_posts.php +189 -0
  101. vendor/toolset/toolset-common/inc/m2m/association/cleanup/factory.php +61 -0
  102. vendor/toolset/toolset-common/inc/m2m/association/cleanup/post.php +295 -0
  103. vendor/toolset/toolset-common/inc/m2m/association/cleanup/troubleshooting_section.php +115 -0
  104. vendor/toolset/toolset-common/inc/m2m/association/factory.php +96 -0
  105. vendor/toolset/toolset-common/inc/m2m/{i_association.php → association/interface.php} +36 -2
  106. vendor/toolset/toolset-common/inc/m2m/association/intermediary_post_persistence.php +273 -0
  107. vendor/toolset/toolset-common/inc/m2m/association/persistence.php +160 -0
  108. vendor/toolset/toolset-common/inc/m2m/association/query/association_query.php +244 -0
  109. vendor/toolset/toolset-common/inc/m2m/association/query/association_query_v2.php +994 -0
  110. vendor/toolset/toolset-common/inc/m2m/association/query/condition/abstract.php +22 -0
  111. vendor/toolset/toolset-common/inc/m2m/association/query/condition/association_id.php +39 -0
  112. vendor/toolset/toolset-common/inc/m2m/association/query/condition/element_id.php +65 -0
  113. vendor/toolset/toolset-common/inc/m2m/association/query/condition/element_id_and_domain.php +109 -0
  114. vendor/toolset/toolset-common/inc/m2m/association/query/condition/element_status.php +118 -0
  115. vendor/toolset/toolset-common/inc/m2m/association/query/condition/empty_intermediary.php +20 -0
  116. vendor/toolset/toolset-common/inc/m2m/association/query/condition/exclude_element.php +16 -0
  117. vendor/toolset/toolset-common/inc/m2m/association/query/condition/has_active_relationship.php +18 -0
  118. vendor/toolset/toolset-common/inc/m2m/association/query/condition/has_domain.php +86 -0
  119. vendor/toolset/toolset-common/inc/m2m/association/query/condition/has_domain_and_type.php +98 -0
  120. vendor/toolset/toolset-common/inc/m2m/association/query/condition/has_legacy_relationship.php +18 -0
  121. vendor/toolset/toolset-common/inc/m2m/association/query/condition/has_type.php +100 -0
  122. vendor/toolset/toolset-common/inc/m2m/association/query/condition/interface.php +14 -0
  123. vendor/toolset/toolset-common/inc/m2m/association/query/condition/postmeta.php +78 -0
  124. vendor/toolset/toolset-common/inc/m2m/association/query/condition/relationship_flag.php +55 -0
  125. vendor/toolset/toolset-common/inc/m2m/association/query/condition/relationship_id.php +41 -0
  126. vendor/toolset/toolset-common/inc/m2m/association/query/condition/search.php +92 -0
  127. vendor/toolset/toolset-common/inc/m2m/association/query/condition/wp_query.php +288 -0
  128. vendor/toolset/toolset-common/inc/m2m/association/query/condition_factory.php +322 -0
  129. vendor/toolset/toolset-common/inc/m2m/association/query/element_selector/abstract.php +95 -0
  130. vendor/toolset/toolset-common/inc/m2m/association/query/element_selector/default.php +94 -0
  131. vendor/toolset/toolset-common/inc/m2m/association/query/element_selector/interface.php +93 -0
  132. vendor/toolset/toolset-common/inc/m2m/association/query/element_selector/provider.php +113 -0
  133. vendor/toolset/toolset-common/inc/m2m/association/query/element_selector/wpml.php +257 -0
  134. vendor/toolset/toolset-common/inc/m2m/association/query/orderby/abstract.php +50 -0
  135. vendor/toolset/toolset-common/inc/m2m/association/query/orderby/interface.php +36 -0
  136. vendor/toolset/toolset-common/inc/m2m/association/query/orderby/nothing.php +21 -0
  137. vendor/toolset/toolset-common/inc/m2m/association/query/orderby/postmeta.php +87 -0
  138. vendor/toolset/toolset-common/inc/m2m/association/query/orderby/title.php +52 -0
  139. vendor/toolset/toolset-common/inc/m2m/association/query/orderby_factory.php +40 -0
  140. vendor/toolset/toolset-common/inc/m2m/association/query/restriction/interface.php +35 -0
  141. vendor/toolset/toolset-common/inc/m2m/association/query/result_transformation/association_instance.php +145 -0
  142. vendor/toolset/toolset-common/inc/m2m/association/query/result_transformation/association_uid.php +39 -0
  143. vendor/toolset/toolset-common/inc/m2m/association/query/result_transformation/element_id.php +52 -0
  144. vendor/toolset/toolset-common/inc/m2m/association/query/result_transformation/element_instance.php +129 -0
  145. vendor/toolset/toolset-common/inc/m2m/association/query/result_transformation/interface.php +35 -0
  146. vendor/toolset/toolset-common/inc/m2m/association/query/sql_expression_builder.php +139 -0
  147. vendor/toolset/toolset-common/inc/m2m/association/query/table_join_manager.php +209 -0
  148. vendor/toolset/toolset-common/inc/m2m/association/query/wpdb_wrapper.php +84 -0
  149. vendor/toolset/toolset-common/inc/m2m/association/translator.php +236 -0
  150. vendor/toolset/toolset-common/inc/m2m/association_base.php +0 -193
  151. vendor/toolset/toolset-common/inc/m2m/association_query.php +0 -932
  152. vendor/toolset/toolset-common/inc/m2m/association_repository.php +0 -260
  153. vendor/toolset/toolset-common/inc/m2m/association_transitional.php +0 -61
  154. vendor/toolset/toolset-common/inc/m2m/association_translation_set.php +0 -135
  155. vendor/toolset/toolset-common/inc/m2m/autoload_classmap.php +101 -51
  156. vendor/toolset/toolset-common/inc/m2m/cardinality.php +2 -2
  157. vendor/toolset/toolset-common/inc/m2m/controller.php +113 -52
  158. vendor/toolset/toolset-common/inc/m2m/database/operations.php +166 -108
  159. vendor/toolset/toolset-common/inc/m2m/driver.php +23 -424
  160. vendor/toolset/toolset-common/inc/m2m/driver_base.php +43 -4
  161. vendor/toolset/toolset-common/inc/m2m/element_type.php +5 -5
  162. vendor/toolset/toolset-common/inc/m2m/migration/associations.php +222 -0
  163. vendor/toolset/toolset-common/inc/m2m/{migration.php → migration/controller.php} +94 -53
  164. vendor/toolset/toolset-common/inc/m2m/migration/post_translation.php +213 -0
  165. vendor/toolset/toolset-common/inc/m2m/migration_associations.php +0 -119
  166. vendor/toolset/toolset-common/inc/m2m/multilingual_mode.php +0 -236
  167. vendor/toolset/toolset-common/inc/m2m/potential_association/distinct_post_query.php +56 -12
  168. vendor/toolset/toolset-common/inc/m2m/potential_association/query_interface.php +16 -1
  169. vendor/toolset/toolset-common/inc/m2m/potential_association/query_posts.php +52 -31
  170. vendor/toolset/toolset-common/inc/m2m/query/comparison_operator.php +28 -0
  171. vendor/toolset/toolset-common/inc/m2m/{relationship_query → query}/condition/and.php +9 -4
  172. vendor/toolset/toolset-common/inc/m2m/query/condition/contradiction.php +30 -0
  173. vendor/toolset/toolset-common/inc/m2m/{relationship_query/condition/i_condition.php → query/condition/interface.php} +2 -6
  174. vendor/toolset/toolset-common/inc/m2m/{relationship_query → query}/condition/operator.php +8 -6
  175. vendor/toolset/toolset-common/inc/m2m/{relationship_query → query}/condition/or.php +4 -4
  176. vendor/toolset/toolset-common/inc/m2m/{relationship_query → query}/condition/tautology.php +10 -1
  177. vendor/toolset/toolset-common/inc/m2m/{query_factory.php → query/factory.php} +12 -4
  178. vendor/toolset/toolset-common/inc/m2m/query_base.php +1 -0
  179. vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/definition.php +37 -24
  180. vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/factory.php +0 -0
  181. vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/interface.php +29 -3
  182. vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/persistence.php +76 -1
  183. vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/repository.php +1 -28
  184. vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/translator.php +1 -1
  185. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/cardinality_match/conjunction.php +0 -0
  186. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/cardinality_match/factory.php +0 -0
  187. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/cardinality_match/interface.php +0 -0
  188. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/cardinality_match/operators.php +0 -0
  189. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/cardinality_match/single.php +0 -0
  190. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/abstract.php +0 -0
  191. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/has_active_types.php +0 -0
  192. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/has_cardinality.php +0 -0
  193. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/has_domain.php +2 -1
  194. vendor/toolset/toolset-common/inc/m2m/relationship/query/condition/interface.php +10 -0
  195. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/is_active.php +0 -0
  196. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/is_boolean_flag.php +0 -0
  197. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/is_legacy.php +0 -0
  198. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/origin.php +0 -0
  199. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/type.php +1 -1
  200. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition_factory.php +6 -6
  201. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/relationship_query.php +0 -0
  202. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/relationship_query_v2.php +77 -2
  203. vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/sql_expression_builder.php +7 -9
  204. vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/abstract.php +0 -0
  205. vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/child.php +0 -0
  206. vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/interface.php +0 -0
  207. vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/intermediary.php +0 -0
  208. vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/parent.php +0 -0
  209. vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/parent_child_interface.php +0 -0
  210. vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/role.php +64 -0
  211. vendor/toolset/toolset-common/inc/m2m/{scope.php → relationship/scope.php} +0 -0
  212. vendor/toolset/toolset-common/inc/m2m/{slug_validator.php → relationship/slug_validator.php} +0 -0
  213. vendor/toolset/toolset-common/inc/m2m/utils.php +26 -0
  214. vendor/toolset/toolset-common/inc/m2m/wpml_interoperability.php +0 -645
  215. vendor/toolset/toolset-common/inc/public_api/legacy_relationships.php +338 -0
  216. vendor/toolset/toolset-common/inc/public_api/loader.php +35 -0
  217. vendor/toolset/toolset-common/inc/public_api/m2m.php +309 -0
  218. vendor/toolset/toolset-common/inc/toolset.ajax.class.php +128 -53
  219. vendor/toolset/toolset-common/inc/toolset.assets.manager.class.php +50 -2
  220. vendor/toolset/toolset-common/inc/toolset.css.component.class.php +2 -1
  221. vendor/toolset/toolset-common/inc/toolset.menu.class.php +6 -6
  222. vendor/toolset/toolset-common/inc/toolset.shortcode.generator.class.php +133 -159
  223. vendor/toolset/toolset-common/inc/toolset.wpml.compatibility.class.php +380 -12
  224. vendor/toolset/toolset-common/lib/whip/CHANGELOG.md +34 -0
  225. vendor/toolset/toolset-common/lib/whip/LICENSE +21 -0
  226. vendor/toolset/toolset-common/lib/whip/README.md +94 -0
  227. vendor/toolset/toolset-common/lib/whip/src/Whip_Configuration.php +54 -0
  228. vendor/toolset/toolset-common/lib/whip/src/Whip_Host.php +88 -0
  229. vendor/toolset/toolset-common/lib/whip/src/Whip_MessageDismisser.php +45 -0
  230. vendor/toolset/toolset-common/lib/whip/src/Whip_MessageFormatter.php +37 -0
  231. vendor/toolset/toolset-common/lib/whip/src/Whip_MessagesManager.php +83 -0
  232. vendor/toolset/toolset-common/lib/whip/src/Whip_RequirementsChecker.php +148 -0
  233. vendor/toolset/toolset-common/lib/whip/src/Whip_VersionRequirement.php +133 -0
  234. vendor/toolset/toolset-common/lib/whip/src/Whip_WPDismissOption.php +36 -0
  235. vendor/toolset/toolset-common/lib/whip/src/Whip_WPMessageDismissListener.php +51 -0
  236. vendor/toolset/toolset-common/lib/whip/src/configs/default.php +5 -0
  237. vendor/toolset/toolset-common/lib/whip/src/configs/version.php +3 -0
  238. vendor/toolset/toolset-common/lib/whip/src/exceptions/Whip_EmptyProperty.php +10 -0
  239. vendor/toolset/toolset-common/lib/whip/src/exceptions/Whip_InvalidOperatorType.php +22 -0
  240. vendor/toolset/toolset-common/lib/whip/src/exceptions/Whip_InvalidType.php +18 -0
  241. vendor/toolset/toolset-common/lib/whip/src/exceptions/Whip_InvalidVersionComparisonString.php +19 -0
  242. vendor/toolset/toolset-common/lib/whip/src/facades/wordpress.php +36 -0
  243. vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_DismissStorage.php +24 -0
  244. vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_Listener.php +15 -0
  245. vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_Message.php +8 -0
  246. vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_MessagePresenter.php +10 -0
  247. vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_Requirement.php +8 -0
  248. vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_VersionDetector.php +21 -0
  249. vendor/toolset/toolset-common/lib/whip/src/messages/Whip_BasicMessage.php +42 -0
  250. vendor/toolset/toolset-common/lib/whip/src/messages/Whip_HostMessage.php +56 -0
  251. vendor/toolset/toolset-common/lib/whip/src/messages/Whip_InvalidVersionRequirementMessage.php +37 -0
  252. vendor/toolset/toolset-common/lib/whip/src/messages/Whip_NullMessage.php +13 -0
  253. vendor/toolset/toolset-common/lib/whip/src/messages/Whip_UpgradePhpMessage.php +50 -0
  254. vendor/toolset/toolset-common/lib/whip/src/presenters/Whip_WPMessagePresenter.php +83 -0
  255. vendor/toolset/toolset-common/loader.php +2 -2
  256. vendor/toolset/toolset-common/recreate_classmap.sh +2 -1
  257. vendor/toolset/toolset-common/res/css/toolset-dialogs.css +86 -8
  258. vendor/toolset/toolset-common/res/css/toolset-notifications.css +10 -0
  259. vendor/toolset/toolset-common/res/js/toolset-bs-component-grids.js +8 -0
  260. vendor/toolset/toolset-common/res/js/toolset-media-manager.js +152 -0
  261. vendor/toolset/toolset-common/res/js/toolset-shortcode.js +155 -23
  262. vendor/toolset/toolset-common/res/lib/parsley/parsley.css +33 -0
  263. vendor/toolset/toolset-common/res/lib/parsley/parsley.js +2438 -0
application/autoload_classmap.php CHANGED
@@ -46,15 +46,15 @@ return array(
46
  'Types_Field_Group_User_Factory' => dirname( __FILE__ ) . '/models/field/group/user_factory.php',
47
  'Types_Fields_Conditional' => dirname( __FILE__ ) . '/../vendor/toolset/types/includes/classes/class.types.fields.conditional.php',
48
  'Types_Field_Type_Converter' => dirname( __FILE__ ) . '/controllers/field/type_converter.php',
49
- 'Types_Field_Type_Definition_Checkbox' => dirname( __FILE__ ) . '/models/field/type/definition/checkbox.php',
50
- 'Types_Field_Type_Definition_Checkboxes' => dirname( __FILE__ ) . '/models/field/type/definition/checkboxes.php',
51
- 'Types_Field_Type_Definition_Date' => dirname( __FILE__ ) . '/models/field/type/definition/date.php',
52
  'Types_Field_Type_Definition' => dirname( __FILE__ ) . '/models/field/type/definition.php',
53
  'Types_Field_Type_Definition_Factory' => dirname( __FILE__ ) . '/models/field/type/definition_factory.php',
54
- 'Types_Field_Type_Definition_Numeric' => dirname( __FILE__ ) . '/models/field/type/definition/numeric.php',
55
- 'Types_Field_Type_Definition_Radio' => dirname( __FILE__ ) . '/models/field/type/definition/radio.php',
56
- 'Types_Field_Type_Definition_Select' => dirname( __FILE__ ) . '/models/field/type/definition/select.php',
57
- 'Types_Field_Type_Definition_Singular' => dirname( __FILE__ ) . '/models/field/type/definition/singular.php',
58
  'Types_Field_Utils' => dirname( __FILE__ ) . '/controllers/field/utils.php',
59
  'Types_Frontend' => dirname( __FILE__ ) . '/controllers/frontend.php',
60
  'Types_Helper_Condition_Archive_Exists' => dirname( __FILE__ ) . '/models/helper/condition/archive/exists.php',
@@ -133,7 +133,7 @@ return array(
133
  'Types_Taxonomy' => dirname( __FILE__ ) . '/models/taxonomy.php',
134
  'Types_Twig_Autoloader' => dirname( __FILE__ ) . '/controllers/twig_autoloader.php',
135
  'Types_Upgrade' => dirname( __FILE__ ) . '/controllers/upgrade.php',
136
- 'Types_Utils' => dirname( __FILE__ ) . '/controllers/utils/utils.php',
137
  'Types_Utils_Post_Type_Option' => dirname( __FILE__ ) . '/controllers/utils/post_type_option.php',
138
  'Types_Wpml_Field_Group' => dirname( __FILE__ ) . '/models/wpml/field_group.php',
139
  'Types_Wpml_Field_Group_String_Description' => dirname( __FILE__ ) . '/models/wpml/field/group/string/description.php',
46
  'Types_Field_Group_User_Factory' => dirname( __FILE__ ) . '/models/field/group/user_factory.php',
47
  'Types_Fields_Conditional' => dirname( __FILE__ ) . '/../vendor/toolset/types/includes/classes/class.types.fields.conditional.php',
48
  'Types_Field_Type_Converter' => dirname( __FILE__ ) . '/controllers/field/type_converter.php',
49
+ 'Types_Field_Type_Definition_Checkbox' => dirname( __FILE__ ) . '/models/field/gateway/checkbox.php',
50
+ 'Types_Field_Type_Definition_Checkboxes' => dirname( __FILE__ ) . '/models/field/gateway/checkboxes.php',
51
+ 'Types_Field_Type_Definition_Date' => dirname( __FILE__ ) . '/models/field/gateway/date.php',
52
  'Types_Field_Type_Definition' => dirname( __FILE__ ) . '/models/field/type/definition.php',
53
  'Types_Field_Type_Definition_Factory' => dirname( __FILE__ ) . '/models/field/type/definition_factory.php',
54
+ 'Types_Field_Type_Definition_Numeric' => dirname( __FILE__ ) . '/models/field/gateway/numeric.php',
55
+ 'Types_Field_Type_Definition_Radio' => dirname( __FILE__ ) . '/models/field/gateway/radio.php',
56
+ 'Types_Field_Type_Definition_Select' => dirname( __FILE__ ) . '/models/field/gateway/select.php',
57
+ 'Types_Field_Type_Definition_Singular' => dirname( __FILE__ ) . '/models/field/gateway/singular.php',
58
  'Types_Field_Utils' => dirname( __FILE__ ) . '/controllers/field/utils.php',
59
  'Types_Frontend' => dirname( __FILE__ ) . '/controllers/frontend.php',
60
  'Types_Helper_Condition_Archive_Exists' => dirname( __FILE__ ) . '/models/helper/condition/archive/exists.php',
133
  'Types_Taxonomy' => dirname( __FILE__ ) . '/models/taxonomy.php',
134
  'Types_Twig_Autoloader' => dirname( __FILE__ ) . '/controllers/twig_autoloader.php',
135
  'Types_Upgrade' => dirname( __FILE__ ) . '/controllers/upgrade.php',
136
+ 'Types_Utils' => dirname( __FILE__ ) . '/controllers/admin_notice/utils.php',
137
  'Types_Utils_Post_Type_Option' => dirname( __FILE__ ) . '/controllers/utils/post_type_option.php',
138
  'Types_Wpml_Field_Group' => dirname( __FILE__ ) . '/models/wpml/field_group.php',
139
  'Types_Wpml_Field_Group_String_Description' => dirname( __FILE__ ) . '/models/wpml/field/group/string/description.php',
application/controllers/{utils → admin_notice}/utils.php RENAMED
File without changes
application/controllers/ajax.php CHANGED
@@ -3,237 +3,74 @@
3
  /**
4
  * Main AJAX call controller for Types.
5
  *
6
- * When DOING_AJAX, you need to run initialize() to register the callbacks, only creating an instance will not be enough.
7
  *
8
- * When implementing AJAX actions, please follow these rules:
9
  *
10
- * 1. All AJAX action names are automatically prefixed with 'wp_ajax_types_'. Only lowercase characters and underscores
11
- * can be used.
12
- * 2. Action names (without a prefix) should be defined as constants, and be part of the Types_Ajax::$callbacks array.
13
- * 3. For each action, there should be a dedicated class implementing the Types_Ajax_Handler_Interface. Name of the class
14
- * must be Types_Ajax_Handler_{%capitalized_action_name}. So for example, for a hook to
15
- * 'wp_ajax_types_field_control_action' you need to create a class 'Types_Ajax_Handler_Field_Control_Action'.
16
- * 4. All callbacks must use the ajax_begin() and ajax_finish() methods.
17
  *
18
  * @since 2.0
19
  */
20
- final class Types_Ajax {
 
21
 
22
  // Action names
23
  const CALLBACK_FIELD_CONTROL_ACTION = 'field_control_action';
24
  const CALLBACK_CHECK_SLUG_CONFLICTS = 'check_slug_conflicts';
25
- const CALLBACK_SETTINGS_ACTION = 'settings_action';
26
-
27
-
28
- /** Prefix for the callback method name */
29
- const CALLBACK_PREFIX = 'callback_';
30
-
31
- /** Prefix for the handler class name */
32
- const HANDLER_CLASS_PREFIX = 'Types_Ajax_Handler_';
33
-
34
- const DELIMITER = '_';
35
-
36
-
37
- private static $instance;
38
-
39
-
40
- public static function get_instance() {
41
- if( null == self::$instance ) {
42
- self::$instance = new self();
43
- }
44
- return self::$instance;
45
- }
46
-
47
-
48
- public static function initialize() {
49
- $instance = self::get_instance();
50
-
51
- $instance->register_callbacks();
52
- $instance->additional_ajax_init();
53
- }
54
-
55
-
56
- private function __clone() { }
57
-
58
-
59
- private function __construct() { }
60
 
61
 
62
  private static $callbacks = array(
63
  self::CALLBACK_FIELD_CONTROL_ACTION,
64
  self::CALLBACK_CHECK_SLUG_CONFLICTS,
65
  self::CALLBACK_SETTINGS_ACTION,
 
 
 
 
 
 
 
 
66
  );
67
 
68
 
69
- private $callbacks_registered = false;
70
 
71
 
72
- /**
73
- * Register all callbacks.
74
- *
75
- * Each callback is registered as a "types_{$callback}" action and needs to have a "callback_{$callback_name}"
76
- * method in this class.
77
- *
78
- * @since 2.0
79
- */
80
- private function register_callbacks() {
81
-
82
- if( $this->callbacks_registered ) {
83
- return;
84
- }
85
-
86
- foreach( self::$callbacks as $callback_name ) {
87
- add_action( 'wp_ajax_types_' . $callback_name, array( $this, self::CALLBACK_PREFIX . $callback_name ) );
88
- }
89
-
90
- $this->callbacks_registered = true;
91
-
92
- }
93
-
94
-
95
- public function get_action_js_name( $action ) {
96
- return 'types_' . $action;
97
- }
98
-
99
-
100
- /**
101
- * Handle a call to undefined method on this class, hopefully an AJAX call.
102
- *
103
- * @param string $name Method name.
104
- * @param array $parameters Method parameters.
105
- * @since 2.1
106
- */
107
- public function __call( $name, $parameters ) {
108
- // Check for the callback prefix in the method name
109
- $name_parts = explode( self::DELIMITER, $name );
110
- if( 0 !== strcmp( $name_parts[0] . self::DELIMITER, self::CALLBACK_PREFIX ) ) {
111
- // Not a callback, resign.
112
- return;
113
- }
114
-
115
- // Deduct the handler class name from the callback name
116
- unset( $name_parts[0] );
117
- $class_name = implode( self::DELIMITER, $name_parts );
118
- $class_name = strtolower( $class_name );
119
- $class_name = mb_convert_case( $class_name, MB_CASE_TITLE );
120
- $class_name = self::HANDLER_CLASS_PREFIX . $class_name;
121
-
122
- // Obtain an instance of the handler class.
123
- try {
124
- /** @var Types_Ajax_Handler_Interface $handler */
125
- $handler = new $class_name( $this );
126
- } catch( Exception $e ) {
127
- // The handler class could not have been instantiated, resign.
128
- return;
129
- }
130
-
131
- // Success
132
- $handler->process_call( $parameters );
133
- }
134
-
135
-
136
-
137
- /**
138
- * Perform basic authentication check.
139
- *
140
- * Check user capability and nonce. Dies with an error message (wp_json_error() by default) if the authentization
141
- * is not successful.
142
- *
143
- * @param array $args Arguments (
144
- * @type string $nonce Name of the nonce that should be verified. Mandatory
145
- * @type string $nonce_parameter Name of the parameter containing nonce value.
146
- * Optional, defaults to "wpnonce".
147
- * @type string $parameter_source Determines where the function should look for the nonce parameter.
148
- * Allowed values are 'get' and 'post'. Optional, defaults to 'post'.
149
- * @type string $capability_needed Capability that user has to have in order to pass the check.
150
- * Optional, default is "manage_options".
151
- * @type string $type_of_death How to indicate failure:
152
- * - 'die': Call wp_json_error with array( 'type' => 'capability'|'nonce', 'message' => $error_message )
153
- * - 'return': Do not die, just return the error array as above.
154
- * Optional, default is 'die'.
155
- * )
156
- *
157
- * @return array|void
158
- *
159
- * @since 2.0
160
- */
161
- private function ajax_authenticate( $args = array() ) {
162
- // Read arguments
163
- $type_of_death = wpcf_getarr( $args, 'type_of_death', 'die', array( 'die', 'return' ) );
164
- $nonce_name = wpcf_getarr( $args, 'nonce' );
165
- $nonce_parameter = wpcf_getarr( $args, 'nonce_parameter', 'wpnonce' );
166
- $capability_needed = wpcf_getarr( $args, 'capability_needed', 'manage_options' );
167
- $parameter_source_name = wpcf_getarr( $args, 'parameter_source', 'post', array( 'get', 'post' ) );
168
- $parameter_source = ( $parameter_source_name == 'get' ) ? $_GET : $_POST;
169
-
170
- $is_error = false;
171
- $error_message = null;
172
- $error_type = null;
173
-
174
- // Check permissions
175
- if ( ! current_user_can( $capability_needed ) ) {
176
- $error_message = __( 'You do not have permissions for that.', 'wpcf' );
177
- $error_type = 'capability';
178
- $is_error = true;
179
- }
180
-
181
- // Check nonce
182
- if ( !$is_error && !wp_verify_nonce( wpcf_getarr( $parameter_source, $nonce_parameter, '' ), $nonce_name ) ) {
183
- $error_message = __( 'Your security credentials have expired. Please reload the page to get new ones.', 'wpcf' );
184
- $error_type = 'nonce';
185
- $is_error = true;
186
- }
187
-
188
- if( $is_error ) {
189
- $error_description = array( 'type' => $error_type, 'message' => $error_message );
190
- switch( $type_of_death ) {
191
-
192
- case 'die':
193
- wp_send_json_error( $error_description );
194
- break;
195
-
196
- case 'return':
197
- default:
198
- return $error_description;
199
- }
200
  }
201
-
202
- return true;
203
  }
204
 
205
-
206
  /**
207
- * Begin an AJAX call handling.
208
- *
209
- * To be extended in the future.
210
- *
211
- * @param array $args See ajax_authenticate for details
212
- * @return array|void
213
- * @since 2.0
214
  */
215
- public function ajax_begin( $args ) {
216
- return $this->ajax_authenticate( $args );
217
  }
218
 
219
 
220
  /**
221
- * Complete an AJAX call handling.
222
- *
223
- * Sends a success/error response in a standard way.
224
- *
225
- * To be extended in the future.
226
- *
227
- * @param array $response Custom response data
228
- * @param bool $is_success
229
- * @since 2.0
230
  */
231
- public function ajax_finish( $response, $is_success = true ) {
232
- if( $is_success ) {
233
- wp_send_json_success( $response );
234
- } else {
235
- wp_send_json_error( $response );
236
- }
237
  }
238
 
239
 
@@ -245,7 +82,7 @@ final class Types_Ajax {
245
  *
246
  * @since 2.1
247
  */
248
- private function additional_ajax_init() {
249
 
250
  // On the Add Term page, we need to initialize the page controller WPCF_GUI_Term_Field_Editing
251
  // so that it saves term fields (if there are any).
@@ -258,7 +95,7 @@ final class Types_Ajax {
258
  // in those functions are set to true (which means that the call was not handled).
259
  add_action( 'wp_ajax_wpcf_ajax', array( $this, 'do_legacy_wpcf_ajax' ) );
260
  }
261
-
262
 
263
  /**
264
  * On the Add Term page, we need to initialize the page controller WPCF_GUI_Term_Field_Editing
@@ -275,8 +112,8 @@ final class Types_Ajax {
275
  // to edit-{$taxonomy}. When creating the term on the post edit page, for example, the screen is not set. We use
276
  // this to further limit the resource wasting. However, initializing the controller even if it's not supposed to
277
  // will not lead to any errors - it gives up gracefully.
278
- $action = wpcf_getpost( 'action' );
279
- $screen = wpcf_getpost( 'screen', null );
280
  if( 'add-tag' == $action && null !== $screen ) {
281
  WPCF_GUI_Term_Field_Editing::initialize();
282
  }
3
  /**
4
  * Main AJAX call controller for Types.
5
  *
6
+ * This class can be used in any way only after the Common Library is loaded.
7
  *
8
+ * Please read the important usage instructions for the superclass:
9
  *
10
+ * @inheritdoc
 
 
 
 
 
 
11
  *
12
  * @since 2.0
13
  */
14
+ class Types_Ajax extends Toolset_Ajax {
15
+ const HANDLER_CLASS_PREFIX = 'Types_Ajax_Handler_';
16
 
17
  // Action names
18
  const CALLBACK_FIELD_CONTROL_ACTION = 'field_control_action';
19
  const CALLBACK_CHECK_SLUG_CONFLICTS = 'check_slug_conflicts';
20
+ const CALLBACK_SETTINGS_ACTION = 'settings_action';
21
+ const CALLBACK_M2M_MIGRATION_PREVIEW_RELATIONSHIPS = 'm2m_migration_preview_relationships';
22
+ const CALLBACK_M2M_MIGRATION_PREVIEW_ASSOCIATIONS = 'm2m_migration_preview_associations';
23
+ const CALLBACK_CUSTOM_FIELDS_ACTION = 'custom_fields_action';
24
+ const CALLBACK_RELATIONSHIPS_ACTION = 'relationships_action';
25
+ const CALLBACK_RELATED_CONTENT_ACTION = 'related_content_action';
26
+ const CALLBACK_FIELD_GROUP_EDIT_ACTION = 'field_group_edit_action';
27
+ const CALLBACK_REPEATABLE_GROUP = 'repeatable_group';
28
+ const CALLBACK_POST_REFERENCE_FIELD = 'post_reference_field';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
 
31
  private static $callbacks = array(
32
  self::CALLBACK_FIELD_CONTROL_ACTION,
33
  self::CALLBACK_CHECK_SLUG_CONFLICTS,
34
  self::CALLBACK_SETTINGS_ACTION,
35
+ self::CALLBACK_M2M_MIGRATION_PREVIEW_RELATIONSHIPS,
36
+ self::CALLBACK_M2M_MIGRATION_PREVIEW_ASSOCIATIONS,
37
+ self::CALLBACK_CUSTOM_FIELDS_ACTION,
38
+ self::CALLBACK_RELATIONSHIPS_ACTION,
39
+ self::CALLBACK_RELATED_CONTENT_ACTION,
40
+ self::CALLBACK_FIELD_GROUP_EDIT_ACTION,
41
+ self::CALLBACK_REPEATABLE_GROUP,
42
+ self::CALLBACK_POST_REFERENCE_FIELD,
43
  );
44
 
45
 
46
+ private static $types_instance;
47
 
48
 
49
+ public static function get_instance() {
50
+ if( null === self::$types_instance ) {
51
+ self::$types_instance = new self();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
+ return self::$types_instance;
 
54
  }
55
 
 
56
  /**
57
+ * @inheritdoc
58
+ * @param bool $capitalized
59
+ * @return string
60
+ * @since m2m
 
 
 
61
  */
62
+ protected function get_plugin_slug( $capitalized = false ) {
63
+ return ( $capitalized ? 'Types' : 'types' );
64
  }
65
 
66
 
67
  /**
68
+ * @inheritdoc
69
+ * @return array
70
+ * @since m2m
 
 
 
 
 
 
71
  */
72
+ protected function get_callback_names() {
73
+ return self::$callbacks;
 
 
 
 
74
  }
75
 
76
 
82
  *
83
  * @since 2.1
84
  */
85
+ protected function additional_ajax_init() {
86
 
87
  // On the Add Term page, we need to initialize the page controller WPCF_GUI_Term_Field_Editing
88
  // so that it saves term fields (if there are any).
95
  // in those functions are set to true (which means that the call was not handled).
96
  add_action( 'wp_ajax_wpcf_ajax', array( $this, 'do_legacy_wpcf_ajax' ) );
97
  }
98
+
99
 
100
  /**
101
  * On the Add Term page, we need to initialize the page controller WPCF_GUI_Term_Field_Editing
112
  // to edit-{$taxonomy}. When creating the term on the post edit page, for example, the screen is not set. We use
113
  // this to further limit the resource wasting. However, initializing the controller even if it's not supposed to
114
  // will not lead to any errors - it gives up gracefully.
115
+ $action = toolset_getpost( 'action' );
116
+ $screen = toolset_getpost( 'screen', null );
117
  if( 'add-tag' == $action && null !== $screen ) {
118
  WPCF_GUI_Term_Field_Editing::initialize();
119
  }
application/controllers/asset/manager.php CHANGED
@@ -25,11 +25,19 @@ final class Types_Asset_Manager extends Toolset_Assets_Manager {
25
  const SCRIPT_ADDITIONAL_VALIDATION_RULES = 'wpcf-form-validation-additional';
26
 
27
 
 
 
 
 
28
  /**
29
  * @return Types_Asset_Manager
30
  */
31
  static public function get_instance() {
32
- return parent::getInstance();
 
 
 
 
33
  }
34
 
35
 
25
  const SCRIPT_ADDITIONAL_VALIDATION_RULES = 'wpcf-form-validation-additional';
26
 
27
 
28
+
29
+ private static $types_instance;
30
+
31
+
32
  /**
33
  * @return Types_Asset_Manager
34
  */
35
  static public function get_instance() {
36
+ if( null === self::$types_instance ) {
37
+ self::$types_instance = new self();
38
+ }
39
+
40
+ return self::$types_instance;
41
  }
42
 
43
 
application/models/field/{type/definition → gateway}/checkbox.php RENAMED
File without changes
application/models/field/{type/definition → gateway}/checkboxes.php RENAMED
File without changes
application/models/field/{type/definition → gateway}/date.php RENAMED
File without changes
application/models/field/{type/definition → gateway}/numeric.php RENAMED
File without changes
application/models/field/{type/definition → gateway}/radio.php RENAMED
File without changes
application/models/field/{type/definition → gateway}/select.php RENAMED
File without changes
application/models/field/{type/definition → gateway}/singular.php RENAMED
File without changes
readme.txt CHANGED
@@ -1,5 +1,5 @@
1
  === Toolset Types - Custom Post Types, Custom Fields and Taxonomies ===
2
- Contributors: AmirHelzer, brucepearson, christianglingener, jadpm, zaantar
3
  Donate link: http://wp-types.com
4
  Tags: CMS, custom field, custom fields, custom post type, custom post types, field, fields post, post type, post types, taxonomies, taxonomy, toolset
5
  Text Domain: wpcf
@@ -7,7 +7,7 @@ Domain Path: /embedded/locale
7
  License: GPLv2
8
  Requires at least: 3.7
9
  Tested up to: 4.9
10
- Stable tag: 2.2.21
11
 
12
  The complete and reliable plugin for managing custom post types, custom taxonomies and custom fields.
13
 
@@ -158,6 +158,12 @@ Additionally, Types is the only plugin that lets you define parent/child relatio
158
 
159
  == Changelog ==
160
 
 
 
 
 
 
 
161
  = 2.2.21 =
162
  * Fixed a compatibility issue with Beaver Builder
163
  * Fixed an issue with extra backslashes when using quotes in field name
1
  === Toolset Types - Custom Post Types, Custom Fields and Taxonomies ===
2
+ Contributors: AmirHelzer, brucepearson, christianglingener, jadpm, zaantar, jmilczarek, kouratoras, displaynone
3
  Donate link: http://wp-types.com
4
  Tags: CMS, custom field, custom fields, custom post type, custom post types, field, fields post, post type, post types, taxonomies, taxonomy, toolset
5
  Text Domain: wpcf
7
  License: GPLv2
8
  Requires at least: 3.7
9
  Tested up to: 4.9
10
+ Stable tag: 2.2.22
11
 
12
  The complete and reliable plugin for managing custom post types, custom taxonomies and custom fields.
13
 
158
 
159
  == Changelog ==
160
 
161
+ = 2.2.22 =
162
+ * First version of the public relationship API that will be sustainable also for many-to-many relationships.
163
+ * Added a warning about dropping the PHP 5.2 support (which is no longer officially supported anyway) in the near future.
164
+ * Fixed: Using the_title filter without the mandatory $id argument.
165
+ * Fixed: Deprecated function notice in PHP 7.2.
166
+
167
  = 2.2.21 =
168
  * Fixed a compatibility issue with Beaver Builder
169
  * Fixed an issue with extra backslashes when using quotes in field name
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInita469bff8809f0826cf254ebc61c9ca28::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInitc3c1dc77e2581741c891ff7b2bf920aa::getLoader();
vendor/composer/autoload_classmap.php CHANGED
@@ -96,24 +96,33 @@ return array(
96
  'FieldFactory' => $vendorDir . '/toolset/toolset-common/toolset-forms/classes/class.field_factory.php',
97
  'FormAbstract' => $vendorDir . '/toolset/toolset-common/toolset-forms/classes/abstract.form.php',
98
  'FormFactory' => $vendorDir . '/toolset/toolset-common/toolset-forms/classes/class.form_factory.php',
99
- 'IToolset_Association' => $vendorDir . '/toolset/toolset-common/inc/m2m/i_association.php',
 
 
 
 
 
 
100
  'IToolset_Element' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/element/i_element.php',
 
101
  'IToolset_Post' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/element/i_post.php',
102
  'IToolset_Post_Type' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type.php',
103
  'IToolset_Post_Type_From_Types' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type_from_types.php',
104
  'IToolset_Post_Type_Registered' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type_registered.php',
105
  'IToolset_Potential_Association_Query' => $vendorDir . '/toolset/toolset-common/inc/m2m/potential_association/query_interface.php',
106
  'IToolset_Query' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/i_query.php',
 
107
  'IToolset_Relationship_Database_Issue' => $vendorDir . '/toolset/toolset-common/inc/m2m/database/issue/interface.php',
108
- 'IToolset_Relationship_Definition' => $vendorDir . '/toolset/toolset-common/inc/m2m/definition/interface.php',
109
  'IToolset_Relationship_Origin' => $vendorDir . '/toolset/toolset-common/inc/m2m/origin/interface.php',
110
- 'IToolset_Relationship_Query_Cardinality_Match' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/cardinality_match/interface.php',
111
- 'IToolset_Relationship_Query_Condition' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/i_condition.php',
112
- 'IToolset_Relationship_Role' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_role/interface.php',
113
- 'IToolset_Relationship_Role_Parent_Child' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_role/parent_child_interface.php',
114
  'IToolset_Upgrade_Command' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/upgrade/command_interface.php',
115
  'ReCaptchaResponse' => $vendorDir . '/toolset/toolset-common/toolset-forms/js/recaptcha-php-1.11/recaptchalib.php',
116
  'Toolset_Admin_Bar_Menu' => $vendorDir . '/toolset/toolset-common/inc/toolset.admin.bar.menu.class.php',
 
117
  'Toolset_Admin_Notice_Abstract' => $vendorDir . '/toolset/toolset-common/utility/admin/notice/abstract.php',
118
  'Toolset_Admin_Notice_Dismissible' => $vendorDir . '/toolset/toolset-common/utility/admin/notice/dismissible.php',
119
  'Toolset_Admin_Notice_Error' => $vendorDir . '/toolset/toolset-common/utility/admin/notice/error.php',
@@ -126,17 +135,72 @@ return array(
126
  'Toolset_Admin_Notices_Manager' => $vendorDir . '/toolset/toolset-common/utility/admin/notices/manager.php',
127
  'Toolset_Ajax' => $vendorDir . '/toolset/toolset-common/inc/toolset.ajax.class.php',
128
  'Toolset_Ajax_Handler_Abstract' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/abstract.php',
 
 
 
 
 
129
  'Toolset_Ajax_Handler_Interface' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/interface.php',
 
130
  'Toolset_Ajax_Handler_Migrate_To_M2M' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/migrate_to_m2m.php',
 
 
 
131
  'Toolset_ArrayUtils' => $vendorDir . '/toolset/toolset-common/utility/utils.php',
132
- 'Toolset_Asset_Manager' => $vendorDir . '/toolset/toolset-common/inc/controller/asset_manager.php',
133
  'Toolset_Assets_Manager' => $vendorDir . '/toolset/toolset-common/inc/toolset.assets.manager.class.php',
134
- 'Toolset_Association' => $vendorDir . '/toolset/toolset-common/inc/m2m/association.php',
135
- 'Toolset_Association_Base' => $vendorDir . '/toolset/toolset-common/inc/m2m/association_base.php',
136
- 'Toolset_Association_Query' => $vendorDir . '/toolset/toolset-common/inc/m2m/association_query.php',
137
- 'Toolset_Association_Repository' => $vendorDir . '/toolset/toolset-common/inc/m2m/association_repository.php',
138
- 'Toolset_Association_Transitional' => $vendorDir . '/toolset/toolset-common/inc/m2m/association_transitional.php',
139
- 'Toolset_Association_Translation_Set' => $vendorDir . '/toolset/toolset-common/inc/m2m/association_translation_set.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  'Toolset_Bootstrap_Loader' => $vendorDir . '/toolset/toolset-common/inc/toolset.bootstrap.loader.class.php',
141
  'Toolset_Common_Autoloader' => $vendorDir . '/toolset/toolset-common/utility/autoloader.php',
142
  'Toolset_Common_Bootstrap' => $vendorDir . '/toolset/toolset-common/bootstrap.php',
@@ -150,11 +214,14 @@ return array(
150
  'Toolset_Condition_Plugin_Layouts_Missing' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/layouts/missing.php',
151
  'Toolset_Condition_Plugin_Layouts_No_Items' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/layouts/no-items.php',
152
  'Toolset_Condition_Plugin_Types_Active' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/types/active.php',
 
153
  'Toolset_Condition_Plugin_Types_Missing' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/types/missing.php',
154
  'Toolset_Condition_Plugin_Types_Ready_For_M2M' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/types/ready_for_m2m.php',
155
  'Toolset_Condition_Plugin_Views_Active' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/views/active.php',
156
  'Toolset_Condition_Plugin_Views_Missing' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/views/missing.php',
157
  'Toolset_Condition_Plugin_Wpml_Doesnt_Support_M2m' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/wpml/doesnt_support_m2m.php',
 
 
158
  'Toolset_Condition_Theme_Avada_Not_Active_Or_Greater_Equal_5_0' => $vendorDir . '/toolset/toolset-common/utility/condition/theme/avada/not-active-or-greater-equal-5-0.php',
159
  'Toolset_Condition_Theme_Layouts_Support_Native_Available' => $vendorDir . '/toolset/toolset-common/utility/condition/theme/layouts-support/native/available.php',
160
  'Toolset_Condition_Theme_Layouts_Support_Native_Missing' => $vendorDir . '/toolset/toolset-common/utility/condition/theme/layouts-support/native/missing.php',
@@ -169,8 +236,10 @@ return array(
169
  'Toolset_Condition_Theme_Toolset_Based_Active' => $vendorDir . '/toolset/toolset-common/utility/condition/theme/toolset-based/active.php',
170
  'Toolset_Condition_Theme_Toolset_Based_Inactive' => $vendorDir . '/toolset/toolset-common/utility/condition/theme/toolset-based/inactive.php',
171
  'Toolset_Condition_User_Role_Admin' => $vendorDir . '/toolset/toolset-common/utility/condition/user/role/admin.php',
172
- 'Toolset_Constants' => $vendorDir . '/toolset/toolset-common/inc/controller/constants.php',
173
- 'Toolset_Controller_Admin_Notices' => $vendorDir . '/toolset/toolset-common/inc/controller/admin/notices.php',
 
 
174
  'Toolset_CssComponent' => $vendorDir . '/toolset/toolset-common/inc/toolset.css.component.class.php',
175
  'Toolset_Date' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
176
  'Toolset_DateParser' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
@@ -196,10 +265,12 @@ return array(
196
  'Toolset_Field_Definition' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition.php',
197
  'Toolset_Field_Definition_Abstract' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_abstract.php',
198
  'Toolset_Field_Definition_Factory' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_factory.php',
 
199
  'Toolset_Field_Definition_Factory_Post' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_post.php',
200
  'Toolset_Field_Definition_Factory_Term' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_term.php',
201
  'Toolset_Field_Definition_Factory_User' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_user.php',
202
  'Toolset_Field_Definition_Generic' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_generic.php',
 
203
  'Toolset_Field_Definition_Post' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_post.php',
204
  'Toolset_Field_Definition_Term' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_term.php',
205
  'Toolset_Field_Definition_User' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_user.php',
@@ -245,6 +316,7 @@ return array(
245
  'Toolset_Field_Type_Definition_Select' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/type/definition/select.php',
246
  'Toolset_Field_Type_Definition_Singular' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/type/definition/singular.php',
247
  'Toolset_Field_Utils' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/utils.php',
 
248
  'Toolset_Functions' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
249
  'Toolset_Gui_Base' => $vendorDir . '/toolset/toolset-common/utility/gui-base/main.php',
250
  'Toolset_HelpVideo' => $vendorDir . '/toolset/toolset-common/utility/help-videos/toolset-help-videos.php',
@@ -254,9 +326,17 @@ return array(
254
  'Toolset_Menu' => $vendorDir . '/toolset/toolset-common/inc/toolset.menu.class.php',
255
  'Toolset_Naming_Helper' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/naming_helper.php',
256
  'Toolset_Object_Relationship' => $vendorDir . '/toolset/toolset-common/inc/toolset.object.relationship.class.php',
 
 
 
 
 
 
 
257
  'Toolset_Parser' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
258
  'Toolset_Post' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/element/post.php',
259
  'Toolset_Post_Translation_Set' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/element/post_translation_set.php',
 
260
  'Toolset_Post_Type_Exclude_List' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/excluded_list.php',
261
  'Toolset_Post_Type_Factory' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/factory.php',
262
  'Toolset_Post_Type_From_Types' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/from_types.php',
@@ -268,63 +348,67 @@ return array(
268
  'Toolset_Potential_Association_Query_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/potential_association/query_factory.php',
269
  'Toolset_Potential_Association_Query_Posts' => $vendorDir . '/toolset/toolset-common/inc/m2m/potential_association/query_posts.php',
270
  'Toolset_Promotion' => $vendorDir . '/toolset/toolset-common/inc/toolset.promotion.class.php',
 
 
 
 
 
 
 
271
  'Toolset_Regex' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
272
  'Toolset_Relationship_Cardinality' => $vendorDir . '/toolset/toolset-common/inc/m2m/cardinality.php',
273
  'Toolset_Relationship_Controller' => $vendorDir . '/toolset/toolset-common/inc/m2m/controller.php',
274
  'Toolset_Relationship_Database_Issue_Missing_Element' => $vendorDir . '/toolset/toolset-common/inc/m2m/database/issue/missing_element.php',
275
  'Toolset_Relationship_Database_Operations' => $vendorDir . '/toolset/toolset-common/inc/m2m/database/operations.php',
276
  'Toolset_Relationship_Database_Unique_Table_Alias' => $vendorDir . '/toolset/toolset-common/inc/m2m/database/unique_table_alias.php',
277
- 'Toolset_Relationship_Definition' => $vendorDir . '/toolset/toolset-common/inc/m2m/definition/definition.php',
278
- 'Toolset_Relationship_Definition_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/definition/factory.php',
279
- 'Toolset_Relationship_Definition_Persistence' => $vendorDir . '/toolset/toolset-common/inc/m2m/definition/persistence.php',
280
- 'Toolset_Relationship_Definition_Repository' => $vendorDir . '/toolset/toolset-common/inc/m2m/definition/repository.php',
281
- 'Toolset_Relationship_Definition_Translator' => $vendorDir . '/toolset/toolset-common/inc/m2m/definition/translator.php',
282
  'Toolset_Relationship_Distinct_Post_Query' => $vendorDir . '/toolset/toolset-common/inc/m2m/potential_association/distinct_post_query.php',
283
  'Toolset_Relationship_Driver' => $vendorDir . '/toolset/toolset-common/inc/m2m/driver.php',
284
  'Toolset_Relationship_Driver_Base' => $vendorDir . '/toolset/toolset-common/inc/m2m/driver_base.php',
285
  'Toolset_Relationship_Element_Type' => $vendorDir . '/toolset/toolset-common/inc/m2m/element_type.php',
286
- 'Toolset_Relationship_Migration' => $vendorDir . '/toolset/toolset-common/inc/m2m/migration.php',
287
- 'Toolset_Relationship_Migration_Associations' => $vendorDir . '/toolset/toolset-common/inc/m2m/migration_associations.php',
288
- 'Toolset_Relationship_Multilingual_Mode' => $vendorDir . '/toolset/toolset-common/inc/m2m/multilingual_mode.php',
 
289
  'Toolset_Relationship_Origin_Post_Reference_Field' => $vendorDir . '/toolset/toolset-common/inc/m2m/origin/post_reference_field.php',
290
  'Toolset_Relationship_Origin_Repeatable_Group' => $vendorDir . '/toolset/toolset-common/inc/m2m/origin/repeatable_group.php',
291
  'Toolset_Relationship_Origin_Wizard' => $vendorDir . '/toolset/toolset-common/inc/m2m/origin/wizard.php',
292
- 'Toolset_Relationship_Query' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/relationship_query.php',
293
  'Toolset_Relationship_Query_Base' => $vendorDir . '/toolset/toolset-common/inc/m2m/query_base.php',
294
  'Toolset_Relationship_Query_Cache' => $vendorDir . '/toolset/toolset-common/inc/m2m/query_cache.php',
295
- 'Toolset_Relationship_Query_Cardinality_Match_Conjunction' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/cardinality_match/conjunction.php',
296
- 'Toolset_Relationship_Query_Cardinality_Match_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/cardinality_match/factory.php',
297
- 'Toolset_Relationship_Query_Cardinality_Match_Operators' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/cardinality_match/operators.php',
298
- 'Toolset_Relationship_Query_Cardinality_Match_Single' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/cardinality_match/single.php',
299
- 'Toolset_Relationship_Query_Condition' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/abstract.php',
300
- 'Toolset_Relationship_Query_Condition_And' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/and.php',
301
- 'Toolset_Relationship_Query_Condition_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition_factory.php',
302
- 'Toolset_Relationship_Query_Condition_Has_Active_Types' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/has_active_types.php',
303
- 'Toolset_Relationship_Query_Condition_Has_Cardinality' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/has_cardinality.php',
304
- 'Toolset_Relationship_Query_Condition_Has_Domain' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/has_domain.php',
305
- 'Toolset_Relationship_Query_Condition_Is_Active' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/is_active.php',
306
- 'Toolset_Relationship_Query_Condition_Is_Boolean_Flag' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/is_boolean_flag.php',
307
- 'Toolset_Relationship_Query_Condition_Is_Legacy' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/is_legacy.php',
308
- 'Toolset_Relationship_Query_Condition_Operator' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/operator.php',
309
- 'Toolset_Relationship_Query_Condition_Or' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/or.php',
310
- 'Toolset_Relationship_Query_Condition_Origin' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/origin.php',
311
- 'Toolset_Relationship_Query_Condition_Tautology' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/tautology.php',
312
- 'Toolset_Relationship_Query_Condition_Type' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/condition/type.php',
313
- 'Toolset_Relationship_Query_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/query_factory.php',
314
- 'Toolset_Relationship_Query_Sql_Expression_Builder' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/sql_expression_builder.php',
315
- 'Toolset_Relationship_Query_V2' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_query/relationship_query_v2.php',
316
- 'Toolset_Relationship_Role' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_role/role.php',
317
- 'Toolset_Relationship_Role_Abstract' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_role/abstract.php',
318
- 'Toolset_Relationship_Role_Child' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_role/child.php',
319
- 'Toolset_Relationship_Role_Intermediary' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_role/intermediary.php',
320
- 'Toolset_Relationship_Role_Parent' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship_role/parent.php',
321
- 'Toolset_Relationship_Scope' => $vendorDir . '/toolset/toolset-common/inc/m2m/scope.php',
322
  'Toolset_Relationship_Service' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/relationship_service.php',
323
- 'Toolset_Relationship_Slug_Validator' => $vendorDir . '/toolset/toolset-common/inc/m2m/slug_validator.php',
324
  'Toolset_Relationship_Table_Name' => $vendorDir . '/toolset/toolset-common/inc/m2m/database/table_name.php',
325
  'Toolset_Relationship_Utils' => $vendorDir . '/toolset/toolset-common/inc/m2m/utils.php',
326
- 'Toolset_Relationship_WPML_Interoperability' => $vendorDir . '/toolset/toolset-common/inc/m2m/wpml_interoperability.php',
327
  'Toolset_Relevanssi_Compatibility' => $vendorDir . '/toolset/toolset-common/inc/toolset.relevanssi.compatibility.class.php',
 
328
  'Toolset_Result' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/result.php',
329
  'Toolset_Result_Set' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/result_set.php',
330
  'Toolset_Result_Updated' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/result_updated.php',
@@ -340,6 +424,7 @@ return array(
340
  'Toolset_Shortcode_Transformer' => $vendorDir . '/toolset/toolset-common/inc/toolset.shortcode.transformer.class.php',
341
  'Toolset_Stack' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
342
  'Toolset_Style' => $vendorDir . '/toolset/toolset-common/inc/toolset.assets.manager.class.php',
 
343
  'Toolset_Tokenizer' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
344
  'Toolset_Twig_Autoloader' => $vendorDir . '/toolset/toolset-common/utility/gui-base/twig_autoloader.php',
345
  'Toolset_Twig_Dialog_Box' => $vendorDir . '/toolset/toolset-common/utility/gui-base/twig_dialog_box.php',
@@ -356,6 +441,7 @@ return array(
356
  'Toolset_User_Editors_Editor_Basic' => $vendorDir . '/toolset/toolset-common/user-editors/editor/basic.php',
357
  'Toolset_User_Editors_Editor_Beaver' => $vendorDir . '/toolset/toolset-common/user-editors/editor/beaver.php',
358
  'Toolset_User_Editors_Editor_Divi' => $vendorDir . '/toolset/toolset-common/user-editors/editor/divi.php',
 
359
  'Toolset_User_Editors_Editor_Interface' => $vendorDir . '/toolset/toolset-common/user-editors/editor/interface.php',
360
  'Toolset_User_Editors_Editor_Native' => $vendorDir . '/toolset/toolset-common/user-editors/editor/native.php',
361
  'Toolset_User_Editors_Editor_Screen_Abstract' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/abstract.php',
@@ -366,6 +452,7 @@ return array(
366
  'Toolset_User_Editors_Editor_Screen_Beaver_Frontend_Editor' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/beaver/frontend-editor.php',
367
  'Toolset_User_Editors_Editor_Screen_Divi_Backend' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/divi/backend.php',
368
  'Toolset_User_Editors_Editor_Screen_Divi_Frontend' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/divi/frontend.php',
 
369
  'Toolset_User_Editors_Editor_Screen_Interface' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/interface.php',
370
  'Toolset_User_Editors_Editor_Screen_Native_Backend' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/native/backend.php',
371
  'Toolset_User_Editors_Editor_Screen_Visual_Composer_Backend' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/visual-composer/backend.php',
@@ -385,6 +472,12 @@ return array(
385
  'Toolset_VideoDetachedPage' => $vendorDir . '/toolset/toolset-common/utility/help-videos/toolset-help-videos.php',
386
  'Toolset_WPLogger' => $vendorDir . '/toolset/toolset-common/inc/toolset.wplogger.class.php',
387
  'Toolset_WPML_Compatibility' => $vendorDir . '/toolset/toolset-common/inc/toolset.wpml.compatibility.class.php',
 
 
 
 
 
 
388
  'Toolset_Wpml_Utils' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/wpml_utils.php',
389
  'Twig_Autoloader' => $vendorDir . '/twig/twig/lib/Twig/Autoloader.php',
390
  'Twig_BaseNodeVisitor' => $vendorDir . '/twig/twig/lib/Twig/BaseNodeVisitor.php',
@@ -611,14 +704,14 @@ return array(
611
  'Types_Field_Group_User_Factory' => $baseDir . '/application/models/field/group/user_factory.php',
612
  'Types_Field_Type_Converter' => $baseDir . '/application/controllers/field/type_converter.php',
613
  'Types_Field_Type_Definition' => $baseDir . '/application/models/field/type/definition.php',
614
- 'Types_Field_Type_Definition_Checkbox' => $baseDir . '/application/models/field/type/definition/checkbox.php',
615
- 'Types_Field_Type_Definition_Checkboxes' => $baseDir . '/application/models/field/type/definition/checkboxes.php',
616
- 'Types_Field_Type_Definition_Date' => $baseDir . '/application/models/field/type/definition/date.php',
617
  'Types_Field_Type_Definition_Factory' => $baseDir . '/application/models/field/type/definition_factory.php',
618
- 'Types_Field_Type_Definition_Numeric' => $baseDir . '/application/models/field/type/definition/numeric.php',
619
- 'Types_Field_Type_Definition_Radio' => $baseDir . '/application/models/field/type/definition/radio.php',
620
- 'Types_Field_Type_Definition_Select' => $baseDir . '/application/models/field/type/definition/select.php',
621
- 'Types_Field_Type_Definition_Singular' => $baseDir . '/application/models/field/type/definition/singular.php',
622
  'Types_Field_Utils' => $baseDir . '/application/controllers/field/utils.php',
623
  'Types_Frontend' => $baseDir . '/application/controllers/frontend.php',
624
  'Types_Helper_Condition' => $baseDir . '/application/models/helper/condition.php',
@@ -697,7 +790,7 @@ return array(
697
  'Types_Taxonomy' => $baseDir . '/application/models/taxonomy.php',
698
  'Types_Twig_Autoloader' => $baseDir . '/application/controllers/twig_autoloader.php',
699
  'Types_Upgrade' => $baseDir . '/application/controllers/upgrade.php',
700
- 'Types_Utils' => $baseDir . '/application/controllers/utils/utils.php',
701
  'Types_Utils_Post_Type_Option' => $baseDir . '/application/controllers/utils/post_type_option.php',
702
  'Types_Wpml_Field_Group' => $baseDir . '/application/models/wpml/field_group.php',
703
  'Types_Wpml_Field_Group_String' => $baseDir . '/application/models/wpml/field/group/string.php',
96
  'FieldFactory' => $vendorDir . '/toolset/toolset-common/toolset-forms/classes/class.field_factory.php',
97
  'FormAbstract' => $vendorDir . '/toolset/toolset-common/toolset-forms/classes/abstract.form.php',
98
  'FormFactory' => $vendorDir . '/toolset/toolset-common/toolset-forms/classes/class.form_factory.php',
99
+ 'IToolset_Association' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/interface.php',
100
+ 'IToolset_Association_Query_Condition' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/interface.php',
101
+ 'IToolset_Association_Query_Element_Selector' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/element_selector/interface.php',
102
+ 'IToolset_Association_Query_Orderby' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/orderby/interface.php',
103
+ 'IToolset_Association_Query_Restriction' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/restriction/interface.php',
104
+ 'IToolset_Association_Query_Result_Transformation' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/result_transformation/interface.php',
105
+ 'IToolset_Cron_Event' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/cron/event_interface.php',
106
  'IToolset_Element' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/element/i_element.php',
107
+ 'IToolset_Output_Template' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/renderer/output_template/interface.php',
108
  'IToolset_Post' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/element/i_post.php',
109
  'IToolset_Post_Type' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type.php',
110
  'IToolset_Post_Type_From_Types' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type_from_types.php',
111
  'IToolset_Post_Type_Registered' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type_registered.php',
112
  'IToolset_Potential_Association_Query' => $vendorDir . '/toolset/toolset-common/inc/m2m/potential_association/query_interface.php',
113
  'IToolset_Query' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/i_query.php',
114
+ 'IToolset_Query_Condition' => $vendorDir . '/toolset/toolset-common/inc/m2m/query/condition/interface.php',
115
  'IToolset_Relationship_Database_Issue' => $vendorDir . '/toolset/toolset-common/inc/m2m/database/issue/interface.php',
116
+ 'IToolset_Relationship_Definition' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/definition/interface.php',
117
  'IToolset_Relationship_Origin' => $vendorDir . '/toolset/toolset-common/inc/m2m/origin/interface.php',
118
+ 'IToolset_Relationship_Query_Cardinality_Match' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/cardinality_match/interface.php',
119
+ 'IToolset_Relationship_Query_Condition' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition/interface.php',
120
+ 'IToolset_Relationship_Role' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/role/interface.php',
121
+ 'IToolset_Relationship_Role_Parent_Child' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/role/parent_child_interface.php',
122
  'IToolset_Upgrade_Command' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/upgrade/command_interface.php',
123
  'ReCaptchaResponse' => $vendorDir . '/toolset/toolset-common/toolset-forms/js/recaptcha-php-1.11/recaptchalib.php',
124
  'Toolset_Admin_Bar_Menu' => $vendorDir . '/toolset/toolset-common/inc/toolset.admin.bar.menu.class.php',
125
+ 'Toolset_Admin_Controller' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/admin.php',
126
  'Toolset_Admin_Notice_Abstract' => $vendorDir . '/toolset/toolset-common/utility/admin/notice/abstract.php',
127
  'Toolset_Admin_Notice_Dismissible' => $vendorDir . '/toolset/toolset-common/utility/admin/notice/dismissible.php',
128
  'Toolset_Admin_Notice_Error' => $vendorDir . '/toolset/toolset-common/utility/admin/notice/error.php',
135
  'Toolset_Admin_Notices_Manager' => $vendorDir . '/toolset/toolset-common/utility/admin/notices/manager.php',
136
  'Toolset_Ajax' => $vendorDir . '/toolset/toolset-common/inc/toolset.ajax.class.php',
137
  'Toolset_Ajax_Handler_Abstract' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/abstract.php',
138
+ 'Toolset_Ajax_Handler_Get_Content_Template_Block_Preview' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/get_ct_block_preview.php',
139
+ 'Toolset_Ajax_Handler_Get_Post_By_Id' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/get_post_by_id.php',
140
+ 'Toolset_Ajax_Handler_Get_Term_By_Id' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/get_term_by_id.php',
141
+ 'Toolset_Ajax_Handler_Get_User_By_Id' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/get_user_by_id.php',
142
+ 'Toolset_Ajax_Handler_Get_View_Block_Preview' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/get_view_block_preview.php',
143
  'Toolset_Ajax_Handler_Interface' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/interface.php',
144
+ 'Toolset_Ajax_Handler_Intermediary_Post_Cleanup' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/intermediary_post_cleanup.php',
145
  'Toolset_Ajax_Handler_Migrate_To_M2M' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/migrate_to_m2m.php',
146
+ 'Toolset_Ajax_Handler_Select2_Suggest_Posts_By_Title' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_posts_by_title.php',
147
+ 'Toolset_Ajax_Handler_Select2_Suggest_Terms' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_terms.php',
148
+ 'Toolset_Ajax_Handler_Select2_Suggest_Users' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_users.php',
149
  'Toolset_ArrayUtils' => $vendorDir . '/toolset/toolset-common/utility/utils.php',
150
+ 'Toolset_Asset_Manager' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/asset_manager.php',
151
  'Toolset_Assets_Manager' => $vendorDir . '/toolset/toolset-common/inc/toolset.assets.manager.class.php',
152
+ 'Toolset_Association' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/association.php',
153
+ 'Toolset_Association_Cleanup_Association' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/cleanup/association.php',
154
+ 'Toolset_Association_Cleanup_Cron_Event' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/cleanup/cron_event.php',
155
+ 'Toolset_Association_Cleanup_Cron_Handler' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/cleanup/cron_handler.php',
156
+ 'Toolset_Association_Cleanup_Dangling_Intermediary_Posts' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/cleanup/dangling_intermediary_posts.php',
157
+ 'Toolset_Association_Cleanup_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/cleanup/factory.php',
158
+ 'Toolset_Association_Cleanup_Post' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/cleanup/post.php',
159
+ 'Toolset_Association_Cleanup_Troubleshooting_Section' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/cleanup/troubleshooting_section.php',
160
+ 'Toolset_Association_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/factory.php',
161
+ 'Toolset_Association_Intermediary_Post_Persistence' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/intermediary_post_persistence.php',
162
+ 'Toolset_Association_Persistence' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/persistence.php',
163
+ 'Toolset_Association_Query' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/association_query.php',
164
+ 'Toolset_Association_Query_Condition' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/abstract.php',
165
+ 'Toolset_Association_Query_Condition_Association_Id' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/association_id.php',
166
+ 'Toolset_Association_Query_Condition_Element_Id' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/element_id.php',
167
+ 'Toolset_Association_Query_Condition_Element_Id_And_Domain' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/element_id_and_domain.php',
168
+ 'Toolset_Association_Query_Condition_Element_Status' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/element_status.php',
169
+ 'Toolset_Association_Query_Condition_Empty_Intermediary' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/empty_intermediary.php',
170
+ 'Toolset_Association_Query_Condition_Exclude_Element' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/exclude_element.php',
171
+ 'Toolset_Association_Query_Condition_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition_factory.php',
172
+ 'Toolset_Association_Query_Condition_Has_Active_Relationship' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/has_active_relationship.php',
173
+ 'Toolset_Association_Query_Condition_Has_Domain' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/has_domain.php',
174
+ 'Toolset_Association_Query_Condition_Has_Domain_And_Type' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/has_domain_and_type.php',
175
+ 'Toolset_Association_Query_Condition_Has_Legacy_Relationship' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/has_legacy_relationship.php',
176
+ 'Toolset_Association_Query_Condition_Has_Type' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/has_type.php',
177
+ 'Toolset_Association_Query_Condition_Postmeta' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/postmeta.php',
178
+ 'Toolset_Association_Query_Condition_Relationship_Flag' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/relationship_flag.php',
179
+ 'Toolset_Association_Query_Condition_Relationship_Id' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/relationship_id.php',
180
+ 'Toolset_Association_Query_Condition_Search' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/search.php',
181
+ 'Toolset_Association_Query_Condition_Wp_Query' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/condition/wp_query.php',
182
+ 'Toolset_Association_Query_Element_Selector_Abstract' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/element_selector/abstract.php',
183
+ 'Toolset_Association_Query_Element_Selector_Default' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/element_selector/default.php',
184
+ 'Toolset_Association_Query_Element_Selector_Provider' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/element_selector/provider.php',
185
+ 'Toolset_Association_Query_Element_Selector_Wpml' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/element_selector/wpml.php',
186
+ 'Toolset_Association_Query_Orderby' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/orderby/abstract.php',
187
+ 'Toolset_Association_Query_Orderby_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/orderby_factory.php',
188
+ 'Toolset_Association_Query_Orderby_Nothing' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/orderby/nothing.php',
189
+ 'Toolset_Association_Query_Orderby_Postmeta' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/orderby/postmeta.php',
190
+ 'Toolset_Association_Query_Orderby_Title' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/orderby/title.php',
191
+ 'Toolset_Association_Query_Result_Transformation_Association_Instance' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/result_transformation/association_instance.php',
192
+ 'Toolset_Association_Query_Result_Transformation_Association_Uid' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/result_transformation/association_uid.php',
193
+ 'Toolset_Association_Query_Result_Transformation_Element_Id' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/result_transformation/element_id.php',
194
+ 'Toolset_Association_Query_Result_Transformation_Element_Instance' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/result_transformation/element_instance.php',
195
+ 'Toolset_Association_Query_Sql_Expression_Builder' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/sql_expression_builder.php',
196
+ 'Toolset_Association_Query_Table_Join_Manager' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/table_join_manager.php',
197
+ 'Toolset_Association_Query_V2' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/association_query_v2.php',
198
+ 'Toolset_Association_Query_Wpdb_Wrapper' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/query/wpdb_wrapper.php',
199
+ 'Toolset_Association_Translator' => $vendorDir . '/toolset/toolset-common/inc/m2m/association/translator.php',
200
+ 'Toolset_Blocks' => $vendorDir . '/toolset/toolset-common/toolset-blocks/toolset-blocks.php',
201
+ 'Toolset_Blocks_Content_Template' => $vendorDir . '/toolset/toolset-common/toolset-blocks/blocks/ct/ct.php',
202
+ 'Toolset_Blocks_Custom_HTML' => $vendorDir . '/toolset/toolset-common/toolset-blocks/blocks/custom-html/custom-html.php',
203
+ 'Toolset_Blocks_View' => $vendorDir . '/toolset/toolset-common/toolset-blocks/blocks/view/view.php',
204
  'Toolset_Bootstrap_Loader' => $vendorDir . '/toolset/toolset-common/inc/toolset.bootstrap.loader.class.php',
205
  'Toolset_Common_Autoloader' => $vendorDir . '/toolset/toolset-common/utility/autoloader.php',
206
  'Toolset_Common_Bootstrap' => $vendorDir . '/toolset/toolset-common/bootstrap.php',
214
  'Toolset_Condition_Plugin_Layouts_Missing' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/layouts/missing.php',
215
  'Toolset_Condition_Plugin_Layouts_No_Items' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/layouts/no-items.php',
216
  'Toolset_Condition_Plugin_Types_Active' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/types/active.php',
217
+ 'Toolset_Condition_Plugin_Types_Has_Legacy_Relationships' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/types/has_legacy_relationships.php',
218
  'Toolset_Condition_Plugin_Types_Missing' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/types/missing.php',
219
  'Toolset_Condition_Plugin_Types_Ready_For_M2M' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/types/ready_for_m2m.php',
220
  'Toolset_Condition_Plugin_Views_Active' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/views/active.php',
221
  'Toolset_Condition_Plugin_Views_Missing' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/views/missing.php',
222
  'Toolset_Condition_Plugin_Wpml_Doesnt_Support_M2m' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/wpml/doesnt_support_m2m.php',
223
+ 'Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/wpml/is_active_and_configured.php',
224
+ 'Toolset_Condition_Plugin_Wpml_Is_Current_Language_Default' => $vendorDir . '/toolset/toolset-common/utility/condition/plugin/wpml/is_current_language_default.php',
225
  'Toolset_Condition_Theme_Avada_Not_Active_Or_Greater_Equal_5_0' => $vendorDir . '/toolset/toolset-common/utility/condition/theme/avada/not-active-or-greater-equal-5-0.php',
226
  'Toolset_Condition_Theme_Layouts_Support_Native_Available' => $vendorDir . '/toolset/toolset-common/utility/condition/theme/layouts-support/native/available.php',
227
  'Toolset_Condition_Theme_Layouts_Support_Native_Missing' => $vendorDir . '/toolset/toolset-common/utility/condition/theme/layouts-support/native/missing.php',
236
  'Toolset_Condition_Theme_Toolset_Based_Active' => $vendorDir . '/toolset/toolset-common/utility/condition/theme/toolset-based/active.php',
237
  'Toolset_Condition_Theme_Toolset_Based_Inactive' => $vendorDir . '/toolset/toolset-common/utility/condition/theme/toolset-based/inactive.php',
238
  'Toolset_Condition_User_Role_Admin' => $vendorDir . '/toolset/toolset-common/utility/condition/user/role/admin.php',
239
+ 'Toolset_Constants' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/constants.php',
240
+ 'Toolset_Controller_Admin_Notices' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/admin/notices.php',
241
+ 'Toolset_Cron' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/cron/cron.php',
242
+ 'Toolset_Cron_Event' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/cron/event.php',
243
  'Toolset_CssComponent' => $vendorDir . '/toolset/toolset-common/inc/toolset.css.component.class.php',
244
  'Toolset_Date' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
245
  'Toolset_DateParser' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
265
  'Toolset_Field_Definition' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition.php',
266
  'Toolset_Field_Definition_Abstract' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_abstract.php',
267
  'Toolset_Field_Definition_Factory' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_factory.php',
268
+ 'Toolset_Field_Definition_Factory_Interface' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_interface.php',
269
  'Toolset_Field_Definition_Factory_Post' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_post.php',
270
  'Toolset_Field_Definition_Factory_Term' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_term.php',
271
  'Toolset_Field_Definition_Factory_User' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_user.php',
272
  'Toolset_Field_Definition_Generic' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_generic.php',
273
+ 'Toolset_Field_Definition_Interface' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_interface.php',
274
  'Toolset_Field_Definition_Post' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_post.php',
275
  'Toolset_Field_Definition_Term' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_term.php',
276
  'Toolset_Field_Definition_User' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/definition_user.php',
316
  'Toolset_Field_Type_Definition_Select' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/type/definition/select.php',
317
  'Toolset_Field_Type_Definition_Singular' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/type/definition/singular.php',
318
  'Toolset_Field_Utils' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/field/utils.php',
319
+ 'Toolset_Files' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/files.php',
320
  'Toolset_Functions' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
321
  'Toolset_Gui_Base' => $vendorDir . '/toolset/toolset-common/utility/gui-base/main.php',
322
  'Toolset_HelpVideo' => $vendorDir . '/toolset/toolset-common/utility/help-videos/toolset-help-videos.php',
326
  'Toolset_Menu' => $vendorDir . '/toolset/toolset-common/inc/toolset.menu.class.php',
327
  'Toolset_Naming_Helper' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/naming_helper.php',
328
  'Toolset_Object_Relationship' => $vendorDir . '/toolset/toolset-common/inc/toolset.object.relationship.class.php',
329
+ 'Toolset_Output_Template' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/renderer/output_template/abstract.php',
330
+ 'Toolset_Output_Template_Factory' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/renderer/output_template_factory.php',
331
+ 'Toolset_Output_Template_Phtml' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/renderer/output_template/phtml.php',
332
+ 'Toolset_Output_Template_Repository' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/renderer/output_template_repository.php',
333
+ 'Toolset_Output_Template_Repository_Abstract' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/renderer/output_template_repository_abstract.php',
334
+ 'Toolset_Output_Template_Static' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/renderer/output_template/static.php',
335
+ 'Toolset_Output_Template_Twig' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/renderer/output_template/twig.php',
336
  'Toolset_Parser' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
337
  'Toolset_Post' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/element/post.php',
338
  'Toolset_Post_Translation_Set' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/element/post_translation_set.php',
339
+ 'Toolset_Post_Type_Abstract' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/abstract.php',
340
  'Toolset_Post_Type_Exclude_List' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/excluded_list.php',
341
  'Toolset_Post_Type_Factory' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/factory.php',
342
  'Toolset_Post_Type_From_Types' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/post_type/from_types.php',
348
  'Toolset_Potential_Association_Query_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/potential_association/query_factory.php',
349
  'Toolset_Potential_Association_Query_Posts' => $vendorDir . '/toolset/toolset-common/inc/m2m/potential_association/query_posts.php',
350
  'Toolset_Promotion' => $vendorDir . '/toolset/toolset-common/inc/toolset.promotion.class.php',
351
+ 'Toolset_Public_API_Loader' => $vendorDir . '/toolset/toolset-common/inc/public_api/loader.php',
352
+ 'Toolset_Query_Comparison_Operator' => $vendorDir . '/toolset/toolset-common/inc/m2m/query/comparison_operator.php',
353
+ 'Toolset_Query_Condition_And' => $vendorDir . '/toolset/toolset-common/inc/m2m/query/condition/and.php',
354
+ 'Toolset_Query_Condition_Contradiction' => $vendorDir . '/toolset/toolset-common/inc/m2m/query/condition/contradiction.php',
355
+ 'Toolset_Query_Condition_Operator' => $vendorDir . '/toolset/toolset-common/inc/m2m/query/condition/operator.php',
356
+ 'Toolset_Query_Condition_Or' => $vendorDir . '/toolset/toolset-common/inc/m2m/query/condition/or.php',
357
+ 'Toolset_Query_Condition_Tautology' => $vendorDir . '/toolset/toolset-common/inc/m2m/query/condition/tautology.php',
358
  'Toolset_Regex' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
359
  'Toolset_Relationship_Cardinality' => $vendorDir . '/toolset/toolset-common/inc/m2m/cardinality.php',
360
  'Toolset_Relationship_Controller' => $vendorDir . '/toolset/toolset-common/inc/m2m/controller.php',
361
  'Toolset_Relationship_Database_Issue_Missing_Element' => $vendorDir . '/toolset/toolset-common/inc/m2m/database/issue/missing_element.php',
362
  'Toolset_Relationship_Database_Operations' => $vendorDir . '/toolset/toolset-common/inc/m2m/database/operations.php',
363
  'Toolset_Relationship_Database_Unique_Table_Alias' => $vendorDir . '/toolset/toolset-common/inc/m2m/database/unique_table_alias.php',
364
+ 'Toolset_Relationship_Definition' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/definition/definition.php',
365
+ 'Toolset_Relationship_Definition_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/definition/factory.php',
366
+ 'Toolset_Relationship_Definition_Persistence' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/definition/persistence.php',
367
+ 'Toolset_Relationship_Definition_Repository' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/definition/repository.php',
368
+ 'Toolset_Relationship_Definition_Translator' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/definition/translator.php',
369
  'Toolset_Relationship_Distinct_Post_Query' => $vendorDir . '/toolset/toolset-common/inc/m2m/potential_association/distinct_post_query.php',
370
  'Toolset_Relationship_Driver' => $vendorDir . '/toolset/toolset-common/inc/m2m/driver.php',
371
  'Toolset_Relationship_Driver_Base' => $vendorDir . '/toolset/toolset-common/inc/m2m/driver_base.php',
372
  'Toolset_Relationship_Element_Type' => $vendorDir . '/toolset/toolset-common/inc/m2m/element_type.php',
373
+ 'Toolset_Relationship_Migration' => $vendorDir . '/toolset/toolset-common/inc/m2m/migration/controller.php',
374
+ 'Toolset_Relationship_Migration_Associations' => $vendorDir . '/toolset/toolset-common/inc/m2m/migration/associations.php',
375
+ 'Toolset_Relationship_Migration_Controller' => $vendorDir . '/toolset/toolset-common/inc/m2m/migration/controller.php',
376
+ 'Toolset_Relationship_Migration_Post_Translation' => $vendorDir . '/toolset/toolset-common/inc/m2m/migration/post_translation.php',
377
  'Toolset_Relationship_Origin_Post_Reference_Field' => $vendorDir . '/toolset/toolset-common/inc/m2m/origin/post_reference_field.php',
378
  'Toolset_Relationship_Origin_Repeatable_Group' => $vendorDir . '/toolset/toolset-common/inc/m2m/origin/repeatable_group.php',
379
  'Toolset_Relationship_Origin_Wizard' => $vendorDir . '/toolset/toolset-common/inc/m2m/origin/wizard.php',
380
+ 'Toolset_Relationship_Query' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/relationship_query.php',
381
  'Toolset_Relationship_Query_Base' => $vendorDir . '/toolset/toolset-common/inc/m2m/query_base.php',
382
  'Toolset_Relationship_Query_Cache' => $vendorDir . '/toolset/toolset-common/inc/m2m/query_cache.php',
383
+ 'Toolset_Relationship_Query_Cardinality_Match_Conjunction' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/cardinality_match/conjunction.php',
384
+ 'Toolset_Relationship_Query_Cardinality_Match_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/cardinality_match/factory.php',
385
+ 'Toolset_Relationship_Query_Cardinality_Match_Operators' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/cardinality_match/operators.php',
386
+ 'Toolset_Relationship_Query_Cardinality_Match_Single' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/cardinality_match/single.php',
387
+ 'Toolset_Relationship_Query_Condition' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition/abstract.php',
388
+ 'Toolset_Relationship_Query_Condition_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition_factory.php',
389
+ 'Toolset_Relationship_Query_Condition_Has_Active_Types' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition/has_active_types.php',
390
+ 'Toolset_Relationship_Query_Condition_Has_Cardinality' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition/has_cardinality.php',
391
+ 'Toolset_Relationship_Query_Condition_Has_Domain' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition/has_domain.php',
392
+ 'Toolset_Relationship_Query_Condition_Is_Active' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition/is_active.php',
393
+ 'Toolset_Relationship_Query_Condition_Is_Boolean_Flag' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition/is_boolean_flag.php',
394
+ 'Toolset_Relationship_Query_Condition_Is_Legacy' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition/is_legacy.php',
395
+ 'Toolset_Relationship_Query_Condition_Origin' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition/origin.php',
396
+ 'Toolset_Relationship_Query_Condition_Type' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/condition/type.php',
397
+ 'Toolset_Relationship_Query_Factory' => $vendorDir . '/toolset/toolset-common/inc/m2m/query/factory.php',
398
+ 'Toolset_Relationship_Query_Sql_Expression_Builder' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/sql_expression_builder.php',
399
+ 'Toolset_Relationship_Query_V2' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/query/relationship_query_v2.php',
400
+ 'Toolset_Relationship_Role' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/role/role.php',
401
+ 'Toolset_Relationship_Role_Abstract' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/role/abstract.php',
402
+ 'Toolset_Relationship_Role_Child' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/role/child.php',
403
+ 'Toolset_Relationship_Role_Intermediary' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/role/intermediary.php',
404
+ 'Toolset_Relationship_Role_Parent' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/role/parent.php',
405
+ 'Toolset_Relationship_Scope' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/scope.php',
 
 
 
 
406
  'Toolset_Relationship_Service' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/relationship_service.php',
407
+ 'Toolset_Relationship_Slug_Validator' => $vendorDir . '/toolset/toolset-common/inc/m2m/relationship/slug_validator.php',
408
  'Toolset_Relationship_Table_Name' => $vendorDir . '/toolset/toolset-common/inc/m2m/database/table_name.php',
409
  'Toolset_Relationship_Utils' => $vendorDir . '/toolset/toolset-common/inc/m2m/utils.php',
 
410
  'Toolset_Relevanssi_Compatibility' => $vendorDir . '/toolset/toolset-common/inc/toolset.relevanssi.compatibility.class.php',
411
+ 'Toolset_Renderer' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/renderer/renderer.php',
412
  'Toolset_Result' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/result.php',
413
  'Toolset_Result_Set' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/result_set.php',
414
  'Toolset_Result_Updated' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/result_updated.php',
424
  'Toolset_Shortcode_Transformer' => $vendorDir . '/toolset/toolset-common/inc/toolset.shortcode.transformer.class.php',
425
  'Toolset_Stack' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
426
  'Toolset_Style' => $vendorDir . '/toolset/toolset-common/inc/toolset.assets.manager.class.php',
427
+ 'Toolset_Template_Dialog_Box' => $vendorDir . '/toolset/toolset-common/utility/gui-base/template_dialog_box.php',
428
  'Toolset_Tokenizer' => $vendorDir . '/toolset/toolset-common/expression-parser/parser.php',
429
  'Toolset_Twig_Autoloader' => $vendorDir . '/toolset/toolset-common/utility/gui-base/twig_autoloader.php',
430
  'Toolset_Twig_Dialog_Box' => $vendorDir . '/toolset/toolset-common/utility/gui-base/twig_dialog_box.php',
441
  'Toolset_User_Editors_Editor_Basic' => $vendorDir . '/toolset/toolset-common/user-editors/editor/basic.php',
442
  'Toolset_User_Editors_Editor_Beaver' => $vendorDir . '/toolset/toolset-common/user-editors/editor/beaver.php',
443
  'Toolset_User_Editors_Editor_Divi' => $vendorDir . '/toolset/toolset-common/user-editors/editor/divi.php',
444
+ 'Toolset_User_Editors_Editor_Gutenberg' => $vendorDir . '/toolset/toolset-common/user-editors/editor/gutenberg.php',
445
  'Toolset_User_Editors_Editor_Interface' => $vendorDir . '/toolset/toolset-common/user-editors/editor/interface.php',
446
  'Toolset_User_Editors_Editor_Native' => $vendorDir . '/toolset/toolset-common/user-editors/editor/native.php',
447
  'Toolset_User_Editors_Editor_Screen_Abstract' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/abstract.php',
452
  'Toolset_User_Editors_Editor_Screen_Beaver_Frontend_Editor' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/beaver/frontend-editor.php',
453
  'Toolset_User_Editors_Editor_Screen_Divi_Backend' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/divi/backend.php',
454
  'Toolset_User_Editors_Editor_Screen_Divi_Frontend' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/divi/frontend.php',
455
+ 'Toolset_User_Editors_Editor_Screen_Gutenberg_Backend' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/gutenberg/backend.php',
456
  'Toolset_User_Editors_Editor_Screen_Interface' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/interface.php',
457
  'Toolset_User_Editors_Editor_Screen_Native_Backend' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/native/backend.php',
458
  'Toolset_User_Editors_Editor_Screen_Visual_Composer_Backend' => $vendorDir . '/toolset/toolset-common/user-editors/editor/screen/visual-composer/backend.php',
472
  'Toolset_VideoDetachedPage' => $vendorDir . '/toolset/toolset-common/utility/help-videos/toolset-help-videos.php',
473
  'Toolset_WPLogger' => $vendorDir . '/toolset/toolset-common/inc/toolset.wplogger.class.php',
474
  'Toolset_WPML_Compatibility' => $vendorDir . '/toolset/toolset-common/inc/toolset.wpml.compatibility.class.php',
475
+ 'Toolset_Wp_Query_Adjustments' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/abstract.php',
476
+ 'Toolset_Wp_Query_Adjustments_Legacy_Relationships' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/legacy_relationships.php',
477
+ 'Toolset_Wp_Query_Adjustments_Loader' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/loader.php',
478
+ 'Toolset_Wp_Query_Adjustments_M2m' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/m2m.php',
479
+ 'Toolset_Wp_Query_Adjustments_Table_Join_Manager' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/table_join_manager.php',
480
+ 'Toolset_Wpdb_User' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/wpdb_user.php',
481
  'Toolset_Wpml_Utils' => $vendorDir . '/toolset/toolset-common/inc/autoloaded/wpml_utils.php',
482
  'Twig_Autoloader' => $vendorDir . '/twig/twig/lib/Twig/Autoloader.php',
483
  'Twig_BaseNodeVisitor' => $vendorDir . '/twig/twig/lib/Twig/BaseNodeVisitor.php',
704
  'Types_Field_Group_User_Factory' => $baseDir . '/application/models/field/group/user_factory.php',
705
  'Types_Field_Type_Converter' => $baseDir . '/application/controllers/field/type_converter.php',
706
  'Types_Field_Type_Definition' => $baseDir . '/application/models/field/type/definition.php',
707
+ 'Types_Field_Type_Definition_Checkbox' => $baseDir . '/application/models/field/gateway/checkbox.php',
708
+ 'Types_Field_Type_Definition_Checkboxes' => $baseDir . '/application/models/field/gateway/checkboxes.php',
709
+ 'Types_Field_Type_Definition_Date' => $baseDir . '/application/models/field/gateway/date.php',
710
  'Types_Field_Type_Definition_Factory' => $baseDir . '/application/models/field/type/definition_factory.php',
711
+ 'Types_Field_Type_Definition_Numeric' => $baseDir . '/application/models/field/gateway/numeric.php',
712
+ 'Types_Field_Type_Definition_Radio' => $baseDir . '/application/models/field/gateway/radio.php',
713
+ 'Types_Field_Type_Definition_Select' => $baseDir . '/application/models/field/gateway/select.php',
714
+ 'Types_Field_Type_Definition_Singular' => $baseDir . '/application/models/field/gateway/singular.php',
715
  'Types_Field_Utils' => $baseDir . '/application/controllers/field/utils.php',
716
  'Types_Frontend' => $baseDir . '/application/controllers/frontend.php',
717
  'Types_Helper_Condition' => $baseDir . '/application/models/helper/condition.php',
790
  'Types_Taxonomy' => $baseDir . '/application/models/taxonomy.php',
791
  'Types_Twig_Autoloader' => $baseDir . '/application/controllers/twig_autoloader.php',
792
  'Types_Upgrade' => $baseDir . '/application/controllers/upgrade.php',
793
+ 'Types_Utils' => $baseDir . '/application/controllers/admin_notice/utils.php',
794
  'Types_Utils_Post_Type_Option' => $baseDir . '/application/controllers/utils/post_type_option.php',
795
  'Types_Wpml_Field_Group' => $baseDir . '/application/models/wpml/field_group.php',
796
  'Types_Wpml_Field_Group_String' => $baseDir . '/application/models/wpml/field/group/string.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInita469bff8809f0826cf254ebc61c9ca28
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInita469bff8809f0826cf254ebc61c9ca28
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInita469bff8809f0826cf254ebc61c9ca28', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInita469bff8809f0826cf254ebc61c9ca28', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInita469bff8809f0826cf254ebc61c9ca28::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@ class ComposerAutoloaderInita469bff8809f0826cf254ebc61c9ca28
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
- $includeFiles = Composer\Autoload\ComposerStaticInita469bff8809f0826cf254ebc61c9ca28::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
- composerRequirea469bff8809f0826cf254ebc61c9ca28($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
- function composerRequirea469bff8809f0826cf254ebc61c9ca28($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInitc3c1dc77e2581741c891ff7b2bf920aa
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInitc3c1dc77e2581741c891ff7b2bf920aa', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInitc3c1dc77e2581741c891ff7b2bf920aa', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInitc3c1dc77e2581741c891ff7b2bf920aa::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
+ $includeFiles = Composer\Autoload\ComposerStaticInitc3c1dc77e2581741c891ff7b2bf920aa::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
+ composerRequirec3c1dc77e2581741c891ff7b2bf920aa($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
+ function composerRequirec3c1dc77e2581741c891ff7b2bf920aa($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
8
  {
9
  public static $files = array (
10
  'a52c1eba913b4ecdd3571194b37baea9' => __DIR__ . '/../..' . '/application/functions.php',
@@ -125,24 +125,33 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
125
  'FieldFactory' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-forms/classes/class.field_factory.php',
126
  'FormAbstract' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-forms/classes/abstract.form.php',
127
  'FormFactory' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-forms/classes/class.form_factory.php',
128
- 'IToolset_Association' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/i_association.php',
 
 
 
 
 
 
129
  'IToolset_Element' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/element/i_element.php',
 
130
  'IToolset_Post' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/element/i_post.php',
131
  'IToolset_Post_Type' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type.php',
132
  'IToolset_Post_Type_From_Types' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type_from_types.php',
133
  'IToolset_Post_Type_Registered' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type_registered.php',
134
  'IToolset_Potential_Association_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/potential_association/query_interface.php',
135
  'IToolset_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/i_query.php',
 
136
  'IToolset_Relationship_Database_Issue' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/database/issue/interface.php',
137
- 'IToolset_Relationship_Definition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/definition/interface.php',
138
  'IToolset_Relationship_Origin' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/origin/interface.php',
139
- 'IToolset_Relationship_Query_Cardinality_Match' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/cardinality_match/interface.php',
140
- 'IToolset_Relationship_Query_Condition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/i_condition.php',
141
- 'IToolset_Relationship_Role' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_role/interface.php',
142
- 'IToolset_Relationship_Role_Parent_Child' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_role/parent_child_interface.php',
143
  'IToolset_Upgrade_Command' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/upgrade/command_interface.php',
144
  'ReCaptchaResponse' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-forms/js/recaptcha-php-1.11/recaptchalib.php',
145
  'Toolset_Admin_Bar_Menu' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.admin.bar.menu.class.php',
 
146
  'Toolset_Admin_Notice_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/utility/admin/notice/abstract.php',
147
  'Toolset_Admin_Notice_Dismissible' => __DIR__ . '/..' . '/toolset/toolset-common/utility/admin/notice/dismissible.php',
148
  'Toolset_Admin_Notice_Error' => __DIR__ . '/..' . '/toolset/toolset-common/utility/admin/notice/error.php',
@@ -155,17 +164,72 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
155
  'Toolset_Admin_Notices_Manager' => __DIR__ . '/..' . '/toolset/toolset-common/utility/admin/notices/manager.php',
156
  'Toolset_Ajax' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.ajax.class.php',
157
  'Toolset_Ajax_Handler_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/abstract.php',
 
 
 
 
 
158
  'Toolset_Ajax_Handler_Interface' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/interface.php',
 
159
  'Toolset_Ajax_Handler_Migrate_To_M2M' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/migrate_to_m2m.php',
 
 
 
160
  'Toolset_ArrayUtils' => __DIR__ . '/..' . '/toolset/toolset-common/utility/utils.php',
161
- 'Toolset_Asset_Manager' => __DIR__ . '/..' . '/toolset/toolset-common/inc/controller/asset_manager.php',
162
  'Toolset_Assets_Manager' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.assets.manager.class.php',
163
- 'Toolset_Association' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association.php',
164
- 'Toolset_Association_Base' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association_base.php',
165
- 'Toolset_Association_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association_query.php',
166
- 'Toolset_Association_Repository' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association_repository.php',
167
- 'Toolset_Association_Transitional' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association_transitional.php',
168
- 'Toolset_Association_Translation_Set' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association_translation_set.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  'Toolset_Bootstrap_Loader' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.bootstrap.loader.class.php',
170
  'Toolset_Common_Autoloader' => __DIR__ . '/..' . '/toolset/toolset-common/utility/autoloader.php',
171
  'Toolset_Common_Bootstrap' => __DIR__ . '/..' . '/toolset/toolset-common/bootstrap.php',
@@ -179,11 +243,14 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
179
  'Toolset_Condition_Plugin_Layouts_Missing' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/layouts/missing.php',
180
  'Toolset_Condition_Plugin_Layouts_No_Items' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/layouts/no-items.php',
181
  'Toolset_Condition_Plugin_Types_Active' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/types/active.php',
 
182
  'Toolset_Condition_Plugin_Types_Missing' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/types/missing.php',
183
  'Toolset_Condition_Plugin_Types_Ready_For_M2M' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/types/ready_for_m2m.php',
184
  'Toolset_Condition_Plugin_Views_Active' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/views/active.php',
185
  'Toolset_Condition_Plugin_Views_Missing' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/views/missing.php',
186
  'Toolset_Condition_Plugin_Wpml_Doesnt_Support_M2m' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/wpml/doesnt_support_m2m.php',
 
 
187
  'Toolset_Condition_Theme_Avada_Not_Active_Or_Greater_Equal_5_0' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/theme/avada/not-active-or-greater-equal-5-0.php',
188
  'Toolset_Condition_Theme_Layouts_Support_Native_Available' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/theme/layouts-support/native/available.php',
189
  'Toolset_Condition_Theme_Layouts_Support_Native_Missing' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/theme/layouts-support/native/missing.php',
@@ -198,8 +265,10 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
198
  'Toolset_Condition_Theme_Toolset_Based_Active' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/theme/toolset-based/active.php',
199
  'Toolset_Condition_Theme_Toolset_Based_Inactive' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/theme/toolset-based/inactive.php',
200
  'Toolset_Condition_User_Role_Admin' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/user/role/admin.php',
201
- 'Toolset_Constants' => __DIR__ . '/..' . '/toolset/toolset-common/inc/controller/constants.php',
202
- 'Toolset_Controller_Admin_Notices' => __DIR__ . '/..' . '/toolset/toolset-common/inc/controller/admin/notices.php',
 
 
203
  'Toolset_CssComponent' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.css.component.class.php',
204
  'Toolset_Date' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
205
  'Toolset_DateParser' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
@@ -225,10 +294,12 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
225
  'Toolset_Field_Definition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition.php',
226
  'Toolset_Field_Definition_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_abstract.php',
227
  'Toolset_Field_Definition_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_factory.php',
 
228
  'Toolset_Field_Definition_Factory_Post' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_post.php',
229
  'Toolset_Field_Definition_Factory_Term' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_term.php',
230
  'Toolset_Field_Definition_Factory_User' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_user.php',
231
  'Toolset_Field_Definition_Generic' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_generic.php',
 
232
  'Toolset_Field_Definition_Post' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_post.php',
233
  'Toolset_Field_Definition_Term' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_term.php',
234
  'Toolset_Field_Definition_User' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_user.php',
@@ -274,6 +345,7 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
274
  'Toolset_Field_Type_Definition_Select' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/type/definition/select.php',
275
  'Toolset_Field_Type_Definition_Singular' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/type/definition/singular.php',
276
  'Toolset_Field_Utils' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/utils.php',
 
277
  'Toolset_Functions' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
278
  'Toolset_Gui_Base' => __DIR__ . '/..' . '/toolset/toolset-common/utility/gui-base/main.php',
279
  'Toolset_HelpVideo' => __DIR__ . '/..' . '/toolset/toolset-common/utility/help-videos/toolset-help-videos.php',
@@ -283,9 +355,17 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
283
  'Toolset_Menu' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.menu.class.php',
284
  'Toolset_Naming_Helper' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/naming_helper.php',
285
  'Toolset_Object_Relationship' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.object.relationship.class.php',
 
 
 
 
 
 
 
286
  'Toolset_Parser' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
287
  'Toolset_Post' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/element/post.php',
288
  'Toolset_Post_Translation_Set' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/element/post_translation_set.php',
 
289
  'Toolset_Post_Type_Exclude_List' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/excluded_list.php',
290
  'Toolset_Post_Type_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/factory.php',
291
  'Toolset_Post_Type_From_Types' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/from_types.php',
@@ -297,63 +377,67 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
297
  'Toolset_Potential_Association_Query_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/potential_association/query_factory.php',
298
  'Toolset_Potential_Association_Query_Posts' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/potential_association/query_posts.php',
299
  'Toolset_Promotion' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.promotion.class.php',
 
 
 
 
 
 
 
300
  'Toolset_Regex' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
301
  'Toolset_Relationship_Cardinality' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/cardinality.php',
302
  'Toolset_Relationship_Controller' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/controller.php',
303
  'Toolset_Relationship_Database_Issue_Missing_Element' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/database/issue/missing_element.php',
304
  'Toolset_Relationship_Database_Operations' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/database/operations.php',
305
  'Toolset_Relationship_Database_Unique_Table_Alias' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/database/unique_table_alias.php',
306
- 'Toolset_Relationship_Definition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/definition/definition.php',
307
- 'Toolset_Relationship_Definition_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/definition/factory.php',
308
- 'Toolset_Relationship_Definition_Persistence' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/definition/persistence.php',
309
- 'Toolset_Relationship_Definition_Repository' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/definition/repository.php',
310
- 'Toolset_Relationship_Definition_Translator' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/definition/translator.php',
311
  'Toolset_Relationship_Distinct_Post_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/potential_association/distinct_post_query.php',
312
  'Toolset_Relationship_Driver' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/driver.php',
313
  'Toolset_Relationship_Driver_Base' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/driver_base.php',
314
  'Toolset_Relationship_Element_Type' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/element_type.php',
315
- 'Toolset_Relationship_Migration' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/migration.php',
316
- 'Toolset_Relationship_Migration_Associations' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/migration_associations.php',
317
- 'Toolset_Relationship_Multilingual_Mode' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/multilingual_mode.php',
 
318
  'Toolset_Relationship_Origin_Post_Reference_Field' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/origin/post_reference_field.php',
319
  'Toolset_Relationship_Origin_Repeatable_Group' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/origin/repeatable_group.php',
320
  'Toolset_Relationship_Origin_Wizard' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/origin/wizard.php',
321
- 'Toolset_Relationship_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/relationship_query.php',
322
  'Toolset_Relationship_Query_Base' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query_base.php',
323
  'Toolset_Relationship_Query_Cache' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query_cache.php',
324
- 'Toolset_Relationship_Query_Cardinality_Match_Conjunction' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/cardinality_match/conjunction.php',
325
- 'Toolset_Relationship_Query_Cardinality_Match_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/cardinality_match/factory.php',
326
- 'Toolset_Relationship_Query_Cardinality_Match_Operators' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/cardinality_match/operators.php',
327
- 'Toolset_Relationship_Query_Cardinality_Match_Single' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/cardinality_match/single.php',
328
- 'Toolset_Relationship_Query_Condition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/abstract.php',
329
- 'Toolset_Relationship_Query_Condition_And' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/and.php',
330
- 'Toolset_Relationship_Query_Condition_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition_factory.php',
331
- 'Toolset_Relationship_Query_Condition_Has_Active_Types' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/has_active_types.php',
332
- 'Toolset_Relationship_Query_Condition_Has_Cardinality' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/has_cardinality.php',
333
- 'Toolset_Relationship_Query_Condition_Has_Domain' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/has_domain.php',
334
- 'Toolset_Relationship_Query_Condition_Is_Active' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/is_active.php',
335
- 'Toolset_Relationship_Query_Condition_Is_Boolean_Flag' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/is_boolean_flag.php',
336
- 'Toolset_Relationship_Query_Condition_Is_Legacy' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/is_legacy.php',
337
- 'Toolset_Relationship_Query_Condition_Operator' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/operator.php',
338
- 'Toolset_Relationship_Query_Condition_Or' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/or.php',
339
- 'Toolset_Relationship_Query_Condition_Origin' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/origin.php',
340
- 'Toolset_Relationship_Query_Condition_Tautology' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/tautology.php',
341
- 'Toolset_Relationship_Query_Condition_Type' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/condition/type.php',
342
- 'Toolset_Relationship_Query_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query_factory.php',
343
- 'Toolset_Relationship_Query_Sql_Expression_Builder' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/sql_expression_builder.php',
344
- 'Toolset_Relationship_Query_V2' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_query/relationship_query_v2.php',
345
- 'Toolset_Relationship_Role' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_role/role.php',
346
- 'Toolset_Relationship_Role_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_role/abstract.php',
347
- 'Toolset_Relationship_Role_Child' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_role/child.php',
348
- 'Toolset_Relationship_Role_Intermediary' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_role/intermediary.php',
349
- 'Toolset_Relationship_Role_Parent' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship_role/parent.php',
350
- 'Toolset_Relationship_Scope' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/scope.php',
351
  'Toolset_Relationship_Service' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/relationship_service.php',
352
- 'Toolset_Relationship_Slug_Validator' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/slug_validator.php',
353
  'Toolset_Relationship_Table_Name' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/database/table_name.php',
354
  'Toolset_Relationship_Utils' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/utils.php',
355
- 'Toolset_Relationship_WPML_Interoperability' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/wpml_interoperability.php',
356
  'Toolset_Relevanssi_Compatibility' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.relevanssi.compatibility.class.php',
 
357
  'Toolset_Result' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/result.php',
358
  'Toolset_Result_Set' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/result_set.php',
359
  'Toolset_Result_Updated' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/result_updated.php',
@@ -369,6 +453,7 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
369
  'Toolset_Shortcode_Transformer' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.shortcode.transformer.class.php',
370
  'Toolset_Stack' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
371
  'Toolset_Style' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.assets.manager.class.php',
 
372
  'Toolset_Tokenizer' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
373
  'Toolset_Twig_Autoloader' => __DIR__ . '/..' . '/toolset/toolset-common/utility/gui-base/twig_autoloader.php',
374
  'Toolset_Twig_Dialog_Box' => __DIR__ . '/..' . '/toolset/toolset-common/utility/gui-base/twig_dialog_box.php',
@@ -385,6 +470,7 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
385
  'Toolset_User_Editors_Editor_Basic' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/basic.php',
386
  'Toolset_User_Editors_Editor_Beaver' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/beaver.php',
387
  'Toolset_User_Editors_Editor_Divi' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/divi.php',
 
388
  'Toolset_User_Editors_Editor_Interface' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/interface.php',
389
  'Toolset_User_Editors_Editor_Native' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/native.php',
390
  'Toolset_User_Editors_Editor_Screen_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/abstract.php',
@@ -395,6 +481,7 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
395
  'Toolset_User_Editors_Editor_Screen_Beaver_Frontend_Editor' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/beaver/frontend-editor.php',
396
  'Toolset_User_Editors_Editor_Screen_Divi_Backend' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/divi/backend.php',
397
  'Toolset_User_Editors_Editor_Screen_Divi_Frontend' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/divi/frontend.php',
 
398
  'Toolset_User_Editors_Editor_Screen_Interface' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/interface.php',
399
  'Toolset_User_Editors_Editor_Screen_Native_Backend' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/native/backend.php',
400
  'Toolset_User_Editors_Editor_Screen_Visual_Composer_Backend' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/visual-composer/backend.php',
@@ -414,6 +501,12 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
414
  'Toolset_VideoDetachedPage' => __DIR__ . '/..' . '/toolset/toolset-common/utility/help-videos/toolset-help-videos.php',
415
  'Toolset_WPLogger' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.wplogger.class.php',
416
  'Toolset_WPML_Compatibility' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.wpml.compatibility.class.php',
 
 
 
 
 
 
417
  'Toolset_Wpml_Utils' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/wpml_utils.php',
418
  'Twig_Autoloader' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Autoloader.php',
419
  'Twig_BaseNodeVisitor' => __DIR__ . '/..' . '/twig/twig/lib/Twig/BaseNodeVisitor.php',
@@ -640,14 +733,14 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
640
  'Types_Field_Group_User_Factory' => __DIR__ . '/../..' . '/application/models/field/group/user_factory.php',
641
  'Types_Field_Type_Converter' => __DIR__ . '/../..' . '/application/controllers/field/type_converter.php',
642
  'Types_Field_Type_Definition' => __DIR__ . '/../..' . '/application/models/field/type/definition.php',
643
- 'Types_Field_Type_Definition_Checkbox' => __DIR__ . '/../..' . '/application/models/field/type/definition/checkbox.php',
644
- 'Types_Field_Type_Definition_Checkboxes' => __DIR__ . '/../..' . '/application/models/field/type/definition/checkboxes.php',
645
- 'Types_Field_Type_Definition_Date' => __DIR__ . '/../..' . '/application/models/field/type/definition/date.php',
646
  'Types_Field_Type_Definition_Factory' => __DIR__ . '/../..' . '/application/models/field/type/definition_factory.php',
647
- 'Types_Field_Type_Definition_Numeric' => __DIR__ . '/../..' . '/application/models/field/type/definition/numeric.php',
648
- 'Types_Field_Type_Definition_Radio' => __DIR__ . '/../..' . '/application/models/field/type/definition/radio.php',
649
- 'Types_Field_Type_Definition_Select' => __DIR__ . '/../..' . '/application/models/field/type/definition/select.php',
650
- 'Types_Field_Type_Definition_Singular' => __DIR__ . '/../..' . '/application/models/field/type/definition/singular.php',
651
  'Types_Field_Utils' => __DIR__ . '/../..' . '/application/controllers/field/utils.php',
652
  'Types_Frontend' => __DIR__ . '/../..' . '/application/controllers/frontend.php',
653
  'Types_Helper_Condition' => __DIR__ . '/../..' . '/application/models/helper/condition.php',
@@ -726,7 +819,7 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
726
  'Types_Taxonomy' => __DIR__ . '/../..' . '/application/models/taxonomy.php',
727
  'Types_Twig_Autoloader' => __DIR__ . '/../..' . '/application/controllers/twig_autoloader.php',
728
  'Types_Upgrade' => __DIR__ . '/../..' . '/application/controllers/upgrade.php',
729
- 'Types_Utils' => __DIR__ . '/../..' . '/application/controllers/utils/utils.php',
730
  'Types_Utils_Post_Type_Option' => __DIR__ . '/../..' . '/application/controllers/utils/post_type_option.php',
731
  'Types_Wpml_Field_Group' => __DIR__ . '/../..' . '/application/models/wpml/field_group.php',
732
  'Types_Wpml_Field_Group_String' => __DIR__ . '/../..' . '/application/models/wpml/field/group/string.php',
@@ -776,10 +869,10 @@ class ComposerStaticInita469bff8809f0826cf254ebc61c9ca28
776
  public static function getInitializer(ClassLoader $loader)
777
  {
778
  return \Closure::bind(function () use ($loader) {
779
- $loader->prefixLengthsPsr4 = ComposerStaticInita469bff8809f0826cf254ebc61c9ca28::$prefixLengthsPsr4;
780
- $loader->prefixDirsPsr4 = ComposerStaticInita469bff8809f0826cf254ebc61c9ca28::$prefixDirsPsr4;
781
- $loader->prefixesPsr0 = ComposerStaticInita469bff8809f0826cf254ebc61c9ca28::$prefixesPsr0;
782
- $loader->classMap = ComposerStaticInita469bff8809f0826cf254ebc61c9ca28::$classMap;
783
 
784
  }, null, ClassLoader::class);
785
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInitc3c1dc77e2581741c891ff7b2bf920aa
8
  {
9
  public static $files = array (
10
  'a52c1eba913b4ecdd3571194b37baea9' => __DIR__ . '/../..' . '/application/functions.php',
125
  'FieldFactory' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-forms/classes/class.field_factory.php',
126
  'FormAbstract' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-forms/classes/abstract.form.php',
127
  'FormFactory' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-forms/classes/class.form_factory.php',
128
+ 'IToolset_Association' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/interface.php',
129
+ 'IToolset_Association_Query_Condition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/interface.php',
130
+ 'IToolset_Association_Query_Element_Selector' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/element_selector/interface.php',
131
+ 'IToolset_Association_Query_Orderby' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/orderby/interface.php',
132
+ 'IToolset_Association_Query_Restriction' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/restriction/interface.php',
133
+ 'IToolset_Association_Query_Result_Transformation' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/result_transformation/interface.php',
134
+ 'IToolset_Cron_Event' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/cron/event_interface.php',
135
  'IToolset_Element' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/element/i_element.php',
136
+ 'IToolset_Output_Template' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/renderer/output_template/interface.php',
137
  'IToolset_Post' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/element/i_post.php',
138
  'IToolset_Post_Type' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type.php',
139
  'IToolset_Post_Type_From_Types' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type_from_types.php',
140
  'IToolset_Post_Type_Registered' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/i_post_type_registered.php',
141
  'IToolset_Potential_Association_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/potential_association/query_interface.php',
142
  'IToolset_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/i_query.php',
143
+ 'IToolset_Query_Condition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query/condition/interface.php',
144
  'IToolset_Relationship_Database_Issue' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/database/issue/interface.php',
145
+ 'IToolset_Relationship_Definition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/definition/interface.php',
146
  'IToolset_Relationship_Origin' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/origin/interface.php',
147
+ 'IToolset_Relationship_Query_Cardinality_Match' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/cardinality_match/interface.php',
148
+ 'IToolset_Relationship_Query_Condition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition/interface.php',
149
+ 'IToolset_Relationship_Role' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/role/interface.php',
150
+ 'IToolset_Relationship_Role_Parent_Child' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/role/parent_child_interface.php',
151
  'IToolset_Upgrade_Command' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/upgrade/command_interface.php',
152
  'ReCaptchaResponse' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-forms/js/recaptcha-php-1.11/recaptchalib.php',
153
  'Toolset_Admin_Bar_Menu' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.admin.bar.menu.class.php',
154
+ 'Toolset_Admin_Controller' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/admin.php',
155
  'Toolset_Admin_Notice_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/utility/admin/notice/abstract.php',
156
  'Toolset_Admin_Notice_Dismissible' => __DIR__ . '/..' . '/toolset/toolset-common/utility/admin/notice/dismissible.php',
157
  'Toolset_Admin_Notice_Error' => __DIR__ . '/..' . '/toolset/toolset-common/utility/admin/notice/error.php',
164
  'Toolset_Admin_Notices_Manager' => __DIR__ . '/..' . '/toolset/toolset-common/utility/admin/notices/manager.php',
165
  'Toolset_Ajax' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.ajax.class.php',
166
  'Toolset_Ajax_Handler_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/abstract.php',
167
+ 'Toolset_Ajax_Handler_Get_Content_Template_Block_Preview' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/get_ct_block_preview.php',
168
+ 'Toolset_Ajax_Handler_Get_Post_By_Id' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/get_post_by_id.php',
169
+ 'Toolset_Ajax_Handler_Get_Term_By_Id' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/get_term_by_id.php',
170
+ 'Toolset_Ajax_Handler_Get_User_By_Id' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/get_user_by_id.php',
171
+ 'Toolset_Ajax_Handler_Get_View_Block_Preview' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/get_view_block_preview.php',
172
  'Toolset_Ajax_Handler_Interface' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/interface.php',
173
+ 'Toolset_Ajax_Handler_Intermediary_Post_Cleanup' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/intermediary_post_cleanup.php',
174
  'Toolset_Ajax_Handler_Migrate_To_M2M' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/migrate_to_m2m.php',
175
+ 'Toolset_Ajax_Handler_Select2_Suggest_Posts_By_Title' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_posts_by_title.php',
176
+ 'Toolset_Ajax_Handler_Select2_Suggest_Terms' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_terms.php',
177
+ 'Toolset_Ajax_Handler_Select2_Suggest_Users' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_users.php',
178
  'Toolset_ArrayUtils' => __DIR__ . '/..' . '/toolset/toolset-common/utility/utils.php',
179
+ 'Toolset_Asset_Manager' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/asset_manager.php',
180
  'Toolset_Assets_Manager' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.assets.manager.class.php',
181
+ 'Toolset_Association' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/association.php',
182
+ 'Toolset_Association_Cleanup_Association' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/cleanup/association.php',
183
+ 'Toolset_Association_Cleanup_Cron_Event' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/cleanup/cron_event.php',
184
+ 'Toolset_Association_Cleanup_Cron_Handler' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/cleanup/cron_handler.php',
185
+ 'Toolset_Association_Cleanup_Dangling_Intermediary_Posts' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/cleanup/dangling_intermediary_posts.php',
186
+ 'Toolset_Association_Cleanup_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/cleanup/factory.php',
187
+ 'Toolset_Association_Cleanup_Post' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/cleanup/post.php',
188
+ 'Toolset_Association_Cleanup_Troubleshooting_Section' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/cleanup/troubleshooting_section.php',
189
+ 'Toolset_Association_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/factory.php',
190
+ 'Toolset_Association_Intermediary_Post_Persistence' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/intermediary_post_persistence.php',
191
+ 'Toolset_Association_Persistence' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/persistence.php',
192
+ 'Toolset_Association_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/association_query.php',
193
+ 'Toolset_Association_Query_Condition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/abstract.php',
194
+ 'Toolset_Association_Query_Condition_Association_Id' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/association_id.php',
195
+ 'Toolset_Association_Query_Condition_Element_Id' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/element_id.php',
196
+ 'Toolset_Association_Query_Condition_Element_Id_And_Domain' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/element_id_and_domain.php',
197
+ 'Toolset_Association_Query_Condition_Element_Status' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/element_status.php',
198
+ 'Toolset_Association_Query_Condition_Empty_Intermediary' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/empty_intermediary.php',
199
+ 'Toolset_Association_Query_Condition_Exclude_Element' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/exclude_element.php',
200
+ 'Toolset_Association_Query_Condition_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition_factory.php',
201
+ 'Toolset_Association_Query_Condition_Has_Active_Relationship' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/has_active_relationship.php',
202
+ 'Toolset_Association_Query_Condition_Has_Domain' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/has_domain.php',
203
+ 'Toolset_Association_Query_Condition_Has_Domain_And_Type' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/has_domain_and_type.php',
204
+ 'Toolset_Association_Query_Condition_Has_Legacy_Relationship' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/has_legacy_relationship.php',
205
+ 'Toolset_Association_Query_Condition_Has_Type' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/has_type.php',
206
+ 'Toolset_Association_Query_Condition_Postmeta' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/postmeta.php',
207
+ 'Toolset_Association_Query_Condition_Relationship_Flag' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/relationship_flag.php',
208
+ 'Toolset_Association_Query_Condition_Relationship_Id' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/relationship_id.php',
209
+ 'Toolset_Association_Query_Condition_Search' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/search.php',
210
+ 'Toolset_Association_Query_Condition_Wp_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/condition/wp_query.php',
211
+ 'Toolset_Association_Query_Element_Selector_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/element_selector/abstract.php',
212
+ 'Toolset_Association_Query_Element_Selector_Default' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/element_selector/default.php',
213
+ 'Toolset_Association_Query_Element_Selector_Provider' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/element_selector/provider.php',
214
+ 'Toolset_Association_Query_Element_Selector_Wpml' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/element_selector/wpml.php',
215
+ 'Toolset_Association_Query_Orderby' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/orderby/abstract.php',
216
+ 'Toolset_Association_Query_Orderby_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/orderby_factory.php',
217
+ 'Toolset_Association_Query_Orderby_Nothing' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/orderby/nothing.php',
218
+ 'Toolset_Association_Query_Orderby_Postmeta' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/orderby/postmeta.php',
219
+ 'Toolset_Association_Query_Orderby_Title' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/orderby/title.php',
220
+ 'Toolset_Association_Query_Result_Transformation_Association_Instance' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/result_transformation/association_instance.php',
221
+ 'Toolset_Association_Query_Result_Transformation_Association_Uid' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/result_transformation/association_uid.php',
222
+ 'Toolset_Association_Query_Result_Transformation_Element_Id' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/result_transformation/element_id.php',
223
+ 'Toolset_Association_Query_Result_Transformation_Element_Instance' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/result_transformation/element_instance.php',
224
+ 'Toolset_Association_Query_Sql_Expression_Builder' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/sql_expression_builder.php',
225
+ 'Toolset_Association_Query_Table_Join_Manager' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/table_join_manager.php',
226
+ 'Toolset_Association_Query_V2' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/association_query_v2.php',
227
+ 'Toolset_Association_Query_Wpdb_Wrapper' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/query/wpdb_wrapper.php',
228
+ 'Toolset_Association_Translator' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/association/translator.php',
229
+ 'Toolset_Blocks' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-blocks/toolset-blocks.php',
230
+ 'Toolset_Blocks_Content_Template' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-blocks/blocks/ct/ct.php',
231
+ 'Toolset_Blocks_Custom_HTML' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-blocks/blocks/custom-html/custom-html.php',
232
+ 'Toolset_Blocks_View' => __DIR__ . '/..' . '/toolset/toolset-common/toolset-blocks/blocks/view/view.php',
233
  'Toolset_Bootstrap_Loader' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.bootstrap.loader.class.php',
234
  'Toolset_Common_Autoloader' => __DIR__ . '/..' . '/toolset/toolset-common/utility/autoloader.php',
235
  'Toolset_Common_Bootstrap' => __DIR__ . '/..' . '/toolset/toolset-common/bootstrap.php',
243
  'Toolset_Condition_Plugin_Layouts_Missing' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/layouts/missing.php',
244
  'Toolset_Condition_Plugin_Layouts_No_Items' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/layouts/no-items.php',
245
  'Toolset_Condition_Plugin_Types_Active' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/types/active.php',
246
+ 'Toolset_Condition_Plugin_Types_Has_Legacy_Relationships' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/types/has_legacy_relationships.php',
247
  'Toolset_Condition_Plugin_Types_Missing' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/types/missing.php',
248
  'Toolset_Condition_Plugin_Types_Ready_For_M2M' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/types/ready_for_m2m.php',
249
  'Toolset_Condition_Plugin_Views_Active' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/views/active.php',
250
  'Toolset_Condition_Plugin_Views_Missing' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/views/missing.php',
251
  'Toolset_Condition_Plugin_Wpml_Doesnt_Support_M2m' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/wpml/doesnt_support_m2m.php',
252
+ 'Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/wpml/is_active_and_configured.php',
253
+ 'Toolset_Condition_Plugin_Wpml_Is_Current_Language_Default' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/plugin/wpml/is_current_language_default.php',
254
  'Toolset_Condition_Theme_Avada_Not_Active_Or_Greater_Equal_5_0' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/theme/avada/not-active-or-greater-equal-5-0.php',
255
  'Toolset_Condition_Theme_Layouts_Support_Native_Available' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/theme/layouts-support/native/available.php',
256
  'Toolset_Condition_Theme_Layouts_Support_Native_Missing' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/theme/layouts-support/native/missing.php',
265
  'Toolset_Condition_Theme_Toolset_Based_Active' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/theme/toolset-based/active.php',
266
  'Toolset_Condition_Theme_Toolset_Based_Inactive' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/theme/toolset-based/inactive.php',
267
  'Toolset_Condition_User_Role_Admin' => __DIR__ . '/..' . '/toolset/toolset-common/utility/condition/user/role/admin.php',
268
+ 'Toolset_Constants' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/constants.php',
269
+ 'Toolset_Controller_Admin_Notices' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/admin/notices.php',
270
+ 'Toolset_Cron' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/cron/cron.php',
271
+ 'Toolset_Cron_Event' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/cron/event.php',
272
  'Toolset_CssComponent' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.css.component.class.php',
273
  'Toolset_Date' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
274
  'Toolset_DateParser' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
294
  'Toolset_Field_Definition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition.php',
295
  'Toolset_Field_Definition_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_abstract.php',
296
  'Toolset_Field_Definition_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_factory.php',
297
+ 'Toolset_Field_Definition_Factory_Interface' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_interface.php',
298
  'Toolset_Field_Definition_Factory_Post' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_post.php',
299
  'Toolset_Field_Definition_Factory_Term' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_term.php',
300
  'Toolset_Field_Definition_Factory_User' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_factory_user.php',
301
  'Toolset_Field_Definition_Generic' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_generic.php',
302
+ 'Toolset_Field_Definition_Interface' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_interface.php',
303
  'Toolset_Field_Definition_Post' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_post.php',
304
  'Toolset_Field_Definition_Term' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_term.php',
305
  'Toolset_Field_Definition_User' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/definition_user.php',
345
  'Toolset_Field_Type_Definition_Select' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/type/definition/select.php',
346
  'Toolset_Field_Type_Definition_Singular' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/type/definition/singular.php',
347
  'Toolset_Field_Utils' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/field/utils.php',
348
+ 'Toolset_Files' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/files.php',
349
  'Toolset_Functions' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
350
  'Toolset_Gui_Base' => __DIR__ . '/..' . '/toolset/toolset-common/utility/gui-base/main.php',
351
  'Toolset_HelpVideo' => __DIR__ . '/..' . '/toolset/toolset-common/utility/help-videos/toolset-help-videos.php',
355
  'Toolset_Menu' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.menu.class.php',
356
  'Toolset_Naming_Helper' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/naming_helper.php',
357
  'Toolset_Object_Relationship' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.object.relationship.class.php',
358
+ 'Toolset_Output_Template' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/renderer/output_template/abstract.php',
359
+ 'Toolset_Output_Template_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/renderer/output_template_factory.php',
360
+ 'Toolset_Output_Template_Phtml' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/renderer/output_template/phtml.php',
361
+ 'Toolset_Output_Template_Repository' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/renderer/output_template_repository.php',
362
+ 'Toolset_Output_Template_Repository_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/renderer/output_template_repository_abstract.php',
363
+ 'Toolset_Output_Template_Static' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/renderer/output_template/static.php',
364
+ 'Toolset_Output_Template_Twig' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/renderer/output_template/twig.php',
365
  'Toolset_Parser' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
366
  'Toolset_Post' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/element/post.php',
367
  'Toolset_Post_Translation_Set' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/element/post_translation_set.php',
368
+ 'Toolset_Post_Type_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/abstract.php',
369
  'Toolset_Post_Type_Exclude_List' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/excluded_list.php',
370
  'Toolset_Post_Type_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/factory.php',
371
  'Toolset_Post_Type_From_Types' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/post_type/from_types.php',
377
  'Toolset_Potential_Association_Query_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/potential_association/query_factory.php',
378
  'Toolset_Potential_Association_Query_Posts' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/potential_association/query_posts.php',
379
  'Toolset_Promotion' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.promotion.class.php',
380
+ 'Toolset_Public_API_Loader' => __DIR__ . '/..' . '/toolset/toolset-common/inc/public_api/loader.php',
381
+ 'Toolset_Query_Comparison_Operator' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query/comparison_operator.php',
382
+ 'Toolset_Query_Condition_And' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query/condition/and.php',
383
+ 'Toolset_Query_Condition_Contradiction' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query/condition/contradiction.php',
384
+ 'Toolset_Query_Condition_Operator' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query/condition/operator.php',
385
+ 'Toolset_Query_Condition_Or' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query/condition/or.php',
386
+ 'Toolset_Query_Condition_Tautology' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query/condition/tautology.php',
387
  'Toolset_Regex' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
388
  'Toolset_Relationship_Cardinality' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/cardinality.php',
389
  'Toolset_Relationship_Controller' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/controller.php',
390
  'Toolset_Relationship_Database_Issue_Missing_Element' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/database/issue/missing_element.php',
391
  'Toolset_Relationship_Database_Operations' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/database/operations.php',
392
  'Toolset_Relationship_Database_Unique_Table_Alias' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/database/unique_table_alias.php',
393
+ 'Toolset_Relationship_Definition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/definition/definition.php',
394
+ 'Toolset_Relationship_Definition_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/definition/factory.php',
395
+ 'Toolset_Relationship_Definition_Persistence' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/definition/persistence.php',
396
+ 'Toolset_Relationship_Definition_Repository' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/definition/repository.php',
397
+ 'Toolset_Relationship_Definition_Translator' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/definition/translator.php',
398
  'Toolset_Relationship_Distinct_Post_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/potential_association/distinct_post_query.php',
399
  'Toolset_Relationship_Driver' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/driver.php',
400
  'Toolset_Relationship_Driver_Base' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/driver_base.php',
401
  'Toolset_Relationship_Element_Type' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/element_type.php',
402
+ 'Toolset_Relationship_Migration' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/migration/controller.php',
403
+ 'Toolset_Relationship_Migration_Associations' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/migration/associations.php',
404
+ 'Toolset_Relationship_Migration_Controller' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/migration/controller.php',
405
+ 'Toolset_Relationship_Migration_Post_Translation' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/migration/post_translation.php',
406
  'Toolset_Relationship_Origin_Post_Reference_Field' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/origin/post_reference_field.php',
407
  'Toolset_Relationship_Origin_Repeatable_Group' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/origin/repeatable_group.php',
408
  'Toolset_Relationship_Origin_Wizard' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/origin/wizard.php',
409
+ 'Toolset_Relationship_Query' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/relationship_query.php',
410
  'Toolset_Relationship_Query_Base' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query_base.php',
411
  'Toolset_Relationship_Query_Cache' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query_cache.php',
412
+ 'Toolset_Relationship_Query_Cardinality_Match_Conjunction' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/cardinality_match/conjunction.php',
413
+ 'Toolset_Relationship_Query_Cardinality_Match_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/cardinality_match/factory.php',
414
+ 'Toolset_Relationship_Query_Cardinality_Match_Operators' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/cardinality_match/operators.php',
415
+ 'Toolset_Relationship_Query_Cardinality_Match_Single' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/cardinality_match/single.php',
416
+ 'Toolset_Relationship_Query_Condition' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition/abstract.php',
417
+ 'Toolset_Relationship_Query_Condition_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition_factory.php',
418
+ 'Toolset_Relationship_Query_Condition_Has_Active_Types' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition/has_active_types.php',
419
+ 'Toolset_Relationship_Query_Condition_Has_Cardinality' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition/has_cardinality.php',
420
+ 'Toolset_Relationship_Query_Condition_Has_Domain' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition/has_domain.php',
421
+ 'Toolset_Relationship_Query_Condition_Is_Active' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition/is_active.php',
422
+ 'Toolset_Relationship_Query_Condition_Is_Boolean_Flag' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition/is_boolean_flag.php',
423
+ 'Toolset_Relationship_Query_Condition_Is_Legacy' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition/is_legacy.php',
424
+ 'Toolset_Relationship_Query_Condition_Origin' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition/origin.php',
425
+ 'Toolset_Relationship_Query_Condition_Type' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/condition/type.php',
426
+ 'Toolset_Relationship_Query_Factory' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/query/factory.php',
427
+ 'Toolset_Relationship_Query_Sql_Expression_Builder' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/sql_expression_builder.php',
428
+ 'Toolset_Relationship_Query_V2' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/query/relationship_query_v2.php',
429
+ 'Toolset_Relationship_Role' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/role/role.php',
430
+ 'Toolset_Relationship_Role_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/role/abstract.php',
431
+ 'Toolset_Relationship_Role_Child' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/role/child.php',
432
+ 'Toolset_Relationship_Role_Intermediary' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/role/intermediary.php',
433
+ 'Toolset_Relationship_Role_Parent' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/role/parent.php',
434
+ 'Toolset_Relationship_Scope' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/scope.php',
 
 
 
 
435
  'Toolset_Relationship_Service' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/relationship_service.php',
436
+ 'Toolset_Relationship_Slug_Validator' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/relationship/slug_validator.php',
437
  'Toolset_Relationship_Table_Name' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/database/table_name.php',
438
  'Toolset_Relationship_Utils' => __DIR__ . '/..' . '/toolset/toolset-common/inc/m2m/utils.php',
 
439
  'Toolset_Relevanssi_Compatibility' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.relevanssi.compatibility.class.php',
440
+ 'Toolset_Renderer' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/renderer/renderer.php',
441
  'Toolset_Result' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/result.php',
442
  'Toolset_Result_Set' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/result_set.php',
443
  'Toolset_Result_Updated' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/result_updated.php',
453
  'Toolset_Shortcode_Transformer' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.shortcode.transformer.class.php',
454
  'Toolset_Stack' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
455
  'Toolset_Style' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.assets.manager.class.php',
456
+ 'Toolset_Template_Dialog_Box' => __DIR__ . '/..' . '/toolset/toolset-common/utility/gui-base/template_dialog_box.php',
457
  'Toolset_Tokenizer' => __DIR__ . '/..' . '/toolset/toolset-common/expression-parser/parser.php',
458
  'Toolset_Twig_Autoloader' => __DIR__ . '/..' . '/toolset/toolset-common/utility/gui-base/twig_autoloader.php',
459
  'Toolset_Twig_Dialog_Box' => __DIR__ . '/..' . '/toolset/toolset-common/utility/gui-base/twig_dialog_box.php',
470
  'Toolset_User_Editors_Editor_Basic' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/basic.php',
471
  'Toolset_User_Editors_Editor_Beaver' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/beaver.php',
472
  'Toolset_User_Editors_Editor_Divi' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/divi.php',
473
+ 'Toolset_User_Editors_Editor_Gutenberg' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/gutenberg.php',
474
  'Toolset_User_Editors_Editor_Interface' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/interface.php',
475
  'Toolset_User_Editors_Editor_Native' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/native.php',
476
  'Toolset_User_Editors_Editor_Screen_Abstract' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/abstract.php',
481
  'Toolset_User_Editors_Editor_Screen_Beaver_Frontend_Editor' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/beaver/frontend-editor.php',
482
  'Toolset_User_Editors_Editor_Screen_Divi_Backend' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/divi/backend.php',
483
  'Toolset_User_Editors_Editor_Screen_Divi_Frontend' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/divi/frontend.php',
484
+ 'Toolset_User_Editors_Editor_Screen_Gutenberg_Backend' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/gutenberg/backend.php',
485
  'Toolset_User_Editors_Editor_Screen_Interface' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/interface.php',
486
  'Toolset_User_Editors_Editor_Screen_Native_Backend' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/native/backend.php',
487
  'Toolset_User_Editors_Editor_Screen_Visual_Composer_Backend' => __DIR__ . '/..' . '/toolset/toolset-common/user-editors/editor/screen/visual-composer/backend.php',
501
  'Toolset_VideoDetachedPage' => __DIR__ . '/..' . '/toolset/toolset-common/utility/help-videos/toolset-help-videos.php',
502
  'Toolset_WPLogger' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.wplogger.class.php',
503
  'Toolset_WPML_Compatibility' => __DIR__ . '/..' . '/toolset/toolset-common/inc/toolset.wpml.compatibility.class.php',
504
+ 'Toolset_Wp_Query_Adjustments' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/abstract.php',
505
+ 'Toolset_Wp_Query_Adjustments_Legacy_Relationships' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/legacy_relationships.php',
506
+ 'Toolset_Wp_Query_Adjustments_Loader' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/loader.php',
507
+ 'Toolset_Wp_Query_Adjustments_M2m' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/m2m.php',
508
+ 'Toolset_Wp_Query_Adjustments_Table_Join_Manager' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/table_join_manager.php',
509
+ 'Toolset_Wpdb_User' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/wpdb_user.php',
510
  'Toolset_Wpml_Utils' => __DIR__ . '/..' . '/toolset/toolset-common/inc/autoloaded/wpml_utils.php',
511
  'Twig_Autoloader' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Autoloader.php',
512
  'Twig_BaseNodeVisitor' => __DIR__ . '/..' . '/twig/twig/lib/Twig/BaseNodeVisitor.php',
733
  'Types_Field_Group_User_Factory' => __DIR__ . '/../..' . '/application/models/field/group/user_factory.php',
734
  'Types_Field_Type_Converter' => __DIR__ . '/../..' . '/application/controllers/field/type_converter.php',
735
  'Types_Field_Type_Definition' => __DIR__ . '/../..' . '/application/models/field/type/definition.php',
736
+ 'Types_Field_Type_Definition_Checkbox' => __DIR__ . '/../..' . '/application/models/field/gateway/checkbox.php',
737
+ 'Types_Field_Type_Definition_Checkboxes' => __DIR__ . '/../..' . '/application/models/field/gateway/checkboxes.php',
738
+ 'Types_Field_Type_Definition_Date' => __DIR__ . '/../..' . '/application/models/field/gateway/date.php',
739
  'Types_Field_Type_Definition_Factory' => __DIR__ . '/../..' . '/application/models/field/type/definition_factory.php',
740
+ 'Types_Field_Type_Definition_Numeric' => __DIR__ . '/../..' . '/application/models/field/gateway/numeric.php',
741
+ 'Types_Field_Type_Definition_Radio' => __DIR__ . '/../..' . '/application/models/field/gateway/radio.php',
742
+ 'Types_Field_Type_Definition_Select' => __DIR__ . '/../..' . '/application/models/field/gateway/select.php',
743
+ 'Types_Field_Type_Definition_Singular' => __DIR__ . '/../..' . '/application/models/field/gateway/singular.php',
744
  'Types_Field_Utils' => __DIR__ . '/../..' . '/application/controllers/field/utils.php',
745
  'Types_Frontend' => __DIR__ . '/../..' . '/application/controllers/frontend.php',
746
  'Types_Helper_Condition' => __DIR__ . '/../..' . '/application/models/helper/condition.php',
819
  'Types_Taxonomy' => __DIR__ . '/../..' . '/application/models/taxonomy.php',
820
  'Types_Twig_Autoloader' => __DIR__ . '/../..' . '/application/controllers/twig_autoloader.php',
821
  'Types_Upgrade' => __DIR__ . '/../..' . '/application/controllers/upgrade.php',
822
+ 'Types_Utils' => __DIR__ . '/../..' . '/application/controllers/admin_notice/utils.php',
823
  'Types_Utils_Post_Type_Option' => __DIR__ . '/../..' . '/application/controllers/utils/post_type_option.php',
824
  'Types_Wpml_Field_Group' => __DIR__ . '/../..' . '/application/models/wpml/field_group.php',
825
  'Types_Wpml_Field_Group_String' => __DIR__ . '/../..' . '/application/models/wpml/field/group/string.php',
869
  public static function getInitializer(ClassLoader $loader)
870
  {
871
  return \Closure::bind(function () use ($loader) {
872
+ $loader->prefixLengthsPsr4 = ComposerStaticInitc3c1dc77e2581741c891ff7b2bf920aa::$prefixLengthsPsr4;
873
+ $loader->prefixDirsPsr4 = ComposerStaticInitc3c1dc77e2581741c891ff7b2bf920aa::$prefixDirsPsr4;
874
+ $loader->prefixesPsr0 = ComposerStaticInitc3c1dc77e2581741c891ff7b2bf920aa::$prefixesPsr0;
875
+ $loader->classMap = ComposerStaticInitc3c1dc77e2581741c891ff7b2bf920aa::$classMap;
876
 
877
  }, null, ClassLoader::class);
878
  }
vendor/composer/installed.json CHANGED
@@ -120,12 +120,12 @@
120
  },
121
  {
122
  "name": "otgs/installer",
123
- "version": "1.8.2",
124
- "version_normalized": "1.8.2.0",
125
  "source": {
126
  "type": "git",
127
  "url": "ssh://git@git.onthegosystems.com:10022/installer/installer.git",
128
- "reference": "36101873478f3590c410701f7869570310271477"
129
  },
130
  "require": {
131
  "composer/installers": "~1.0",
@@ -134,7 +134,7 @@
134
  "require-dev": {
135
  "phpunit/phpunit": "~4.5"
136
  },
137
- "time": "2017-08-04T15:33:42+00:00",
138
  "type": "library",
139
  "extra": {
140
  "branch-alias": {
@@ -149,7 +149,7 @@
149
  ]
150
  },
151
  "license": [
152
- "GPL-2.0"
153
  ],
154
  "authors": [
155
  {
@@ -217,12 +217,12 @@
217
  },
218
  {
219
  "name": "toolset/toolset-common",
220
- "version": "2.5.8",
221
- "version_normalized": "2.5.8.0",
222
  "source": {
223
  "type": "git",
224
  "url": "ssh://git@git.onthegosystems.com:10022/toolset/toolset-common.git",
225
- "reference": "afd2128b775ac8942402ea6c3ab0bbeb85e0dc0b"
226
  },
227
  "require": {
228
  "php": ">=5.2.0"
@@ -233,7 +233,7 @@
233
  "otgs/unit-tests-framework": "~1.2.0",
234
  "phpunit/php-token-stream": "<2.0"
235
  },
236
- "time": "2017-12-07T11:25:32+00:00",
237
  "type": "library",
238
  "extra": {
239
  "branch-alias": {
@@ -248,11 +248,17 @@
248
  "expression-parser/",
249
  "inc/",
250
  "toolset-forms/",
 
251
  "user-editors/",
252
  "utility/",
253
  "bootstrap.php"
254
  ]
255
  },
 
 
 
 
 
256
  "scripts": {
257
  "test": [
258
  "phpunit"
120
  },
121
  {
122
  "name": "otgs/installer",
123
+ "version": "1.8.8",
124
+ "version_normalized": "1.8.8.0",
125
  "source": {
126
  "type": "git",
127
  "url": "ssh://git@git.onthegosystems.com:10022/installer/installer.git",
128
+ "reference": "4f33032eed7d02bf2cd1871706d249370ecf7032"
129
  },
130
  "require": {
131
  "composer/installers": "~1.0",
134
  "require-dev": {
135
  "phpunit/phpunit": "~4.5"
136
  },
137
+ "time": "2018-03-01T13:01:25+00:00",
138
  "type": "library",
139
  "extra": {
140
  "branch-alias": {
149
  ]
150
  },
151
  "license": [
152
+ "GPL-2.0-or-later"
153
  ],
154
  "authors": [
155
  {
217
  },
218
  {
219
  "name": "toolset/toolset-common",
220
+ "version": "2.6.2",
221
+ "version_normalized": "2.6.2.0",
222
  "source": {
223
  "type": "git",
224
  "url": "ssh://git@git.onthegosystems.com:10022/toolset/toolset-common.git",
225
+ "reference": "f8084f2b13708b5589842bb8b1ab6a4c77a8e9ac"
226
  },
227
  "require": {
228
  "php": ">=5.2.0"
233
  "otgs/unit-tests-framework": "~1.2.0",
234
  "phpunit/php-token-stream": "<2.0"
235
  },
236
+ "time": "2018-03-01T14:00:14+00:00",
237
  "type": "library",
238
  "extra": {
239
  "branch-alias": {
248
  "expression-parser/",
249
  "inc/",
250
  "toolset-forms/",
251
+ "toolset-blocks/",
252
  "user-editors/",
253
  "utility/",
254
  "bootstrap.php"
255
  ]
256
  },
257
+ "autoload-dev": {
258
+ "classmap": [
259
+ "tests/res/stubs"
260
+ ]
261
+ },
262
  "scripts": {
263
  "test": [
264
  "phpunit"
vendor/otgs/installer/changelog.txt CHANGED
@@ -1,3 +1,13 @@
 
 
 
 
 
 
 
 
 
 
1
  = 1.8.2 =
2
  * Bug fix: registration warning was shown for free plugins
3
 
1
+ = 1.8.8 =
2
+ * Fixed some conficts
3
+
4
+ = 1.8.7 =
5
+ * Updated version numbers to all files
6
+
7
+ = 1.8.6 =
8
+ * Bug fix: When Windows file paths were longer than 256 chars updating of plugins wasn't possible
9
+ * Bug fix: PHP 7.2 warnings
10
+
11
  = 1.8.2 =
12
  * Bug fix: registration warning was shown for free plugins
13
 
vendor/otgs/installer/includes/class-installer-theme.php CHANGED
@@ -936,7 +936,7 @@ class Installer_Theme_Class {
936
  public function installer_theme_filter_themes_by_subscription( $themes, $active_tab ) {
937
 
938
  //Step1, we only filter OTGS themes
939
- $orig = count( $themes );
940
  if ( in_array( $active_tab, $this->theme_repo ) ) {
941
  //OTGS Theme
942
  //Step2, we retrieved the available themes based on client subscription
@@ -959,7 +959,7 @@ class Installer_Theme_Class {
959
  }
960
  }
961
  }
962
- $new = count( $themes );
963
  if ( $orig != $new ) {
964
  //It is filtered
965
  $themes = array_values( $themes );
936
  public function installer_theme_filter_themes_by_subscription( $themes, $active_tab ) {
937
 
938
  //Step1, we only filter OTGS themes
939
+ $orig = is_array( $themes ) ? count( $themes ) : 0;
940
  if ( in_array( $active_tab, $this->theme_repo ) ) {
941
  //OTGS Theme
942
  //Step2, we retrieved the available themes based on client subscription
959
  }
960
  }
961
  }
962
+ $new = is_array( $themes ) ? count( $themes ) : 0;
963
  if ( $orig != $new ) {
964
  //It is filtered
965
  $themes = array_values( $themes );
vendor/otgs/installer/includes/class-otgs-installer-filename-hooks.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class OTGS_Installer_Filename_Hooks {
4
+
5
+ /**
6
+ * @var OTGS_Installer_PHP_Functions
7
+ */
8
+ private $built_in_functions;
9
+
10
+ public function __construct( OTGS_Installer_PHP_Functions $built_in_functions ) {
11
+ $this->built_in_functions = $built_in_functions;
12
+ }
13
+
14
+ public function add_hooks() {
15
+ if ( in_array( $this->built_in_functions->constant( 'PHP_OS' ), array( 'WIN32', 'WINNT', 'Windows' ), true ) ) {
16
+ add_filter( 'wp_unique_filename', array( $this, 'fix_filename_for_win' ), 10, 3 );
17
+ }
18
+ }
19
+
20
+ /**
21
+ * @param string $filename
22
+ * @param string $ext
23
+ * @param string $dir
24
+ *
25
+ * @return string
26
+ */
27
+ public function fix_filename_for_win( $filename, $ext, $dir ) {
28
+ if ( $dir === get_temp_dir() ) {
29
+ return md5( $filename . $this->built_in_functions->time() ) . 'tmp';
30
+ }
31
+ return $filename;
32
+ }
33
+ }
vendor/otgs/installer/includes/class-otgs-installer-php-functions.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class OTGS_Installer_PHP_Functions {
4
+
5
+ /**
6
+ * @param string $constant_name
7
+ *
8
+ * @return bool
9
+ */
10
+ public function defined( $constant_name ) {
11
+ return defined( $constant_name );
12
+ }
13
+
14
+ /**
15
+ * @param string $constant_name
16
+ *
17
+ * @return string|int|null
18
+ */
19
+ public function constant( $constant_name ) {
20
+ return $this->defined( $constant_name ) ? constant( $constant_name ) : null;
21
+ }
22
+
23
+ /**
24
+ * @return int
25
+ */
26
+ public function time() {
27
+ return time();
28
+ }
29
+ }
vendor/otgs/installer/includes/class-wp-installer.php CHANGED
@@ -302,24 +302,19 @@ final class WP_Installer {
302
  foreach ( $this->settings['repositories'] as $repository_id => $repository ) {
303
 
304
  foreach ( $repository['data']['packages'] as $package ) {
305
-
306
  foreach ( $package['products'] as $product ) {
307
-
308
- foreach ( $product['plugins'] as $plugin_slug ) {
309
-
310
- $download = $this->settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
311
-
312
- if ( ! isset( $repositories_plugins[ $repository_id ][ $download['slug'] ] ) ) {
313
- $repositories_plugins[ $repository_id ][ $download['slug'] ] = array(
314
- 'name' => $download['name'],
315
- 'registered' => $this->plugin_is_registered( $repository_id, $download['slug'] ) ? 1 : 0
316
- );
317
  }
318
-
319
  }
320
-
321
  }
322
-
323
  }
324
 
325
  foreach ( $plugins as $plugin_id => $plugin ) {
@@ -547,7 +542,7 @@ final class WP_Installer {
547
  );
548
 
549
  if ( ! empty( $response['error'] ) ) {
550
- $this->remove_site_key( $repository_id );
551
 
552
  $this->admin_messages[] = array(
553
  'type' => 'error',
@@ -652,6 +647,19 @@ final class WP_Installer {
652
  return $site_url;
653
  }
654
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
  public function show_site_key_nags() {
656
  $screen = get_current_screen();
657
 
@@ -1016,8 +1024,10 @@ final class WP_Installer {
1016
  // downloads
1017
  if ( isset( $subscription_type ) && ! $expired && ( $product['subscription_type'] == $subscription_type || $product['subscription_type_equivalent'] == $subscription_type ) ) {
1018
 
1019
- foreach ( $product['plugins'] as $plugin_slug ) {
1020
- $row['downloads'][ $plugin_slug ] = $this->settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
 
 
1021
  }
1022
 
1023
  }
@@ -1162,7 +1172,8 @@ final class WP_Installer {
1162
  $this->settings['repositories'][ $repository_id ]['subscription'] = array(
1163
  'key' => $site_key,
1164
  'data' => $subscription_data,
1165
- 'registered_by' => get_current_user_id()
 
1166
  );
1167
  $this->save_settings();
1168
  } else {
@@ -1209,11 +1220,13 @@ final class WP_Installer {
1209
  return WP_Installer::get_repository_site_key( $repository_id );
1210
  }
1211
 
1212
- public function remove_site_key( $repository_id ) {
1213
  if ( isset( $this->settings['repositories'][ $repository_id ] ) ) {
1214
  unset( $this->settings['repositories'][ $repository_id ]['subscription'] );
1215
  $this->save_settings();
1216
- $this->refresh_repositories_data();
 
 
1217
  }
1218
  }
1219
 
@@ -1565,20 +1578,22 @@ final class WP_Installer {
1565
 
1566
  foreach ( $package['products'] as $product ) {
1567
 
1568
- foreach ( $product['plugins'] as $plugin_slug ) {
 
1569
 
1570
- $download = $this->settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
1571
 
1572
- if ( $download['slug'] == $slug || $download['name'] == $plugin['Name'] || $download['name'] == $plugin['Title'] ) { //match order: slug, name, title
1573
 
1574
- if ( isset( $subscriptions_with_warnings[ $product['subscription_type'] ] ) ) {
1575
 
1576
- $this->_plugins_renew_warnings[ $plugin_id ] = $subscriptions_with_warnings[ $product['subscription_type'] ];
 
 
1577
 
1578
  }
1579
 
1580
  }
1581
-
1582
  }
1583
 
1584
  }
@@ -2249,33 +2264,30 @@ final class WP_Installer {
2249
  }
2250
 
2251
  foreach ( $repository['data']['packages'] as $package ) {
2252
-
2253
  foreach ( $package['products'] as $product ) {
 
 
2254
 
2255
- foreach ( $product['plugins'] as $plugin_slug ) {
 
 
 
2256
 
2257
- $download = $this->settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
2258
- if ( ! empty( $download['free-on-wporg'] ) && $download['channel'] == WP_Installer_Channels::CHANNEL_PRODUCTION ) {
2259
- continue;
2260
- }
2261
 
2262
- if ( $download['slug'] == $slug || $download['name'] == $name ) {
 
 
 
 
 
2263
 
2264
- if ( ! $site_key || ! $this->plugin_is_registered( $repository_id, $download['slug'] ) ) {
2265
- add_action( "after_plugin_row_" . $plugin_id, array(
2266
- $this,
2267
- 'show_purchase_notice_under_plugin'
2268
- ), 10, 3 );
2269
  }
2270
 
2271
  }
2272
-
2273
  }
2274
-
2275
  }
2276
-
2277
  }
2278
-
2279
  }
2280
 
2281
  }
@@ -2554,11 +2566,11 @@ final class WP_Installer {
2554
  }
2555
 
2556
  // order parents
2557
- usort( $ordered_packages, array( $this, '_order_packages_callback' ) );
2558
  //order sub-packages
2559
  foreach ( $ordered_packages as $package_id => $package ) {
2560
  if ( ! empty( $package['sub-packages'] ) ) {
2561
- usort( $ordered_packages[ $package_id ]['sub-packages'], create_function( '$a, $b', 'return $a[\'order\'] > $b[\'order\'];' ) );
2562
  }
2563
  }
2564
 
@@ -2571,8 +2583,8 @@ final class WP_Installer {
2571
 
2572
  }
2573
 
2574
- public function _order_packages_callback( $a, $b ) {
2575
- return $a['order'] > $b['order'];
2576
  }
2577
 
2578
  public function get_support_tag_by_name( $name, $repository ) {
@@ -2765,4 +2777,13 @@ final class WP_Installer {
2765
 
2766
  }
2767
 
 
 
 
 
 
 
 
 
 
2768
  }
302
  foreach ( $this->settings['repositories'] as $repository_id => $repository ) {
303
 
304
  foreach ( $repository['data']['packages'] as $package ) {
 
305
  foreach ( $package['products'] as $product ) {
306
+ if ( $this->has_plugins( $product ) ) {
307
+ foreach ( $product['plugins'] as $plugin_slug ) {
308
+ $download = $this->settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
309
+ if ( ! isset( $repositories_plugins[ $repository_id ][ $download['slug'] ] ) ) {
310
+ $repositories_plugins[ $repository_id ][ $download['slug'] ] = array(
311
+ 'name' => $download['name'],
312
+ 'registered' => $this->plugin_is_registered( $repository_id, $download['slug'] ) ? 1 : 0
313
+ );
314
+ }
 
315
  }
 
316
  }
 
317
  }
 
318
  }
319
 
320
  foreach ( $plugins as $plugin_id => $plugin ) {
542
  );
543
 
544
  if ( ! empty( $response['error'] ) ) {
545
+ $this->remove_site_key( $repository_id, false );
546
 
547
  $this->admin_messages[] = array(
548
  'type' => 'error',
647
  return $site_url;
648
  }
649
 
650
+ /**
651
+ * @param string $repository_id
652
+ *
653
+ * @return string|null
654
+ */
655
+ public function get_registered_site_url( $repository_id ) {
656
+ if ( isset( $this->settings['repositories'][ $repository_id ]['subscription']['site_url'] ) ) {
657
+ return $this->settings['repositories'][ $repository_id ]['subscription']['site_url'];
658
+ }
659
+
660
+ return null;
661
+ }
662
+
663
  public function show_site_key_nags() {
664
  $screen = get_current_screen();
665
 
1024
  // downloads
1025
  if ( isset( $subscription_type ) && ! $expired && ( $product['subscription_type'] == $subscription_type || $product['subscription_type_equivalent'] == $subscription_type ) ) {
1026
 
1027
+ if ( $this->has_plugins( $product ) ) {
1028
+ foreach ( $product['plugins'] as $plugin_slug ) {
1029
+ $row['downloads'][ $plugin_slug ] = $this->settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
1030
+ }
1031
  }
1032
 
1033
  }
1172
  $this->settings['repositories'][ $repository_id ]['subscription'] = array(
1173
  'key' => $site_key,
1174
  'data' => $subscription_data,
1175
+ 'registered_by' => get_current_user_id(),
1176
+ 'site_url' => get_site_url(),
1177
  );
1178
  $this->save_settings();
1179
  } else {
1220
  return WP_Installer::get_repository_site_key( $repository_id );
1221
  }
1222
 
1223
+ public function remove_site_key( $repository_id, $refresh_repositories_data = true ) {
1224
  if ( isset( $this->settings['repositories'][ $repository_id ] ) ) {
1225
  unset( $this->settings['repositories'][ $repository_id ]['subscription'] );
1226
  $this->save_settings();
1227
+ if( $refresh_repositories_data ){
1228
+ $this->refresh_repositories_data();
1229
+ }
1230
  }
1231
  }
1232
 
1578
 
1579
  foreach ( $package['products'] as $product ) {
1580
 
1581
+ if ( $this->has_plugins( $product ) ) {
1582
+ foreach ( $product['plugins'] as $plugin_slug ) {
1583
 
1584
+ $download = $this->settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
1585
 
1586
+ if ( $download['slug'] == $slug || $download['name'] == $plugin['Name'] || $download['name'] == $plugin['Title'] ) { //match order: slug, name, title
1587
 
1588
+ if ( isset( $subscriptions_with_warnings[ $product['subscription_type'] ] ) ) {
1589
 
1590
+ $this->_plugins_renew_warnings[ $plugin_id ] = $subscriptions_with_warnings[ $product['subscription_type'] ];
1591
+
1592
+ }
1593
 
1594
  }
1595
 
1596
  }
 
1597
  }
1598
 
1599
  }
2264
  }
2265
 
2266
  foreach ( $repository['data']['packages'] as $package ) {
 
2267
  foreach ( $package['products'] as $product ) {
2268
+ if ( $this->has_plugins( $product ) ) {
2269
+ foreach ( $product['plugins'] as $plugin_slug ) {
2270
 
2271
+ $download = $this->settings['repositories'][ $repository_id ]['data']['downloads']['plugins'][ $plugin_slug ];
2272
+ if ( ! empty( $download['free-on-wporg'] ) && $download['channel'] == WP_Installer_Channels::CHANNEL_PRODUCTION ) {
2273
+ continue;
2274
+ }
2275
 
2276
+ if ( $download['slug'] == $slug || $download['name'] == $name ) {
 
 
 
2277
 
2278
+ if ( ! $site_key || ! $this->plugin_is_registered( $repository_id, $download['slug'] ) ) {
2279
+ add_action( "after_plugin_row_" . $plugin_id, array(
2280
+ $this,
2281
+ 'show_purchase_notice_under_plugin'
2282
+ ), 10, 3 );
2283
+ }
2284
 
 
 
 
 
 
2285
  }
2286
 
2287
  }
 
2288
  }
 
2289
  }
 
2290
  }
 
2291
  }
2292
 
2293
  }
2566
  }
2567
 
2568
  // order parents
2569
+ usort( $ordered_packages, array( $this, 'compare_package_order' ) );
2570
  //order sub-packages
2571
  foreach ( $ordered_packages as $package_id => $package ) {
2572
  if ( ! empty( $package['sub-packages'] ) ) {
2573
+ usort( $ordered_packages[ $package_id ]['sub-packages'], array( $this, 'compare_package_order' ) );
2574
  }
2575
  }
2576
 
2583
 
2584
  }
2585
 
2586
+ public function compare_package_order($a, $b) {
2587
+ return $a['order'] > $b['order'];
2588
  }
2589
 
2590
  public function get_support_tag_by_name( $name, $repository ) {
2777
 
2778
  }
2779
 
2780
+ /**
2781
+ * @param array $product
2782
+ *
2783
+ * @return bool
2784
+ */
2785
+ private function has_plugins( $product ) {
2786
+ return isset( $product['plugins'] ) && is_array( $product['plugins'] );
2787
+ }
2788
+
2789
  }
vendor/otgs/installer/installer.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- define( 'WP_INSTALLER_VERSION', '1.8.2' );
3
 
4
  include_once dirname( __FILE__ ) . '/includes/functions-core.php';
5
  include_once dirname( __FILE__ ) . '/includes/class-wp-installer.php';
@@ -9,10 +9,14 @@ include_once WP_Installer()->plugin_path() . '/includes/class-translation-servic
9
  include_once WP_Installer()->plugin_path() . '/includes/class-installer-dependencies.php';
10
  include_once WP_Installer()->plugin_path() . '/includes/class-wp-installer-channels.php';
11
 
 
 
 
12
  include_once WP_Installer()->plugin_path() . '/includes/functions-templates.php';
13
 
14
  // Initialization
15
  WP_Installer();
16
  WP_Installer_Channels();
17
 
18
-
 
1
  <?php
2
+ define( 'WP_INSTALLER_VERSION', '1.8.8' );
3
 
4
  include_once dirname( __FILE__ ) . '/includes/functions-core.php';
5
  include_once dirname( __FILE__ ) . '/includes/class-wp-installer.php';
9
  include_once WP_Installer()->plugin_path() . '/includes/class-installer-dependencies.php';
10
  include_once WP_Installer()->plugin_path() . '/includes/class-wp-installer-channels.php';
11
 
12
+ include_once WP_Installer()->plugin_path() . '/includes/class-otgs-installer-filename-hooks.php';
13
+ include_once WP_Installer()->plugin_path() . '/includes/class-otgs-installer-php-functions.php';
14
+
15
  include_once WP_Installer()->plugin_path() . '/includes/functions-templates.php';
16
 
17
  // Initialization
18
  WP_Installer();
19
  WP_Installer_Channels();
20
 
21
+ $filename_hooks = new OTGS_Installer_Filename_Hooks( new OTGS_Installer_PHP_Functions() );
22
+ $filename_hooks->add_hooks();
vendor/otgs/installer/loader.php CHANGED
@@ -19,7 +19,7 @@ $wp_installer_instance = dirname(__FILE__) . '/installer.php';
19
  global $wp_installer_instances;
20
  $wp_installer_instances[$wp_installer_instance] = array(
21
  'bootfile' => $wp_installer_instance,
22
- 'version' => '1.8.2'
23
  );
24
 
25
 
19
  global $wp_installer_instances;
20
  $wp_installer_instances[$wp_installer_instance] = array(
21
  'bootfile' => $wp_installer_instance,
22
+ 'version' => '1.8.8'
23
  );
24
 
25
 
vendor/toolset/toolset-common/api.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * List of all available public filters.
4
+ *
5
+ * These filters should only be used to get data (by using apply_filters()) and not be extended (by using add_filter())
6
+ */
7
+
8
+ /**
9
+ * Filter: toolset_m2m_translated_relationships
10
+ * to get all relationships, which include at least one translated post type
11
+ *
12
+ * @param mixed $user_value will be returned if no relationships with translated post types are available
13
+ *
14
+ * @return IToolset_Relationship_Definition[]
15
+ * @since m2m
16
+ */
17
+ if( ! function_exists( 'toolset_filter_toolset_m2m_translated_relationships' ) ) {
18
+ function toolset_filter_toolset_m2m_translated_relationships( $user_value ) {
19
+ do_action( 'toolset_do_m2m_full_init' );
20
+
21
+ if( ! apply_filters( 'toolset_is_m2m_enabled', false ) ) {
22
+ // m2m not active
23
+ return $user_value;
24
+ }
25
+
26
+ $relationships_with_translated_types = Toolset_Relationship_Utils::get_all_translated_relationships();
27
+ return ! empty( $relationships_with_translated_types ) ? $relationships_with_translated_types : $user_value;
28
+ }
29
+ }
30
+
31
+ add_filter( 'toolset_m2m_translated_relationships', 'toolset_filter_toolset_m2m_translated_relationships' );
vendor/toolset/toolset-common/autoload_classmap.php CHANGED
@@ -1,27 +1,43 @@
1
  <?php
2
  // Generated by ZF2's ./bin/classmap_generator.php
3
  return array(
 
4
  'IToolset_Element' => dirname( __FILE__ ) . '/inc/autoloaded/element/i_element.php',
 
5
  'IToolset_Post' => dirname( __FILE__ ) . '/inc/autoloaded/element/i_post.php',
6
  'IToolset_Post_Type' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/i_post_type.php',
7
  'IToolset_Post_Type_From_Types' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/i_post_type_from_types.php',
8
  'IToolset_Post_Type_Registered' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/i_post_type_registered.php',
9
  'IToolset_Query' => dirname( __FILE__ ) . '/inc/autoloaded/i_query.php',
10
  'IToolset_Upgrade_Command' => dirname( __FILE__ ) . '/inc/autoloaded/upgrade/command_interface.php',
 
11
  'Toolset_Admin_Notice_Abstract' => dirname( __FILE__ ) . '/utility/admin/notice/abstract.php',
12
  'Toolset_Admin_Notice_Dismissible' => dirname( __FILE__ ) . '/utility/admin/notice/dismissible.php',
13
  'Toolset_Admin_Notice_Error' => dirname( __FILE__ ) . '/utility/admin/notice/error.php',
14
  'Toolset_Admin_Notice_Interface' => dirname( __FILE__ ) . '/utility/admin/notice/interface.php',
15
  'Toolset_Admin_Notice_Layouts_Help' => dirname( __FILE__ ) . '/utility/admin/notice/layouts/help.php',
16
  'Toolset_Admin_Notice_Required_Action' => dirname( __FILE__ ) . '/utility/admin/notice/required/action.php',
17
- 'Toolset_Admin_Notices_Manager' => dirname( __FILE__ ) . '/utility/admin/notices/manager.php',
18
  'Toolset_Admin_Notice_Success' => dirname( __FILE__ ) . '/utility/admin/notice/success.php',
19
  'Toolset_Admin_Notice_Undismissible' => dirname( __FILE__ ) . '/utility/admin/notice/undismissible.php',
20
  'Toolset_Admin_Notice_Warning' => dirname( __FILE__ ) . '/utility/admin/notice/warning.php',
 
21
  'Toolset_Ajax_Handler_Abstract' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/abstract.php',
 
 
 
 
 
22
  'Toolset_Ajax_Handler_Interface' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/interface.php',
 
23
  'Toolset_Ajax_Handler_Migrate_To_M2M' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/migrate_to_m2m.php',
24
- 'Toolset_Asset_Manager' => dirname( __FILE__ ) . '/inc/controller/asset_manager.php',
 
 
 
 
 
 
 
25
  'Toolset_Condition_Interface' => dirname( __FILE__ ) . '/utility/condition/interface.php',
26
  'Toolset_Condition_Plugin_Access_Active' => dirname( __FILE__ ) . '/utility/condition/plugin/access/active.php',
27
  'Toolset_Condition_Plugin_Access_Missing' => dirname( __FILE__ ) . '/utility/condition/plugin/access/missing.php',
@@ -32,11 +48,14 @@ return array(
32
  'Toolset_Condition_Plugin_Layouts_Missing' => dirname( __FILE__ ) . '/utility/condition/plugin/layouts/missing.php',
33
  'Toolset_Condition_Plugin_Layouts_No_Items' => dirname( __FILE__ ) . '/utility/condition/plugin/layouts/no-items.php',
34
  'Toolset_Condition_Plugin_Types_Active' => dirname( __FILE__ ) . '/utility/condition/plugin/types/active.php',
 
35
  'Toolset_Condition_Plugin_Types_Missing' => dirname( __FILE__ ) . '/utility/condition/plugin/types/missing.php',
36
  'Toolset_Condition_Plugin_Types_Ready_For_M2M' => dirname( __FILE__ ) . '/utility/condition/plugin/types/ready_for_m2m.php',
37
  'Toolset_Condition_Plugin_Views_Active' => dirname( __FILE__ ) . '/utility/condition/plugin/views/active.php',
38
  'Toolset_Condition_Plugin_Views_Missing' => dirname( __FILE__ ) . '/utility/condition/plugin/views/missing.php',
39
  'Toolset_Condition_Plugin_Wpml_Doesnt_Support_M2m' => dirname( __FILE__ ) . '/utility/condition/plugin/wpml/doesnt_support_m2m.php',
 
 
40
  'Toolset_Condition_Theme_Avada_Not_Active_Or_Greater_Equal_5_0' => dirname( __FILE__ ) . '/utility/condition/theme/avada/not-active-or-greater-equal-5-0.php',
41
  'Toolset_Condition_Theme_Layouts_Support_Native_Available' => dirname( __FILE__ ) . '/utility/condition/theme/layouts-support/native/available.php',
42
  'Toolset_Condition_Theme_Layouts_Support_Native_Missing' => dirname( __FILE__ ) . '/utility/condition/theme/layouts-support/native/missing.php',
@@ -51,8 +70,10 @@ return array(
51
  'Toolset_Condition_Theme_Toolset_Based_Active' => dirname( __FILE__ ) . '/utility/condition/theme/toolset-based/active.php',
52
  'Toolset_Condition_Theme_Toolset_Based_Inactive' => dirname( __FILE__ ) . '/utility/condition/theme/toolset-based/inactive.php',
53
  'Toolset_Condition_User_Role_Admin' => dirname( __FILE__ ) . '/utility/condition/user/role/admin.php',
54
- 'Toolset_Constants' => dirname( __FILE__ ) . '/inc/controller/constants.php',
55
- 'Toolset_Controller_Admin_Notices' => dirname( __FILE__ ) . '/inc/controller/admin/notices.php',
 
 
56
  'Toolset_Date' => dirname( __FILE__ ) . '/expression-parser/parser.php',
57
  'Toolset_DateParser' => dirname( __FILE__ ) . '/expression-parser/parser.php',
58
  'Toolset_Date_Utils' => dirname( __FILE__ ) . '/inc/autoloaded/date_utils.php',
@@ -71,13 +92,15 @@ return array(
71
  'Toolset_Field_Data_Mapper_Checkboxes' => dirname( __FILE__ ) . '/inc/autoloaded/field/data_mapper/checkboxes.php',
72
  'Toolset_Field_Data_Mapper_Identity' => dirname( __FILE__ ) . '/inc/autoloaded/field/data_mapper/identity.php',
73
  'Toolset_Field_Data_Saver' => dirname( __FILE__ ) . '/inc/autoloaded/field/data_saver.php',
74
- 'Toolset_Field_Definition_Abstract' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_abstract.php',
75
  'Toolset_Field_Definition' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition.php',
 
76
  'Toolset_Field_Definition_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_factory.php',
 
77
  'Toolset_Field_Definition_Factory_Post' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_factory_post.php',
78
  'Toolset_Field_Definition_Factory_Term' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_factory_term.php',
79
  'Toolset_Field_Definition_Factory_User' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_factory_user.php',
80
  'Toolset_Field_Definition_Generic' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_generic.php',
 
81
  'Toolset_Field_Definition_Post' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_post.php',
82
  'Toolset_Field_Definition_Term' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_term.php',
83
  'Toolset_Field_Definition_User' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_user.php',
@@ -89,8 +112,8 @@ return array(
89
  'Toolset_Field_Group_Term_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/field/group/term_factory.php',
90
  'Toolset_Field_Group_User' => dirname( __FILE__ ) . '/inc/autoloaded/field/group/user.php',
91
  'Toolset_Field_Group_User_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/field/group/user_factory.php',
92
- 'Toolset_Field_Instance_Abstract' => dirname( __FILE__ ) . '/inc/autoloaded/field/instance_abstract.php',
93
  'Toolset_Field_Instance' => dirname( __FILE__ ) . '/inc/autoloaded/field/instance.php',
 
94
  'Toolset_Field_Instance_Post' => dirname( __FILE__ ) . '/inc/autoloaded/field/instance_post.php',
95
  'Toolset_Field_Instance_Term' => dirname( __FILE__ ) . '/inc/autoloaded/field/instance_term.php',
96
  'Toolset_Field_Instance_Unsaved' => dirname( __FILE__ ) . '/inc/autoloaded/field/instance_unsaved.php',
@@ -113,21 +136,30 @@ return array(
113
  'Toolset_Field_Renderer_Purpose' => dirname( __FILE__ ) . '/inc/autoloaded/field/renderer/purpose.php',
114
  'Toolset_Field_Renderer_Toolset_Forms' => dirname( __FILE__ ) . '/inc/autoloaded/field/renderer/toolset_forms.php',
115
  'Toolset_Field_Renderer_Toolset_Forms_Repeatable_Group' => dirname( __FILE__ ) . '/inc/autoloaded/field/renderer/toolset_forms_repeatable_group.php',
 
116
  'Toolset_Field_Type_Definition_Checkbox' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/checkbox.php',
117
  'Toolset_Field_Type_Definition_Checkboxes' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/checkboxes.php',
118
  'Toolset_Field_Type_Definition_Date' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/date.php',
119
- 'Toolset_Field_Type_Definition' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition.php',
120
  'Toolset_Field_Type_Definition_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition_factory.php',
121
  'Toolset_Field_Type_Definition_Numeric' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/numeric.php',
122
  'Toolset_Field_Type_Definition_Radio' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/radio.php',
123
  'Toolset_Field_Type_Definition_Select' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/select.php',
124
  'Toolset_Field_Type_Definition_Singular' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/singular.php',
125
  'Toolset_Field_Utils' => dirname( __FILE__ ) . '/inc/autoloaded/field/utils.php',
 
126
  'Toolset_Functions' => dirname( __FILE__ ) . '/expression-parser/parser.php',
127
  'Toolset_Naming_Helper' => dirname( __FILE__ ) . '/inc/autoloaded/naming_helper.php',
 
 
 
 
 
 
 
128
  'Toolset_Parser' => dirname( __FILE__ ) . '/expression-parser/parser.php',
129
  'Toolset_Post' => dirname( __FILE__ ) . '/inc/autoloaded/element/post.php',
130
  'Toolset_Post_Translation_Set' => dirname( __FILE__ ) . '/inc/autoloaded/element/post_translation_set.php',
 
131
  'Toolset_Post_Type_Exclude_List' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/excluded_list.php',
132
  'Toolset_Post_Type_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/factory.php',
133
  'Toolset_Post_Type_From_Types' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/from_types.php',
@@ -138,6 +170,7 @@ return array(
138
  'Toolset_Post_Type_Repository' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/repository.php',
139
  'Toolset_Regex' => dirname( __FILE__ ) . '/expression-parser/parser.php',
140
  'Toolset_Relationship_Service' => dirname( __FILE__ ) . '/inc/autoloaded/relationship_service.php',
 
141
  'Toolset_Result' => dirname( __FILE__ ) . '/inc/autoloaded/result.php',
142
  'Toolset_Result_Set' => dirname( __FILE__ ) . '/inc/autoloaded/result_set.php',
143
  'Toolset_Result_Updated' => dirname( __FILE__ ) . '/inc/autoloaded/result_updated.php',
@@ -159,6 +192,7 @@ return array(
159
  'Toolset_User_Editors_Editor_Basic' => dirname( __FILE__ ) . '/user-editors/editor/basic.php',
160
  'Toolset_User_Editors_Editor_Beaver' => dirname( __FILE__ ) . '/user-editors/editor/beaver.php',
161
  'Toolset_User_Editors_Editor_Divi' => dirname( __FILE__ ) . '/user-editors/editor/divi.php',
 
162
  'Toolset_User_Editors_Editor_Interface' => dirname( __FILE__ ) . '/user-editors/editor/interface.php',
163
  'Toolset_User_Editors_Editor_Native' => dirname( __FILE__ ) . '/user-editors/editor/native.php',
164
  'Toolset_User_Editors_Editor_Screen_Abstract' => dirname( __FILE__ ) . '/user-editors/editor/screen/abstract.php',
@@ -169,6 +203,7 @@ return array(
169
  'Toolset_User_Editors_Editor_Screen_Beaver_Frontend_Editor' => dirname( __FILE__ ) . '/user-editors/editor/screen/beaver/frontend-editor.php',
170
  'Toolset_User_Editors_Editor_Screen_Divi_Backend' => dirname( __FILE__ ) . '/user-editors/editor/screen/divi/backend.php',
171
  'Toolset_User_Editors_Editor_Screen_Divi_Frontend' => dirname( __FILE__ ) . '/user-editors/editor/screen/divi/frontend.php',
 
172
  'Toolset_User_Editors_Editor_Screen_Interface' => dirname( __FILE__ ) . '/user-editors/editor/screen/interface.php',
173
  'Toolset_User_Editors_Editor_Screen_Native_Backend' => dirname( __FILE__ ) . '/user-editors/editor/screen/native/backend.php',
174
  'Toolset_User_Editors_Editor_Screen_Visual_Composer_Backend' => dirname( __FILE__ ) . '/user-editors/editor/screen/visual-composer/backend.php',
@@ -184,5 +219,36 @@ return array(
184
  'Toolset_User_Editors_Medium_Screen_Content_Template_Frontend' => dirname( __FILE__ ) . '/user-editors/medium/screen/content-template/frontend.php',
185
  'Toolset_User_Editors_Medium_Screen_Content_Template_Frontend_Editor' => dirname( __FILE__ ) . '/user-editors/medium/screen/content-template/frontend-editor.php',
186
  'Toolset_User_Editors_Medium_Screen_Interface' => dirname( __FILE__ ) . '/user-editors/medium/screen/interface.php',
 
 
 
 
 
 
187
  'Toolset_Wpml_Utils' => dirname( __FILE__ ) . '/inc/autoloaded/wpml_utils.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  );
1
  <?php
2
  // Generated by ZF2's ./bin/classmap_generator.php
3
  return array(
4
+ 'IToolset_Cron_Event' => dirname( __FILE__ ) . '/inc/autoloaded/cron/event_interface.php',
5
  'IToolset_Element' => dirname( __FILE__ ) . '/inc/autoloaded/element/i_element.php',
6
+ 'IToolset_Output_Template' => dirname( __FILE__ ) . '/inc/autoloaded/renderer/output_template/interface.php',
7
  'IToolset_Post' => dirname( __FILE__ ) . '/inc/autoloaded/element/i_post.php',
8
  'IToolset_Post_Type' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/i_post_type.php',
9
  'IToolset_Post_Type_From_Types' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/i_post_type_from_types.php',
10
  'IToolset_Post_Type_Registered' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/i_post_type_registered.php',
11
  'IToolset_Query' => dirname( __FILE__ ) . '/inc/autoloaded/i_query.php',
12
  'IToolset_Upgrade_Command' => dirname( __FILE__ ) . '/inc/autoloaded/upgrade/command_interface.php',
13
+ 'Toolset_Admin_Controller' => dirname( __FILE__ ) . '/inc/autoloaded/admin.php',
14
  'Toolset_Admin_Notice_Abstract' => dirname( __FILE__ ) . '/utility/admin/notice/abstract.php',
15
  'Toolset_Admin_Notice_Dismissible' => dirname( __FILE__ ) . '/utility/admin/notice/dismissible.php',
16
  'Toolset_Admin_Notice_Error' => dirname( __FILE__ ) . '/utility/admin/notice/error.php',
17
  'Toolset_Admin_Notice_Interface' => dirname( __FILE__ ) . '/utility/admin/notice/interface.php',
18
  'Toolset_Admin_Notice_Layouts_Help' => dirname( __FILE__ ) . '/utility/admin/notice/layouts/help.php',
19
  'Toolset_Admin_Notice_Required_Action' => dirname( __FILE__ ) . '/utility/admin/notice/required/action.php',
 
20
  'Toolset_Admin_Notice_Success' => dirname( __FILE__ ) . '/utility/admin/notice/success.php',
21
  'Toolset_Admin_Notice_Undismissible' => dirname( __FILE__ ) . '/utility/admin/notice/undismissible.php',
22
  'Toolset_Admin_Notice_Warning' => dirname( __FILE__ ) . '/utility/admin/notice/warning.php',
23
+ 'Toolset_Admin_Notices_Manager' => dirname( __FILE__ ) . '/utility/admin/notices/manager.php',
24
  'Toolset_Ajax_Handler_Abstract' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/abstract.php',
25
+ 'Toolset_Ajax_Handler_Get_Content_Template_Block_Preview' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/get_ct_block_preview.php',
26
+ 'Toolset_Ajax_Handler_Get_Post_By_Id' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/get_post_by_id.php',
27
+ 'Toolset_Ajax_Handler_Get_Term_By_Id' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/get_term_by_id.php',
28
+ 'Toolset_Ajax_Handler_Get_User_By_Id' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/get_user_by_id.php',
29
+ 'Toolset_Ajax_Handler_Get_View_Block_Preview' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/get_view_block_preview.php',
30
  'Toolset_Ajax_Handler_Interface' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/interface.php',
31
+ 'Toolset_Ajax_Handler_Intermediary_Post_Cleanup' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/intermediary_post_cleanup.php',
32
  'Toolset_Ajax_Handler_Migrate_To_M2M' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/migrate_to_m2m.php',
33
+ 'Toolset_Ajax_Handler_Select2_Suggest_Posts_By_Title' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/select2_suggest_posts_by_title.php',
34
+ 'Toolset_Ajax_Handler_Select2_Suggest_Terms' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/select2_suggest_terms.php',
35
+ 'Toolset_Ajax_Handler_Select2_Suggest_Users' => dirname( __FILE__ ) . '/inc/autoloaded/ajax_handler/select2_suggest_users.php',
36
+ 'Toolset_Asset_Manager' => dirname( __FILE__ ) . '/inc/autoloaded/asset_manager.php',
37
+ 'Toolset_Blocks' => dirname( __FILE__ ) . '/toolset-blocks/toolset-blocks.php',
38
+ 'Toolset_Blocks_Content_Template' => dirname( __FILE__ ) . '/toolset-blocks/blocks/ct/ct.php',
39
+ 'Toolset_Blocks_Custom_HTML' => dirname( __FILE__ ) . '/toolset-blocks/blocks/custom-html/custom-html.php',
40
+ 'Toolset_Blocks_View' => dirname( __FILE__ ) . '/toolset-blocks/blocks/view/view.php',
41
  'Toolset_Condition_Interface' => dirname( __FILE__ ) . '/utility/condition/interface.php',
42
  'Toolset_Condition_Plugin_Access_Active' => dirname( __FILE__ ) . '/utility/condition/plugin/access/active.php',
43
  'Toolset_Condition_Plugin_Access_Missing' => dirname( __FILE__ ) . '/utility/condition/plugin/access/missing.php',
48
  'Toolset_Condition_Plugin_Layouts_Missing' => dirname( __FILE__ ) . '/utility/condition/plugin/layouts/missing.php',
49
  'Toolset_Condition_Plugin_Layouts_No_Items' => dirname( __FILE__ ) . '/utility/condition/plugin/layouts/no-items.php',
50
  'Toolset_Condition_Plugin_Types_Active' => dirname( __FILE__ ) . '/utility/condition/plugin/types/active.php',
51
+ 'Toolset_Condition_Plugin_Types_Has_Legacy_Relationships' => dirname( __FILE__ ) . '/utility/condition/plugin/types/has_legacy_relationships.php',
52
  'Toolset_Condition_Plugin_Types_Missing' => dirname( __FILE__ ) . '/utility/condition/plugin/types/missing.php',
53
  'Toolset_Condition_Plugin_Types_Ready_For_M2M' => dirname( __FILE__ ) . '/utility/condition/plugin/types/ready_for_m2m.php',
54
  'Toolset_Condition_Plugin_Views_Active' => dirname( __FILE__ ) . '/utility/condition/plugin/views/active.php',
55
  'Toolset_Condition_Plugin_Views_Missing' => dirname( __FILE__ ) . '/utility/condition/plugin/views/missing.php',
56
  'Toolset_Condition_Plugin_Wpml_Doesnt_Support_M2m' => dirname( __FILE__ ) . '/utility/condition/plugin/wpml/doesnt_support_m2m.php',
57
+ 'Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured' => dirname( __FILE__ ) . '/utility/condition/plugin/wpml/is_active_and_configured.php',
58
+ 'Toolset_Condition_Plugin_Wpml_Is_Current_Language_Default' => dirname( __FILE__ ) . '/utility/condition/plugin/wpml/is_current_language_default.php',
59
  'Toolset_Condition_Theme_Avada_Not_Active_Or_Greater_Equal_5_0' => dirname( __FILE__ ) . '/utility/condition/theme/avada/not-active-or-greater-equal-5-0.php',
60
  'Toolset_Condition_Theme_Layouts_Support_Native_Available' => dirname( __FILE__ ) . '/utility/condition/theme/layouts-support/native/available.php',
61
  'Toolset_Condition_Theme_Layouts_Support_Native_Missing' => dirname( __FILE__ ) . '/utility/condition/theme/layouts-support/native/missing.php',
70
  'Toolset_Condition_Theme_Toolset_Based_Active' => dirname( __FILE__ ) . '/utility/condition/theme/toolset-based/active.php',
71
  'Toolset_Condition_Theme_Toolset_Based_Inactive' => dirname( __FILE__ ) . '/utility/condition/theme/toolset-based/inactive.php',
72
  'Toolset_Condition_User_Role_Admin' => dirname( __FILE__ ) . '/utility/condition/user/role/admin.php',
73
+ 'Toolset_Constants' => dirname( __FILE__ ) . '/inc/autoloaded/constants.php',
74
+ 'Toolset_Controller_Admin_Notices' => dirname( __FILE__ ) . '/inc/autoloaded/admin/notices.php',
75
+ 'Toolset_Cron' => dirname( __FILE__ ) . '/inc/autoloaded/cron/cron.php',
76
+ 'Toolset_Cron_Event' => dirname( __FILE__ ) . '/inc/autoloaded/cron/event.php',
77
  'Toolset_Date' => dirname( __FILE__ ) . '/expression-parser/parser.php',
78
  'Toolset_DateParser' => dirname( __FILE__ ) . '/expression-parser/parser.php',
79
  'Toolset_Date_Utils' => dirname( __FILE__ ) . '/inc/autoloaded/date_utils.php',
92
  'Toolset_Field_Data_Mapper_Checkboxes' => dirname( __FILE__ ) . '/inc/autoloaded/field/data_mapper/checkboxes.php',
93
  'Toolset_Field_Data_Mapper_Identity' => dirname( __FILE__ ) . '/inc/autoloaded/field/data_mapper/identity.php',
94
  'Toolset_Field_Data_Saver' => dirname( __FILE__ ) . '/inc/autoloaded/field/data_saver.php',
 
95
  'Toolset_Field_Definition' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition.php',
96
+ 'Toolset_Field_Definition_Abstract' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_abstract.php',
97
  'Toolset_Field_Definition_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_factory.php',
98
+ 'Toolset_Field_Definition_Factory_Interface' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_factory_interface.php',
99
  'Toolset_Field_Definition_Factory_Post' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_factory_post.php',
100
  'Toolset_Field_Definition_Factory_Term' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_factory_term.php',
101
  'Toolset_Field_Definition_Factory_User' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_factory_user.php',
102
  'Toolset_Field_Definition_Generic' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_generic.php',
103
+ 'Toolset_Field_Definition_Interface' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_interface.php',
104
  'Toolset_Field_Definition_Post' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_post.php',
105
  'Toolset_Field_Definition_Term' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_term.php',
106
  'Toolset_Field_Definition_User' => dirname( __FILE__ ) . '/inc/autoloaded/field/definition_user.php',
112
  'Toolset_Field_Group_Term_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/field/group/term_factory.php',
113
  'Toolset_Field_Group_User' => dirname( __FILE__ ) . '/inc/autoloaded/field/group/user.php',
114
  'Toolset_Field_Group_User_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/field/group/user_factory.php',
 
115
  'Toolset_Field_Instance' => dirname( __FILE__ ) . '/inc/autoloaded/field/instance.php',
116
+ 'Toolset_Field_Instance_Abstract' => dirname( __FILE__ ) . '/inc/autoloaded/field/instance_abstract.php',
117
  'Toolset_Field_Instance_Post' => dirname( __FILE__ ) . '/inc/autoloaded/field/instance_post.php',
118
  'Toolset_Field_Instance_Term' => dirname( __FILE__ ) . '/inc/autoloaded/field/instance_term.php',
119
  'Toolset_Field_Instance_Unsaved' => dirname( __FILE__ ) . '/inc/autoloaded/field/instance_unsaved.php',
136
  'Toolset_Field_Renderer_Purpose' => dirname( __FILE__ ) . '/inc/autoloaded/field/renderer/purpose.php',
137
  'Toolset_Field_Renderer_Toolset_Forms' => dirname( __FILE__ ) . '/inc/autoloaded/field/renderer/toolset_forms.php',
138
  'Toolset_Field_Renderer_Toolset_Forms_Repeatable_Group' => dirname( __FILE__ ) . '/inc/autoloaded/field/renderer/toolset_forms_repeatable_group.php',
139
+ 'Toolset_Field_Type_Definition' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition.php',
140
  'Toolset_Field_Type_Definition_Checkbox' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/checkbox.php',
141
  'Toolset_Field_Type_Definition_Checkboxes' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/checkboxes.php',
142
  'Toolset_Field_Type_Definition_Date' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/date.php',
 
143
  'Toolset_Field_Type_Definition_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition_factory.php',
144
  'Toolset_Field_Type_Definition_Numeric' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/numeric.php',
145
  'Toolset_Field_Type_Definition_Radio' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/radio.php',
146
  'Toolset_Field_Type_Definition_Select' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/select.php',
147
  'Toolset_Field_Type_Definition_Singular' => dirname( __FILE__ ) . '/inc/autoloaded/field/type/definition/singular.php',
148
  'Toolset_Field_Utils' => dirname( __FILE__ ) . '/inc/autoloaded/field/utils.php',
149
+ 'Toolset_Files' => dirname( __FILE__ ) . '/inc/autoloaded/files.php',
150
  'Toolset_Functions' => dirname( __FILE__ ) . '/expression-parser/parser.php',
151
  'Toolset_Naming_Helper' => dirname( __FILE__ ) . '/inc/autoloaded/naming_helper.php',
152
+ 'Toolset_Output_Template' => dirname( __FILE__ ) . '/inc/autoloaded/renderer/output_template/abstract.php',
153
+ 'Toolset_Output_Template_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/renderer/output_template_factory.php',
154
+ 'Toolset_Output_Template_Phtml' => dirname( __FILE__ ) . '/inc/autoloaded/renderer/output_template/phtml.php',
155
+ 'Toolset_Output_Template_Repository' => dirname( __FILE__ ) . '/inc/autoloaded/renderer/output_template_repository.php',
156
+ 'Toolset_Output_Template_Repository_Abstract' => dirname( __FILE__ ) . '/inc/autoloaded/renderer/output_template_repository_abstract.php',
157
+ 'Toolset_Output_Template_Static' => dirname( __FILE__ ) . '/inc/autoloaded/renderer/output_template/static.php',
158
+ 'Toolset_Output_Template_Twig' => dirname( __FILE__ ) . '/inc/autoloaded/renderer/output_template/twig.php',
159
  'Toolset_Parser' => dirname( __FILE__ ) . '/expression-parser/parser.php',
160
  'Toolset_Post' => dirname( __FILE__ ) . '/inc/autoloaded/element/post.php',
161
  'Toolset_Post_Translation_Set' => dirname( __FILE__ ) . '/inc/autoloaded/element/post_translation_set.php',
162
+ 'Toolset_Post_Type_Abstract' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/abstract.php',
163
  'Toolset_Post_Type_Exclude_List' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/excluded_list.php',
164
  'Toolset_Post_Type_Factory' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/factory.php',
165
  'Toolset_Post_Type_From_Types' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/from_types.php',
170
  'Toolset_Post_Type_Repository' => dirname( __FILE__ ) . '/inc/autoloaded/post_type/repository.php',
171
  'Toolset_Regex' => dirname( __FILE__ ) . '/expression-parser/parser.php',
172
  'Toolset_Relationship_Service' => dirname( __FILE__ ) . '/inc/autoloaded/relationship_service.php',
173
+ 'Toolset_Renderer' => dirname( __FILE__ ) . '/inc/autoloaded/renderer/renderer.php',
174
  'Toolset_Result' => dirname( __FILE__ ) . '/inc/autoloaded/result.php',
175
  'Toolset_Result_Set' => dirname( __FILE__ ) . '/inc/autoloaded/result_set.php',
176
  'Toolset_Result_Updated' => dirname( __FILE__ ) . '/inc/autoloaded/result_updated.php',
192
  'Toolset_User_Editors_Editor_Basic' => dirname( __FILE__ ) . '/user-editors/editor/basic.php',
193
  'Toolset_User_Editors_Editor_Beaver' => dirname( __FILE__ ) . '/user-editors/editor/beaver.php',
194
  'Toolset_User_Editors_Editor_Divi' => dirname( __FILE__ ) . '/user-editors/editor/divi.php',
195
+ 'Toolset_User_Editors_Editor_Gutenberg' => dirname( __FILE__ ) . '/user-editors/editor/gutenberg.php',
196
  'Toolset_User_Editors_Editor_Interface' => dirname( __FILE__ ) . '/user-editors/editor/interface.php',
197
  'Toolset_User_Editors_Editor_Native' => dirname( __FILE__ ) . '/user-editors/editor/native.php',
198
  'Toolset_User_Editors_Editor_Screen_Abstract' => dirname( __FILE__ ) . '/user-editors/editor/screen/abstract.php',
203
  'Toolset_User_Editors_Editor_Screen_Beaver_Frontend_Editor' => dirname( __FILE__ ) . '/user-editors/editor/screen/beaver/frontend-editor.php',
204
  'Toolset_User_Editors_Editor_Screen_Divi_Backend' => dirname( __FILE__ ) . '/user-editors/editor/screen/divi/backend.php',
205
  'Toolset_User_Editors_Editor_Screen_Divi_Frontend' => dirname( __FILE__ ) . '/user-editors/editor/screen/divi/frontend.php',
206
+ 'Toolset_User_Editors_Editor_Screen_Gutenberg_Backend' => dirname( __FILE__ ) . '/user-editors/editor/screen/gutenberg/backend.php',
207
  'Toolset_User_Editors_Editor_Screen_Interface' => dirname( __FILE__ ) . '/user-editors/editor/screen/interface.php',
208
  'Toolset_User_Editors_Editor_Screen_Native_Backend' => dirname( __FILE__ ) . '/user-editors/editor/screen/native/backend.php',
209
  'Toolset_User_Editors_Editor_Screen_Visual_Composer_Backend' => dirname( __FILE__ ) . '/user-editors/editor/screen/visual-composer/backend.php',
219
  'Toolset_User_Editors_Medium_Screen_Content_Template_Frontend' => dirname( __FILE__ ) . '/user-editors/medium/screen/content-template/frontend.php',
220
  'Toolset_User_Editors_Medium_Screen_Content_Template_Frontend_Editor' => dirname( __FILE__ ) . '/user-editors/medium/screen/content-template/frontend-editor.php',
221
  'Toolset_User_Editors_Medium_Screen_Interface' => dirname( __FILE__ ) . '/user-editors/medium/screen/interface.php',
222
+ 'Toolset_Wp_Query_Adjustments' => dirname( __FILE__ ) . '/inc/autoloaded/wp_query_adjustments/abstract.php',
223
+ 'Toolset_Wp_Query_Adjustments_Legacy_Relationships' => dirname( __FILE__ ) . '/inc/autoloaded/wp_query_adjustments/legacy_relationships.php',
224
+ 'Toolset_Wp_Query_Adjustments_Loader' => dirname( __FILE__ ) . '/inc/autoloaded/wp_query_adjustments/loader.php',
225
+ 'Toolset_Wp_Query_Adjustments_M2m' => dirname( __FILE__ ) . '/inc/autoloaded/wp_query_adjustments/m2m.php',
226
+ 'Toolset_Wp_Query_Adjustments_Table_Join_Manager' => dirname( __FILE__ ) . '/inc/autoloaded/wp_query_adjustments/table_join_manager.php',
227
+ 'Toolset_Wpdb_User' => dirname( __FILE__ ) . '/inc/autoloaded/wpdb_user.php',
228
  'Toolset_Wpml_Utils' => dirname( __FILE__ ) . '/inc/autoloaded/wpml_utils.php',
229
+ 'Whip_BasicMessage' => dirname( __FILE__ ) . '/lib/whip/src/messages/Whip_BasicMessage.php',
230
+ 'Whip_Configuration' => dirname( __FILE__ ) . '/lib/whip/src/Whip_Configuration.php',
231
+ 'Whip_DismissStorage' => dirname( __FILE__ ) . '/lib/whip/src/interfaces/Whip_DismissStorage.php',
232
+ 'Whip_EmptyProperty' => dirname( __FILE__ ) . '/lib/whip/src/exceptions/Whip_EmptyProperty.php',
233
+ 'Whip_Host' => dirname( __FILE__ ) . '/lib/whip/src/Whip_Host.php',
234
+ 'Whip_HostMessage' => dirname( __FILE__ ) . '/lib/whip/src/messages/Whip_HostMessage.php',
235
+ 'Whip_InvalidOperatorType' => dirname( __FILE__ ) . '/lib/whip/src/exceptions/Whip_InvalidOperatorType.php',
236
+ 'Whip_InvalidType' => dirname( __FILE__ ) . '/lib/whip/src/exceptions/Whip_InvalidType.php',
237
+ 'Whip_InvalidVersionComparisonString' => dirname( __FILE__ ) . '/lib/whip/src/exceptions/Whip_InvalidVersionComparisonString.php',
238
+ 'Whip_InvalidVersionRequirementMessage' => dirname( __FILE__ ) . '/lib/whip/src/messages/Whip_InvalidVersionRequirementMessage.php',
239
+ 'Whip_Listener' => dirname( __FILE__ ) . '/lib/whip/src/interfaces/Whip_Listener.php',
240
+ 'Whip_Message' => dirname( __FILE__ ) . '/lib/whip/src/interfaces/Whip_Message.php',
241
+ 'Whip_MessageDismisser' => dirname( __FILE__ ) . '/lib/whip/src/Whip_MessageDismisser.php',
242
+ 'Whip_MessageFormatter' => dirname( __FILE__ ) . '/lib/whip/src/Whip_MessageFormatter.php',
243
+ 'Whip_MessagePresenter' => dirname( __FILE__ ) . '/lib/whip/src/interfaces/Whip_MessagePresenter.php',
244
+ 'Whip_MessagesManager' => dirname( __FILE__ ) . '/lib/whip/src/Whip_MessagesManager.php',
245
+ 'Whip_NullMessage' => dirname( __FILE__ ) . '/lib/whip/src/messages/Whip_NullMessage.php',
246
+ 'Whip_Requirement' => dirname( __FILE__ ) . '/lib/whip/src/interfaces/Whip_Requirement.php',
247
+ 'Whip_RequirementsChecker' => dirname( __FILE__ ) . '/lib/whip/src/Whip_RequirementsChecker.php',
248
+ 'Whip_UpgradePhpMessage' => dirname( __FILE__ ) . '/lib/whip/src/messages/Whip_UpgradePhpMessage.php',
249
+ 'Whip_VersionDetector' => dirname( __FILE__ ) . '/lib/whip/src/interfaces/Whip_VersionDetector.php',
250
+ 'Whip_VersionRequirement' => dirname( __FILE__ ) . '/lib/whip/src/Whip_VersionRequirement.php',
251
+ 'Whip_WPDismissOption' => dirname( __FILE__ ) . '/lib/whip/src/Whip_WPDismissOption.php',
252
+ 'Whip_WPMessageDismissListener' => dirname( __FILE__ ) . '/lib/whip/src/Whip_WPMessageDismissListener.php',
253
+ 'Whip_WPMessagePresenter' => dirname( __FILE__ ) . '/lib/whip/src/presenters/Whip_WPMessagePresenter.php',
254
  );
vendor/toolset/toolset-common/bootstrap.php CHANGED
@@ -46,8 +46,10 @@ class Toolset_Common_Bootstrap {
46
 
47
  // Names of various sections/modules of the common library that can be loaded.
48
  const TOOLSET_AUTOLOADER = 'toolset_autoloader';
 
49
  const TOOLSET_DEBUG = 'toolset_debug';
50
  const TOOLSET_FORMS = 'toolset_forms';
 
51
  const TOOLSET_VISUAL_EDITOR = 'toolset_visual_editor';
52
  const TOOLSET_PARSER = 'toolset_parser';
53
  const TOOLSET_USER_EDITOR = 'toolset_user_editor';
@@ -187,6 +189,11 @@ class Toolset_Common_Bootstrap {
187
  $this->register_toolset_forms();
188
  }
189
 
 
 
 
 
 
190
  // Maybe register the editor addon
191
  if ( $this->should_load_section( $load, self::TOOLSET_VISUAL_EDITOR ) ) {
192
  $this->register_visual_editor();
@@ -321,7 +328,7 @@ class Toolset_Common_Bootstrap {
321
 
322
  if ( ! class_exists( 'Toolset_Bootstrap_Loader', false ) ) {
323
  require_once( TOOLSET_COMMON_PATH . '/inc/toolset.bootstrap.loader.class.php' );
324
- $toolset_load_bootstrap = Toolset_Bootstrap_Loader::getInstance();
325
  }
326
 
327
  // Load Admin Notices Manager
@@ -332,7 +339,6 @@ class Toolset_Common_Bootstrap {
332
 
333
  // Load Admin Notices Controller (user of our Toolset_Admin_Notices_Manager)
334
  if( ! class_exists( 'Toolset_Controller_Admin_Notices', false ) ) {
335
- require_once( TOOLSET_COMMON_PATH . '/inc/controller/admin/notices.php' );
336
  new Toolset_Controller_Admin_Notices();
337
  }
338
 
@@ -357,6 +363,19 @@ class Toolset_Common_Bootstrap {
357
 
358
  $this->register_relationships();
359
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
  $this->apply_filters_on_sections_loaded( 'toolset_register_include_section' );
361
  }
362
  }
@@ -375,6 +394,11 @@ class Toolset_Common_Bootstrap {
375
  require_once TOOLSET_COMMON_PATH . '/utility/utils.php';
376
  }
377
 
 
 
 
 
 
378
  // Although this is full of DDL prefixes, we need to actually port before using it.
379
  if ( ! $this->is_section_loaded( self::TOOLSET_DIALOGS ) ) {
380
  $this->add_section_loaded( self::TOOLSET_DIALOGS );
@@ -421,6 +445,15 @@ class Toolset_Common_Bootstrap {
421
  }
422
  }
423
 
 
 
 
 
 
 
 
 
 
424
  public function register_visual_editor() {
425
 
426
  if ( ! $this->is_section_loaded( self::TOOLSET_VISUAL_EDITOR ) ) {
46
 
47
  // Names of various sections/modules of the common library that can be loaded.
48
  const TOOLSET_AUTOLOADER = 'toolset_autoloader';
49
+ const TOOLSET_API = 'toolset_api';
50
  const TOOLSET_DEBUG = 'toolset_debug';
51
  const TOOLSET_FORMS = 'toolset_forms';
52
+ const TOOLSET_BLOCKS = 'toolset_blocks';
53
  const TOOLSET_VISUAL_EDITOR = 'toolset_visual_editor';
54
  const TOOLSET_PARSER = 'toolset_parser';
55
  const TOOLSET_USER_EDITOR = 'toolset_user_editor';
189
  $this->register_toolset_forms();
190
  }
191
 
192
+ // Maybe register Toolset blocks
193
+ if ( $this->should_load_section( $load, self::TOOLSET_BLOCKS ) ) {
194
+ $this->register_toolset_blocks();
195
+ }
196
+
197
  // Maybe register the editor addon
198
  if ( $this->should_load_section( $load, self::TOOLSET_VISUAL_EDITOR ) ) {
199
  $this->register_visual_editor();
328
 
329
  if ( ! class_exists( 'Toolset_Bootstrap_Loader', false ) ) {
330
  require_once( TOOLSET_COMMON_PATH . '/inc/toolset.bootstrap.loader.class.php' );
331
+ Toolset_Bootstrap_Loader::getInstance();
332
  }
333
 
334
  // Load Admin Notices Manager
339
 
340
  // Load Admin Notices Controller (user of our Toolset_Admin_Notices_Manager)
341
  if( ! class_exists( 'Toolset_Controller_Admin_Notices', false ) ) {
 
342
  new Toolset_Controller_Admin_Notices();
343
  }
344
 
363
 
364
  $this->register_relationships();
365
 
366
+ // Initialize the admin controller for various tasks if we're in the backend.
367
+ if( self::MODE_ADMIN === $this->get_request_mode() ) {
368
+ $admin_controller = new Toolset_Admin_Controller();
369
+ $admin_controller->initialize();
370
+ }
371
+
372
+ require_once TOOLSET_COMMON_PATH . '/inc/public_api/loader.php';
373
+ $public_api_loader = new Toolset_Public_API_Loader();
374
+ $public_api_loader->initialize();
375
+
376
+ $wp_query_adjustments = new Toolset_Wp_Query_Adjustments_Loader();
377
+ $wp_query_adjustments->initialize();
378
+
379
  $this->apply_filters_on_sections_loaded( 'toolset_register_include_section' );
380
  }
381
  }
394
  require_once TOOLSET_COMMON_PATH . '/utility/utils.php';
395
  }
396
 
397
+ if ( ! $this->is_section_loaded( self::TOOLSET_API ) ) {
398
+ $this->add_section_loaded( self::TOOLSET_API );
399
+ require_once TOOLSET_COMMON_PATH . '/api.php';
400
+ }
401
+
402
  // Although this is full of DDL prefixes, we need to actually port before using it.
403
  if ( ! $this->is_section_loaded( self::TOOLSET_DIALOGS ) ) {
404
  $this->add_section_loaded( self::TOOLSET_DIALOGS );
445
  }
446
  }
447
 
448
+ public function register_toolset_blocks() {
449
+ if ( ! $this->is_section_loaded( self::TOOLSET_BLOCKS ) ) {
450
+ $this->add_section_loaded( self::TOOLSET_BLOCKS );
451
+ $toolset_blocks = new Toolset_Blocks();
452
+ $toolset_blocks->load_blocks();
453
+ $this->apply_filters_on_sections_loaded( 'toolset_register_toolset_blocks_section' );
454
+ }
455
+ }
456
+
457
  public function register_visual_editor() {
458
 
459
  if ( ! $this->is_section_loaded( self::TOOLSET_VISUAL_EDITOR ) ) {
vendor/toolset/toolset-common/changelog.md CHANGED
@@ -1,7 +1,37 @@
1
  # Toolset Common Library
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ## 2.5.8
4
- * New admin notice about Types becoming commercial
 
5
 
6
  ## 2.5.7
7
  * (toolsetcommon-305) Improve the database structure for relationships and associations.
@@ -10,7 +40,7 @@
10
  * Many improvements to the m2m API, especially to the relationship query.
11
  * (toolsetcommon-328) Enforce cardinality limits when creating associations between two elements.
12
  * (toolsetcommon-330) Prevent upgrade routines from running repeatedly. Fix a m2m activation issue.
13
- * (toolsetcommon-249) The Toolset_Twig_Autoloader now bails out when it's possible to load the Twig_Environment class.
14
 
15
  ## 2.5.6
16
  * Fixed a but that prevented CRED attributes offered as select2 instances from getting their values in the final shortcode.
@@ -92,7 +122,7 @@
92
  - Only include the jQuery datepicker stylesheet on demand when the current page contains a datepicker from Toolset.
93
  - Include the user editors in the common bootstrap class.
94
  - toolsetcommon-127, toolsetcommon-55: Include knockout.js
95
- - toolsetcommon-139: Clean up Toolset_Assets_Manager and define constants for asset handles
96
  - toolsetcommon-144: Added Toolset_Admin_Notices_Manager
97
  - toolsetcommon-137: Make the toolset-forms classes autoloaded.
98
  - toolsetcommon-72: Implemented a classmap-based autoloader for all Toolset plugins.
@@ -105,7 +135,7 @@
105
 
106
  ## 2.2.9
107
 
108
- - Fix a validation issue for file, audio, video and embed fields affecting Types.
109
  Allow URLs with non-latin characters, but only for URLs that point to attachments
110
  from the Media Library (validated by WordPress media upload mechanism) (types-1013).
111
  - Improve the validation for non-required Skype fields (toolsetcommon-128).
@@ -118,7 +148,7 @@
118
  - Extend WPToolset_Cake_Validation with the "url2" validation as a counterpart to the validation method in JQuery UI (types-988).
119
 
120
  ## 2.2.5 (November 5, 2016)
121
-
122
  - Thorough check for security vulnerabilities.
123
 
124
  ## 2.2.4 (November 2, 2016)
@@ -140,9 +170,9 @@
140
  - Added an internal Toolset compatibility class
141
 
142
  ## 2.2.1 (August 25, 2016)
143
-
144
  - Avoid translating the Toolset top level admin menu label
145
-
146
  ## 2.2 (August 24, 2016)
147
 
148
  - Added compatibility classes for Relevanssi and Beaver Builder
@@ -168,11 +198,11 @@
168
  - Fixed various bugs
169
 
170
  ## 1.9.2 (March 17, 2016)
171
-
172
  - Fixed issue in validation messages on Amazon S3
173
 
174
  ## 1.9.1 (March 15, 2016)
175
-
176
  - Added control to filter array to prevent exceptions
177
  - Prevented error when object does not have property or key is not set in array filter callback
178
  - Fixed glitch in validation library
@@ -180,7 +210,7 @@
180
  - Fixed search terms with language translation
181
 
182
  ## 1.9 (February 15, 2016)
183
-
184
  - Tagged for Types 1.9, Views 1.12, CRED 1.5, Layouts 1.5 and Access 1.2.8
185
  - Updated parser.php constructors for PHP7 compatibility.
186
  - Updated the adodb time library for PHP7 compatibility.
@@ -188,7 +218,7 @@
188
  - New utils.
189
 
190
  ## 1.8 (November 10, 2015)
191
-
192
  - Tagged for Views 1.11.1, Types 1.8.9 and CRED 1.4.2
193
  - Improved the media manager script.
194
  - Added helper functions for dealing with $_GET, $_POST and arrays.
@@ -197,23 +227,23 @@
197
  - Improved usermeta fields management in CRED forms.
198
 
199
  ## 1.7 (October 30, 2015)
200
-
201
  - Tagged for Views 1.11 and Layouts 1.4
202
 
203
  ## 1.6.2 (September 25, 2015)
204
-
205
  - Tagged for CRED 1.4, Types 1.8.2
206
 
207
  ## 1.6.1 (August 17, 2015)
208
-
209
  - Tagged for Composer Types 1.8, Views 1.10, CRED 1.4 and Layouts 1.3
210
 
211
  ## 1.6 (June 11, 2015)
212
-
213
  - Tagged for Types 1.7, Views 1.9 and Layouts 1.2
214
 
215
  ## 1.5 (Apr 1, 2015)
216
-
217
  - Tagged for Types 1.6.6, Views 1.8, CRED 1.3.6 and Layouts 1.1.
218
  - Fixed issue when there is more than one CRED form on a page with the same taxonomy.
219
  - Fixed a little problem with edit skype button modal window - was too narrow.
@@ -224,16 +254,16 @@ https://wp-types.com/forums/topic/populate-select-field-in-wpcf-um-group/
224
  - Updated CakePHP validation URL method to allow new TLD's.
225
 
226
  ## 1.4 (Feb 2 2015)
227
-
228
  - Tagged for Views 1.7, Types 1.6.5, CRED 1.3.5 and Layouts 1.0 beta1
229
  - Updated Installer to 1.5
230
 
231
  ## 1.3.1 (Dec 16 2014)
232
-
233
  - Tagged for Views 1.7 beta1 and Layouts 1.0 beta1
234
  - Fixed issue about Editor addon and ACF compatibility
235
  - Fixed issue about branding loader
236
 
237
  ## 1.3 (Dec 15 2014)
238
-
239
  - Tagged for Views 1.7 beta1 and Layouts 1.0 beta1
1
  # Toolset Common Library
2
 
3
+ ## 2.6.2
4
+ * Various minor bugfixes.
5
+ * (toolsetcommon-290) First version of the public relationship API for both legacy and m2m relationships.
6
+ * (types-1436) Removed a notice about Types becoming commercial if there's no Types 2.2.* version or below active.
7
+
8
+ ## 2.6.1
9
+ * Fixed an issue regarding the Gutenberg integration with the extension of the Custom HTML block.
10
+ * Fixed a link to documentation about relationships and WPML.
11
+ * Removed a final keyword on some classes.
12
+
13
+ ## 2.6.0
14
+ * Released with Types 2.3-b3, Views 2.6-b2 and CRED 2.0-b1
15
+ * Breaking change in the Toolset_Ajax implementation and subclassing mechanism.
16
+
17
+ ## 2.5.10
18
+ * (toolsetcommon-315) Added a WHIP package warning about dropping the PHP 5.2 support.
19
+ * (toolsetcommon-361) Types custom fields can't be saved
20
+ * (toolsetcommon-334) Introduce a new, more flexible version of the association query class.
21
+ * (toolsetcommon-345) Delete the intermediary post when an association is deleted.
22
+ * (toolsetcommon-346, toolsetcommon-349, toolsetcommon-355, toolsetcommon-370, toolsetcommon-359) Heavy changes to the m2m API to bring WPML support.
23
+ * (toolsetcommon-368) Create intermediary posts even if there are no association fields
24
+ * (toolsetcommon-351) Make sure that the translation mode of a post type involved in a relationship cannot be changed
25
+ * (types-1376) Fixed: Post Type API does not update relationships when post type slug is changed.
26
+ * (types-1413) Fixed: Bug when creating an association with a translatable IPT in a non-default language.
27
+
28
+ ## 2.5.9
29
+ * Released with Views 2.5.2, CRED 1.9.4 and Layouts 2.2
30
+ * (types-1339) Prevent PHP errors when offering to display data from a legacy Types relationship when the parent side post type no longer exists.
31
+
32
  ## 2.5.8
33
+ * New admin notice about Types becoming commercial.
34
+ * (toolsetcommon-339) Extend the relationship query with a mechanism to obtain the total number of found rows.
35
 
36
  ## 2.5.7
37
  * (toolsetcommon-305) Improve the database structure for relationships and associations.
40
  * Many improvements to the m2m API, especially to the relationship query.
41
  * (toolsetcommon-328) Enforce cardinality limits when creating associations between two elements.
42
  * (toolsetcommon-330) Prevent upgrade routines from running repeatedly. Fix a m2m activation issue.
43
+ * (toolsetcommon-249) The Toolset_Twig_Autoloader now bails out when it's possible to load the Twig_Environment class.
44
 
45
  ## 2.5.6
46
  * Fixed a but that prevented CRED attributes offered as select2 instances from getting their values in the final shortcode.
122
  - Only include the jQuery datepicker stylesheet on demand when the current page contains a datepicker from Toolset.
123
  - Include the user editors in the common bootstrap class.
124
  - toolsetcommon-127, toolsetcommon-55: Include knockout.js
125
+ - toolsetcommon-139: Clean up Toolset_Assets_Manager and define constants for asset handles
126
  - toolsetcommon-144: Added Toolset_Admin_Notices_Manager
127
  - toolsetcommon-137: Make the toolset-forms classes autoloaded.
128
  - toolsetcommon-72: Implemented a classmap-based autoloader for all Toolset plugins.
135
 
136
  ## 2.2.9
137
 
138
+ - Fix a validation issue for file, audio, video and embed fields affecting Types.
139
  Allow URLs with non-latin characters, but only for URLs that point to attachments
140
  from the Media Library (validated by WordPress media upload mechanism) (types-1013).
141
  - Improve the validation for non-required Skype fields (toolsetcommon-128).
148
  - Extend WPToolset_Cake_Validation with the "url2" validation as a counterpart to the validation method in JQuery UI (types-988).
149
 
150
  ## 2.2.5 (November 5, 2016)
151
+
152
  - Thorough check for security vulnerabilities.
153
 
154
  ## 2.2.4 (November 2, 2016)
170
  - Added an internal Toolset compatibility class
171
 
172
  ## 2.2.1 (August 25, 2016)
173
+
174
  - Avoid translating the Toolset top level admin menu label
175
+
176
  ## 2.2 (August 24, 2016)
177
 
178
  - Added compatibility classes for Relevanssi and Beaver Builder
198
  - Fixed various bugs
199
 
200
  ## 1.9.2 (March 17, 2016)
201
+
202
  - Fixed issue in validation messages on Amazon S3
203
 
204
  ## 1.9.1 (March 15, 2016)
205
+
206
  - Added control to filter array to prevent exceptions
207
  - Prevented error when object does not have property or key is not set in array filter callback
208
  - Fixed glitch in validation library
210
  - Fixed search terms with language translation
211
 
212
  ## 1.9 (February 15, 2016)
213
+
214
  - Tagged for Types 1.9, Views 1.12, CRED 1.5, Layouts 1.5 and Access 1.2.8
215
  - Updated parser.php constructors for PHP7 compatibility.
216
  - Updated the adodb time library for PHP7 compatibility.
218
  - New utils.
219
 
220
  ## 1.8 (November 10, 2015)
221
+
222
  - Tagged for Views 1.11.1, Types 1.8.9 and CRED 1.4.2
223
  - Improved the media manager script.
224
  - Added helper functions for dealing with $_GET, $_POST and arrays.
227
  - Improved usermeta fields management in CRED forms.
228
 
229
  ## 1.7 (October 30, 2015)
230
+
231
  - Tagged for Views 1.11 and Layouts 1.4
232
 
233
  ## 1.6.2 (September 25, 2015)
234
+
235
  - Tagged for CRED 1.4, Types 1.8.2
236
 
237
  ## 1.6.1 (August 17, 2015)
238
+
239
  - Tagged for Composer Types 1.8, Views 1.10, CRED 1.4 and Layouts 1.3
240
 
241
  ## 1.6 (June 11, 2015)
242
+
243
  - Tagged for Types 1.7, Views 1.9 and Layouts 1.2
244
 
245
  ## 1.5 (Apr 1, 2015)
246
+
247
  - Tagged for Types 1.6.6, Views 1.8, CRED 1.3.6 and Layouts 1.1.
248
  - Fixed issue when there is more than one CRED form on a page with the same taxonomy.
249
  - Fixed a little problem with edit skype button modal window - was too narrow.
254
  - Updated CakePHP validation URL method to allow new TLD's.
255
 
256
  ## 1.4 (Feb 2 2015)
257
+
258
  - Tagged for Views 1.7, Types 1.6.5, CRED 1.3.5 and Layouts 1.0 beta1
259
  - Updated Installer to 1.5
260
 
261
  ## 1.3.1 (Dec 16 2014)
262
+
263
  - Tagged for Views 1.7 beta1 and Layouts 1.0 beta1
264
  - Fixed issue about Editor addon and ACF compatibility
265
  - Fixed issue about branding loader
266
 
267
  ## 1.3 (Dec 15 2014)
268
+
269
  - Tagged for Views 1.7 beta1 and Layouts 1.0 beta1
vendor/toolset/toolset-common/debug/main.js CHANGED
@@ -76,9 +76,9 @@ Toolset.Gui.TroubleshootingPage = function($) {
76
  vm.buttonClass = ko.pureComputed(function() {
77
  if(vm.canProceed()) {
78
  if(vm.isDangerous) {
79
- return 'button-primary toolset-red-button';
80
  } else {
81
- return 'toolset-red-button';
82
  }
83
  } else {
84
  return 'button-secondary';
@@ -91,7 +91,7 @@ Toolset.Gui.TroubleshootingPage = function($) {
91
 
92
 
93
  vm.isOutputEmpty = ko.computed(function() {
94
- return (0 == vm.output().length);
95
  });
96
 
97
 
@@ -194,6 +194,7 @@ Toolset.Gui.TroubleshootingPage = function($) {
194
  success: function (originalResponse) {
195
  var response = WPV_Toolset.Utils.Ajax.parseResponse(originalResponse);
196
 
 
197
  self.debug('AJAX response', actionData, originalResponse);
198
 
199
  if (response.success) {
76
  vm.buttonClass = ko.pureComputed(function() {
77
  if(vm.canProceed()) {
78
  if(vm.isDangerous) {
79
+ return 'button button-primary toolset-red-button';
80
  } else {
81
+ return 'button button-primary';
82
  }
83
  } else {
84
  return 'button-secondary';
91
 
92
 
93
  vm.isOutputEmpty = ko.computed(function() {
94
+ return (0 === vm.output().length);
95
  });
96
 
97
 
194
  success: function (originalResponse) {
195
  var response = WPV_Toolset.Utils.Ajax.parseResponse(originalResponse);
196
 
197
+ // noinspection JSUnusedAssignment
198
  self.debug('AJAX response', actionData, originalResponse);
199
 
200
  if (response.success) {
vendor/toolset/toolset-common/debug/main.twig CHANGED
@@ -51,10 +51,9 @@
51
  </label>
52
  </p>
53
 
54
- <span class="spinner" style="float: right" data-bind="style: { visibility: (isInProgress() ? 'visible' : 'hidden') }"></span>
55
 
56
- <button class="button-primary"
57
- data-bind="
58
  text: buttonLabel,
59
  enable: canProceed,
60
  attr: { class: buttonClass() },
51
  </label>
52
  </p>
53
 
54
+ <span class="spinner" data-bind="style: { visibility: (isInProgress() ? 'visible' : 'hidden') }"></span>
55
 
56
+ <button data-bind="
 
57
  text: buttonLabel,
58
  enable: canProceed,
59
  attr: { class: buttonClass() },
vendor/toolset/toolset-common/functions.php DELETED
@@ -1,9 +0,0 @@
1
- <?php
2
-
3
- _doing_it_wrong(
4
- 'toolset-common/functions.php',
5
- 'The file functions.php in Toolset Common is deprecated and will be removed before next release. The functions are now defined in another file that\'s being automatically loaded by Toolset_Common_Bootstrap. Please stop including this file!',
6
- 'Toolset Common Library 2.1'
7
- );
8
-
9
- require_once dirname( __FILE__ ) . '/inc/toolset.function.helpers.php';
 
 
 
 
 
 
 
 
 
vendor/toolset/toolset-common/inc/autoloaded/admin.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Main controller for Toolset Common tasks in the backend.
5
+ *
6
+ * This class has to be loaded only after the autoloader is initialized.
7
+ *
8
+ * @since 2.5.7
9
+ */
10
+ class Toolset_Admin_Controller {
11
+
12
+
13
+ public function initialize() {
14
+ $this->load_whip();
15
+ }
16
+
17
+
18
+ /**
19
+ * Show a customized WHIP notice for PHP 5.2 users.
20
+ */
21
+ private function load_whip() {
22
+ if ( 'index.php' !== $GLOBALS['pagenow'] && current_user_can( 'manage_options' ) ) {
23
+ return;
24
+ }
25
+
26
+ require_once TOOLSET_COMMON_PATH . '/lib/whip/src/facades/wordpress.php';
27
+
28
+ add_filter( 'whip_hosting_page_url_wordpress', '__return_true' );
29
+ whip_wp_check_versions( array( 'php' => '>=5.3' ) );
30
+ }
31
+
32
+ }
vendor/toolset/toolset-common/inc/{controller → autoloaded}/admin/notices.php RENAMED
@@ -357,6 +357,11 @@ class Toolset_Controller_Admin_Notices {
357
  return false;
358
  }
359
 
 
 
 
 
 
360
  $notice = new Toolset_Admin_Notice_Dismissible( 'types_free_version_support_ends', '', $this->constants );
361
  $notice->set_content( $this->tpl_path . '/types-free-version-ends.phtml' );
362
  Toolset_Admin_Notices_Manager::add_notice( $notice );
@@ -492,4 +497,4 @@ class Toolset_Controller_Admin_Notices {
492
  Toolset_Admin_Notices_Manager::add_notice( $notice );
493
  }
494
 
495
- }
357
  return false;
358
  }
359
 
360
+ $is_m2m_ready = new Toolset_Condition_Plugin_Types_Ready_For_M2M();
361
+ if ( $is_m2m_ready->is_met() ) {
362
+ return false;
363
+ }
364
+
365
  $notice = new Toolset_Admin_Notice_Dismissible( 'types_free_version_support_ends', '', $this->constants );
366
  $notice->set_content( $this->tpl_path . '/types-free-version-ends.phtml' );
367
  Toolset_Admin_Notices_Manager::add_notice( $notice );
497
  Toolset_Admin_Notices_Manager::add_notice( $notice );
498
  }
499
 
500
+ }
vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/get_ct_block_preview.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles AJAX calls to get the Content Template block preview.
5
+ *
6
+ * @since m2m
7
+ */
8
+ class Toolset_Ajax_Handler_Get_Content_Template_Block_Preview extends Toolset_Ajax_Handler_Abstract {
9
+
10
+
11
+ /**
12
+ * @param array $arguments Original action arguments.
13
+ *
14
+ * @return void
15
+ */
16
+ function process_call( $arguments ) {
17
+
18
+ $this->ajax_begin(
19
+ array(
20
+ 'nonce' => Toolset_Ajax::CALLBACK_GET_CONTENT_TEMPLATE_BLOCK_PREVIEW,
21
+ 'is_public' => false,
22
+ )
23
+ );
24
+
25
+ $ct_post_name = sanitize_text_field( toolset_getpost( 'ct_post_name', '' ) );
26
+
27
+ if ( empty( $ct_post_name ) ) {
28
+ $this->ajax_finish( array( 'message' => __( 'Content Template not set.', 'wpv-views' ) ), false );
29
+ }
30
+
31
+ $args = array(
32
+ 'name' => $ct_post_name,
33
+ 'posts_per_page' => 1,
34
+ 'post_type' => 'view-template',
35
+ 'post_status' => 'publish',
36
+ );
37
+
38
+ $ct = get_posts( $args );
39
+
40
+ if (
41
+ null !== $ct
42
+ && count( $ct ) == 1
43
+ ) {
44
+ $ct_post_content = str_replace( "\t", '&nbsp;&nbsp;&nbsp;&nbsp;', str_replace( "\n", '<br />', $ct[0]->post_content ) );
45
+ $this->ajax_finish( $ct_post_content, true );
46
+ }
47
+
48
+ $this->ajax_finish( array( 'message' => sprintf( __( 'Error while retrieving the Content Template preview. The selected Content Template (Slug: "%s") was not found.', 'wpv-views' ), $ct_post_name ) ), false );
49
+ }
50
+ }
vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/get_post_by_id.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles AJAX calls to get a post title by its ID.
5
+ *
6
+ * @since m2m
7
+ */
8
+ class Toolset_Ajax_Handler_Get_Post_By_Id extends Toolset_Ajax_Handler_Abstract {
9
+
10
+
11
+ /**
12
+ * @param array $arguments Original action arguments.
13
+ *
14
+ * @return void
15
+ */
16
+ function process_call( $arguments ) {
17
+
18
+ $this->ajax_begin(
19
+ array(
20
+ 'nonce' => Toolset_Ajax::CALLBACK_GET_POST_BY_ID,
21
+ 'is_public' => true
22
+ )
23
+ );
24
+
25
+ // Read and validate input
26
+ $s = toolset_getpost( 's' );
27
+
28
+
29
+ if ( empty( $s ) ) {
30
+ $this->ajax_finish( array( 'message' => __( 'Wrong or missing query.', 'wpv-views' ) ), false );
31
+ }
32
+
33
+ global $wpdb;
34
+
35
+ $result = $wpdb->get_var(
36
+ $wpdb->prepare(
37
+ "SELECT post_title
38
+ FROM {$wpdb->posts}
39
+ WHERE ID = %d
40
+ LIMIT 1",
41
+ $s
42
+ )
43
+ );
44
+
45
+ if ( isset( $result ) ) {
46
+ $output = array( 'label' => $result );
47
+ $this->ajax_finish( $output, true );
48
+ }
49
+
50
+ $this->ajax_finish( array( 'message' => __( 'Error while retrieving result.', 'wpv-views' ) ), false );
51
+
52
+ }
53
+
54
+ }
vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/get_term_by_id.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles AJAX calls to get a term name by its ID.
5
+ *
6
+ * @since m2m
7
+ */
8
+ class Toolset_Ajax_Handler_Get_Term_By_Id extends Toolset_Ajax_Handler_Abstract {
9
+
10
+
11
+ /**
12
+ * @param array $arguments Original action arguments.
13
+ *
14
+ * @return void
15
+ */
16
+ function process_call( $arguments ) {
17
+
18
+ $this->ajax_begin(
19
+ array(
20
+ 'nonce' => Toolset_Ajax::CALLBACK_GET_TERM_BY_ID,
21
+ 'is_public' => true
22
+ )
23
+ );
24
+
25
+ // Read and validate input
26
+ $s = toolset_getpost( 's' );
27
+
28
+
29
+ if ( empty( $s ) ) {
30
+ $this->ajax_finish( array( 'message' => __( 'Wrong or missing query.', 'wpv-views' ) ), false );
31
+ }
32
+
33
+ global $wpdb;
34
+
35
+ $result = $wpdb->get_var(
36
+ $wpdb->prepare(
37
+ "SELECT name
38
+ FROM {$wpdb->terms}
39
+ WHERE term_id = %d
40
+ LIMIT 1",
41
+ $s
42
+ )
43
+ );
44
+
45
+ if ( isset( $result ) ) {
46
+ $output = array( 'label' => $result );
47
+ $this->ajax_finish( $output, true );
48
+ }
49
+
50
+ $this->ajax_finish( array( 'message' => __( 'Error while retrieving result.', 'wpv-views' ) ), false );
51
+
52
+ }
53
+
54
+ }
vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/get_user_by_id.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles AJAX calls to get an user display name by its ID.
5
+ *
6
+ * @since m2m
7
+ */
8
+ class Toolset_Ajax_Handler_Get_User_By_Id extends Toolset_Ajax_Handler_Abstract {
9
+
10
+
11
+ /**
12
+ * @param array $arguments Original action arguments.
13
+ *
14
+ * @return void
15
+ */
16
+ function process_call( $arguments ) {
17
+
18
+ $this->ajax_begin(
19
+ array(
20
+ 'nonce' => Toolset_Ajax::CALLBACK_GET_USER_BY_ID,
21
+ 'is_public' => true
22
+ )
23
+ );
24
+
25
+ // Read and validate input
26
+ $s = toolset_getpost( 's' );
27
+
28
+
29
+ if ( empty( $s ) ) {
30
+ $this->ajax_finish( array( 'message' => __( 'Wrong or missing query.', 'wpv-views' ) ), false );
31
+ }
32
+
33
+ global $wpdb;
34
+
35
+ $result = $wpdb->get_var(
36
+ $wpdb->prepare(
37
+ "SELECT display_name
38
+ FROM {$wpdb->users}
39
+ WHERE ID = %d
40
+ LIMIT 1",
41
+ $s
42
+ )
43
+ );
44
+
45
+ if ( isset( $result ) ) {
46
+ $output = array( 'label' => $result );
47
+ $this->ajax_finish( $output, true );
48
+ }
49
+
50
+ $this->ajax_finish( array( 'message' => __( 'Error while retrieving result.', 'wpv-views' ) ), false );
51
+
52
+ }
53
+
54
+ }
vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/get_view_block_preview.php ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles AJAX calls to get the view block preview.
5
+ *
6
+ * @since m2m
7
+ */
8
+ class Toolset_Ajax_Handler_Get_View_Block_Preview extends Toolset_Ajax_Handler_Abstract {
9
+
10
+
11
+ /**
12
+ * @param array $arguments Original action arguments.
13
+ *
14
+ * @return void
15
+ */
16
+ function process_call( $arguments ) {
17
+
18
+ $this->ajax_begin(
19
+ array(
20
+ 'nonce' => Toolset_Ajax::CALLBACK_GET_VIEW_BLOCK_PREVIEW,
21
+ 'is_public' => false,
22
+ )
23
+ );
24
+
25
+ $view_id = isset( $_POST['view_id'] ) ? sanitize_text_field( $_POST['view_id'] ) : '';
26
+
27
+ if ( empty( $view_id ) ) {
28
+ $this->ajax_finish( array( 'message' => __( 'View ID not set.', 'wpv-views' ) ), false );
29
+ }
30
+
31
+ global $WP_Views;
32
+
33
+ $view = WPV_View_Base::get_instance( $view_id );
34
+ if ( null !== $view ) {
35
+ $limit = sanitize_text_field( toolset_getpost( 'limit', -1 ) );
36
+ $offset = sanitize_text_field( toolset_getpost( 'offset', 0 ) );
37
+ $orderby = sanitize_text_field( toolset_getpost( 'orderby', '' ) );
38
+ $order = sanitize_text_field( toolset_getpost( 'order', '' ) );
39
+ $secondary_order_by = sanitize_text_field( toolset_getpost( 'secondaryOrderby', '' ) );
40
+ $secondary_order = sanitize_text_field( toolset_getpost( 'secondaryOrder', '' ) );
41
+
42
+ //$view_settings = apply_filters( 'wpv_filter_wpv_get_view_settings', array(), $view_id );
43
+ $view_settings = null !== $view ? $view->view_settings : null;
44
+ //$view_meta = apply_filters( 'wpv_filter_wpv_get_view_layout_settings', array(), $view_id );
45
+ $view_meta = null !== $view ? $view->loop_settings : null;
46
+
47
+ $has_parametric_search = $WP_Views->does_view_have_form_controls( $view_id );
48
+ $has_submit = false;
49
+ $has_extra_attributes = get_view_allowed_attributes( $view_id );
50
+
51
+ if ( isset( $view_settings['filter_meta_html'] ) ) {
52
+ $filter_meta_html = $view_settings['filter_meta_html'];
53
+
54
+ if ( strpos( $filter_meta_html, '[wpv-filter-submit' ) !== false ) {
55
+ $has_submit = true;
56
+ }
57
+ }
58
+
59
+ $view_purpose = '';
60
+
61
+ if ( $view->is_a_view() ) {
62
+ $view_output = get_view_query_results(
63
+ $view_id,
64
+ null,
65
+ null,
66
+ array(
67
+ 'limit' => $limit,
68
+ 'offset' => $offset,
69
+ 'orderby' => $orderby,
70
+ 'order' => $order,
71
+ 'orderby_second' => $secondary_order_by,
72
+ 'order_second' => $secondary_order,
73
+ )
74
+ );
75
+ if ( ! isset( $view_settings['view_purpose'] ) ) {
76
+ $view_settings['view_purpose'] = 'full';
77
+ }
78
+ switch ( $view_settings['view_purpose'] ) {
79
+ case 'all':
80
+ $view_purpose = __( 'Display all results', 'wpv-views' );
81
+ break;
82
+
83
+ case 'pagination':
84
+ $view_purpose = __( 'Display the results with pagination', 'wpv-views' );
85
+ break;
86
+
87
+ case 'slider':
88
+ $view_purpose = __( 'Display the results as a slider', 'wpv-views' );
89
+ break;
90
+
91
+ case 'parametric':
92
+ $view_purpose = __( 'Custom search', 'wpv-views' );
93
+ break;
94
+ case 'full':
95
+ $view_purpose = __( 'Displays a fully customized display', 'wpv-views' );
96
+ break;
97
+ }
98
+ } else {
99
+ $view_output = array();
100
+
101
+ if (
102
+ 'bootstrap-grid' === $view_meta['style']
103
+ || 'table' === $view_meta['style']
104
+ ) {
105
+ if ( 'bootstrap-grid' === $view_meta['style'] ) {
106
+ $col_number = $view_meta['bootstrap_grid_cols'];
107
+ } else {
108
+ $col_number = $view_meta['table_cols'];
109
+ }
110
+
111
+ // add 2 rows of items.
112
+ for ( $i = 1; $i <= 2 * $col_number; $i++ ) {
113
+ $item = new stdClass();
114
+ $item->post_title = sprintf( __( 'Post %d', 'wp-views' ), $i );
115
+ $view_output[] = $item;
116
+ }
117
+ } else {
118
+ // just add 3 items
119
+ for ( $i = 1; $i <= 3; $i++ ) {
120
+ $item = new stdClass();
121
+ $item->post_title = sprintf( __( 'Post %d', 'wp-views' ), $i );
122
+ $view_output[] = $item;
123
+ }
124
+ }
125
+ }
126
+
127
+ $output = array(
128
+ 'view_title' => null !== $view ? $view->title : '',
129
+ 'view_purpose' => $view_purpose,
130
+ 'view_meta' => $view_meta,
131
+ 'view_output' => $view_output,
132
+ 'hasCustomSearch' => $has_parametric_search,
133
+ 'hasSubmit' => $has_submit,
134
+ 'hasExtraAttributes' => $has_extra_attributes,
135
+ );
136
+
137
+ $this->ajax_finish( $output, true );
138
+ }
139
+
140
+ $this->ajax_finish( array( 'message' => sprintf( __( 'Error while retrieving the View preview. The selected View (ID: %s) was not found.', 'wpv-views' ), $view_id ) ), false );
141
+ }
142
+ }
vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/intermediary_post_cleanup.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles an AJAX call coming from the Troubleshooting page that is supposed to clean all the dangling intermediary
5
+ * posts.
6
+ *
7
+ * Continues until there are no posts left to delete.
8
+ *
9
+ * See Toolset_Association_Cleanup_Dangling_Intermediary_Posts for details.
10
+ *
11
+ * @since 2.5.10
12
+ */
13
+ class Toolset_Ajax_Handler_Intermediary_Post_Cleanup extends Toolset_Ajax_Handler_Abstract {
14
+
15
+
16
+ /** @var Toolset_Association_Cleanup_Factory */
17
+ private $cleanup_factory;
18
+
19
+
20
+ /** @var Toolset_Cron */
21
+ private $cron;
22
+
23
+
24
+ /**
25
+ * Toolset_Ajax_Handler_Intermediary_Post_Cleanup constructor.
26
+ *
27
+ * @param Toolset_Ajax $ajax_manager
28
+ * @param Toolset_Association_Cleanup_Factory|null $cleanup_factory_di
29
+ * @param Toolset_Cron|null $cron_di
30
+ */
31
+ public function __construct(
32
+ Toolset_Ajax $ajax_manager,
33
+ Toolset_Association_Cleanup_Factory $cleanup_factory_di = null,
34
+ Toolset_Cron $cron_di = null
35
+ ) {
36
+ parent::__construct( $ajax_manager );
37
+
38
+ $this->cleanup_factory = $cleanup_factory_di ?: new Toolset_Association_Cleanup_Factory();
39
+ $this->cron = $cron_di ?: Toolset_Cron::get_instance();
40
+ }
41
+
42
+
43
+ /**
44
+ * Processes the Ajax call
45
+ *
46
+ * @param array $arguments Original action arguments.
47
+ *
48
+ * @return void
49
+ */
50
+ function process_call( $arguments ) {
51
+ $this->ajax_begin( array( 'nonce' => Toolset_Ajax::CALLBACK_INTERMEDIARY_POST_CLEANUP ) );
52
+
53
+ $current_step = (int) toolset_getpost( 'current_step' );
54
+ $cleanup = $this->cleanup_factory->dangling_intermediary_posts();
55
+ $cleanup->do_batch();
56
+
57
+ $number_of_deleted_posts = $cleanup->get_deleted_posts();
58
+
59
+ // This will consequently hide the admin notice about dangling intermediary posts needing to be deleted.
60
+ if( ! $cleanup->has_remaining_posts() ) {
61
+ $event = $this->cleanup_factory->cron_event();
62
+ $this->cron->unschedule_event( $event );
63
+ }
64
+
65
+ $message = sprintf(
66
+ (
67
+ $cleanup->has_remaining_posts()
68
+ ? __( 'Deleted %d dangling intermediary posts...', 'wpcf' )
69
+ : __( 'Deleted %d dangling intermediary posts. Operation completed.', 'wpcf' )
70
+ ),
71
+ $number_of_deleted_posts
72
+ );
73
+
74
+ $this->ajax_finish(
75
+ array(
76
+ 'continue' => $cleanup->has_remaining_posts(),
77
+ 'message' => $message,
78
+ 'ajax_arguments' => array(
79
+ 'current_step' => $current_step + 1
80
+ )
81
+ )
82
+ );
83
+ }
84
+
85
+ }
vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/migrate_to_m2m.php CHANGED
@@ -26,14 +26,21 @@ class Toolset_Ajax_Handler_Migrate_To_M2M extends Toolset_Ajax_Handler_Abstract
26
  /** @var Toolset_Relationship_Controller */
27
  private $relationship_controller;
28
 
29
- /** @var null|Toolset_Relationship_Migration */
30
  private $migration_controller;
31
 
32
 
 
 
 
 
 
 
 
33
  public function __construct(
34
  $ajax_manager,
35
  Toolset_Relationship_Controller $di_relationship_controller = null,
36
- Toolset_Relationship_Migration $di_migration_controller = null
37
  ) {
38
  parent::__construct( $ajax_manager );
39
 
@@ -49,7 +56,7 @@ class Toolset_Ajax_Handler_Migrate_To_M2M extends Toolset_Ajax_Handler_Abstract
49
 
50
  private function get_migration_controller() {
51
  if( null === $this->migration_controller ) {
52
- $this->migration_controller = new Toolset_Relationship_Migration();
53
  }
54
  return $this->migration_controller;
55
  }
@@ -73,6 +80,7 @@ class Toolset_Ajax_Handler_Migrate_To_M2M extends Toolset_Ajax_Handler_Abstract
73
  $migration_controller = $this->get_migration_controller();
74
 
75
  $step_number = (int) toolset_getarr( $_POST, 'step', 0 );
 
76
 
77
  // If this is set to false, the migration process halts (there will not be another AJAX call)
78
  $continue = true;
@@ -100,11 +108,9 @@ class Toolset_Ajax_Handler_Migrate_To_M2M extends Toolset_Ajax_Handler_Abstract
100
  switch ( $current_phase ) {
101
 
102
  case self::PHASE_DBDELTA: {
103
-
104
  $continue = $this->phase_dbdelta( $step_number , $migration_controller, $results, $next_phase );
105
-
106
- break;
107
- }
108
 
109
  case self::PHASE_DEFINITION_MIGRATION: {
110
  // Second step - (re)create relationship definitions.
@@ -130,8 +136,15 @@ class Toolset_Ajax_Handler_Migrate_To_M2M extends Toolset_Ajax_Handler_Abstract
130
 
131
  $migration_step = $step_number - $steps_before_association_migration;
132
  $offset = $items_per_step * $migration_step;
 
 
133
 
134
- $data_migration_result = $migration_controller->migrate_associations( $offset, $items_per_step );
 
 
 
 
 
135
 
136
  // Decide if we have to continue.
137
  if ( $data_migration_result instanceof Toolset_Result_Updated
@@ -151,9 +164,6 @@ class Toolset_Ajax_Handler_Migrate_To_M2M extends Toolset_Ajax_Handler_Abstract
151
  $next_phase = self::PHASE_FINISH;
152
  }
153
 
154
- } else {
155
- // Fail or a result without count of updated items.
156
- $results->add( $data_migration_result );
157
  }
158
 
159
  break;
@@ -172,14 +182,16 @@ class Toolset_Ajax_Handler_Migrate_To_M2M extends Toolset_Ajax_Handler_Abstract
172
 
173
  $this->ajax_finish(
174
  array(
175
- 'message' => $results->concat_messages( "\n" ),
176
  'continue' => $continue,
177
  'previous_phase' => $current_phase,
178
  'is_complete_success' => $results->is_complete_success(),
179
  'ajax_arguments' => array(
180
  'step' => $step_number + 1,
181
  'phase' => $next_phase,
182
- 'first_phase_step' => $steps_before_association_migration
 
 
183
  )
184
  ),
185
  true // the call is a success, it doesn't say anything about the actual operation
@@ -193,7 +205,7 @@ class Toolset_Ajax_Handler_Migrate_To_M2M extends Toolset_Ajax_Handler_Abstract
193
  * This involves changing database structure.
194
  *
195
  * @param int $step_number Current step of this phase.
196
- * @param Toolset_Relationship_Migration $migration_controller
197
  * @param Toolset_Result_Set $results
198
  * @param int $next_phase The ID of the phase that should follow after this step. Must be set to current phase initially.
199
  *
26
  /** @var Toolset_Relationship_Controller */
27
  private $relationship_controller;
28
 
29
+ /** @var null|Toolset_Relationship_Migration_Controller */
30
  private $migration_controller;
31
 
32
 
33
+ /**
34
+ * Toolset_Ajax_Handler_Migrate_To_M2M constructor.
35
+ *
36
+ * @param Toolset_Ajax $ajax_manager
37
+ * @param Toolset_Relationship_Controller|null $di_relationship_controller
38
+ * @param Toolset_Relationship_Migration_Controller|null $di_migration_controller
39
+ */
40
  public function __construct(
41
  $ajax_manager,
42
  Toolset_Relationship_Controller $di_relationship_controller = null,
43
+ Toolset_Relationship_Migration_Controller $di_migration_controller = null
44
  ) {
45
  parent::__construct( $ajax_manager );
46
 
56
 
57
  private function get_migration_controller() {
58
  if( null === $this->migration_controller ) {
59
+ $this->migration_controller = new Toolset_Relationship_Migration_Controller();
60
  }
61
  return $this->migration_controller;
62
  }
80
  $migration_controller = $this->get_migration_controller();
81
 
82
  $step_number = (int) toolset_getarr( $_POST, 'step', 0 );
83
+ $options = toolset_ensarr( toolset_getarr( $_POST, 'options' ) );
84
 
85
  // If this is set to false, the migration process halts (there will not be another AJAX call)
86
  $continue = true;
108
  switch ( $current_phase ) {
109
 
110
  case self::PHASE_DBDELTA: {
 
111
  $continue = $this->phase_dbdelta( $step_number , $migration_controller, $results, $next_phase );
112
+ break;
113
+ }
 
114
 
115
  case self::PHASE_DEFINITION_MIGRATION: {
116
  // Second step - (re)create relationship definitions.
136
 
137
  $migration_step = $step_number - $steps_before_association_migration;
138
  $offset = $items_per_step * $migration_step;
139
+ $create_default_language_if_missing = ( 'create' === toolset_getarr( $options, 'posts_without_default_translation' ) );
140
+ $copy_post_content_when_creating = (bool) toolset_getarr( $options, 'copy_content_when_creating_posts' );
141
 
142
+ $data_migration_result = $migration_controller->migrate_associations(
143
+ $offset, $items_per_step, $create_default_language_if_missing, $copy_post_content_when_creating
144
+ );
145
+
146
+ // Always add the original result, as it may contain additional information, even in case of success.
147
+ $results->add( $data_migration_result );
148
 
149
  // Decide if we have to continue.
150
  if ( $data_migration_result instanceof Toolset_Result_Updated
164
  $next_phase = self::PHASE_FINISH;
165
  }
166
 
 
 
 
167
  }
168
 
169
  break;
182
 
183
  $this->ajax_finish(
184
  array(
185
+ 'message' => $results->concat_messages( "\n> " ),
186
  'continue' => $continue,
187
  'previous_phase' => $current_phase,
188
  'is_complete_success' => $results->is_complete_success(),
189
  'ajax_arguments' => array(
190
  'step' => $step_number + 1,
191
  'phase' => $next_phase,
192
+ 'first_phase_step' => $steps_before_association_migration,
193
+ // pass the unchanged options so that they're available for all migration steps
194
+ 'options' => $options
195
  )
196
  ),
197
  true // the call is a success, it doesn't say anything about the actual operation
205
  * This involves changing database structure.
206
  *
207
  * @param int $step_number Current step of this phase.
208
+ * @param Toolset_Relationship_Migration_Controller $migration_controller
209
  * @param Toolset_Result_Set $results
210
  * @param int $next_phase The ID of the phase that should follow after this step. Must be set to current phase initially.
211
  *
vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_posts_by_title.php ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles toolset_select2 instances that suggest post by title.
5
+ *
6
+ * If a given post type is not provided, it will return results in any post type but the excluded ones.
7
+ * If a return value among [ 'ID', 'post_name' ] is not provided, it will return result built upon post ID.
8
+ *
9
+ * @since m2m
10
+ */
11
+ class Toolset_Ajax_Handler_Select2_Suggest_Posts_By_Title extends Toolset_Ajax_Handler_Abstract {
12
+
13
+
14
+ /**
15
+ * @param array $arguments Original action arguments.
16
+ *
17
+ * @return void
18
+ */
19
+ function process_call( $arguments ) {
20
+
21
+ $this->ajax_begin(
22
+ array(
23
+ 'nonce' => Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_POSTS_BY_TITLE,
24
+ 'is_public' => true
25
+ )
26
+ );
27
+
28
+ // Read and validate input
29
+ $s = toolset_getpost( 's' );
30
+
31
+
32
+ if ( empty( $s ) ) {
33
+ $this->ajax_finish( array( 'message' => __( 'Wrong or missing query.', 'wpv-views' ) ), false );
34
+ }
35
+
36
+ $return = toolset_getpost( 'valueType' );
37
+ $return = in_array( $return, array( 'ID', 'post_name' ) )
38
+ ? $return
39
+ : 'ID';
40
+
41
+ global $wpdb;
42
+ $values_to_prepare = array();
43
+
44
+ if ( method_exists( $wpdb, 'esc_like' ) ) {
45
+ $s = '%' . $wpdb->esc_like( $s ) . '%';
46
+ } else {
47
+ $s = '%' . like_escape( esc_sql( $s ) ) . '%';
48
+ }
49
+
50
+ $values_to_prepare[] = $s;
51
+
52
+ $post_type_query = '';
53
+ $force_post_type = toolset_getpost( 'postType' );
54
+ if ( empty( $force_post_type ) ) {
55
+ $toolset_post_type_exclude = new Toolset_Post_Type_Exclude_List();
56
+ $toolset_post_type_exclude_list = $toolset_post_type_exclude->get();
57
+ $toolset_post_type_exclude_list_string = "'" . implode( "', '", $toolset_post_type_exclude_list ) . "'";
58
+
59
+ $post_type_query = "AND post_type NOT IN ( {$toolset_post_type_exclude_list_string} ) ";
60
+ } else {
61
+ $post_type_query = "AND post_type = %s ";
62
+ $values_to_prepare[] = $force_post_type;
63
+ }
64
+
65
+ $toolset_post_type_exclude = new Toolset_Post_Type_Exclude_List();
66
+ $toolset_post_type_exclude_list = $toolset_post_type_exclude->get();
67
+ $toolset_post_type_exclude_list_string = "'" . implode( "', '", $toolset_post_type_exclude_list ) . "'";
68
+
69
+ $results = $wpdb->get_results(
70
+ $wpdb->prepare(
71
+ "SELECT ID, post_type, post_title, post_name
72
+ FROM {$wpdb->posts}
73
+ WHERE post_title LIKE %s
74
+ AND post_status = 'publish'
75
+ {$post_type_query}
76
+ LIMIT 0, 15",
77
+ $values_to_prepare
78
+ )
79
+ );
80
+
81
+
82
+ if (
83
+ isset( $results )
84
+ && ! empty( $results )
85
+ ) {
86
+
87
+ $final = array();
88
+
89
+ if ( is_array( $results ) ) {
90
+
91
+ // create list of unique post types in result set
92
+ $selected_post_types = array_map( array( $this,'get_post_type' ), $results );
93
+ $unique_post_types = array_unique( $selected_post_types );
94
+
95
+
96
+ foreach ( $unique_post_types as $key => $post_type ) {
97
+ $post_type_details = get_post_type_object( $post_type );
98
+ $final[ $post_type ] = array(
99
+ 'text' => $post_type_details->label,
100
+ 'children' => array()
101
+ );
102
+ }
103
+ foreach ( $results as $result ) {
104
+ $final[ $result->post_type ]['children'][] = array(
105
+ 'id' => $result->$return,
106
+ 'text' => $result->post_title
107
+ );
108
+ }
109
+
110
+ $final = array_values( $final );
111
+
112
+ }
113
+ $this->ajax_finish( $final, true );
114
+
115
+ } else {
116
+ // return empty result set
117
+ $result = array();
118
+ $this->ajax_finish( $result, true );
119
+ }
120
+
121
+ $this->ajax_finish( array( 'message' => __( 'Error while retrieving result.', 'wpv-views' ) ), false );
122
+
123
+ }
124
+
125
+ /**
126
+ * Return only post type from post object, used for array_map
127
+ * @param $one_post
128
+ * @return string
129
+ */
130
+ private function get_post_type( $one_post ){
131
+ return $one_post->post_type;
132
+ }
133
+
134
+ }
vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_terms.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles toolset_select2 instances that suggest terms.
5
+ *
6
+ * @since m2m
7
+ */
8
+ class Toolset_Ajax_Handler_Select2_Suggest_Terms extends Toolset_Ajax_Handler_Abstract {
9
+
10
+
11
+ /**
12
+ * @param array $arguments Original action arguments.
13
+ *
14
+ * @return void
15
+ */
16
+ function process_call( $arguments ) {
17
+
18
+ $this->ajax_begin(
19
+ array(
20
+ 'nonce' => Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_TERMS,
21
+ 'is_public' => true
22
+ )
23
+ );
24
+
25
+ // Read and validate input
26
+ $s = toolset_getpost( 's' );
27
+
28
+
29
+ if ( empty( $s ) ) {
30
+ $this->ajax_finish( array( 'message' => __( 'Wrong or missing query.', 'wpv-views' ) ), false );
31
+ }
32
+
33
+ global $wpdb;
34
+
35
+ if ( method_exists( $wpdb, 'esc_like' ) ) {
36
+ $s = '%' . $wpdb->esc_like( $s ) . '%';
37
+ } else {
38
+ $s = '%' . like_escape( esc_sql( $s ) ) . '%';
39
+ }
40
+
41
+ $results = $wpdb->get_results(
42
+ $wpdb->prepare(
43
+ "SELECT term_id, name
44
+ FROM {$wpdb->terms}
45
+ WHERE name LIKE %s
46
+ LIMIT 0, 15",
47
+ $s
48
+ )
49
+ );
50
+
51
+ if (
52
+ isset( $results )
53
+ && ! empty( $results )
54
+ ) {
55
+ $output = array();
56
+ if ( is_array( $results ) ) {
57
+ foreach ( $results as $result ) {
58
+ $output[] = array(
59
+ 'text' => $result->name,
60
+ 'id' => $result->term_id,
61
+ );
62
+ }
63
+ }
64
+ $this->ajax_finish( $output, true );
65
+ }
66
+
67
+ $this->ajax_finish( array( 'message' => __( 'Error while retrieving result.', 'wpv-views' ) ), false );
68
+
69
+ }
70
+
71
+ }
vendor/toolset/toolset-common/inc/autoloaded/ajax_handler/select2_suggest_users.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles toolset_select2 instances that suggest users.
5
+ *
6
+ * @since m2m
7
+ */
8
+ class Toolset_Ajax_Handler_Select2_Suggest_Users extends Toolset_Ajax_Handler_Abstract {
9
+
10
+
11
+ /**
12
+ * @param array $arguments Original action arguments.
13
+ *
14
+ * @return void
15
+ */
16
+ function process_call( $arguments ) {
17
+
18
+ $this->ajax_begin(
19
+ array(
20
+ 'nonce' => Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_USERS,
21
+ 'is_public' => true
22
+ )
23
+ );
24
+
25
+ // Read and validate input
26
+ $s = toolset_getpost( 's' );
27
+
28
+
29
+ if ( empty( $s ) ) {
30
+ $this->ajax_finish( array( 'message' => __( 'Wrong or missing query.', 'wpv-views' ) ), false );
31
+ }
32
+
33
+ global $wpdb;
34
+
35
+ if ( method_exists( $wpdb, 'esc_like' ) ) {
36
+ $s = '%' . $wpdb->esc_like( $s ) . '%';
37
+ } else {
38
+ $s = '%' . like_escape( esc_sql( $s ) ) . '%';
39
+ }
40
+
41
+ $results = $wpdb->get_results(
42
+ $wpdb->prepare(
43
+ "SELECT ID, display_name
44
+ FROM {$wpdb->users}
45
+ WHERE display_name LIKE %s
46
+ OR user_login LIKE %s
47
+ OR user_nicename LIKE %s
48
+ LIMIT 0, 15",
49
+ $s,
50
+ $s,
51
+ $s
52
+ )
53
+ );
54
+
55
+ if (
56
+ isset( $results )
57
+ && ! empty( $results )
58
+ ) {
59
+ $output = array();
60
+ if ( is_array( $results ) ) {
61
+ foreach ( $results as $result ) {
62
+ $output[] = array(
63
+ 'text' => $result->display_name,
64
+ 'id' => $result->ID,
65
+ );
66
+ }
67
+ }
68
+ $this->ajax_finish( $output, true );
69
+ }
70
+
71
+ $this->ajax_finish( array( 'message' => __( 'Error while retrieving result.', 'wpv-views' ) ), false );
72
+
73
+ }
74
+
75
+ }
vendor/toolset/toolset-common/inc/{controller → autoloaded}/asset_manager.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/{controller → autoloaded}/constants.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/autoloaded/cron/cron.php ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Helper class for interaction with WP-Cron.
5
+ *
6
+ * Allows scheduling and unscheduling events easier with by allowing events to be defined
7
+ * as objects implementing the IToolset_Cront_Event interface. Additionally, it tracks
8
+ * scheduled events by plugin they come from and allows then batch unscheduling when given plugin
9
+ * is being deactivated.
10
+ *
11
+ * If a plugin is using WP-Cron, it should also include a deactivation hook that will handle this
12
+ * unscheduling.
13
+ *
14
+ * For m2m WP-Cron events originating from Toolset Common, the "types" plugin slug should be used,
15
+ * since without Types, there is no m2m functionality to speak of.
16
+ *
17
+ * Note that events of IToolset_Cront_Event are supposed to have a slug. This slug must
18
+ * be unique throughout Toolset. The event hook (action which will be called by WP-Cron) is built
19
+ * from the HOOK_PREFIX and this unique slug (see get_hook_name()).
20
+ *
21
+ * If two events have different arguments, they are *not* considered equal by WP-Cron.
22
+ * Be sure to thoroughly test such a scenario with this API.
23
+ *
24
+ * @link https://developer.wordpress.org/plugins/cron/
25
+ * @since 2.5.10
26
+ */
27
+ class Toolset_Cron {
28
+
29
+
30
+ /** Prefix of each event hook. Must not be changed, otherwise existing events will break. */
31
+ const HOOK_PREFIX = 'toolset_cron_';
32
+
33
+
34
+ /** Option where the event information is stored (slug + parent plugin) */
35
+ const SCHEDULED_EVENTS_OPTION = 'toolset_cron_events';
36
+
37
+
38
+ /** @var Toolset_Cron */
39
+ private static $instance;
40
+
41
+
42
+ /**
43
+ * @return Toolset_Cron
44
+ */
45
+ public static function get_instance() {
46
+ if( null === self::$instance ) {
47
+ self::$instance = new self();
48
+ }
49
+ return self::$instance;
50
+ }
51
+
52
+
53
+ /**
54
+ * Schedule a new event if it's not scheduled already.
55
+ *
56
+ * @param IToolset_Cron_Event $event
57
+ *
58
+ * @return Toolset_Result Will succeed if an event is scheduled (now or before).
59
+ */
60
+ public function schedule_event( IToolset_Cron_Event $event ) {
61
+ if( $this->is_scheduled( $event ) ) {
62
+ return new Toolset_Result( true );
63
+ }
64
+
65
+ $result = wp_schedule_event(
66
+ time(), $event->get_interval(), $this->get_hook_name( $event ), $event->get_args()
67
+ );
68
+
69
+ $is_success = ( false !== $result );
70
+
71
+ if( $is_success ) {
72
+ $this->save_event( $event );
73
+ }
74
+
75
+ return new Toolset_Result( $is_success );
76
+ }
77
+
78
+
79
+ /**
80
+ * True if an event is already scheduled.
81
+ *
82
+ * @param IToolset_Cron_Event $event
83
+ *
84
+ * @return bool
85
+ */
86
+ public function is_scheduled( IToolset_Cron_Event $event ) {
87
+ $timestamp = wp_next_scheduled( $this->get_hook_name( $event ), $event->get_args() );
88
+ return ( false !== $timestamp );
89
+ }
90
+
91
+
92
+ /**
93
+ * Get a full name of the hook that will be called when WP-Cron executes the event.
94
+ *
95
+ * @param IToolset_Cron_Event $event
96
+ *
97
+ * @return string
98
+ */
99
+ public function get_hook_name( IToolset_Cron_Event $event ) {
100
+ return $this->get_hook_from_slug( $event->get_unique_slug() );
101
+ }
102
+
103
+
104
+ /**
105
+ * @param string $event_slug
106
+ *
107
+ * @return string
108
+ */
109
+ private function get_hook_from_slug( $event_slug ) {
110
+ return self::HOOK_PREFIX . $event_slug;
111
+ }
112
+
113
+
114
+ /**
115
+ * Save the newly scheduled event into the option, so that we know what to deactivate
116
+ * when a Toolset plugin is being deactivated.
117
+ *
118
+ * @param IToolset_Cron_Event $event
119
+ */
120
+ private function save_event( IToolset_Cron_Event $event ) {
121
+ $events = toolset_ensarr( get_option( self::SCHEDULED_EVENTS_OPTION ) );
122
+ $events[ $event->get_unique_slug() ] = array(
123
+ 'slug' => $event->get_unique_slug(),
124
+ 'plugin' => $event->get_parent_plugin()
125
+ );
126
+ update_option( self::SCHEDULED_EVENTS_OPTION, $events, false );
127
+ }
128
+
129
+
130
+ /**
131
+ * Remove an event from the stored option when it was unscheduled.
132
+ *
133
+ * @param string $event_unique_slug
134
+ */
135
+ private function remove_event( $event_unique_slug ) {
136
+ $events = toolset_ensarr( get_option( self::SCHEDULED_EVENTS_OPTION ) );
137
+ unset( $events[ $event_unique_slug ] );
138
+ update_option( self::SCHEDULED_EVENTS_OPTION, $events, false );
139
+ }
140
+
141
+
142
+ /**
143
+ * Unschedule an event.
144
+ *
145
+ * @param IToolset_Cron_Event $event
146
+ *
147
+ * @return Toolset_Result Will succeed if the event was unscheduled or if it there was
148
+ * nothing to unschedule.
149
+ */
150
+ public function unschedule_event( IToolset_Cron_Event $event ) {
151
+ if( ! $this->is_scheduled( $event ) ) {
152
+ return new Toolset_Result( true );
153
+ }
154
+
155
+ $timestamp = wp_next_scheduled( $this->get_hook_name( $event ), $event->get_args() );
156
+ $result = wp_unschedule_event( $timestamp, $this->get_hook_name( $event ) );
157
+
158
+ $was_unscheduled = ( false !== $result );
159
+
160
+ $this->remove_event( $event->get_unique_slug() );
161
+
162
+ return new Toolset_Result( $was_unscheduled );
163
+ }
164
+
165
+
166
+ /**
167
+ * This should be called when a plugin that uses Toolset_Cron is being deactivated.
168
+ *
169
+ * @param string $plugin_slug
170
+ */
171
+ public function on_plugin_deactivation( $plugin_slug ) {
172
+ $events = toolset_ensarr( get_option( self::SCHEDULED_EVENTS_OPTION ) );
173
+ foreach( $events as $event_unique_slug => $event ) {
174
+ $event_parent_plugin = toolset_getarr( $event, 'plugin' );
175
+ if( $event_parent_plugin === $plugin_slug ) {
176
+ wp_unschedule_hook( $this->get_hook_from_slug( $event_unique_slug ) );
177
+ $this->remove_event( $event_unique_slug );
178
+ }
179
+ }
180
+ }
181
+
182
+ }
vendor/toolset/toolset-common/inc/autoloaded/cron/event.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Basic IToolset_Cron_Event implementation.
5
+ *
6
+ * @since 2.5.10
7
+ */
8
+ abstract class Toolset_Cron_Event implements IToolset_Cron_Event {
9
+
10
+
11
+ // These are guaranteed WP-Cron intervals. Anything else is site-specific.
12
+ const INTERVAL_HOURLY = 'hourly';
13
+ const INTERVAL_TWICE_DAILY = 'twicedaily';
14
+ const INTERVAL_DAILY = 'daily';
15
+
16
+
17
+ /**
18
+ * @inheritdoc
19
+ *
20
+ * @return string
21
+ */
22
+ public function get_interval() {
23
+ return self::INTERVAL_DAILY;
24
+ }
25
+
26
+
27
+ /**
28
+ * @inheritdoc
29
+ *
30
+ * @return array
31
+ */
32
+ public function get_args() {
33
+ return array();
34
+ }
35
+
36
+
37
+ }
vendor/toolset/toolset-common/inc/autoloaded/cron/event_interface.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * An interface that represents a WP-Cron event, to be used with Toolset_Cron.
5
+ *
6
+ * @since 2.5.10
7
+ */
8
+ interface IToolset_Cron_Event {
9
+
10
+ /**
11
+ * Event slug.
12
+ *
13
+ * Needs to be unique throughout Toolset.
14
+ *
15
+ * @return string
16
+ */
17
+ public function get_unique_slug();
18
+
19
+
20
+ /**
21
+ * A valid WP-Cron interval. Check Toolset_Cron_Event constants for values that are available
22
+ * at all times.
23
+ *
24
+ * @return string
25
+ */
26
+ public function get_interval();
27
+
28
+
29
+ /**
30
+ * Arguments that will be passed to the event hook when executed.
31
+ *
32
+ * @return array
33
+ */
34
+ public function get_args();
35
+
36
+
37
+ /**
38
+ * Slug of the plugin that owns this event. If the plugin uses Toolset_Cron properly,
39
+ * the right events will be unscheduled if the plugin is deactivated.
40
+ *
41
+ * @return string
42
+ */
43
+ public function get_parent_plugin();
44
+
45
+ }
vendor/toolset/toolset-common/inc/autoloaded/element/element.php CHANGED
@@ -54,88 +54,17 @@ abstract class Toolset_Element implements IToolset_Element {
54
  *
55
  * @param string $domain Valid element domain as defined in Toolset_Field_Utils.
56
  * @param mixed $object_source Source of the underlying object that will be recognized by the specific element class.
57
- * It also recognizes translation sets (array of sources, indexed by language code) for posts.
58
  *
59
  * @return IToolset_Element
60
  * @since m2m
61
  * @deprecated Use Toolset_Element_Factory::get_element() instead.
62
  */
63
  public static function get_instance( $domain, $object_source ) {
64
-
65
- switch( $domain ) {
66
-
67
- /*case Toolset_Field_Utils::DOMAIN_POSTS:
68
-
69
- if( $object_source instanceof IToolset_Post ) {
70
- // todo handle Toolset_Post where we should be returning Toolset_Post_Translation_Set
71
- return $object_source;
72
-
73
- }
74
-
75
- if( Toolset_WPML_Compatibility::get_instance()->is_wpml_active_and_configured() ) {
76
-
77
- // If we got a post object and we know it's not translatable, we don't need to bother.
78
- //
79
- // Without the post object (when we get only an ID, for example), we won't bother for performance reasons.
80
- if( $object_source instanceof WP_Post && ! Toolset_Wpml_Utils::is_post_type_translatable( $object_source->post_type ) ) {
81
- return self::get_untranslated_instance( $domain, $object_source );
82
- }
83
-
84
- if( ! is_array( $object_source ) ) {
85
- $object_source = array( $object_source );
86
- }
87
-
88
- $translated_posts = array();
89
-
90
- // Get a Toolset_Post for each translation
91
- foreach( $object_source as $language_code => $post_id ) {
92
-
93
- if( ! is_string( $language_code ) || empty( $language_code ) ) {
94
- // no (known) language here
95
- $language_code = null;
96
- }
97
-
98
- $post = Toolset_Post::get_instance( $post_id, $language_code );
99
-
100
- $translated_posts[ $post->get_language() ] = $post;
101
- }
102
-
103
- return new Toolset_Post_Translation_Set( $translated_posts );
104
-
105
- }
106
-
107
- // No WPML, simply return the post object.
108
- return self::get_untranslated_instance( $domain, $object_source );*/
109
-
110
-
111
- default:
112
- return self::get_untranslated_instance( $domain, $object_source );
113
- }
114
  }
115
 
116
 
117
- /**
118
- * Get an element instance without attempting translation.
119
- *
120
- * Use with care. Normally you should never need this one and stick with get_instance().
121
- *
122
- * @param string $domain Valid element domain as defined in Toolset_Field_Utils.
123
- * @param mixed $object_source Source of the underlying object that will be recognized by the specific element class.
124
- *
125
- * @return IToolset_Element
126
- */
127
- public static function get_untranslated_instance( $domain, $object_source ) {
128
- switch( $domain ) {
129
- case Toolset_Field_Utils::DOMAIN_POSTS:
130
- return Toolset_Post::get_instance( $object_source );
131
- case Toolset_Field_Utils::DOMAIN_TERMS:
132
- case Toolset_Field_Utils::DOMAIN_USERS:
133
- throw new RuntimeException( 'Not implemented.' );
134
- default:
135
- throw new InvalidArgumentException( 'Invalid domain name.' );
136
- }
137
- }
138
-
139
 
140
  /**
141
  * @return string One of the Toolset_Field_Utils::get_domains() values.
@@ -322,4 +251,30 @@ abstract class Toolset_Element implements IToolset_Element {
322
  return false;
323
  }
324
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  }
54
  *
55
  * @param string $domain Valid element domain as defined in Toolset_Field_Utils.
56
  * @param mixed $object_source Source of the underlying object that will be recognized by the specific element class.
 
57
  *
58
  * @return IToolset_Element
59
  * @since m2m
60
  * @deprecated Use Toolset_Element_Factory::get_element() instead.
61
  */
62
  public static function get_instance( $domain, $object_source ) {
63
+ $factory = new Toolset_Element_Factory();
64
+ return $factory->get_element( $domain, $object_source );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  }
66
 
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
  /**
70
  * @return string One of the Toolset_Field_Utils::get_domains() values.
251
  return false;
252
  }
253
 
254
+
255
+ /**
256
+ * @inheritdoc
257
+ *
258
+ * @param string $language_code
259
+ * @param bool $exact_match_only
260
+ *
261
+ * @return IToolset_Element|null
262
+ */
263
+ public function translate( $language_code, $exact_match_only = false ) {
264
+ // We can afford this even for posts. If WPML is active at all, all posts will be
265
+ // instantiated as translation sets.
266
+ return $this;
267
+ }
268
+
269
+
270
+ /**
271
+ * @inheritdoc
272
+ *
273
+ * @return int
274
+ * @since 2.5.10
275
+ */
276
+ public function get_default_language_id() {
277
+ return $this->get_id();
278
+ }
279
+
280
  }
vendor/toolset/toolset-common/inc/autoloaded/element/element_factory.php CHANGED
@@ -3,41 +3,122 @@
3
  /**
4
  * Factory for IToolset_Element.
5
  *
6
- * Note: Currently used only for the purpose of unit test mocking. Eventually the relevant code should be moved here.
7
- *
8
  * @since m2m
 
 
 
9
  */
10
  class Toolset_Element_Factory {
11
 
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  /**
14
  * Get an element instance based on it's domain.
15
  *
16
  * @param string $domain Valid element domain as defined in Toolset_Field_Utils.
17
- * @param mixed $object_source Source of the underlying object that will be recognized by the specific element class.
18
- * It also recognizes translation sets (array of sources, indexed by language code) for posts.
19
  *
20
  * @return IToolset_Element
 
21
  * @since m2m
22
  */
23
  public function get_element( $domain, $object_source ) {
24
- return Toolset_Element::get_instance( $domain, $object_source );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  }
26
 
27
 
28
  /**
29
  * Instantiate the post.
30
  *
31
- * To be used only within m2m API. For instantiating Toolset elements, you should
32
- * always use Toolset_Element::get_instance().
 
 
33
  *
34
- * @param string|WP_Post $object_source
35
- * @param null|string $language_code
 
36
  *
37
  * @return Toolset_Post
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  */
39
- public function get_post( $object_source, $language_code = null ) {
40
- return Toolset_Post::get_instance( $object_source, $language_code );
 
 
 
41
  }
42
 
43
  }
3
  /**
4
  * Factory for IToolset_Element.
5
  *
 
 
6
  * @since m2m
7
+ * @since 2.5.10 The get_post() method is open to external use and can return the post translation
8
+ * set as well, if WPML is active. get_post_untranslated() can be used instead of the previous
9
+ * get_post() implementation.
10
  */
11
  class Toolset_Element_Factory {
12
 
13
 
14
+ /** @var Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured */
15
+ private $is_wpml_active;
16
+
17
+
18
+ /** @var Toolset_WPML_Compatibility */
19
+ private $wpml_service;
20
+
21
+
22
+ /**
23
+ * Toolset_Element_Factory constructor.
24
+ *
25
+ * @param Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured|null $is_wpml_active
26
+ * @param Toolset_WPML_Compatibility|null $wpml_service
27
+ */
28
+ public function __construct(
29
+ Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured $is_wpml_active = null,
30
+ Toolset_WPML_Compatibility $wpml_service = null
31
+ ) {
32
+ $this->is_wpml_active = ( null === $is_wpml_active ? new Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured() : $is_wpml_active );
33
+ $this->wpml_service = ( null === $wpml_service ? Toolset_WPML_Compatibility::get_instance() : $wpml_service );
34
+ }
35
+
36
+
37
  /**
38
  * Get an element instance based on it's domain.
39
  *
40
  * @param string $domain Valid element domain as defined in Toolset_Field_Utils.
41
+ * @param mixed $object_source Source of the underlying object that will be recognized by the specific element
42
+ * class. It also recognizes translation sets (array of sources, indexed by language code) for posts.
43
  *
44
  * @return IToolset_Element
45
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
46
  * @since m2m
47
  */
48
  public function get_element( $domain, $object_source ) {
49
+ switch( $domain ) {
50
+ case Toolset_Element_Domain::POSTS:
51
+ return $this->get_post( $object_source );
52
+
53
+ case Toolset_Element_Domain::TERMS:
54
+ case Toolset_Element_Domain::USERS:
55
+ throw new RuntimeException( 'Not implemented.' );
56
+ }
57
+
58
+ throw new InvalidArgumentException( 'Invalid domain name.' );
59
+ }
60
+
61
+
62
+ /**
63
+ * Instantiate the post.
64
+ *
65
+ * @param int|WP_Post $object_source
66
+ *
67
+ * @return IToolset_Post
68
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
69
+ */
70
+ public function get_post( $object_source ) {
71
+ if( $this->is_wpml_active->is_met() ) {
72
+
73
+ if( ! $object_source instanceof WP_Post
74
+ || $this->wpml_service->is_post_type_translatable( $object_source->post_type )
75
+ ) {
76
+ // Either we don't know the post type yet or we know it is translatable.
77
+ return $this->get_post_translation_set( $object_source );
78
+ }
79
+ }
80
+
81
+ return $this->get_post_untranslated( $object_source );
82
  }
83
 
84
 
85
  /**
86
  * Instantiate the post.
87
  *
88
+ * This is an WPML-unaware version that will always return a Toolset_Post instance.
89
+ * Use only in cases where this is explicitly needed.
90
+ *
91
+ * Otherwise, for instantiating Toolset elements, you should use the get_element() method.
92
  *
93
+ * @param int|WP_Post $object_source
94
+ * @param null|string $language_code Language of the post being created.
95
+ * If it's passed here, it might save one WPML interaction later when requested.
96
  *
97
  * @return Toolset_Post
98
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
99
+ */
100
+ public function get_post_untranslated( $object_source, $language_code = null ) {
101
+ return new Toolset_Post(
102
+ $object_source, $language_code, null, null, $this
103
+ );
104
+ }
105
+
106
+
107
+ /**
108
+ * Instantiate the post as a translation set.
109
+ *
110
+ * This method must not be used when WPML is not active, and there should be no reasonable need to use
111
+ * it instead of get_element() or get_post().
112
+ *
113
+ * @param array|WP_Post|int $object_source
114
+ *
115
+ * @return Toolset_Post_Translation_Set
116
  */
117
+ public function get_post_translation_set( $object_source ) {
118
+ if( ! is_array( $object_source ) ) {
119
+ $object_source = array( $object_source );
120
+ }
121
+ return new Toolset_Post_Translation_Set( $object_source, $this->wpml_service, $this );
122
  }
123
 
124
  }
vendor/toolset/toolset-common/inc/autoloaded/element/i_element.php CHANGED
@@ -15,19 +15,19 @@ interface IToolset_Element {
15
  /**
16
  * @return string One of the Toolset_Field_Utils::get_domains() values.
17
  */
18
- function get_domain();
19
 
20
 
21
  /**
22
  * @return int ID of the underlying object.
23
  */
24
- function get_id();
25
 
26
 
27
  /**
28
  * @return string Element title.
29
  */
30
- function get_title();
31
 
32
 
33
  /**
@@ -36,13 +36,13 @@ interface IToolset_Element {
36
  * @return void
37
  * @since m2m
38
  */
39
- function initialize_fields();
40
 
41
 
42
  /**
43
  * @return bool
44
  */
45
- function are_fields_loaded();
46
 
47
 
48
  /**
@@ -51,7 +51,7 @@ interface IToolset_Element {
51
  * @return mixed Depends on the implementation.
52
  * @since m2m
53
  */
54
- function get_underlying_object();
55
 
56
 
57
  /**
@@ -65,7 +65,7 @@ interface IToolset_Element {
65
  * @throws InvalidArgumentException When the field source has a wrong type.
66
  * @since m2m
67
  */
68
- function has_field( $field_source );
69
 
70
 
71
  /**
@@ -77,7 +77,7 @@ interface IToolset_Element {
77
  * @return Toolset_Field_Instance
78
  * @throws InvalidArgumentException When the field source has a wrong type.
79
  */
80
- function get_field( $field_source );
81
 
82
 
83
  /**
@@ -86,10 +86,10 @@ interface IToolset_Element {
86
  * @return Toolset_Field_Instance[]
87
  * @since m2m
88
  */
89
- function get_fields();
90
 
91
 
92
- function get_field_count();
93
 
94
 
95
  /**
@@ -97,7 +97,7 @@ interface IToolset_Element {
97
  *
98
  * @return bool
99
  */
100
- function is_translatable();
101
 
102
 
103
  /**
@@ -106,5 +106,33 @@ interface IToolset_Element {
106
  * @return string Language code or an empty string if not applicable.
107
  * @since m2m
108
  */
109
- function get_language();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  }
15
  /**
16
  * @return string One of the Toolset_Field_Utils::get_domains() values.
17
  */
18
+ public function get_domain();
19
 
20
 
21
  /**
22
  * @return int ID of the underlying object.
23
  */
24
+ public function get_id();
25
 
26
 
27
  /**
28
  * @return string Element title.
29
  */
30
+ public function get_title();
31
 
32
 
33
  /**
36
  * @return void
37
  * @since m2m
38
  */
39
+ public function initialize_fields();
40
 
41
 
42
  /**
43
  * @return bool
44
  */
45
+ public function are_fields_loaded();
46
 
47
 
48
  /**
51
  * @return mixed Depends on the implementation.
52
  * @since m2m
53
  */
54
+ public function get_underlying_object();
55
 
56
 
57
  /**
65
  * @throws InvalidArgumentException When the field source has a wrong type.
66
  * @since m2m
67
  */
68
+ public function has_field( $field_source );
69
 
70
 
71
  /**
77
  * @return Toolset_Field_Instance
78
  * @throws InvalidArgumentException When the field source has a wrong type.
79
  */
80
+ public function get_field( $field_source );
81
 
82
 
83
  /**
86
  * @return Toolset_Field_Instance[]
87
  * @since m2m
88
  */
89
+ public function get_fields();
90
 
91
 
92
+ public function get_field_count();
93
 
94
 
95
  /**
97
  *
98
  * @return bool
99
  */
100
+ public function is_translatable();
101
 
102
 
103
  /**
106
  * @return string Language code or an empty string if not applicable.
107
  * @since m2m
108
  */
109
+ public function get_language();
110
+
111
+
112
+ /**
113
+ * Return an element translation.
114
+ *
115
+ * If the element domain and type are non-translatable, it will return itself.
116
+ *
117
+ * If the element could be translated to the target language but is not,
118
+ * the return value will depend on the $exact_match_only parameter:
119
+ * If it's true, it will return null. Otherwise, it will return the best possible
120
+ * translation (default language/original/any).
121
+ *
122
+ * @param string $language_code
123
+ * @param bool $exact_match_only
124
+ *
125
+ * @return IToolset_Element|null
126
+ * @since 2.5.10
127
+ */
128
+ public function translate( $language_code, $exact_match_only = false );
129
+
130
+
131
+ /**
132
+ * ID of the element in the default language or same as get_id() if not applicable.
133
+ *
134
+ * @return int
135
+ * @since 2.5.10
136
+ */
137
+ public function get_default_language_id();
138
  }
vendor/toolset/toolset-common/inc/autoloaded/element/i_post.php CHANGED
@@ -15,6 +15,13 @@ interface IToolset_Post extends IToolset_Element {
15
  public function get_type();
16
 
17
 
 
 
 
 
 
 
 
18
  /**
19
  * @return string Post title
20
  * @since m2m
@@ -33,7 +40,28 @@ interface IToolset_Post extends IToolset_Element {
33
 
34
  /**
35
  * @return string Post slug
36
- * @since m2M
37
  */
38
  public function get_slug();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  }
15
  public function get_type();
16
 
17
 
18
+ /**
19
+ * @return IToolset_Post_Type|null
20
+ * @since 2.5.10
21
+ */
22
+ public function get_type_object();
23
+
24
+
25
  /**
26
  * @return string Post title
27
  * @since m2m
40
 
41
  /**
42
  * @return string Post slug
43
+ * @since m2m
44
  */
45
  public function get_slug();
46
+
47
+
48
+ /**
49
+ * @return bool
50
+ * @since 2.5.10
51
+ */
52
+ public function is_revision();
53
+
54
+
55
+ /**
56
+ * @return int ID of the post author.
57
+ * @since 2.5.11
58
+ */
59
+ public function get_author();
60
+
61
+
62
+ /**
63
+ * @return int The trid of the translation set if WPML is active and the post is part of one, zero otherwise.
64
+ * @since 2.5.11
65
+ */
66
+ public function get_trid();
67
  }
vendor/toolset/toolset-common/inc/autoloaded/element/post.php CHANGED
@@ -5,12 +5,17 @@
5
  *
6
  * Simplifies the access to field instances and associations.
7
  *
 
 
8
  * @since m2m
9
  */
10
  class Toolset_Post extends Toolset_Element implements IToolset_Post {
11
 
 
 
12
  const SORTORDER_META_KEY = 'toolset-post-sortorder';
13
 
 
14
  /** @var WP_Post */
15
  private $post;
16
 
@@ -19,6 +24,15 @@ class Toolset_Post extends Toolset_Element implements IToolset_Post {
19
  private $language_code = null;
20
 
21
 
 
 
 
 
 
 
 
 
 
22
  /**
23
  * Toolset_Element constructor.
24
  *
@@ -27,11 +41,22 @@ class Toolset_Post extends Toolset_Element implements IToolset_Post {
27
  * "this post has no language", while null can be passed if this unknown (and it will be
28
  * determined first time it's needed).
29
  * @param null|Toolset_Field_Group_Post_Factory $group_post_factory DI for phpunit
 
 
 
30
  *
31
  * @throws Toolset_Element_Exception_Element_Doesnt_Exist
32
  * @since m2m
33
  */
34
- protected function __construct( $object_source, $language_code = null, $group_post_factory = null ) {
 
 
 
 
 
 
 
 
35
 
36
  if( Toolset_Utils::is_natural_numeric( $object_source ) ) {
37
  $post = WP_Post::get_instance( $object_source );
@@ -53,8 +78,9 @@ class Toolset_Post extends Toolset_Element implements IToolset_Post {
53
  parent::__construct( $post, $group_post_factory );
54
 
55
  $this->post = $post;
56
-
57
  $this->language_code = $language_code;
 
 
58
  }
59
 
60
 
@@ -70,16 +96,18 @@ class Toolset_Post extends Toolset_Element implements IToolset_Post {
70
  * @deprecated Use Toolset_Element_Factory::get_post() instead.
71
  *
72
  * @return Toolset_Post
 
73
  */
74
  public static function get_instance( $object_source, $language_code = null ) {
75
- return new self( $object_source, $language_code );
 
76
  }
77
 
78
 
79
  /**
80
  * @return string One of the Toolset_Field_Utils::get_domains() values.
81
  */
82
- public function get_domain() { return Toolset_Field_Utils::DOMAIN_POSTS; }
83
 
84
 
85
  /**
@@ -121,7 +149,7 @@ class Toolset_Post extends Toolset_Element implements IToolset_Post {
121
  * @return bool
122
  */
123
  public function is_translatable() {
124
- return Toolset_Wpml_Utils::is_post_type_translatable( $this->get_type() );
125
  }
126
 
127
 
@@ -129,10 +157,9 @@ class Toolset_Post extends Toolset_Element implements IToolset_Post {
129
  * @inheritdoc
130
  * @return string
131
  */
132
- function get_language() {
133
  if( null === $this->language_code ) {
134
- $post_language_details = apply_filters( 'wpml_post_language_details', null, $this->get_id() );
135
- $this->language_code = toolset_getarr( $post_language_details, 'language_code', '' );
136
  }
137
 
138
  return $this->language_code;
@@ -159,4 +186,93 @@ class Toolset_Post extends Toolset_Element implements IToolset_Post {
159
  }
160
 
161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  }
5
  *
6
  * Simplifies the access to field instances and associations.
7
  *
8
+ * Always use Toolset_Element_Factory to instantiate this class.
9
+ *
10
  * @since m2m
11
  */
12
  class Toolset_Post extends Toolset_Element implements IToolset_Post {
13
 
14
+
15
+ // FIXME document this
16
  const SORTORDER_META_KEY = 'toolset-post-sortorder';
17
 
18
+
19
  /** @var WP_Post */
20
  private $post;
21
 
24
  private $language_code = null;
25
 
26
 
27
+ private $_post_type_repository;
28
+
29
+ private $element_factory;
30
+
31
+
32
+ /** @var Toolset_WPML_Compatibility */
33
+ private $wpml_service;
34
+
35
+
36
  /**
37
  * Toolset_Element constructor.
38
  *
41
  * "this post has no language", while null can be passed if this unknown (and it will be
42
  * determined first time it's needed).
43
  * @param null|Toolset_Field_Group_Post_Factory $group_post_factory DI for phpunit
44
+ * @param Toolset_Post_Type_Repository|null $post_type_repository_di
45
+ * @param Toolset_Element_Factory|null $element_factory_di
46
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
47
  *
48
  * @throws Toolset_Element_Exception_Element_Doesnt_Exist
49
  * @since m2m
50
  */
51
+ public function __construct(
52
+ $object_source,
53
+ $language_code = null,
54
+ $group_post_factory = null,
55
+ Toolset_Post_Type_Repository $post_type_repository_di = null,
56
+ Toolset_Element_Factory $element_factory_di = null,
57
+ Toolset_WPML_Compatibility $wpml_service_di = null
58
+ ) {
59
+ $this->_post_type_repository = $post_type_repository_di;
60
 
61
  if( Toolset_Utils::is_natural_numeric( $object_source ) ) {
62
  $post = WP_Post::get_instance( $object_source );
78
  parent::__construct( $post, $group_post_factory );
79
 
80
  $this->post = $post;
 
81
  $this->language_code = $language_code;
82
+ $this->element_factory = ( null === $element_factory_di ? new Toolset_Element_Factory() : $element_factory_di );
83
+ $this->wpml_service = ( null === $wpml_service_di ? Toolset_WPML_Compatibility::get_instance() : $wpml_service_di );
84
  }
85
 
86
 
96
  * @deprecated Use Toolset_Element_Factory::get_post() instead.
97
  *
98
  * @return Toolset_Post
99
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
100
  */
101
  public static function get_instance( $object_source, $language_code = null ) {
102
+ $element_factory = new Toolset_Element_Factory();
103
+ return $element_factory->get_post_untranslated( $object_source, $language_code );
104
  }
105
 
106
 
107
  /**
108
  * @return string One of the Toolset_Field_Utils::get_domains() values.
109
  */
110
+ public function get_domain() { return Toolset_Element_Domain::POSTS; }
111
 
112
 
113
  /**
149
  * @return bool
150
  */
151
  public function is_translatable() {
152
+ return $this->wpml_service->is_post_type_translatable( $this->get_type() );
153
  }
154
 
155
 
157
  * @inheritdoc
158
  * @return string
159
  */
160
+ public function get_language() {
161
  if( null === $this->language_code ) {
162
+ $this->language_code = $this->wpml_service->get_post_language( $this->get_id() );
 
163
  }
164
 
165
  return $this->language_code;
186
  }
187
 
188
 
189
+ protected function get_post_type_repository() {
190
+ if( null === $this->_post_type_repository ) {
191
+ $this->_post_type_repository = Toolset_Post_Type_Repository::get_instance();
192
+ }
193
+
194
+ return $this->_post_type_repository;
195
+ }
196
+
197
+
198
+ /**
199
+ * @return IToolset_Post_Type|null
200
+ * @since 2.5.10
201
+ */
202
+ public function get_type_object() {
203
+ return $this->get_post_type_repository()->get( $this->get_type() );
204
+ }
205
+
206
+
207
+ /**
208
+ * @inheritdoc
209
+ *
210
+ * @param string $language_code
211
+ * @param bool $exact_match_only
212
+ *
213
+ * @return IToolset_Element|null
214
+ */
215
+ public function translate( $language_code, $exact_match_only = false ) {
216
+ if( ! $this->is_translatable() ) {
217
+ return $this;
218
+ }
219
+
220
+ // This could happen only in very rare cases, when WPML is active,
221
+ // someone obtains a translation set from Toolset_Element_Factory,
222
+ // calls translate() on it, which would return this instance, and then
223
+ // they call translate() again... and here we are.
224
+ $translation_set = $this->element_factory->get_post_translation_set( array( $this ) );
225
+ return $translation_set->translate( $language_code, $exact_match_only );
226
+ }
227
+
228
+
229
+ /**
230
+ * @inheritdoc
231
+ *
232
+ * @return int
233
+ * @since 2.5.10
234
+ */
235
+ public function get_default_language_id() {
236
+ if( ! $this->is_translatable() ) {
237
+ return $this->get_id();
238
+ }
239
+
240
+ // This could happen only in very rare cases, when WPML is active,
241
+ // someone obtains a translation set from Toolset_Element_Factory,
242
+ // calls translate() on it, which would return this instance, and then
243
+ // they call this method... and here we are.
244
+ $translation_set = $this->element_factory->get_post_translation_set( array( $this ) );
245
+ return $translation_set->get_default_language_id();
246
+ }
247
+
248
+
249
+ /**
250
+ * @return bool
251
+ * @since 2.5.10
252
+ */
253
+ public function is_revision() {
254
+ return ( 'revision' === $this->get_type() );
255
+ }
256
+
257
+
258
+ /**
259
+ * @inheritdoc
260
+ *
261
+ * @return int
262
+ * @since 2.5.11
263
+ */
264
+ public function get_author() {
265
+ return (int) $this->post->post_author;
266
+ }
267
+
268
+
269
+ /**
270
+ * @inheritdoc
271
+ *
272
+ * @return int
273
+ * @since 2.5.11
274
+ */
275
+ public function get_trid() {
276
+ return $this->wpml_service->get_post_trid( $this->get_id() );
277
+ }
278
  }
vendor/toolset/toolset-common/inc/autoloaded/element/post_translation_set.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  * Represents a set of post translations.
5
  *
6
- * This class can act as a single post, working as a proxy to one language version of it.
7
  *
8
  * Each of the interface methods has an additional parameter where a language code may be specified. If it isn't,
9
  * the best available translation will be chosen: current language > default language > original post language.
@@ -11,7 +11,7 @@
11
  * In all other aspects, these methods act exactly the same way as in Toolset_Post.
12
  *
13
  * Note: It is not possible to instantiate this class when WPML is not active. You should always
14
- * use Toolset_Element::get_instance() instead of reinventing its logic elsewhere.
15
  *
16
  * @since m2m
17
  */
@@ -30,17 +30,46 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
30
  private $best_translation_for = array();
31
 
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  /**
34
  * Toolset_Post_Translation_Set constructor.
35
  *
36
  * @param Toolset_Post[] $translations Array of this post's translations indexed by language codes.
37
  * It doesn't need to be complete, but having these values ready can improve performance.
 
 
 
38
  *
39
  * @since m2m
 
40
  */
41
- public function __construct( $translations ) {
42
-
43
- if ( ! Toolset_WPML_Compatibility::get_instance()->is_wpml_active_and_configured() ) {
 
 
 
 
 
 
 
 
 
44
  throw new RuntimeException( 'Attempted to use a post translation set while WPML was inactive' );
45
  }
46
 
@@ -50,15 +79,18 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
50
 
51
  foreach ( $translations as $translation ) {
52
  if ( ! $translation instanceof Toolset_Post ) {
53
- $translation = Toolset_Element::get_instance( $this->get_domain(), $translation );
54
  }
55
 
56
  $this->translations[ $translation->get_language() ] = $translation;
57
  }
58
 
59
- /** @var Toolset_Post $some_translation */
60
- $some_translation = array_shift( array_slice( $this->translations, 0, 1 ) );
61
- $this->starting_post_id = $some_translation->get_id();
 
 
 
62
  }
63
 
64
 
@@ -76,9 +108,12 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
76
  //
77
  // Notice that $return_original_if_missing is set to false by default, so we'll not get a result that's not
78
  // truly translated.
79
- $id = (int) apply_filters( 'wpml_object_id', $this->starting_post_id, $this->get_type(), $return_original_if_missing, $language_code );
 
 
 
 
80
 
81
- // fixme handle when there's no translation and the same ID is returned as the starting one
82
  return $id;
83
  }
84
 
@@ -98,7 +133,7 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
98
  if ( ! array_key_exists( $language_code, $this->translations ) ) {
99
  $translated_post_id = $this->fetch_translation( $language_code );
100
  if ( $translated_post_id !== 0 ) {
101
- $translation = Toolset_Post::get_instance( $translated_post_id, $language_code );
102
  } else {
103
  $translation = null;
104
  }
@@ -124,12 +159,15 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
124
  * @return Toolset_Post
125
  */
126
  private function get_original_translation() {
127
- $translated_post_id = $this->fetch_translation( Toolset_Wpml_Utils::get_default_language(), true );
 
 
 
128
 
129
  $post_language_details = apply_filters( 'wpml_post_language_details', null, $translated_post_id );
130
  $language_code = toolset_getarr( $post_language_details, 'language_code' );
131
 
132
- $translation = Toolset_Post::get_instance( $translated_post_id, $language_code );
133
 
134
  // Store it in cache only if we got a language code. At this point I don't trust anything.
135
  if ( is_string( $language_code ) && ! empty( $language_code ) ) {
@@ -152,7 +190,7 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
152
  private function get_best_translation( $language_code = null ) {
153
 
154
  if ( null === $language_code ) {
155
- $language_code = Toolset_Wpml_Utils::get_current_language();
156
  }
157
 
158
  if( array_key_exists( $language_code, $this->best_translation_for ) ) {
@@ -162,7 +200,7 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
162
  if ( $this->is_translated_to( $language_code ) ) {
163
  $post = $this->get_translation( $language_code );
164
  } else {
165
- $default_language = Toolset_Wpml_Utils::get_default_language();
166
  if ( $this->is_translated_to( $default_language ) ) {
167
  $post = $this->get_translation( $default_language );
168
  } else {
@@ -180,9 +218,10 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
180
  * @return string One of the Toolset_Field_Utils::get_domains() values.
181
  */
182
  public function get_domain() {
183
- return Toolset_Field_Utils::DOMAIN_POSTS;
184
  }
185
 
 
186
  /**
187
  * @param null|string $language_code If null, the best translation will be selected automatically.
188
  *
@@ -203,7 +242,7 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
203
  }
204
 
205
 
206
- /**
207
  * @param null|string $language_code If null, the best translation will be selected automatically.
208
  *
209
  * @return string Post type slug.
@@ -226,6 +265,7 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
226
  $this->get_best_translation( $language_code )->initialize_fields();
227
  }
228
 
 
229
  /**
230
  * @param null|string $language_code If null, the best translation will be selected automatically.
231
  *
@@ -235,6 +275,7 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
235
  return $this->get_best_translation( $language_code )->are_fields_loaded();
236
  }
237
 
 
238
  /**
239
  * Get the object this model is wrapped around.
240
  *
@@ -294,6 +335,7 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
294
  return $this->get_best_translation( $language_code )->get_fields();
295
  }
296
 
 
297
  /**
298
  * @param null|string $language_code If null, the best translation will be selected automatically.
299
  *
@@ -308,8 +350,10 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
308
  * @return bool
309
  */
310
  function is_translatable() {
311
- // fixme actually check this
312
- return true;
 
 
313
  }
314
 
315
 
@@ -337,6 +381,7 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
337
  return $this->get_best_translation( $language_code )->get_slug();
338
  }
339
 
 
340
  /**
341
  * @param string $title New post title
342
  *
@@ -348,4 +393,99 @@ class Toolset_Post_Translation_Set implements IToolset_Post {
348
  public function set_title( $title, $language_code = null ) {
349
  $this->get_best_translation( $language_code )->set_title( $title );
350
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  }
3
  /**
4
  * Represents a set of post translations.
5
  *
6
+ * This class can act as a single post, working as a proxy to one of its translations.
7
  *
8
  * Each of the interface methods has an additional parameter where a language code may be specified. If it isn't,
9
  * the best available translation will be chosen: current language > default language > original post language.
11
  * In all other aspects, these methods act exactly the same way as in Toolset_Post.
12
  *
13
  * Note: It is not possible to instantiate this class when WPML is not active. You should always
14
+ * use Toolset_Elemen_Factory::get_post() instead of reinventing its logic elsewhere.
15
  *
16
  * @since m2m
17
  */
30
  private $best_translation_for = array();
31
 
32
 
33
+ /** @var Toolset_WPML_Compatibility */
34
+ private $wpml_service;
35
+
36
+
37
+ /** @var Toolset_Element_Factory */
38
+ private $element_factory;
39
+
40
+
41
+ /** @var null|Toolset_Post_Type_Repository */
42
+ private $_post_type_repository;
43
+
44
+
45
+ /** @var null|int */
46
+ private $_trid;
47
+
48
+
49
  /**
50
  * Toolset_Post_Translation_Set constructor.
51
  *
52
  * @param Toolset_Post[] $translations Array of this post's translations indexed by language codes.
53
  * It doesn't need to be complete, but having these values ready can improve performance.
54
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
55
+ * @param Toolset_Element_Factory|null $element_factory_di
56
+ * @param Toolset_Post_Type_Repository|null $post_type_repository_di
57
  *
58
  * @since m2m
59
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
60
  */
61
+ public function __construct(
62
+ $translations,
63
+ Toolset_WPML_Compatibility $wpml_service_di = null,
64
+ Toolset_Element_Factory $element_factory_di = null,
65
+ Toolset_Post_Type_Repository $post_type_repository_di = null
66
+ ) {
67
+
68
+ $this->wpml_service = ( null === $wpml_service_di ? Toolset_WPML_Compatibility::get_instance() : $wpml_service_di );
69
+ $this->element_factory = ( null === $element_factory_di ? new Toolset_Element_Factory() : $element_factory_di );
70
+ $this->_post_type_repository = $post_type_repository_di;
71
+
72
+ if ( ! $this->wpml_service->is_wpml_active_and_configured() ) {
73
  throw new RuntimeException( 'Attempted to use a post translation set while WPML was inactive' );
74
  }
75
 
79
 
80
  foreach ( $translations as $translation ) {
81
  if ( ! $translation instanceof Toolset_Post ) {
82
+ $translation = $this->element_factory->get_post_untranslated( $translation );
83
  }
84
 
85
  $this->translations[ $translation->get_language() ] = $translation;
86
  }
87
 
88
+ if( array_key_exists( $this->wpml_service->get_default_language(), $this->translations ) ) {
89
+ $this->starting_post_id = $this->translations[ $this->wpml_service->get_default_language() ]->get_id();
90
+ } else {
91
+ $some_translation = reset( $this->translations );
92
+ $this->starting_post_id = $some_translation->get_id();
93
+ }
94
  }
95
 
96
 
108
  //
109
  // Notice that $return_original_if_missing is set to false by default, so we'll not get a result that's not
110
  // truly translated.
111
+ //
112
+ // P.S.: Can't use get_type() for the third argument because that requires having a
113
+ // post instance and it could create an infinite recursion. Luckily, WPML interprets the 'any'
114
+ // type as "any post type".
115
+ $id = (int) apply_filters( 'wpml_object_id', $this->starting_post_id, 'any', $return_original_if_missing, $language_code );
116
 
 
117
  return $id;
118
  }
119
 
133
  if ( ! array_key_exists( $language_code, $this->translations ) ) {
134
  $translated_post_id = $this->fetch_translation( $language_code );
135
  if ( $translated_post_id !== 0 ) {
136
+ $translation = $this->element_factory->get_post_untranslated( $translated_post_id, $language_code );
137
  } else {
138
  $translation = null;
139
  }
159
  * @return Toolset_Post
160
  */
161
  private function get_original_translation() {
162
+ $translated_post_id = $this->fetch_translation(
163
+ $this->wpml_service->get_default_language(),
164
+ true
165
+ );
166
 
167
  $post_language_details = apply_filters( 'wpml_post_language_details', null, $translated_post_id );
168
  $language_code = toolset_getarr( $post_language_details, 'language_code' );
169
 
170
+ $translation = $this->element_factory->get_post_untranslated( $translated_post_id, $language_code );
171
 
172
  // Store it in cache only if we got a language code. At this point I don't trust anything.
173
  if ( is_string( $language_code ) && ! empty( $language_code ) ) {
190
  private function get_best_translation( $language_code = null ) {
191
 
192
  if ( null === $language_code ) {
193
+ $language_code = $this->wpml_service->get_current_language();
194
  }
195
 
196
  if( array_key_exists( $language_code, $this->best_translation_for ) ) {
200
  if ( $this->is_translated_to( $language_code ) ) {
201
  $post = $this->get_translation( $language_code );
202
  } else {
203
+ $default_language = $this->wpml_service->get_default_language();
204
  if ( $this->is_translated_to( $default_language ) ) {
205
  $post = $this->get_translation( $default_language );
206
  } else {
218
  * @return string One of the Toolset_Field_Utils::get_domains() values.
219
  */
220
  public function get_domain() {
221
+ return Toolset_Element_Domain::POSTS;
222
  }
223
 
224
+
225
  /**
226
  * @param null|string $language_code If null, the best translation will be selected automatically.
227
  *
242
  }
243
 
244
 
245
+ /**
246
  * @param null|string $language_code If null, the best translation will be selected automatically.
247
  *
248
  * @return string Post type slug.
265
  $this->get_best_translation( $language_code )->initialize_fields();
266
  }
267
 
268
+
269
  /**
270
  * @param null|string $language_code If null, the best translation will be selected automatically.
271
  *
275
  return $this->get_best_translation( $language_code )->are_fields_loaded();
276
  }
277
 
278
+
279
  /**
280
  * Get the object this model is wrapped around.
281
  *
335
  return $this->get_best_translation( $language_code )->get_fields();
336
  }
337
 
338
+
339
  /**
340
  * @param null|string $language_code If null, the best translation will be selected automatically.
341
  *
350
  * @return bool
351
  */
352
  function is_translatable() {
353
+ // Assumption: get_type() is the same for all translations, so it doesn't
354
+ // matter which one gets picked up. If this doesn't work as expected,
355
+ // the site has way more serious problems.
356
+ return $this->wpml_service->is_post_type_translatable( $this->get_type() );
357
  }
358
 
359
 
381
  return $this->get_best_translation( $language_code )->get_slug();
382
  }
383
 
384
+
385
  /**
386
  * @param string $title New post title
387
  *
393
  public function set_title( $title, $language_code = null ) {
394
  $this->get_best_translation( $language_code )->set_title( $title );
395
  }
396
+
397
+
398
+ protected function get_post_type_repository() {
399
+ if( null === $this->_post_type_repository ) {
400
+ $this->_post_type_repository = Toolset_Post_Type_Repository::get_instance();
401
+ }
402
+
403
+ return $this->_post_type_repository;
404
+ }
405
+
406
+
407
+ /**
408
+ * @return IToolset_Post_Type|null
409
+ * @since 2.5.10
410
+ */
411
+ public function get_type_object() {
412
+ return $this->get_post_type_repository()->get( $this->get_type() );
413
+ }
414
+
415
+
416
+ /**
417
+ * Return an element translation.
418
+ *
419
+ * If the element domain and type are non-translatable, it will return itself.
420
+ *
421
+ * If the element could be translated to the target language but is not,
422
+ * the return value will depend on the $exact_match_only parameter:
423
+ * If it's true, it will return null. Otherwise, it will return the best possible
424
+ * translation (default language/original/any).
425
+ *
426
+ * @param string $language_code
427
+ * @param bool $exact_match_only
428
+ *
429
+ * @return IToolset_Element|null
430
+ */
431
+ public function translate( $language_code, $exact_match_only = false ) {
432
+ if( $exact_match_only && $this->is_translatable() ) {
433
+ return $this->get_translation( $language_code );
434
+ } else {
435
+ return $this->get_best_translation( $language_code );
436
+ }
437
+ }
438
+
439
+
440
+ /**
441
+ * @inheritdoc
442
+ *
443
+ * @return int
444
+ * @since 2.5.10
445
+ */
446
+ public function get_default_language_id() {
447
+ $translation = $this->get_translation( $this->wpml_service->get_default_language() );
448
+ if( null === $translation ) {
449
+ return 0;
450
+ }
451
+
452
+ return $translation->get_id();
453
+ }
454
+
455
+ /**
456
+ * @param string|null $language_code
457
+ *
458
+ * @return bool
459
+ * @since 2.5.10
460
+ */
461
+ public function is_revision( $language_code = null ) {
462
+ return $this->get_best_translation( $language_code )->is_revision();
463
+ }
464
+
465
+
466
+ /**
467
+ * @inheritdoc
468
+ *
469
+ * @param string|null $language_code
470
+ *
471
+ * @return int
472
+ * @since 2.5.11
473
+ */
474
+ public function get_author( $language_code = null ) {
475
+ return $this->get_best_translation( $language_code )->get_author();
476
+ }
477
+
478
+
479
+ /**
480
+ * @inheritdoc
481
+ *
482
+ * @return int
483
+ * @since 2.5.11
484
+ */
485
+ public function get_trid() {
486
+ if( null === $this->_trid ) {
487
+ $this->_trid = $this->wpml_service->get_post_trid( $this->starting_post_id );
488
+ }
489
+ return $this->_trid;
490
+ }
491
  }
vendor/toolset/toolset-common/inc/autoloaded/field/definition.php CHANGED
@@ -120,7 +120,9 @@ abstract class Toolset_Field_Definition extends Toolset_Field_Definition_Abstrac
120
  if( $this->get_is_required() && !empty( $display_name ) ) {
121
  $display_name .= '&#42;';
122
  }
123
- return $display_name;
 
 
124
  }
125
 
126
 
@@ -579,6 +581,13 @@ abstract class Toolset_Field_Definition extends Toolset_Field_Definition_Abstrac
579
  }
580
 
581
 
 
 
 
 
 
 
 
582
  /**
583
  * Create an instance of the field for a specific element.
584
  *
120
  if( $this->get_is_required() && !empty( $display_name ) ) {
121
  $display_name .= '&#42;';
122
  }
123
+
124
+ // we need to get rid of auto added slashes (WP Core adds them)
125
+ return stripslashes( $display_name );
126
  }
127
 
128
 
581
  }
582
 
583
 
584
+ /**
585
+ * @return string Domain where this field belongs to.
586
+ * @since 2.5.8
587
+ */
588
+ public abstract function get_domain();
589
+
590
+
591
  /**
592
  * Create an instance of the field for a specific element.
593
  *
vendor/toolset/toolset-common/inc/autoloaded/field/definition_abstract.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  * Abstract of a field definition (common interface and code for generic and Types field definitions).
5
  */
6
- abstract class Toolset_Field_Definition_Abstract {
7
 
8
  /**
9
  * @return string Field definition slug.
3
  /**
4
  * Abstract of a field definition (common interface and code for generic and Types field definitions).
5
  */
6
+ abstract class Toolset_Field_Definition_Abstract implements Toolset_Field_Definition_Interface {
7
 
8
  /**
9
  * @return string Field definition slug.
vendor/toolset/toolset-common/inc/autoloaded/field/definition_factory.php CHANGED
@@ -7,7 +7,7 @@
7
  *
8
  * @since 1.9
9
  */
10
- abstract class Toolset_Field_Definition_Factory {
11
 
12
  /**
13
  * Singleton parent.
@@ -275,9 +275,9 @@ abstract class Toolset_Field_Definition_Factory {
275
 
276
  /**
277
  * Update the option that stores field definitions for current domain with new value.
278
- *
279
  * This is a low-level method. No validation or sanitization is performed whatsoever.
280
- *
281
  * @param array $updated_value New value to be stored.
282
  * @since 2.0
283
  */
@@ -333,7 +333,7 @@ abstract class Toolset_Field_Definition_Factory {
333
  foreach ( $field_slugs as $slug ) {
334
  $field_definition = $this->load_field_definition( $slug );
335
  if ( null != $field_definition ) {
336
- $field_definitions[] = $field_definition;
337
  }
338
  }
339
 
@@ -629,7 +629,7 @@ abstract class Toolset_Field_Definition_Factory {
629
  $slug_to_delete = $field_definiton->get_slug();
630
  $this->erase_field_definition_from_options( $slug_to_delete );
631
  }
632
-
633
  return $is_success;
634
  }
635
 
@@ -686,8 +686,8 @@ abstract class Toolset_Field_Definition_Factory {
686
 
687
 
688
  /**
689
- * Temporary workaround to access field definitions on a very deep level.
690
- *
691
  * @param $field_slug
692
  * @param $definition_array
693
  * @deprecated Do not use, it will be removed.
@@ -701,7 +701,7 @@ abstract class Toolset_Field_Definition_Factory {
701
  /**
702
  * Temporary workaround to access field definitions on a very deep level.
703
  * Do not use, it will be removed.
704
- *
705
  * @return string
706
  * @deprecated Do not use, it will be removed.
707
  * @since 2.1
@@ -711,4 +711,4 @@ abstract class Toolset_Field_Definition_Factory {
711
  }
712
 
713
 
714
- }
7
  *
8
  * @since 1.9
9
  */
10
+ abstract class Toolset_Field_Definition_Factory implements Toolset_Field_Definition_Factory_Interface {
11
 
12
  /**
13
  * Singleton parent.
275
 
276
  /**
277
  * Update the option that stores field definitions for current domain with new value.
278
+ *
279
  * This is a low-level method. No validation or sanitization is performed whatsoever.
280
+ *
281
  * @param array $updated_value New value to be stored.
282
  * @since 2.0
283
  */
333
  foreach ( $field_slugs as $slug ) {
334
  $field_definition = $this->load_field_definition( $slug );
335
  if ( null != $field_definition ) {
336
+ $field_definitions[ $slug ] = $field_definition;
337
  }
338
  }
339
 
629
  $slug_to_delete = $field_definiton->get_slug();
630
  $this->erase_field_definition_from_options( $slug_to_delete );
631
  }
632
+
633
  return $is_success;
634
  }
635
 
686
 
687
 
688
  /**
689
+ * Temporary workaround to access field definitions on a very deep level.
690
+ *
691
  * @param $field_slug
692
  * @param $definition_array
693
  * @deprecated Do not use, it will be removed.
701
  /**
702
  * Temporary workaround to access field definitions on a very deep level.
703
  * Do not use, it will be removed.
704
+ *
705
  * @return string
706
  * @deprecated Do not use, it will be removed.
707
  * @since 2.1
711
  }
712
 
713
 
714
+ }
vendor/toolset/toolset-common/inc/autoloaded/field/definition_factory_interface.php ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface for field definitions factory.
5
+ *
6
+ * @since 2.3
7
+ */
8
+ interface Toolset_Field_Definition_Factory_Interface {
9
+ /**
10
+ * Load an existing field definition.
11
+ *
12
+ * For now, we're using legacy code to read fields from the options table.
13
+ *
14
+ * Note that field definitions for fields not currently managed by Types may be loaded as well.
15
+ *
16
+ * @param string $field_key Key used to store the field configuration in options, or field slug (which should be
17
+ * equal to the key).
18
+ *
19
+ * @return null|Toolset_Field_Definition Field definition or null if it can't be loaded.
20
+ */
21
+ public function load_field_definition( $field_key );
22
+
23
+
24
+ /**
25
+ * This method is to be used only for bringing existing fields under Types control.
26
+ *
27
+ * At this point it is assumed that there doesn't exist any field definition for given meta_key.
28
+ * See Toolset_Field_Utils::start_managing_field() for details.
29
+ *
30
+ * Maybe the usage could be wider, but that is not yet clear from the legacy code. The behaviour is slightly
31
+ * different for meta_keys with the wpcf- prefix from the ones without it. More details in the code.
32
+ *
33
+ * The field will be created as a text field.
34
+ *
35
+ * @param string $meta_key Field meta key.
36
+ *
37
+ * @return string|false New field slug on success, false otherwise.
38
+ * @since 2.0
39
+ */
40
+ public function create_field_definition_for_existing_fields( $meta_key );
41
+
42
+
43
+ /**
44
+ * Removes a single field definition from the storage of existing instances.
45
+ *
46
+ * It also completely clears the cache of the (legacy) wpcf_admin_fields_get_fields.
47
+ * Note that this method is public only temporarily and that this is not a mere cache clearing.
48
+ *
49
+ * @param string|null $field_slug If null, the cache will be emptied completely.
50
+ */
51
+ public function clear_definition_storage( $field_slug = null );
52
+
53
+
54
+ /**
55
+ * Determine if there exists any Types field definition (within the domain) that uses this key.
56
+ *
57
+ * @param string $meta_key
58
+ * @param string [$return='boolean'] For 'boolean', the method simply returns true/false answer, for 'definition'
59
+ * it returns either the field definition instance or null if no such one exists.
60
+ *
61
+ * @return bool|Toolset_Field_Definition|null
62
+ * @since 1.9
63
+ */
64
+ public function meta_key_belongs_to_types_field( $meta_key, $return = 'boolean' );
65
+
66
+
67
+ /**
68
+ * @return Toolset_Field_Group_Factory
69
+ * @since 2.0
70
+ */
71
+ public function get_group_factory();
72
+
73
+
74
+ /**
75
+ * @return Toolset_Field_Definition_Generic[] Definitions of all generic fields that exist in the database within
76
+ * current domain.
77
+ */
78
+ public function load_generic_field_definitions();
79
+
80
+
81
+ /**
82
+ * @return Toolset_Field_Definition_Abstract[] All field definitions (generic and Types-controlled).
83
+ */
84
+ public function load_all_definitions();
85
+
86
+
87
+ /**
88
+ * Reorder an array of field definitions.
89
+ *
90
+ * @param Toolset_Field_Definition_Abstract[] $definitions
91
+ * @param string $orderby 'name'|'slug'|'is_under_types_control'|'field_type'
92
+ * @param string $order 'asc'|'desc'
93
+ *
94
+ * @return Toolset_Field_Definition_Abstract[] Reordered array.
95
+ */
96
+ public function order_definitions( $definitions, $orderby = 'name', $order = 'asc' );
97
+
98
+
99
+ /**
100
+ * Compare function for ordering by name in order_definitions().
101
+ *
102
+ * @param $first Toolset_Field_Definition_Abstract
103
+ * @param $second Toolset_Field_Definition_Abstract
104
+ *
105
+ * @return int
106
+ */
107
+ public function compare_definitions_by_name( $first, $second );
108
+
109
+
110
+ /**
111
+ * Compare function for ordering by slug in order_definitions().
112
+ *
113
+ * @param $first Toolset_Field_Definition_Abstract
114
+ * @param $second Toolset_Field_Definition_Abstract
115
+ *
116
+ * @return int
117
+ */
118
+ public function compare_definitions_by_slug( $first, $second );
119
+
120
+
121
+ /**
122
+ * Compare function for ordering by the Types control status in order_definitions().
123
+ *
124
+ * @param $first Toolset_Field_Definition_Abstract
125
+ * @param $second Toolset_Field_Definition_Abstract
126
+ *
127
+ * @return int
128
+ */
129
+ public function compare_definition_by_types_control( $first, $second );
130
+
131
+
132
+ /**
133
+ * Compare function for ordering by field type in order_definitions().
134
+ *
135
+ * @param $first Toolset_Field_Definition_Abstract
136
+ * @param $second Toolset_Field_Definition_Abstract
137
+ *
138
+ * @return int
139
+ */
140
+ public function compare_definitions_by_field_type( $first, $second );
141
+
142
+
143
+ /**
144
+ * Query field definitions.
145
+ *
146
+ * @param array $args Following arguments are recognized:
147
+ *
148
+ * - filter: What field definitions should be retrieved: 'types'|'generic'|'all'
149
+ * - orderby: 'name'|'slug'|'is_under_types_control'|'field_type'
150
+ * - order: 'asc'|'desc'
151
+ * - search: String for fulltext search.
152
+ * - field_type: string|array Field type slug(s). Allowed only for Types fields.
153
+ * - group_id: int Field group ID where this field belongs to. Allowed only for Types fields.
154
+ * - group_slug: string Slug of an existing firld group where this field belongs to. If defined, overrides
155
+ * the group_id argument. Allowed only for Types fields.
156
+ *
157
+ * @return Toolset_Field_Definition_Abstract[] Field definitions that match query arguments.
158
+ *
159
+ * @since 1.9
160
+ */
161
+ public function query_definitions( $args );
162
+
163
+
164
+ /**
165
+ * Permanently delete field definition.
166
+ *
167
+ * That means:
168
+ * - remove it from all field groups,
169
+ * - delete field data from the database (sic!) and
170
+ * - delete the definition itself.
171
+ *
172
+ * After calling this method, the field definition object passed as parameter should never be used again.
173
+ *
174
+ * @param Toolset_Field_Definition_Abstract $field_definiton
175
+ *
176
+ * @return bool
177
+ */
178
+ public function delete_definition( Toolset_Field_Definition_Abstract $field_definiton );
179
+
180
+
181
+ /**
182
+ * Update existing field definition.
183
+ *
184
+ * @param Toolset_Field_Definition_Abstract $field_definition
185
+ *
186
+ * @throws InvalidArgumentException
187
+ * @return bool True when the update was successful, false otherwise.
188
+ * @since 2.0
189
+ */
190
+ public function update_definition( Toolset_Field_Definition_Abstract $field_definition );
191
+
192
+
193
+ /**
194
+ * Temporary workaround to access field definitions on a very deep level.
195
+ *
196
+ * @param $field_slug
197
+ * @param $definition_array
198
+ * @deprecated Do not use, it will be removed.
199
+ * @since 2.1
200
+ */
201
+ public function set_field_definition_workaround( $field_slug, $definition_array );
202
+
203
+ /**
204
+ * Temporary workaround to access field definitions on a very deep level.
205
+ * Do not use, it will be removed.
206
+ *
207
+ * @return string
208
+ * @deprecated Do not use, it will be removed.
209
+ * @since 2.1
210
+ */
211
+ public function get_option_name_workaround();
212
+ }
vendor/toolset/toolset-common/inc/autoloaded/field/definition_factory_post.php CHANGED
@@ -5,7 +5,7 @@
5
  *
6
  * @since 2.0
7
  */
8
- final class Toolset_Field_Definition_Factory_Post extends Toolset_Field_Definition_Factory {
9
 
10
 
11
  /** Name of the option used to store field definitions. */
5
  *
6
  * @since 2.0
7
  */
8
+ class Toolset_Field_Definition_Factory_Post extends Toolset_Field_Definition_Factory {
9
 
10
 
11
  /** Name of the option used to store field definitions. */
vendor/toolset/toolset-common/inc/autoloaded/field/definition_factory_term.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  * Factory for term field definitions.
5
  */
6
- final class Toolset_Field_Definition_Factory_Term extends Toolset_Field_Definition_Factory {
7
 
8
  /**
9
  * Name of the option used to store term field definitions.
3
  /**
4
  * Factory for term field definitions.
5
  */
6
+ class Toolset_Field_Definition_Factory_Term extends Toolset_Field_Definition_Factory {
7
 
8
  /**
9
  * Name of the option used to store term field definitions.
vendor/toolset/toolset-common/inc/autoloaded/field/definition_factory_user.php CHANGED
@@ -5,7 +5,7 @@
5
  *
6
  * @since 2.0
7
  */
8
- final class Toolset_Field_Definition_Factory_User extends Toolset_Field_Definition_Factory {
9
 
10
 
11
  /** Name of the option used to store field definitions. */
5
  *
6
  * @since 2.0
7
  */
8
+ class Toolset_Field_Definition_Factory_User extends Toolset_Field_Definition_Factory {
9
 
10
 
11
  /** Name of the option used to store field definitions. */
vendor/toolset/toolset-common/inc/autoloaded/field/definition_interface.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface of a field definition
5
+ *
6
+ * @since 2.3
7
+ */
8
+ interface Toolset_Field_Definition_Interface {
9
+
10
+ /**
11
+ * @return string Field definition slug.
12
+ */
13
+ public function get_slug();
14
+
15
+
16
+ /**
17
+ * @return string Field definition display name.
18
+ */
19
+ public function get_name();
20
+
21
+
22
+ /**
23
+ * @return string Description provided by the user.
24
+ */
25
+ public function get_description();
26
+
27
+
28
+ /**
29
+ * @return string Meta key used to store values of these fields.
30
+ */
31
+ public function get_meta_key();
32
+
33
+ /**
34
+ * Determine whether the field is currently under Types control.
35
+ *
36
+ * @return mixed
37
+ */
38
+ public function is_under_types_control();
39
+
40
+
41
+ /**
42
+ * @return Toolset_Field_Group[]
43
+ */
44
+ public function get_associated_groups();
45
+
46
+
47
+ /**
48
+ * Does the field definition match a certain string?
49
+ *
50
+ * Searches it's name and slug.
51
+ *
52
+ * @param string $search_string
53
+ * @return bool
54
+ */
55
+ public function is_match( $search_string );
56
+
57
+
58
+ /**
59
+ * Get field definition data as an associative array for coversion to JSON.
60
+ *
61
+ * Doesn't return the JSON string directly because child classes may reuse this method and add their own
62
+ * properties.
63
+ *
64
+ * Guaranteed properties are: isUnderTypesControl, slug, displayName, groups.
65
+ *
66
+ * @return array
67
+ * @since 2.0
68
+ */
69
+ public function to_json();
70
+
71
+ }
vendor/toolset/toolset-common/inc/autoloaded/field/definition_post.php CHANGED
@@ -7,7 +7,7 @@
7
  *
8
  * @since 2.0
9
  */
10
- final class Toolset_Field_Definition_Post extends Toolset_Field_Definition {
11
 
12
  /**
13
  * Get an accessor for a specific field instance.
@@ -84,4 +84,12 @@ final class Toolset_Field_Definition_Post extends Toolset_Field_Definition {
84
  return new Toolset_Field_Instance_Post( $this, $element_id );
85
  }
86
 
 
 
 
 
 
 
 
 
87
  }
7
  *
8
  * @since 2.0
9
  */
10
+ class Toolset_Field_Definition_Post extends Toolset_Field_Definition {
11
 
12
  /**
13
  * Get an accessor for a specific field instance.
84
  return new Toolset_Field_Instance_Post( $this, $element_id );
85
  }
86
 
87
+
88
+ /**
89
+ * @return string Domain where this field belongs to.
90
+ * @since 2.5.8
91
+ */
92
+ public function get_domain() {
93
+ return Toolset_Element_Domain::POSTS;
94
+ }
95
  }
vendor/toolset/toolset-common/inc/autoloaded/field/definition_term.php CHANGED
@@ -82,4 +82,12 @@ class Toolset_Field_Definition_Term extends Toolset_Field_Definition {
82
  return new Toolset_Field_Instance_Term( $this, $element_id );
83
  }
84
 
 
 
 
 
 
 
 
 
85
  }
82
  return new Toolset_Field_Instance_Term( $this, $element_id );
83
  }
84
 
85
+
86
+ /**
87
+ * @return string Domain where this field belongs to.
88
+ * @since 2.5.8
89
+ */
90
+ public function get_domain() {
91
+ return Toolset_Element_Domain::TERMS;
92
+ }
93
  }
vendor/toolset/toolset-common/inc/autoloaded/field/definition_user.php CHANGED
@@ -79,4 +79,12 @@ class Toolset_Field_Definition_User extends Toolset_Field_Definition {
79
  throw new RuntimeException( 'Not implemented.' );
80
  }
81
 
 
 
 
 
 
 
 
 
82
  }
79
  throw new RuntimeException( 'Not implemented.' );
80
  }
81
 
82
+
83
+ /**
84
+ * @return string Domain where this field belongs to.
85
+ * @since 2.5.8
86
+ */
87
+ public function get_domain() {
88
+ return Toolset_Element_Domain::USERS;
89
+ }
90
  }
vendor/toolset/toolset-common/inc/autoloaded/field/group.php CHANGED
@@ -38,7 +38,7 @@ abstract class Toolset_Field_Group {
38
  /**
39
  * @var WP_Post Post object that represents the field group.
40
  */
41
- private $post;
42
 
43
 
44
  /** @var Toolset_Post_Type_Repository|null */
@@ -513,7 +513,7 @@ abstract class Toolset_Field_Group {
513
  if ( $type_input instanceof IToolset_Post_Type ) {
514
  $post_type_slug = $type_input->get_slug();
515
  $post_type = $type_input;
516
- } elseif( is_string( $type_input ) ) {
517
  $post_type_slug = $type_input;
518
  $post_type = null;
519
  } else {
38
  /**
39
  * @var WP_Post Post object that represents the field group.
40
  */
41
+ protected $post;
42
 
43
 
44
  /** @var Toolset_Post_Type_Repository|null */
513
  if ( $type_input instanceof IToolset_Post_Type ) {
514
  $post_type_slug = $type_input->get_slug();
515
  $post_type = $type_input;
516
+ } elseif( is_string( $type_input ) || is_int( $type_input )) {
517
  $post_type_slug = $type_input;
518
  $post_type = null;
519
  } else {
vendor/toolset/toolset-common/inc/autoloaded/files.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Wrapper for a mockable access to file functions.
5
+ *
6
+ * The principle is similar to Toolset_Constants.
7
+ *
8
+ * Note: Use this *only* if you need it in unit tests!
9
+ *
10
+ * @since 2.5.7
11
+ */
12
+ class Toolset_Files {
13
+
14
+ /**
15
+ * is_file()
16
+ *
17
+ * @link http://php.net/manual/en/function.is-file.php
18
+ * @param string $path
19
+ * @return bool
20
+ */
21
+ public function is_file( $path ) {
22
+ return is_file( $path );
23
+ }
24
+
25
+
26
+ /**
27
+ * Extract provided context variable, include the file and return the output.
28
+ *
29
+ * @param string $filename
30
+ * @param array $context_vars
31
+ *
32
+ * @return string
33
+ */
34
+ public function get_include_file_output( $filename, $context_vars = array() ) {
35
+ ob_start();
36
+ extract( $context_vars );
37
+ include $filename;
38
+ $output = ob_get_clean();
39
+ return $output;
40
+ }
41
+
42
+
43
+ /**
44
+ * file_get_contents()
45
+ *
46
+ * @link http://php.net/manual/en/function.file-get-contents.php
47
+ * @param string $filename
48
+ * @return bool|string
49
+ */
50
+ public function file_get_contents( $filename ) {
51
+ return file_get_contents( $filename );
52
+ }
53
+
54
+ }
vendor/toolset/toolset-common/inc/autoloaded/naming_helper.php CHANGED
@@ -298,7 +298,7 @@ class Toolset_Naming_Helper {
298
  get_post_types( array(), 'names' )
299
  );
300
 
301
- if( in_array( $value, $post_types ) ) {
302
  $conflict = array(
303
  'conflicting_id' => $value,
304
  'message' => sprintf(
298
  get_post_types( array(), 'names' )
299
  );
300
 
301
+ if( in_array( $value, $post_types, true ) ) {
302
  $conflict = array(
303
  'conflicting_id' => $value,
304
  'message' => sprintf(
vendor/toolset/toolset-common/inc/autoloaded/post_type/abstract.php ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Shared functionality for all kinds of post types.
5
+ *
6
+ * @since 2.5.10
7
+ */
8
+ abstract class Toolset_Post_Type_Abstract implements IToolset_Post_Type {
9
+
10
+
11
+ /** @var Toolset_WPML_Compatibility|null */
12
+ private $_wpml_compatibility;
13
+
14
+
15
+ /** @var Toolset_Relationship_Query_Factory|null */
16
+ private $_relationship_definition_query_factory;
17
+
18
+
19
+ /**
20
+ * Toolset_Post_Type_Abstract constructor.
21
+ *
22
+ * @param Toolset_WPML_Compatibility|null $wpml_compatibility_di
23
+ * @param null|Toolset_Relationship_Query_Factory $relationship_definition_query_factory_di
24
+ */
25
+ public function __construct(
26
+ Toolset_WPML_Compatibility $wpml_compatibility_di = null,
27
+ $relationship_definition_query_factory_di = null
28
+ ) {
29
+ $this->_wpml_compatibility = $wpml_compatibility_di;
30
+ $this->_relationship_definition_query_factory = $relationship_definition_query_factory_di;
31
+ }
32
+
33
+
34
+ /**
35
+ * @return Toolset_WPML_Compatibility
36
+ */
37
+ protected function get_wpml_compatibility() {
38
+ if( null === $this->_wpml_compatibility ) {
39
+ $this->_wpml_compatibility = Toolset_WPML_Compatibility::get_instance();
40
+ }
41
+ return $this->_wpml_compatibility;
42
+ }
43
+
44
+
45
+ /**
46
+ * @return Toolset_Relationship_Query_V2
47
+ */
48
+ protected function get_relationship_definition_query() {
49
+ if( null === $this->_relationship_definition_query_factory ) {
50
+ if ( ! apply_filters( 'toolset_is_m2m_enabled', false ) ) {
51
+ throw new InvalidArgumentException( 'Trying to use m2m functionality without m2m enabled.' );
52
+ }
53
+
54
+ do_action( 'toolset_do_m2m_full_init' );
55
+
56
+ $this->_relationship_definition_query_factory = new Toolset_Relationship_Query_Factory();
57
+ }
58
+
59
+ return $this->_relationship_definition_query_factory->relationships_v2();
60
+ }
61
+
62
+
63
+ /**
64
+ * @inheritdoc
65
+ * @return bool
66
+ */
67
+ public function is_translatable() {
68
+ return $this->get_wpml_compatibility()->is_post_type_translatable( $this->get_slug() );
69
+ }
70
+
71
+
72
+ /**
73
+ * @inheritdoc
74
+ * @return bool
75
+ */
76
+ public function is_in_display_as_translated_mode() {
77
+ return $this->get_wpml_compatibility()->is_post_type_display_as_translated( $this->get_slug() );
78
+ }
79
+
80
+ /**
81
+ * @inheritdoc
82
+ * @return bool
83
+ */
84
+ public function can_be_used_in_relationship() {
85
+ if( ! $this->get_wpml_compatibility()->is_wpml_active_and_configured() ) {
86
+ // no wpml = no limitations on relationships
87
+ return true;
88
+ }
89
+
90
+ if( ! $this->is_translatable() ) {
91
+ // no translation mode selected = all good
92
+ return true;
93
+ }
94
+
95
+ if( $this->is_in_display_as_translated_mode() ) {
96
+ // "display as translated" mode selected = all good
97
+ return true;
98
+ }
99
+
100
+ return false;
101
+ }
102
+
103
+
104
+ /**
105
+ * @inheritdoc
106
+ *
107
+ * Note: This operation may be rather expensive.
108
+ *
109
+ * @return bool
110
+ */
111
+ public function is_involved_in_relationship() {
112
+ if( $this->is_intermediary() ) {
113
+ return true;
114
+ }
115
+
116
+ $query = $this->get_relationship_definition_query();
117
+
118
+ $results = $query
119
+ ->add( $query->has_domain_and_type( $this->get_slug(), Toolset_Element_Domain::POSTS ) )
120
+ ->get_results();
121
+
122
+ return ( count( $results ) > 0 );
123
+ }
124
+
125
+ }
vendor/toolset/toolset-common/inc/autoloaded/post_type/excluded_list.php CHANGED
@@ -10,6 +10,7 @@ class Toolset_Post_Type_Exclude_List {
10
  private static $initial_list = array(
11
  'cred-form',
12
  'cred-user-form',
 
13
  'custom_css',
14
  'customize_changeset',
15
  'dd_layouts',
10
  private static $initial_list = array(
11
  'cred-form',
12
  'cred-user-form',
13
+ 'cred_rel_form',
14
  'custom_css',
15
  'customize_changeset',
16
  'dd_layouts',
vendor/toolset/toolset-common/inc/autoloaded/post_type/from_types.php CHANGED
@@ -10,7 +10,7 @@
10
  *
11
  * @since m2m
12
  */
13
- class Toolset_Post_Type_From_Types implements IToolset_Post_Type_From_Types {
14
 
15
  /** @var string Post type slug */
16
  private $slug;
@@ -50,6 +50,11 @@ class Toolset_Post_Type_From_Types implements IToolset_Post_Type_From_Types {
50
 
51
  const DEF_PUBLIC = 'public';
52
 
 
 
 
 
 
53
 
54
  /**
55
  * Toolset_Post_Type_From_Types constructor.
@@ -59,11 +64,16 @@ class Toolset_Post_Type_From_Types implements IToolset_Post_Type_From_Types {
59
  * @param IToolset_Post_Type_Registered|null $registered_post_type If the post type is registered on the site,
60
  * this must not be null.
61
  * @param Toolset_Constants|null $constants_di
 
62
  */
63
  public function __construct(
64
- $slug, $definition, IToolset_Post_Type_Registered $registered_post_type = null,
65
- Toolset_Constants $constants_di = null
 
 
66
  ) {
 
 
67
  $this->slug = $slug;
68
 
69
  /**
@@ -442,6 +452,30 @@ class Toolset_Post_Type_From_Types implements IToolset_Post_Type_From_Types {
442
  }
443
 
444
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
445
  /**
446
  * Set the flag indicating whether this post type acts as a repeating field group.
447
  *
@@ -449,6 +483,9 @@ class Toolset_Post_Type_From_Types implements IToolset_Post_Type_From_Types {
449
  */
450
  public function set_is_repeating_field_group( $value ) {
451
  $this->set_flag_to_definition( self::DEF_IS_REPEATING_FIELD_GROUP, (bool) $value );
 
 
 
452
  $this->set_is_public( false );
453
  }
454
 
10
  *
11
  * @since m2m
12
  */
13
+ class Toolset_Post_Type_From_Types extends Toolset_Post_Type_Abstract implements IToolset_Post_Type_From_Types {
14
 
15
  /** @var string Post type slug */
16
  private $slug;
50
 
51
  const DEF_PUBLIC = 'public';
52
 
53
+ const DEF_DISABLED = 'disabled';
54
+
55
+ // Do not rename this value, it's hardcoded in Types (because of timing issues).
56
+ const DEF_NEEDS_FLUSH_REWRITE_RULES = '_needs_flush_rewrite_rules';
57
+
58
 
59
  /**
60
  * Toolset_Post_Type_From_Types constructor.
64
  * @param IToolset_Post_Type_Registered|null $registered_post_type If the post type is registered on the site,
65
  * this must not be null.
66
  * @param Toolset_Constants|null $constants_di
67
+ * @param Toolset_WPML_Compatibility|null $wpml_compatibility_di
68
  */
69
  public function __construct(
70
+ $slug, $definition,
71
+ IToolset_Post_Type_Registered $registered_post_type = null,
72
+ Toolset_Constants $constants_di = null,
73
+ Toolset_WPML_Compatibility $wpml_compatibility_di = null
74
  ) {
75
+ parent::__construct( $wpml_compatibility_di );
76
+
77
  $this->slug = $slug;
78
 
79
  /**
452
  }
453
 
454
 
455
+ /**
456
+ * @inheritdoc
457
+ * @return bool
458
+ */
459
+ public function is_disabled() {
460
+ return (
461
+ '1' === toolset_getarr( $this->definition, self::DEF_DISABLED, '', array( '1', '' ) )
462
+ );
463
+ }
464
+
465
+
466
+ /**
467
+ * Set the 'disabled' option of the post type.
468
+ *
469
+ * @param bool $value
470
+ */
471
+ public function set_is_disabled( $value ) {
472
+ if( $value ){
473
+ $this->definition[ self::DEF_DISABLED ] = '1';
474
+ } else {
475
+ unset( $this->definition[ self::DEF_DISABLED ] );
476
+ }
477
+ }
478
+
479
  /**
480
  * Set the flag indicating whether this post type acts as a repeating field group.
481
  *
483
  */
484
  public function set_is_repeating_field_group( $value ) {
485
  $this->set_flag_to_definition( self::DEF_IS_REPEATING_FIELD_GROUP, (bool) $value );
486
+ if ( $value ) {
487
+ $this->definition['supports'] = array( 'post_title', 'author', 'custom-fields', 'revisions' );
488
+ }
489
  $this->set_is_public( false );
490
  }
491
 
vendor/toolset/toolset-common/inc/autoloaded/post_type/i_post_type.php CHANGED
@@ -98,4 +98,41 @@ interface IToolset_Post_Type {
98
  */
99
  public function allows_field_group( Toolset_Field_Group $field_group );
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  }
98
  */
99
  public function allows_field_group( Toolset_Field_Group $field_group );
100
 
101
+
102
+ /**
103
+ * Check if the post type is translatable by WPML.
104
+ *
105
+ * @return bool
106
+ * @since 2.5.10
107
+ */
108
+ public function is_translatable();
109
+
110
+
111
+ /**
112
+ * Check if the post type is translatable and has the "display as translated" mode.
113
+ *
114
+ * @return bool
115
+ * @since 2.5.10
116
+ */
117
+ public function is_in_display_as_translated_mode();
118
+
119
+
120
+ /**
121
+ * Check if the post type can be used in a relationship.
122
+ *
123
+ * @return bool
124
+ * @since 2.5.10
125
+ */
126
+ public function can_be_used_in_relationship();
127
+
128
+
129
+ /**
130
+ * Check if the post type is already used in an existing relationship.
131
+ *
132
+ * Needs m2m.
133
+ *
134
+ * @return bool
135
+ * @since 2.5.11
136
+ */
137
+ public function is_involved_in_relationship();
138
  }
vendor/toolset/toolset-common/inc/autoloaded/post_type/i_post_type_from_types.php CHANGED
@@ -62,4 +62,26 @@ interface IToolset_Post_Type_From_Types extends IToolset_Post_Type {
62
  * @param string $new_value
63
  */
64
  public function set_slug( $new_value );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  }
62
  * @param string $new_value
63
  */
64
  public function set_slug( $new_value );
65
+
66
+
67
+ /**
68
+ * Set the 'public' option of the post type.
69
+ *
70
+ * @param bool $value
71
+ */
72
+ public function set_is_public( $value );
73
+
74
+
75
+ /**
76
+ * Set the 'disabled' option of the post type.
77
+ *
78
+ * @param bool $value
79
+ */
80
+ public function set_is_disabled( $value );
81
+
82
+
83
+ /**
84
+ * @return bool Corresponds with the disabled status of the post type.
85
+ */
86
+ public function is_disabled();
87
  }
vendor/toolset/toolset-common/inc/autoloaded/post_type/query.php CHANGED
@@ -15,6 +15,7 @@
15
  * for arbitrary use like standard post types)? If there's no query for this, is_intermediary
16
  * or is_repeating_field_group, this query argument defaults to false. Providing null will return
17
  * both special and non-special post types.
 
18
  *
19
  * Feel free to extend this with new query arguments.
20
  *
@@ -30,6 +31,8 @@ class Toolset_Post_Type_Query {
30
  const IS_EXCLUDED = 'is_excluded';
31
  const IS_PUBLIC = 'is_public';
32
  const IS_REGISTERED = 'is_registered';
 
 
33
 
34
  const RETURN_TYPE = 'return';
35
 
@@ -96,7 +99,15 @@ class Toolset_Post_Type_Query {
96
  self::IS_REGISTERED => array(
97
  'callback' => array( $this, 'filter_bool_property' ),
98
  'filter_args' => 'is_registered'
99
- )
 
 
 
 
 
 
 
 
100
  );
101
 
102
  $this->post_type_repository = (
15
  * for arbitrary use like standard post types)? If there's no query for this, is_intermediary
16
  * or is_repeating_field_group, this query argument defaults to false. Providing null will return
17
  * both special and non-special post types.
18
+ * ...
19
  *
20
  * Feel free to extend this with new query arguments.
21
  *
31
  const IS_EXCLUDED = 'is_excluded';
32
  const IS_PUBLIC = 'is_public';
33
  const IS_REGISTERED = 'is_registered';
34
+ const IS_INVOLVED_IN_RELATIONSHIP = 'is_involved_in_relationship';
35
+ const IS_TRANSLATABLE = 'is_translatable';
36
 
37
  const RETURN_TYPE = 'return';
38
 
99
  self::IS_REGISTERED => array(
100
  'callback' => array( $this, 'filter_bool_property' ),
101
  'filter_args' => 'is_registered'
102
+ ),
103
+ self::IS_INVOLVED_IN_RELATIONSHIP => array(
104
+ 'callback' => array( $this, 'filter_bool_property' ),
105
+ 'filter_args' => 'is_involved_in_relationship'
106
+ ),
107
+ self::IS_TRANSLATABLE => array(
108
+ 'callback' => array( $this, 'filter_bool_property' ),
109
+ 'filter_args' => 'is_translatable'
110
+ ),
111
  );
112
 
113
  $this->post_type_repository = (
vendor/toolset/toolset-common/inc/autoloaded/post_type/registered.php CHANGED
@@ -7,7 +7,7 @@
7
  *
8
  * @since m2m
9
  */
10
- class Toolset_Post_Type_Registered implements IToolset_Post_Type_Registered {
11
 
12
 
13
  /** @var WP_Post_Type */
@@ -21,8 +21,10 @@ class Toolset_Post_Type_Registered implements IToolset_Post_Type_Registered {
21
  * Toolset_Post_Type_Registered constructor.
22
  *
23
  * @param WP_Post_Type $wp_post_type The core object representing the post type.
 
24
  */
25
- public function __construct( WP_Post_Type $wp_post_type ) {
 
26
  $this->wp_post_type = $wp_post_type;
27
  }
28
 
7
  *
8
  * @since m2m
9
  */
10
+ class Toolset_Post_Type_Registered extends Toolset_Post_Type_Abstract implements IToolset_Post_Type_Registered {
11
 
12
 
13
  /** @var WP_Post_Type */
21
  * Toolset_Post_Type_Registered constructor.
22
  *
23
  * @param WP_Post_Type $wp_post_type The core object representing the post type.
24
+ * @param Toolset_WPML_Compatibility|null $wpml_compatibility_di
25
  */
26
+ public function __construct( WP_Post_Type $wp_post_type, Toolset_WPML_Compatibility $wpml_compatibility_di = null ) {
27
+ parent::__construct( $wpml_compatibility_di );
28
  $this->wp_post_type = $wp_post_type;
29
  }
30
 
vendor/toolset/toolset-common/inc/autoloaded/post_type/repository.php CHANGED
@@ -240,12 +240,13 @@ class Toolset_Post_Type_Repository {
240
  // wpcf_custom_types_register_translation( $post_type, $definition );
241
  // }
242
 
243
- // Note: this has to run on the next page load
244
- // flush_rewrite_rules();
245
-
246
  $custom_types = get_option( self::POST_TYPES_OPTION_NAME, array() );
247
 
248
  $post_type_definition = $post_type->get_definition();
 
 
 
 
249
  $custom_types[ $post_type->get_slug() ] = $post_type_definition;
250
 
251
  update_option( self::POST_TYPES_OPTION_NAME, $custom_types, true );
@@ -370,6 +371,9 @@ class Toolset_Post_Type_Repository {
370
  )
371
  );
372
 
 
 
 
373
  if( $wpdb->last_error ) {
374
  throw new RuntimeException( 'The posts could not be updated: ' . $wpdb->last_error );
375
  }
240
  // wpcf_custom_types_register_translation( $post_type, $definition );
241
  // }
242
 
 
 
 
243
  $custom_types = get_option( self::POST_TYPES_OPTION_NAME, array() );
244
 
245
  $post_type_definition = $post_type->get_definition();
246
+
247
+ // Signal Types to run flush_rewrite_rules() after registering the post type.
248
+ $post_type_definition[ Toolset_Post_Type_From_Types::DEF_NEEDS_FLUSH_REWRITE_RULES ] = true;
249
+
250
  $custom_types[ $post_type->get_slug() ] = $post_type_definition;
251
 
252
  update_option( self::POST_TYPES_OPTION_NAME, $custom_types, true );
371
  )
372
  );
373
 
374
+ // announce to Types that a post type has been renamed
375
+ do_action( 'wpcf_post_type_renamed', $new_slug, $old_slug );
376
+
377
  if( $wpdb->last_error ) {
378
  throw new RuntimeException( 'The posts could not be updated: ' . $wpdb->last_error );
379
  }
vendor/toolset/toolset-common/inc/autoloaded/relationship_service.php CHANGED
@@ -63,6 +63,10 @@ class Toolset_Relationship_Service {
63
  $child_id,
64
  $parent_slug = null
65
  ) {
 
 
 
 
66
  $qry_args = array(
67
  Toolset_Association_Query::QUERY_RELATIONSHIP_SLUG => $relationship->get_slug(),
68
  Toolset_Association_Query::QUERY_CHILD_ID => $child_id,
@@ -90,6 +94,10 @@ class Toolset_Relationship_Service {
90
  $parent_id,
91
  $child_slug = null
92
  ) {
 
 
 
 
93
  $qry_args = array(
94
  Toolset_Association_Query::QUERY_RELATIONSHIP_SLUG => $relationship->get_slug(),
95
  Toolset_Association_Query::QUERY_PARENT_ID => $parent_id,
@@ -113,6 +121,10 @@ class Toolset_Relationship_Service {
113
  *
114
  */
115
  public function find_intermediary_by_relationship_and_child_id( IToolset_Relationship_Definition $relationship, $post_id ) {
 
 
 
 
116
  $qry_args = array(
117
  Toolset_Association_Query::QUERY_RELATIONSHIP_SLUG => $relationship->get_slug(),
118
  Toolset_Association_Query::QUERY_CHILD_ID => $post_id,
@@ -132,6 +144,10 @@ class Toolset_Relationship_Service {
132
  *
133
  */
134
  public function find_intermediary_by_relationship_and_parent_id( IToolset_Relationship_Definition $relationship, $post_id ) {
 
 
 
 
135
  $qry_args = array(
136
  Toolset_Association_Query::QUERY_RELATIONSHIP_SLUG => $relationship->get_slug(),
137
  Toolset_Association_Query::QUERY_PARENT_ID => $post_id,
@@ -170,9 +186,13 @@ class Toolset_Relationship_Service {
170
  * @internal param string $child_slug
171
  */
172
  public function find_children_ids_by_parent_id( $parent_id, $children_args = array() ) {
 
 
 
 
173
  $children_args = wp_parse_args( $children_args, array(
174
  'post_type' => 'any',
175
- 'post_status' => 'published',
176
  'numberposts' => -1,
177
  'suppress_filters' => 0,
178
  ) );
@@ -193,7 +213,7 @@ class Toolset_Relationship_Service {
193
  */
194
  public function find_associations_by_id( $post_id ) {
195
  if( ! $this->is_m2m_enabled() ) {
196
- return false;
197
  }
198
 
199
  $associations_parent = $this->find_associations_by_parent_id( $post_id );
@@ -252,7 +272,7 @@ class Toolset_Relationship_Service {
252
  */
253
  public function find_parents_by_child_id_and_parent_slug( $child_id, $parent_slug ) {
254
  if( ! $this->is_m2m_enabled() ) {
255
- return false;
256
  }
257
 
258
  $associations = $this->find_associations_by_child_id( $child_id );
@@ -285,6 +305,10 @@ class Toolset_Relationship_Service {
285
  * @return bool|int
286
  */
287
  public function legacy_find_parent_id_by_child_id_and_parent_slug( $child_id, $parent_slug ) {
 
 
 
 
288
  $parent_slug = sanitize_title( $parent_slug );
289
 
290
  $option_key = '_wpcf_belongs_' . $parent_slug . '_id';
63
  $child_id,
64
  $parent_slug = null
65
  ) {
66
+ if( ! $this->is_m2m_enabled() ) {
67
+ return false;
68
+ }
69
+
70
  $qry_args = array(
71
  Toolset_Association_Query::QUERY_RELATIONSHIP_SLUG => $relationship->get_slug(),
72
  Toolset_Association_Query::QUERY_CHILD_ID => $child_id,
94
  $parent_id,
95
  $child_slug = null
96
  ) {
97
+ if( ! $this->is_m2m_enabled() ) {
98
+ return false;
99
+ }
100
+
101
  $qry_args = array(
102
  Toolset_Association_Query::QUERY_RELATIONSHIP_SLUG => $relationship->get_slug(),
103
  Toolset_Association_Query::QUERY_PARENT_ID => $parent_id,
121
  *
122
  */
123
  public function find_intermediary_by_relationship_and_child_id( IToolset_Relationship_Definition $relationship, $post_id ) {
124
+ if( ! $this->is_m2m_enabled() ) {
125
+ return false;
126
+ }
127
+
128
  $qry_args = array(
129
  Toolset_Association_Query::QUERY_RELATIONSHIP_SLUG => $relationship->get_slug(),
130
  Toolset_Association_Query::QUERY_CHILD_ID => $post_id,
144
  *
145
  */
146
  public function find_intermediary_by_relationship_and_parent_id( IToolset_Relationship_Definition $relationship, $post_id ) {
147
+ if( ! $this->is_m2m_enabled() ) {
148
+ return false;
149
+ }
150
+
151
  $qry_args = array(
152
  Toolset_Association_Query::QUERY_RELATIONSHIP_SLUG => $relationship->get_slug(),
153
  Toolset_Association_Query::QUERY_PARENT_ID => $post_id,
186
  * @internal param string $child_slug
187
  */
188
  public function find_children_ids_by_parent_id( $parent_id, $children_args = array() ) {
189
+ if( ! $this->is_m2m_enabled() ) {
190
+ return false;
191
+ }
192
+
193
  $children_args = wp_parse_args( $children_args, array(
194
  'post_type' => 'any',
195
+ 'post_status' => 'publish',
196
  'numberposts' => -1,
197
  'suppress_filters' => 0,
198
  ) );
213
  */
214
  public function find_associations_by_id( $post_id ) {
215
  if( ! $this->is_m2m_enabled() ) {
216
+ return array();
217
  }
218
 
219
  $associations_parent = $this->find_associations_by_parent_id( $post_id );
272
  */
273
  public function find_parents_by_child_id_and_parent_slug( $child_id, $parent_slug ) {
274
  if( ! $this->is_m2m_enabled() ) {
275
+ return array();
276
  }
277
 
278
  $associations = $this->find_associations_by_child_id( $child_id );
305
  * @return bool|int
306
  */
307
  public function legacy_find_parent_id_by_child_id_and_parent_slug( $child_id, $parent_slug ) {
308
+ if( ! $this->is_m2m_enabled() ) {
309
+ return false;
310
+ }
311
+
312
  $parent_slug = sanitize_title( $parent_slug );
313
 
314
  $option_key = '_wpcf_belongs_' . $parent_slug . '_id';
vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template/abstract.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Common functionality for all template types.
5
+ *
6
+ * @since 2.5.9
7
+ */
8
+ abstract class Toolset_Output_Template implements IToolset_Output_Template {
9
+
10
+
11
+ /** @var string */
12
+ protected $base_path;
13
+
14
+
15
+ /** @var string */
16
+ protected $template_name;
17
+
18
+
19
+ /**
20
+ * Toolset_Output_Template constructor.
21
+ *
22
+ * @param string $base_path
23
+ * @param string $template_name
24
+ */
25
+ public function __construct( $base_path, $template_name ) {
26
+ $this->base_path = $base_path;
27
+ $this->template_name = $template_name;
28
+ }
29
+
30
+
31
+ /**
32
+ * @inheritdoc
33
+ * @return string
34
+ */
35
+ public function get_full_path() {
36
+ return trailingslashit( $this->base_path ) . $this->template_name;
37
+ }
38
+
39
+
40
+ /**
41
+ * @inheritdoc
42
+ * @return string
43
+ */
44
+ public function get_name() {
45
+ return $this->template_name;
46
+ }
47
+
48
+ }
vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template/interface.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface for output templates.
5
+ *
6
+ * See Toolset_Renderer for detailed usage instructions.
7
+ *
8
+ * @since 2.5.9
9
+ */
10
+ interface IToolset_Output_Template {
11
+
12
+
13
+ /**
14
+ * @return string Full path to the template file.
15
+ */
16
+ public function get_full_path();
17
+
18
+
19
+ /**
20
+ * @return string Name of the template.
21
+ */
22
+ public function get_name();
23
+ }
vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template/phtml.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Template for static files.
5
+ *
6
+ * @since 2.5.9
7
+ */
8
+ class Toolset_Output_Template_Phtml extends Toolset_Output_Template {
9
+
10
+
11
+ const FILE_EXTENSION = '.phtml';
12
+
13
+
14
+ /**
15
+ * Toolset_Output_Template_Phtml constructor.
16
+ *
17
+ * @param string $base_path
18
+ * @param string $template_name
19
+ * @throws InvalidArgumentException Thrown if a file with a wrong suffix is provided.
20
+ */
21
+ public function __construct( $base_path, $template_name ) {
22
+
23
+ if( self::FILE_EXTENSION !== substr( $template_name, - strlen( self::FILE_EXTENSION ) ) ) {
24
+ throw new InvalidArgumentException( 'Provided template file is not a PHTML.' );
25
+ }
26
+
27
+ parent::__construct( $base_path, $template_name );
28
+ }
29
+ }
vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template/static.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Template for static files.
5
+ *
6
+ * Nothing to do here, we just use a different class to recognize the template type.
7
+ *
8
+ * @since 2.5.9
9
+ */
10
+ class Toolset_Output_Template_Static extends Toolset_Output_Template {
11
+
12
+ }
vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template/twig.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Template for Twig templates.
5
+ *
6
+ * @since 2.5.9
7
+ */
8
+ class Toolset_Output_Template_Twig extends Toolset_Output_Template {
9
+
10
+
11
+ /**
12
+ * @var array Namespaces that the Twig environment requires to render this template properly.
13
+ */
14
+ private $twig_namespaces;
15
+
16
+
17
+ /**
18
+ * @var null|string Hash created from the requirements for Twig environment,
19
+ * which allows to reuse these environments.
20
+ */
21
+ private $environment_hash = null;
22
+
23
+
24
+ const FILE_EXTENSION = '.twig';
25
+
26
+
27
+ /**
28
+ * Toolset_Output_Template_Twig constructor.
29
+ *
30
+ * @param string $base_path
31
+ * @param string $template_name
32
+ * @param array $twig_namespaces
33
+ * @throws InvalidArgumentException if a file with a wrong suffix is provided.
34
+ */
35
+ public function __construct( $base_path, $template_name, $twig_namespaces = array() ) {
36
+
37
+ if( self::FILE_EXTENSION !== substr( $template_name, - strlen( self::FILE_EXTENSION ) ) ) {
38
+ throw new InvalidArgumentException( 'Provided template file is not a Twig template.' );
39
+ }
40
+
41
+ parent::__construct( $base_path, $template_name );
42
+
43
+ $this->twig_namespaces = toolset_ensarr( $twig_namespaces );
44
+ }
45
+
46
+
47
+ /**
48
+ * @return array Get the namespaces required for the Twig environment.
49
+ */
50
+ public function get_twig_namespaces() {
51
+ return $this->twig_namespaces;
52
+ }
53
+
54
+
55
+ /**
56
+ * @return string Hash created from the requirements for Twig environment,
57
+ * which allows to reuse these environments.
58
+ */
59
+ public function get_twig_environment_hash() {
60
+ if( null === $this->environment_hash ) {
61
+ $hash_source = '';
62
+ foreach ( $this->twig_namespaces as $namespace => $namespace_path ) {
63
+ $hash_source .= $namespace . '-->' . $namespace_path . ';';
64
+ }
65
+ $this->environment_hash = md5( $hash_source );
66
+ }
67
+ return $this->environment_hash;
68
+ }
69
+
70
+ }
vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template_factory.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Factory for IToolset_Output_Template.
5
+ *
6
+ * It should be needed only by Toolset_Output_Template_Repository_Abstract and its subclasses.
7
+ *
8
+ * @since 2.5.9
9
+ */
10
+ class Toolset_Output_Template_Factory {
11
+
12
+
13
+ /**
14
+ * @param string $base_path
15
+ * @param string $template_name
16
+ *
17
+ * @return Toolset_Output_Template_Static
18
+ */
19
+ public function static_template( $base_path, $template_name ) {
20
+ return new Toolset_Output_Template_Static( $base_path, $template_name );
21
+ }
22
+
23
+
24
+ /**
25
+ * @param string $base_path
26
+ * @param string $template_name
27
+ *
28
+ * @return Toolset_Output_Template_Phtml
29
+ */
30
+ public function phtml_template( $base_path, $template_name ) {
31
+ return new Toolset_Output_Template_Phtml( $base_path, $template_name );
32
+ }
33
+
34
+
35
+ /**
36
+ * @param string $base_path
37
+ * @param string $template_name
38
+ * @param array $twig_namespaces
39
+ *
40
+ * @return Toolset_Output_Template_Twig
41
+ */
42
+ public function twig_template( $base_path, $template_name, $twig_namespaces ) {
43
+ // Add the main namespace as a base path, in case it's missing.
44
+ // If the template doesn't use it, no harm done.
45
+ if( ! array_key_exists( '__main__', $twig_namespaces ) ) {
46
+ $twig_namespaces['__main__'] = $base_path;
47
+ }
48
+ return new Toolset_Output_Template_Twig( $base_path, $template_name, $twig_namespaces );
49
+ }
50
+
51
+
52
+ /**
53
+ * Create the right type of template object according to the suffix of the template name.
54
+ *
55
+ * @param string $base_path
56
+ * @param string $template_name
57
+ * @param array $twig_namespaces
58
+ *
59
+ * @return IToolset_Output_Template
60
+ * @throws RuntimeException Thrown if the template type is not recognized (wrong suffix).
61
+ */
62
+ public function create_by_suffix( $base_path, $template_name, $twig_namespaces = array() ) {
63
+ $file_suffix = $this->get_suffix( $template_name );
64
+
65
+ switch( $file_suffix ) {
66
+ case 'twig':
67
+ return $this->twig_template( $base_path, $template_name, $twig_namespaces );
68
+ case 'phtml':
69
+ return $this->phtml_template( $base_path, $template_name );
70
+ case 'html':
71
+ return $this->static_template( $base_path, $template_name );
72
+ default:
73
+ throw new RuntimeException( 'Template type not recognized from the suffix.' );
74
+ }
75
+ }
76
+
77
+
78
+ /**
79
+ * Get a suffix from the file name.
80
+ *
81
+ * @param string $template_name
82
+ *
83
+ * @return bool|string The suffix or false if it's not detected.
84
+ */
85
+ private function get_suffix( $template_name ) {
86
+ $name_parts = explode( '.', $template_name );
87
+
88
+ if( count( $name_parts ) < 2 ) {
89
+ return false;
90
+ }
91
+
92
+ $extension = end( $name_parts );
93
+
94
+ if( empty( $extension ) ) {
95
+ return false;
96
+ }
97
+
98
+ return $extension;
99
+ }
100
+
101
+
102
+ }
vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template_repository.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Repository for templates in Toolset Common.
5
+ *
6
+ * See Toolset_Renderer for a detailed usage instructions.
7
+ *
8
+ * @since 2.5.9
9
+ */
10
+ class Toolset_Output_Template_Repository extends Toolset_Output_Template_Repository_Abstract {
11
+
12
+ // Names of the templates go here and to $templates
13
+ //
14
+ //
15
+
16
+ const FAUX_TEMPLATE = 'faux_template.twig';
17
+
18
+
19
+ /**
20
+ * @var array Template definitions.
21
+ */
22
+ private $templates = array(
23
+ self::FAUX_TEMPLATE => array(
24
+ 'base_path' => null,
25
+ 'namespaces' => array()
26
+ )
27
+ );
28
+
29
+
30
+ /** @var Toolset_Output_Template_Repository */
31
+ private static $instance;
32
+
33
+
34
+ /**
35
+ * @return Toolset_Output_Template_Repository
36
+ */
37
+ public static function get_instance() {
38
+ if( null === self::$instance ) {
39
+ self::$instance = new self();
40
+ }
41
+
42
+ return self::$instance;
43
+ }
44
+
45
+
46
+ /**
47
+ * @inheritdoc
48
+ * @return string
49
+ */
50
+ protected function get_default_base_path() {
51
+ return $this->constants->constant( 'TOOLSET_COMMON_PATH' ) . '/utility/gui-base/twig-templates';
52
+ }
53
+
54
+
55
+ /**
56
+ * Get the array with template definitions.
57
+ *
58
+ * @return array
59
+ */
60
+ protected function get_templates() {
61
+ return $this->templates;
62
+ }
63
+ }
vendor/toolset/toolset-common/inc/autoloaded/renderer/output_template_repository_abstract.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Repository for templates that can be subclassed to use in your plugin with Toolset_Renderer.
5
+ *
6
+ * @since 2.5.9
7
+ */
8
+ abstract class Toolset_Output_Template_Repository_Abstract {
9
+
10
+
11
+ /** @var Toolset_Output_Template_Factory */
12
+ private $template_factory;
13
+
14
+
15
+ /** @var Toolset_Constants */
16
+ protected $constants;
17
+
18
+
19
+ /**
20
+ * Toolset_Output_Template_Repository_Abstract constructor.
21
+ *
22
+ * @param Toolset_Output_Template_Factory|null $template_factory_di
23
+ * @param Toolset_Constants|null $constants_di
24
+ */
25
+ public function __construct(
26
+ Toolset_Output_Template_Factory $template_factory_di = null,
27
+ Toolset_Constants $constants_di = null
28
+ ) {
29
+ $this->template_factory = (
30
+ null === $template_factory_di
31
+ ? new Toolset_Output_Template_Factory()
32
+ : $template_factory_di
33
+ );
34
+
35
+ $this->constants = (
36
+ null === $constants_di
37
+ ? new Toolset_Constants()
38
+ : $constants_di
39
+ );
40
+ }
41
+
42
+
43
+ /**
44
+ * Get the array with template definitions.
45
+ *
46
+ * @return array
47
+ */
48
+ abstract protected function get_templates();
49
+
50
+
51
+ /**
52
+ * Load a template from its name.
53
+ *
54
+ * @param string $template_name
55
+ *
56
+ * @return IToolset_Output_Template
57
+ * @throws InvalidArgumentException
58
+ */
59
+ public function get( $template_name ) {
60
+ $templates = $this->get_templates();
61
+ if( ! array_key_exists( $template_name, $templates ) ) {
62
+ throw new InvalidArgumentException( 'Template is not defined' );
63
+ }
64
+
65
+ $template_definition = toolset_ensarr( $templates[ $template_name ] );
66
+ $base_path = toolset_getarr( $template_definition, 'base_path', $this->get_default_base_path() );
67
+ $namespaces = toolset_ensarr( toolset_getarr( $template_definition, 'namespaces' ) );
68
+
69
+ return $this->template_factory->create_by_suffix( $base_path, $template_name, $namespaces );
70
+ }
71
+
72
+
73
+ /**
74
+ * Get the default base path for templates.
75
+ *
76
+ * @return string
77
+ */
78
+ abstract protected function get_default_base_path();
79
+ }
vendor/toolset/toolset-common/inc/autoloaded/renderer/renderer.php ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Entry point for the template rendering API.
5
+ *
6
+ * How it works:
7
+ *
8
+ * Each template file is registered in Toolset_Output_Template_Repository or in another subclass of
9
+ * Toolset_Output_Template_Repository if it's contained only in a specific plugin. The registration already
10
+ * includes everything necessary for rendering the template (path and also required namespaces in case of
11
+ * Twig templates), except the template context (which is for passing along dynamic data at the time of rendering).
12
+ *
13
+ * So far, three types of templates are supported:
14
+ * - static templates (.html)
15
+ * - PHTML (PHP + HTML) (.phtml)
16
+ * - Twig templates (.twig)
17
+ *
18
+ * The difference between static templates and PHTML is that the latter can be passed some context information
19
+ * at the time of rendering, while the former is truly static without any sort of context.
20
+ *
21
+ * Toolset_Renderer accepts the template as an IToolset_Output_Template instance (which is provided by the repository)
22
+ * and uses the correct mechanism to render it (print or return).
23
+ *
24
+ * For Twig templates, there's a caching mechanism that reuses the same Twig environment if two templates have identical
25
+ * Twig namespaces.
26
+ *
27
+ * Usage:
28
+ *
29
+ * 1. Choose where to put your template. If it's in Toolset Common, use the Toolset_Output_Template_Repository class.
30
+ * Otherwise you may need to subclass Toolset_Output_Template_Repository_Abstract to add plugin-specific templates.
31
+ * 2. Define your template in the repository class. The template name must be the name of the actual template file.
32
+ * The filename suffis is relevant: "twig" for Twig templates, "phtml" for PHTML ones and "html" for static templates.
33
+ * Nothing else will be accepted.
34
+ * 3. Use the renderer like this:
35
+ *
36
+ * $template_repository = MyPlugin_Output_Template_Repository::get_instance()
37
+ * $renderer = Toolset_Renderer::get_instance();
38
+ * $output = $renderer->render(
39
+ * $template_repository->get( MyPlugin_Output_Template_Repository::MY_TEMPLATE ),
40
+ * $context,
41
+ * false // do not print but return the result
42
+ * );
43
+ *
44
+ * Note: Except reusable templates in Toolset Common, you may also use the template directly
45
+ * instead of registering it inside a template repository class, if you prefer.
46
+ *
47
+ * @since 2.5.9
48
+ */
49
+ class Toolset_Renderer {
50
+
51
+
52
+ /** @var Toolset_Renderer */
53
+ private static $instance;
54
+
55
+
56
+ /** @var null|Toolset_Gui_Base */
57
+ private $_gui_base;
58
+
59
+
60
+ /** @var Toolset_Files */
61
+ private $files;
62
+
63
+
64
+ /** @var Twig_Environment[] */
65
+ private $twig_environments = array();
66
+
67
+
68
+ /**
69
+ * Toolset_Renderer constructor.
70
+ *
71
+ * @param Toolset_Gui_Base|null $gui_base_di
72
+ * @param Toolset_Files|null $files_di
73
+ */
74
+ public function __construct(
75
+ Toolset_Gui_Base $gui_base_di = null,
76
+ Toolset_Files $files_di = null
77
+ ) {
78
+ $this->_gui_base = $gui_base_di;
79
+ $this->files = ( null === $files_di ? new Toolset_Files() : $files_di );
80
+ }
81
+
82
+
83
+ /**
84
+ * @return Toolset_Renderer
85
+ */
86
+ public static function get_instance() {
87
+ if ( null === self::$instance ) {
88
+ self::$instance = new self();
89
+ }
90
+
91
+ return self::$instance;
92
+ }
93
+
94
+
95
+ /**
96
+ * Render a template.
97
+ *
98
+ * @param IToolset_Output_Template $template
99
+ * @param mixed $context Arbitrary context that will be passed to the template, depending
100
+ * on its type.
101
+ * @param bool $echo Should the output be echoed?
102
+ *
103
+ * @return string
104
+ * @throws Twig_Error_Loader In case of incorrect Twig configuration.
105
+ * @throws Twig_Error_Runtime In case of incorrect Twig configuration.
106
+ * @throws Twig_Error_Syntax In case of incorrect Twig configuration.
107
+ */
108
+ public function render( IToolset_Output_Template $template, $context, $echo = true ) {
109
+
110
+ if( $template instanceof Toolset_Output_Template_Twig ) {
111
+ $output = $this->render_twig_template( $template, $context );
112
+ } elseif( $template instanceof Toolset_Output_Template_Phtml ) {
113
+ $output = $this->render_phtml_template( $template, $context );
114
+ } else {
115
+ $output = $this->render_static_template( $template );
116
+ }
117
+
118
+ if( $echo ) {
119
+ echo $output;
120
+ }
121
+
122
+ return $output;
123
+ }
124
+
125
+
126
+ /**
127
+ * Render the given PHTML/HTML template.
128
+ *
129
+ * @param Toolset_Output_Template $template The path of the template to render.
130
+ * @param mixed $context The context of the template for passing some additional data to the template, if needed.
131
+ *
132
+ * @return string The template output.
133
+ */
134
+ private function render_phtml_template( $template, $context ) {
135
+ $template_path = $template->get_full_path();
136
+ $template_output = '';
137
+ if ( $this->files->is_file( $template_path ) ) {
138
+ $template_output = $this->files->get_include_file_output(
139
+ $template_path, array( 'context' => $context )
140
+ );
141
+ }
142
+
143
+ return $template_output;
144
+ }
145
+
146
+
147
+ /**
148
+ * @param IToolset_Output_Template $template
149
+ *
150
+ * @return string
151
+ */
152
+ private function render_static_template( $template ) {
153
+ if( ! $this->files->is_file( $template->get_full_path() ) ) {
154
+ return '';
155
+ }
156
+
157
+ $output = $this->files->file_get_contents( $template->get_full_path() );
158
+
159
+ if( false === $output ) {
160
+ return '';
161
+ }
162
+
163
+ return $output;
164
+ }
165
+
166
+
167
+ /**
168
+ * @param Toolset_Output_Template_Twig $template
169
+ * @param array $context
170
+ *
171
+ * @return string
172
+ * @throws Twig_Error_Loader In case of incorrect Twig configuration.
173
+ * @throws Twig_Error_Runtime In case of incorrect Twig configuration.
174
+ * @throws Twig_Error_Syntax In case of incorrect Twig configuration.
175
+ */
176
+ private function render_twig_template( Toolset_Output_Template_Twig $template, $context ) {
177
+
178
+ $twig = $this->get_twig(
179
+ $template->get_twig_namespaces(),
180
+ $template->get_twig_environment_hash()
181
+ );
182
+
183
+ return $twig->render( $template->get_name(), $context );
184
+ }
185
+
186
+
187
+ /**
188
+ * Returns GUI Base
189
+ *
190
+ * @return Toolset_Gui_Base
191
+ * @since m2m
192
+ */
193
+ private function get_gui_base() {
194
+ if( null === $this->_gui_base ) {
195
+ $toolset_common_bootstrap = Toolset_Common_Bootstrap::get_instance();
196
+ $toolset_common_bootstrap->register_gui_base();
197
+
198
+ $gui_base = Toolset_Gui_Base::get_instance();
199
+ $gui_base->init();
200
+
201
+ $this->_gui_base = $gui_base;
202
+ }
203
+
204
+ return $this->_gui_base;
205
+ }
206
+
207
+
208
+ /**
209
+ * Retrieve a Twig environment initialized by the Toolset GUI base.
210
+ *
211
+ * @param string[] $namespaces
212
+ * @param string $hash
213
+ *
214
+ * @return Twig_Environment In case of incorrect Twig configuration.
215
+ * @since m2m
216
+ * @throws Twig_Error_Loader In case of incorrect Twig configuration.
217
+ */
218
+ private function get_twig( $namespaces, $hash ) {
219
+ if( ! array_key_exists( $hash, $this->twig_environments ) ) {
220
+ $gui_base = $this->get_gui_base();
221
+ $this->twig_environments[ $hash ] = $gui_base->create_twig_environment( $namespaces );
222
+ }
223
+
224
+ return $this->twig_environments[ $hash ];
225
+ }
226
+
227
+
228
+ }
vendor/toolset/toolset-common/inc/autoloaded/result_set.php CHANGED
@@ -15,6 +15,10 @@
15
  */
16
  class Toolset_Result_Set {
17
 
 
 
 
 
18
  /** @var array Mixed array of Toolset_Result and Toolset_Result_Set instances. */
19
  private $results = array();
20
 
@@ -199,11 +203,12 @@ class Toolset_Result_Set {
199
  /**
200
  * Turn the whole result set into a (simplified) result.
201
  *
 
202
  * @return Toolset_Result
203
  * @since 2.3
204
  */
205
- public function aggregate() {
206
- return new Toolset_Result( $this->is_complete_success(), $this->concat_messages() );
207
  }
208
 
209
  }
15
  */
16
  class Toolset_Result_Set {
17
 
18
+
19
+ const DEFAULT_SEPARATOR = '; ';
20
+
21
+
22
  /** @var array Mixed array of Toolset_Result and Toolset_Result_Set instances. */
23
  private $results = array();
24
 
203
  /**
204
  * Turn the whole result set into a (simplified) result.
205
  *
206
+ * @param string $separator
207
  * @return Toolset_Result
208
  * @since 2.3
209
  */
210
+ public function aggregate( $separator = self::DEFAULT_SEPARATOR ) {
211
+ return new Toolset_Result( $this->is_complete_success(), $this->concat_messages( $separator ) );
212
  }
213
 
214
  }
vendor/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/abstract.php ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Adjusts the WP_Query functionality.
5
+ *
6
+ * Covers the need for querying by post relationship by adding a new query argument 'toolset_relationships'.
7
+ *
8
+ * Usage:
9
+ *
10
+ * $query = new WP_Query( array(
11
+ * ...,
12
+ * 'toolset_relationships' => array(
13
+ * // ... relationship args
14
+ * )
15
+ * );
16
+ *
17
+ * The relationship arguments can contain one or multiple conditions. Each condition is represented by
18
+ * a nested associative array, but if there is only a single condition, it doesn't have to be nested.
19
+ *
20
+ * If multiple conditions are used, they're handled as conjunctions (AND).
21
+ *
22
+ * Each condition array has these elements:
23
+ *
24
+ * - 'role': 'parent'|'child'|'intermediary' - role of the queried post (the one that will be included in the results).
25
+ * Optional, default is 'child'.
26
+ * - 'related_to': int|WP_Post - post to which the results are connected. Mandatory.
27
+ * - 'relationship': string|string[] - relationship identified either by its slug or by a pair of the parent and child post types.
28
+ * The array variant can be used only for legacy relationships (or those migrated from the legacy implementation).
29
+ * The relationship slug variant will obviously work only if m2m is already enabled. Mandatory.
30
+ * - 'role_to_query_by': 'parent'|'child'|'intermediary'|'other'. Role of the 'related_to' post in the relationship.
31
+ * 'other' means the opposite of 'role' and can be used only if 'role' is 'parent' or 'child'.
32
+ * Optional, default is 'other'.
33
+ *
34
+ * Examples:
35
+ *
36
+ * // Single condition
37
+ * $query = new WP_Query( array(
38
+ * ...,
39
+ * 'toolset_relationships' => array(
40
+ * 'role' => 'child',
41
+ * 'related_to' => $parent_post,
42
+ * 'relationship' => array( 'parent_type', 'post_type' )
43
+ * )
44
+ * );
45
+ *
46
+ * // Multiple conditions
47
+ * //
48
+ * // Query posts that are children of $parent_post in the relationship between 'parent_type' and 'post_type'
49
+ * // migrated from the legacy implementation and at the same time parents of $child_post
50
+ * // in the relationship 'another_relationship' (because we used the slug, this will work only if
51
+ * // m2m is enabled).
52
+ * //
53
+ * $query = new WP_Query( array(
54
+ * ...,
55
+ * 'toolset_relationships' => array(
56
+ * array(
57
+ * 'role' => 'child',
58
+ * 'related_to' => $parent_post,
59
+ * 'relationship' => array( 'parent_type', 'post_type' )
60
+ * ),
61
+ * array(
62
+ * 'role' => 'parent',
63
+ * 'related_to' => $child_post,
64
+ * 'relationship' => 'another_relationship'
65
+ *
66
+ * )
67
+ * );
68
+ *
69
+ * @since 2.6.1
70
+ */
71
+ abstract class Toolset_Wp_Query_Adjustments extends Toolset_Wpdb_User {
72
+
73
+ // Must not be changed, third-party software depends on it.
74
+ const RELATIONSHIP_QUERY_ARG = 'toolset_relationships';
75
+
76
+
77
+ /**
78
+ * Initialize the query adjustments.
79
+ */
80
+ public function initialize() {
81
+ add_action( 'pre_get_posts', array( $this, 'check_custom_query_args' ) );
82
+ }
83
+
84
+
85
+ /**
86
+ * Using the approach described here: http://www.danielauener.com/extend-wp_query-with-custom-parameters/
87
+ *
88
+ * @param $query
89
+ */
90
+ public function check_custom_query_args( $query ) {
91
+ if( ! $query instanceof WP_Query ) {
92
+ // Something weird is happening.
93
+ return;
94
+ }
95
+
96
+ if( array_key_exists( self::RELATIONSHIP_QUERY_ARG, $query->query_vars ) ) {
97
+ $query->{self::RELATIONSHIP_QUERY_ARG} = $query->query_vars[ self::RELATIONSHIP_QUERY_ARG ];
98
+ }
99
+ }
100
+
101
+
102
+ /**
103
+ * Get the table join manager object attached to the WP_Query instance or create and attach a new one.
104
+ *
105
+ * @param WP_Query $query
106
+ *
107
+ * @return Toolset_Wp_Query_Adjustments_Table_Join_Manager
108
+ */
109
+ protected function get_table_join_manager( WP_Query $query ) {
110
+ // This is a dirty hack but still cleanest considering we need to use this object
111
+ // in different callbacks from WP_Query.
112
+ $property_name = 'toolset_join_manager';
113
+ if( ! property_exists( $query, $property_name ) ) {
114
+ $query->{$property_name} = new Toolset_Wp_Query_Adjustments_Table_Join_Manager();
115
+ }
116
+ return $query->{$property_name};
117
+ }
118
+
119
+
120
+ /**
121
+ * Turn the relationship query argument into an array of conditions.
122
+ *
123
+ * @param array $query_args
124
+ *
125
+ * @return array
126
+ * @throws InvalidArgumentException
127
+ */
128
+ protected function normalize_relationship_query_args( $query_args ) {
129
+ $has_strings = $this->array_has_strings( $query_args );
130
+ $has_arrays = $this->array_has_arrays( $query_args );
131
+
132
+ if( $has_arrays && $has_strings ) {
133
+ // Can't have both.
134
+ throw new InvalidArgumentException( 'The toolset_relationship query argument contains mixed content (arrays and string values).' );
135
+ }
136
+
137
+ if( $has_strings ) {
138
+ return array( $query_args );
139
+ }
140
+
141
+ return $query_args;
142
+ }
143
+
144
+
145
+ private function array_has_strings( $array ) {
146
+ foreach( $array as $element ) {
147
+ if( is_string( $element ) ) {
148
+ return true;
149
+ }
150
+ }
151
+
152
+ return false;
153
+ }
154
+
155
+
156
+ private function array_has_arrays( $array ) {
157
+ foreach( $array as $key => $element ) {
158
+ // The "relationship" element will not be considered as a nested condition.
159
+ // If there is something weird going on, it will fail later on during the validation
160
+ // of individual parameters.
161
+ if( is_array( $element ) && 'relationship' !== $key ) {
162
+ return true;
163
+ }
164
+ }
165
+
166
+ return false;
167
+
168
+ }
169
+
170
+ }
vendor/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/legacy_relationships.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Adjust the WP_Query functionality for legacy post relationships.
5
+ *
6
+ * This assumes m2m is *not* enabled.
7
+ *
8
+ * See the superclass for details.
9
+ *
10
+ * @since 2.6.1
11
+ */
12
+ class Toolset_Wp_Query_Adjustments_Legacy_Relationships extends Toolset_Wp_Query_Adjustments {
13
+
14
+ /**
15
+ * Call to register required hook.
16
+ */
17
+ public function initialize() {
18
+ add_action( 'pre_get_posts', array( $this, 'convert_toolset_relationships_argument_to_meta_query' ) );
19
+ }
20
+
21
+ /**
22
+ * Will convert 'toolset_relationship' argument to 'meta_query' of WP_Query
23
+ *
24
+ * @action pre_get_posts
25
+ *
26
+ * @param $query
27
+ */
28
+ public function convert_toolset_relationships_argument_to_meta_query( $query ) {
29
+ if( ! $query instanceof WP_Query ) {
30
+ // Something weird is happening.
31
+ return;
32
+ }
33
+
34
+ if( ! array_key_exists( self::RELATIONSHIP_QUERY_ARG, $query->query_vars ) ) {
35
+ // 'toolset_relationship' argument is not used
36
+ return;
37
+ }
38
+
39
+ // get meta_query
40
+ $meta_query = $this->get_meta_query_by_toolset_argument( $query->query_vars[ self::RELATIONSHIP_QUERY_ARG ] );
41
+
42
+ if( ! empty( $meta_query ) ) {
43
+ if( ! isset( $query->query_vars['meta_query'] ) ) {
44
+ // no meta_query yet, open collection
45
+ $query->query_vars['meta_query'] = array();
46
+ }
47
+ // add our converted 'toolset_relationship' argument to the WP_Query
48
+ $query->query_vars['meta_query'][] = $meta_query;
49
+ };
50
+
51
+ // important to unset our argument, otherwise each get_posts call will append the same conditions again
52
+ unset( $query->query_vars[ self::RELATIONSHIP_QUERY_ARG ] );
53
+ }
54
+
55
+ /**
56
+ * Get all conditions of 'toolset_relationships' and store them to $this->meta_query_conditions.
57
+ *
58
+ * @param $toolset_relationships The 'toolset_relationships' argument
59
+ *
60
+ * @return array
61
+ */
62
+ private function get_meta_query_by_toolset_argument( $toolset_relationships ) {
63
+ if( ! is_array( reset( $toolset_relationships ) ) ) {
64
+ // normalise array
65
+ $toolset_relationships = array( $toolset_relationships );
66
+ }
67
+
68
+ $meta_query = array();
69
+
70
+ foreach( $toolset_relationships as $condition ) {
71
+ if( ! $condition = $this->valid_query_array( $condition ) ){
72
+ // slug of relationships is not supported by legacy
73
+ continue;
74
+ }
75
+
76
+ // normalise related_to value to be an integer
77
+ $related_to = $condition['related_to'] instanceof WP_Post
78
+ ? (int) $condition['related_to']->ID
79
+ : (int) $condition['related_to'];
80
+
81
+ $meta_query[] = array(
82
+ 'key' => '_wpcf_belongs_'.reset( $condition['relationship'] ).'_id',
83
+ 'value' => $related_to,
84
+ 'compare' => '=',
85
+ );
86
+ }
87
+
88
+ if( ! empty( $meta_query ) ) {
89
+ $meta_query['relation'] = 'AND';
90
+ }
91
+
92
+ return $meta_query;
93
+ }
94
+
95
+ /**
96
+ * Validation of a condition array. For legacy we have a more strict validation
97
+ * than for m2m as a bunch of features is not available for legacy relationships
98
+ *
99
+ * @param $condition
100
+ *
101
+ * @return bool
102
+ */
103
+ private function valid_query_array( $condition ) {
104
+ if( ! isset( $condition['related_to'] ) ) {
105
+ // required
106
+ throw new InvalidArgumentException( "WP_Query > 'toolset_relationships' requires 'related_to' key." );
107
+ }
108
+
109
+ if( ( ! is_numeric( $condition['related_to'] ) || strpos( $condition['related_to'], '.' ) !== false )
110
+ && ! $condition['related_to'] instanceof WP_Post ) // no WP_Post
111
+ {
112
+ // no integer NOR object of WP_Post
113
+ throw new InvalidArgumentException( "WP_Query > 'toolset_relationships' > 'related_to' must be a post_ID or a WP_Post object." );
114
+ }
115
+
116
+ if( ! isset( $condition['relationship'] ) // not set at all
117
+ || ! is_array( $condition[ 'relationship' ] ) // no array, which is not possible for legacy relationship
118
+ || ! is_string( reset( $condition[ 'relationship' ] ) ) // first array element is no string -> not valid
119
+ ) {
120
+ throw new InvalidArgumentException( "WP_Query > 'toolset_relationships' > 'relationship' must be an array( 'parent_slug', 'child_slug' )." );
121
+ }
122
+
123
+ if( ! isset( $condition['role'] ) && ! isset( $condition['role_to_query_by'] ) ) {
124
+ // default value
125
+ $condition['role'] = 'child';
126
+ }
127
+
128
+ if( isset( $condition['role'] ) && $condition['role'] != 'child' ) {
129
+ // only child role is possible for legacy
130
+ throw new InvalidArgumentException( "WP_Query > 'toolset_relationships' > 'role' invalid value. You can only use 'child' for legacy relationships." );
131
+ }
132
+
133
+ if( isset( $condition['role_to_query_by'] ) && ( $condition['role_to_query_by'] == 'child' || $condition['role_to_query_by'] == 'intermediary' ) ) {
134
+ // not possible to query by child or intermediary
135
+ throw new InvalidArgumentException( "WP_Query > 'toolset_relationships' > 'role_to_query_by' invalid value. You can only use 'parent' for legacy relationships." );
136
+ }
137
+
138
+ // all fine
139
+ return $condition;
140
+ }
141
+ }
vendor/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/loader.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Apply WP_Query adjustments.
5
+ *
6
+ * Depending on the status of the m2m functionality, a proper adjustment class will be instantiated
7
+ * to allow for querying by post relationship in a sustainable way.
8
+ *
9
+ * @since 2.6.1
10
+ */
11
+ class Toolset_Wp_Query_Adjustments_Loader {
12
+
13
+
14
+ public function initialize() {
15
+
16
+ if( apply_filters( 'toolset_is_m2m_enabled', false ) ) {
17
+ $adjustments = new Toolset_Wp_Query_Adjustments_M2m();
18
+ } else {
19
+ $adjustments = new Toolset_Wp_Query_Adjustments_Legacy_Relationships();
20
+ }
21
+
22
+ $adjustments->initialize();
23
+ }
24
+
25
+ }
vendor/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/m2m.php ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Adjust the WP_Query functionality for m2m relationships.
5
+ *
6
+ * This assumes m2m is enabled.
7
+ *
8
+ * See the superclass for details.
9
+ *
10
+ * @since 2.6.1
11
+ */
12
+ class Toolset_Wp_Query_Adjustments_M2m extends Toolset_Wp_Query_Adjustments {
13
+
14
+
15
+ /** @var Toolset_Relationship_Database_Operations|null */
16
+ private $_database_operations;
17
+
18
+
19
+ /** @var null|Toolset_Element_Factory */
20
+ private $_element_factory;
21
+
22
+
23
+ /**
24
+ * Toolset_Wp_Query_Adjustments_M2m constructor.
25
+ *
26
+ * @param wpdb|null $wpdb_di
27
+ * @param Toolset_Relationship_Database_Operations|null $database_operations_di
28
+ * @param Toolset_Element_Factory|null $element_factory_di
29
+ */
30
+ public function __construct(
31
+ wpdb $wpdb_di = null,
32
+ Toolset_Relationship_Database_Operations $database_operations_di = null,
33
+ Toolset_Element_Factory $element_factory_di = null
34
+
35
+ ) {
36
+ parent::__construct( $wpdb_di );
37
+ $this->_database_operations = $database_operations_di;
38
+ $this->_element_factory = $element_factory_di;
39
+ }
40
+
41
+
42
+ /**
43
+ * @inheritdoc
44
+ */
45
+ public function initialize() {
46
+ parent::initialize();
47
+
48
+ do_action( 'toolset_do_m2m_full_init' );
49
+
50
+ add_filter( 'posts_where', array( $this, 'posts_where' ), 10, 2 );
51
+ add_filter( 'posts_join', array( $this, 'posts_join' ), 10, 2 );
52
+ }
53
+
54
+
55
+ /**
56
+ * Add conditions to the WHERE clause.
57
+ *
58
+ * @param string $where
59
+ * @param WP_Query $wp_query
60
+ *
61
+ * @return string
62
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
63
+ */
64
+ public function posts_where( $where, $wp_query ) {
65
+ if( property_exists( $wp_query, self::RELATIONSHIP_QUERY_ARG ) ) {
66
+ $where = $this->add_relationship_query_where( $where, $wp_query->{self::RELATIONSHIP_QUERY_ARG}, $wp_query );
67
+ }
68
+ return $where;
69
+ }
70
+
71
+
72
+ /**
73
+ * Add tables to the JOIN clause.
74
+ *
75
+ * @param string $join
76
+ * @param WP_Query $wp_query
77
+ *
78
+ * @return string
79
+ */
80
+ public function posts_join( $join, $wp_query ) {
81
+ if( property_exists( $wp_query, self::RELATIONSHIP_QUERY_ARG ) ) {
82
+ $join = $this->add_relationship_query_join( $join, $wp_query );
83
+ }
84
+ return $join;
85
+ }
86
+
87
+
88
+ /**
89
+ * @param string $where
90
+ * @param array $relationship_query
91
+ * @param WP_Query $wp_query
92
+ *
93
+ * @return string
94
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
95
+ */
96
+ private function add_relationship_query_where( $where, $relationship_query, WP_Query $wp_query ) {
97
+ $relationship_query = $this->normalize_relationship_query_args( $relationship_query );
98
+
99
+ foreach( $relationship_query as $query_condition ) {
100
+ $where .= ' ' . $this->add_relationship_query_condition( $query_condition, $wp_query );
101
+ }
102
+
103
+ return $where;
104
+ }
105
+
106
+
107
+ /**
108
+ * @param $query_condition
109
+ * @param WP_Query $wp_query
110
+ *
111
+ * @return string
112
+ */
113
+ private function add_relationship_query_condition( $query_condition, WP_Query $wp_query ) {
114
+ $relationship_slug = $this->get_relationship_slug( $query_condition );
115
+ $related_to_post = $this->get_post( $query_condition );
116
+
117
+ if( null === $relationship_slug || null === $related_to_post ) {
118
+ // The relationship or the post doesn't exist but it is not a misconfiguration of the
119
+ // wp_query argument - we just return no results.
120
+ return ' AND 0 = 1 ';
121
+ }
122
+
123
+ $role_to_return = $this->get_role( $query_condition, 'role' );
124
+ $associations_table = $this->get_table_join_manager( $wp_query )->associations_table( $relationship_slug, $role_to_return );
125
+
126
+ $role_to_query_by = $this->get_role( $query_condition, 'role_to_query_by', $role_to_return );
127
+ $role_to_query_by_column = $this->get_database_operations()->role_to_column( $role_to_query_by );
128
+
129
+ $clause = $this->wpdb->prepare(
130
+ " AND $associations_table.$role_to_query_by_column = %d ",
131
+ $related_to_post->get_default_language_id()
132
+ );
133
+
134
+ return $clause;
135
+ }
136
+
137
+
138
+ private function add_relationship_query_join( $join, $wp_query ) {
139
+ // Just add the tables from the JOIN manager which has been filled by data during the processing
140
+ // of the posts_where filter (it comes before posts_join)
141
+ return $join . ' ' . $this->get_table_join_manager( $wp_query )->get_join_clauses() . ' ';
142
+ }
143
+
144
+
145
+ /**
146
+ * Resolve the relationship slug from a given query condition.
147
+ *
148
+ * Also supports an array with a pair of post types that identify a legacy relationship.
149
+ *
150
+ * @param array $query_condition
151
+ *
152
+ * @return string
153
+ * @throws InvalidArgumentException
154
+ */
155
+ private function get_relationship_slug( $query_condition ) {
156
+ $relationship = toolset_getarr( $query_condition, 'relationship' );
157
+
158
+ if( is_array( $relationship ) ) {
159
+ if( count( $relationship ) !== 2 ) {
160
+ throw new InvalidArgumentException( 'Invalid relationship query argument.' );
161
+ }
162
+
163
+ $relationship_definition = Toolset_Relationship_Definition_Repository::get_instance()->get_legacy_definition(
164
+ $relationship[0], $relationship[1]
165
+ );
166
+ } elseif( ! is_string( $relationship ) || empty( $relationship ) ) {
167
+ throw new InvalidArgumentException( 'Invalid relationship query argument.' );
168
+ } else {
169
+ $relationship_definition = Toolset_Relationship_Definition_Repository::get_instance()->get_definition( $relationship );
170
+ }
171
+
172
+ if( null === $relationship_definition ) {
173
+ return null;
174
+ }
175
+
176
+ return $relationship_definition->get_slug();
177
+ }
178
+
179
+
180
+ /**
181
+ * Resolve the role object from the query condition.
182
+ *
183
+ * @param string[] $query_condition
184
+ * @param string $key Key of the element in the query condition that contains the role name.
185
+ * @param IToolset_Relationship_Role|null $other_role If this is provided and is a parent or child,
186
+ * the role in $key can be empty/other - the opposite of $other_role will be used in that case.
187
+ *
188
+ * @return IToolset_Relationship_Role
189
+ */
190
+ private function get_role( $query_condition, $key, IToolset_Relationship_Role $other_role = null ) {
191
+ $role_name = toolset_getarr( $query_condition, $key, 'other' );
192
+
193
+ if( 'other' === $role_name && $other_role instanceof IToolset_Relationship_Role_Parent_Child ) {
194
+ return $other_role->other();
195
+ }
196
+
197
+ return Toolset_Relationship_Role::role_from_name( $role_name );
198
+ }
199
+
200
+
201
+ /**
202
+ * @return Toolset_Relationship_Database_Operations
203
+ */
204
+ private function get_database_operations() {
205
+ if( null === $this->_database_operations ) {
206
+ $this->_database_operations = Toolset_Relationship_Database_Operations::get_instance();
207
+ }
208
+
209
+ return $this->_database_operations;
210
+ }
211
+
212
+
213
+ /**
214
+ * @return Toolset_Element_Factory
215
+ */
216
+ private function get_element_factory() {
217
+ if( null === $this->_element_factory ) {
218
+ $this->_element_factory = new Toolset_Element_Factory();
219
+ }
220
+
221
+ return $this->_element_factory;
222
+ }
223
+
224
+
225
+ /**
226
+ * Get the "related_to" post from the query condition array.
227
+ *
228
+ * @param $query_condition
229
+ *
230
+ * @return IToolset_Post
231
+ */
232
+ private function get_post( $query_condition ) {
233
+ $related_to_post_id = toolset_getarr( $query_condition, 'related_to' );
234
+ if( $related_to_post_id instanceof WP_Post ) {
235
+ $related_to_post_id = $related_to_post_id->ID;
236
+ } elseif( ! Toolset_Utils::is_natural_numeric( $related_to_post_id ) ) {
237
+ throw new InvalidArgumentException( 'Invalid relationship query argument.' );
238
+ } else {
239
+ $related_to_post_id = (int) $related_to_post_id;
240
+ }
241
+
242
+ try {
243
+ $post = $this->get_element_factory()->get_post( $related_to_post_id );
244
+ } catch ( Toolset_Element_Exception_Element_Doesnt_Exist $e ) {
245
+ return null;
246
+ }
247
+
248
+ return $post;
249
+ }
250
+
251
+ }
vendor/toolset/toolset-common/inc/autoloaded/wp_query_adjustments/table_join_manager.php ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Collect the JOINed tables in Toolset_Wp_Query_Adjustments_M2m and generate the JOIN clause.
5
+ *
6
+ * @since 2.6.1
7
+ */
8
+ class Toolset_Wp_Query_Adjustments_Table_Join_Manager extends Toolset_Wpdb_User {
9
+
10
+
11
+ /**
12
+ * @var string[][] Unique aliases for the associations table, indexed by a relationship slug and a role name.
13
+ */
14
+ private $joins = array();
15
+
16
+
17
+ /** @var Toolset_Relationship_Table_Name */
18
+ private $table_name;
19
+
20
+
21
+ /** @var Toolset_Relationship_Database_Unique_Table_Alias */
22
+ private $uniqe_table_alias;
23
+
24
+
25
+ /** @var Toolset_Relationship_Database_Operations */
26
+ private $database_operations;
27
+
28
+
29
+ /** @var Toolset_Relationship_Definition_Repository */
30
+ private $definition_repository;
31
+
32
+
33
+ /** @var Toolset_WPML_Compatibility */
34
+ private $wpml_service;
35
+
36
+
37
+ /**
38
+ * Toolset_Wp_Query_Adjustments_Table_Join_Manager constructor.
39
+ *
40
+ * @param wpdb|null $wpdb_di
41
+ * @param Toolset_Relationship_Database_Unique_Table_Alias|null $unique_table_alias_di
42
+ * @param Toolset_Relationship_Table_Name|null $table_name_di
43
+ * @param Toolset_Relationship_Database_Operations|null $database_operations_di
44
+ * @param Toolset_Relationship_Definition_Repository|null $definition_repository_di
45
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
46
+ */
47
+ public function __construct(
48
+ wpdb $wpdb_di = null,
49
+ Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias_di = null,
50
+ Toolset_Relationship_Table_Name $table_name_di = null,
51
+ Toolset_Relationship_Database_Operations $database_operations_di = null,
52
+ Toolset_Relationship_Definition_Repository $definition_repository_di = null,
53
+ Toolset_WPML_Compatibility $wpml_service_di = null
54
+ ) {
55
+ parent::__construct( $wpdb_di );
56
+ $this->uniqe_table_alias = $unique_table_alias_di ?: new Toolset_Relationship_Database_Unique_Table_Alias();
57
+ $this->table_name = $table_name_di ?: new Toolset_Relationship_Table_Name();
58
+ $this->database_operations = $database_operations_di ?: Toolset_Relationship_Database_Operations::get_instance();
59
+ $this->definition_repository = $definition_repository_di ?: Toolset_Relationship_Definition_Repository::get_instance();
60
+ $this->wpml_service = $wpml_service_di ?: Toolset_WPML_Compatibility::get_instance();
61
+ }
62
+
63
+
64
+ /**
65
+ * Generate the JOIN clause based on previously made requests for table aliases.
66
+ *
67
+ * @return string
68
+ */
69
+ public function get_join_clauses() {
70
+ $results = '';
71
+
72
+ foreach( $this->joins as $relationship_slug => $role_joins ) {
73
+ foreach( $role_joins as $role_name => $table_alias ) {
74
+ $results .= $this->get_single_join_clause( $relationship_slug, $table_alias, $role_name );
75
+ }
76
+ }
77
+
78
+ return $results;
79
+ }
80
+
81
+
82
+ private function get_single_join_clause( $relationship_slug, $associations_table_alias, $role_name ) {
83
+
84
+ $element_id_column = $this->database_operations->role_to_column( $role_name );
85
+ $relationship_definition = $this->definition_repository->get_definition( $relationship_slug );
86
+
87
+ if( null === $relationship_definition ) {
88
+ // This should have failed already during the WHERE clause processing and never get to this point.
89
+ throw new InvalidArgumentException( 'Unknown relationship "' . sanitize_text_field( $relationship_slug ) . '".' );
90
+ }
91
+
92
+ $relationship_id = $relationship_definition->get_row_id();
93
+
94
+ if( $this->wpml_service->is_wpml_active_and_configured() ) {
95
+ return $this->get_single_join_clause_for_wpml( $relationship_id, $associations_table_alias, $element_id_column );
96
+ }
97
+
98
+ return $this->wpdb->prepare(
99
+ "JOIN {$this->table_name->association_table()} AS {$associations_table_alias} ON (
100
+ wp_posts.ID = {$associations_table_alias}.{$element_id_column}
101
+ AND {$associations_table_alias}.relationship_id = %d
102
+ ) ",
103
+ $relationship_id
104
+ );
105
+ }
106
+
107
+
108
+ /**
109
+ * Join the associations table by either using the wp_posts.ID directly or by
110
+ * translating it to the default language first.
111
+ *
112
+ * @param int $relationship_id
113
+ * @param string $associations_table_alias
114
+ * @param string $element_id_column
115
+ *
116
+ * @return string
117
+ */
118
+ private function get_single_join_clause_for_wpml( $relationship_id, $associations_table_alias, $element_id_column ) {
119
+
120
+ $clause = $this->wpdb->prepare(
121
+ "
122
+ # join the icl_translations table independently from WPML's 't'
123
+ # because that one may not be joined at all time, but we
124
+ # need it always - this is safer than trying to reuse the 't' one
125
+ LEFT JOIN {$this->wpml_service->icl_translations_table_name()} AS toolset_post_t ON (
126
+ wp_posts.ID = toolset_post_t.element_id
127
+ AND toolset_post_t.element_type = CONCAT('post_', wp_posts.post_type)
128
+ ) LEFT JOIN {$this->wpml_service->icl_translations_table_name()} AS toolset_post_dl ON (
129
+ toolset_post_t.trid = toolset_post_dl.trid
130
+ AND toolset_post_dl.language_code = %s
131
+ ) JOIN {$this->table_name->association_table()} AS {$associations_table_alias} ON (
132
+ (
133
+ # join the association row if either the post ID matches the
134
+ # proper column in the associations table or if the ID of the default
135
+ # language version of the post matches it
136
+ wp_posts.ID = {$associations_table_alias}.{$element_id_column}
137
+ OR toolset_post_dl.element_id = {$associations_table_alias}.{$element_id_column}
138
+ )
139
+ AND {$associations_table_alias}.relationship_id = %d
140
+ )",
141
+ $this->wpml_service->get_default_language(),
142
+ $relationship_id
143
+ );
144
+
145
+ return $clause;
146
+ }
147
+
148
+
149
+ /**
150
+ * Request an alias for the associations table.
151
+ *
152
+ * The table will be JOINed on wp_posts.ID by a given relationship slug and element role.
153
+ *
154
+ * @param string $relationship_slug
155
+ * @param IToolset_Relationship_Role $role
156
+ *
157
+ * @return string
158
+ */
159
+ public function associations_table( $relationship_slug, IToolset_Relationship_Role $role ) {
160
+ if( ! array_key_exists( $relationship_slug, $this->joins ) ) {
161
+ $this->joins[ $relationship_slug ] = array();
162
+ }
163
+
164
+ if( ! array_key_exists( $role->get_name(), $this->joins[ $relationship_slug ] ) ) {
165
+ $unique_alias = $this->uniqe_table_alias->generate( $this->table_name->association_table(), true );
166
+ $this->joins[ $relationship_slug ][ $role->get_name() ] = $unique_alias;
167
+ }
168
+
169
+ return $this->joins[ $relationship_slug ][ $role->get_name() ];
170
+ }
171
+
172
+ }
vendor/toolset/toolset-common/inc/autoloaded/wpdb_user.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class that uses $wpdb, can be extended to avoid repetition of the dependency injection.
5
+ *
6
+ * @since 2.5.10
7
+ */
8
+ abstract class Toolset_Wpdb_User {
9
+
10
+
11
+ /** @var wpdb */
12
+ protected $wpdb;
13
+
14
+
15
+ /**
16
+ * Toolset_Wpdb_User constructor.
17
+ *
18
+ * @param wpdb|null $wpdb_di
19
+ */
20
+ public function __construct( wpdb $wpdb_di = null ) {
21
+ global $wpdb;
22
+
23
+ if( null === $wpdb_di ) {
24
+ $this->wpdb = $wpdb;
25
+ } else {
26
+ $this->wpdb = $wpdb_di;
27
+ }
28
+ }
29
+
30
+ }
vendor/toolset/toolset-common/inc/autoloaded/wpml_utils.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  * WPML-related helper functions.
5
  *
6
- * todo merge this with Toolset_Wpml_Compatibility.
7
  *
8
  * @since m2m
9
  */
@@ -12,6 +12,7 @@ class Toolset_Wpml_Utils {
12
 
13
  /**
14
  * @return string icl_translations table name.
 
15
  */
16
  public static function icl_translations_tn() {
17
  global $wpdb;
@@ -89,6 +90,7 @@ class Toolset_Wpml_Utils {
89
  * @param int $post_id
90
  * @return int "trid" value or zero.
91
  * @since m2m
 
92
  */
93
  public static function get_post_trid( $post_id ) {
94
  global $wpdb;
@@ -116,6 +118,7 @@ class Toolset_Wpml_Utils {
116
  * @param int $post_id
117
  * @return int[]
118
  * @since m2m
 
119
  */
120
  public static function get_post_translations_directly( $post_id ) {
121
 
@@ -133,12 +136,12 @@ class Toolset_Wpml_Utils {
133
  }
134
 
135
  $query = $wpdb->prepare(
136
- "SELECT
137
- element_id AS post_id,
138
- language_code AS language_code
139
- FROM
140
  $icl_translations_table
141
- WHERE
142
  element_type LIKE %s
143
  AND trid = %d",
144
  'post_%',
@@ -164,15 +167,13 @@ class Toolset_Wpml_Utils {
164
  * @param string $post_type_slug
165
  * @return bool
166
  * @since m2m
 
167
  */
168
  public static function is_post_type_translatable( $post_type_slug ) {
169
- return (bool) apply_filters( 'wpml_is_translated_post_type', false, $post_type_slug );
170
  }
171
 
172
 
173
- private static $current_language = null;
174
-
175
-
176
  /**
177
  * Get the current language.
178
  *
@@ -180,21 +181,13 @@ class Toolset_Wpml_Utils {
180
  *
181
  * @return string
182
  * @since m2m
 
183
  */
184
  public static function get_current_language() {
185
- if(
186
- null === self::$current_language
187
- && Toolset_WPML_Compatibility::get_instance()->is_wpml_active_and_configured()
188
- ) {
189
- self::$current_language = apply_filters( 'wpml_current_language', null );
190
- }
191
- return self::$current_language;
192
  }
193
 
194
 
195
- private static $default_language = null;
196
-
197
-
198
  /**
199
  * Get the default site language.
200
  *
@@ -202,15 +195,10 @@ class Toolset_Wpml_Utils {
202
  *
203
  * @return string
204
  * @since m2m
 
205
  */
206
  public static function get_default_language() {
207
- if(
208
- null === self::$default_language
209
- && Toolset_WPML_Compatibility::get_instance()->is_wpml_active_and_configured()
210
- ) {
211
- self::$default_language = apply_filters( 'wpml_default_language', null );
212
- }
213
- return self::$default_language;
214
  }
215
 
216
 
@@ -245,4 +233,41 @@ class Toolset_Wpml_Utils {
245
  }
246
  }
247
 
248
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  /**
4
  * WPML-related helper functions.
5
  *
6
+ * @deprecated Do not add new methods. Merge this class with Toolset_Wpml_Compatibility.
7
  *
8
  * @since m2m
9
  */
12
 
13
  /**
14
  * @return string icl_translations table name.
15
+ * @deprecated Use Toolset_WPML_Compatibility::icl_translations_table_name
16
  */
17
  public static function icl_translations_tn() {
18
  global $wpdb;
90
  * @param int $post_id
91
  * @return int "trid" value or zero.
92
  * @since m2m
93
+ * @deprecated Use Toolset_WPML_Compatibility::get_post_trid
94
  */
95
  public static function get_post_trid( $post_id ) {
96
  global $wpdb;
118
  * @param int $post_id
119
  * @return int[]
120
  * @since m2m
121
+ * @deprecated Use Toolset_WPML_Compatibility::get_post_translations_directly
122
  */
123
  public static function get_post_translations_directly( $post_id ) {
124
 
136
  }
137
 
138
  $query = $wpdb->prepare(
139
+ "SELECT
140
+ element_id AS post_id,
141
+ language_code AS language_code
142
+ FROM
143
  $icl_translations_table
144
+ WHERE
145
  element_type LIKE %s
146
  AND trid = %d",
147
  'post_%',
167
  * @param string $post_type_slug
168
  * @return bool
169
  * @since m2m
170
+ * @deprecated Use Toolset_WPML_Compatibility::is_post_type_translatable() instead.
171
  */
172
  public static function is_post_type_translatable( $post_type_slug ) {
173
+ return Toolset_WPML_Compatibility::get_instance()->is_post_type_translatable( $post_type_slug );
174
  }
175
 
176
 
 
 
 
177
  /**
178
  * Get the current language.
179
  *
181
  *
182
  * @return string
183
  * @since m2m
184
+ * @deprecated Use Toolset_WPML_Compatibility::get_current_language()
185
  */
186
  public static function get_current_language() {
187
+ return Toolset_WPML_Compatibility::get_instance()->get_current_language();
 
 
 
 
 
 
188
  }
189
 
190
 
 
 
 
191
  /**
192
  * Get the default site language.
193
  *
195
  *
196
  * @return string
197
  * @since m2m
198
+ * @deprecated Use Toolset_WPML_Compatibility::get_default_language()
199
  */
200
  public static function get_default_language() {
201
+ return Toolset_WPML_Compatibility::get_instance()->get_default_language();
 
 
 
 
 
 
202
  }
203
 
204
 
233
  }
234
  }
235
 
236
+
237
+ /**
238
+ * Check whether a default language of a post exists.
239
+ *
240
+ * Returns true if WPML is not active, as in that case, all posts are considered
241
+ * to be in the "default" language.
242
+ *
243
+ * Also returns true if the provided post itself is in the default language.
244
+ *
245
+ * @param int $post_id ID of the post
246
+ * @return boolean
247
+ * @since m2m
248
+ */
249
+ public static function has_default_language_translation( $post_id ) {
250
+ $wpml_service = Toolset_WPML_Compatibility::get_instance();
251
+ if( ! $wpml_service->is_wpml_active_and_configured() ) {
252
+ return true;
253
+ }
254
+
255
+ $default_language = $wpml_service->get_default_language();
256
+
257
+ $translated_post_id = apply_filters( 'wpml_object_id', (int) $post_id, 'any', false, $default_language );
258
+
259
+ return ( null !== $translated_post_id );
260
+ }
261
+
262
+
263
+ /**
264
+ * Gets active languages information
265
+ *
266
+ * @return array
267
+ * @since m2m
268
+ * @link https://wpml.org/documentation/getting-started-guide/language-setup/custom-language-switcher/
269
+ */
270
+ public static function get_active_languages() {
271
+ return apply_filters( 'wpml_active_languages', null, '' );
272
+ }
273
+ }
vendor/toolset/toolset-common/inc/m2m/association.php DELETED
@@ -1,191 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Translation-unaware m2m association between two elements.
5
- *
6
- * This can be used only when the multilingual mode is off/transitional
7
- *
8
- * Not to be used directly outside of the m2m API.
9
- *
10
- * @since m2m
11
- */
12
- class Toolset_Association extends Toolset_Association_Base {
13
-
14
-
15
- /** @var int[] IDs of elements, always complete. */
16
- private $element_ids = array();
17
-
18
- /** @var int */
19
- private $intermediary_id;
20
-
21
-
22
- /**
23
- * Toolset_Association constructor.
24
- *
25
- * See superclass for parameter description.
26
- *
27
- * It is assumed that the relationship definition uses the Toolset_Relationship_Driver driver.
28
- *
29
- * @param int $trid Translation group ID.
30
- * @param Toolset_Relationship_Definition $relationship_definition
31
- * @param array $element_sources Associative array with both element keys. Each item can be either an ID
32
- * or a matching Toolset_Element instance.
33
- * @param int|Toolset_Post $intermediary_source Intermediary post with association fields or its ID. If a
34
- * Toolset_Post instance is provided, it must have the type matching with the relationship definition.
35
- *
36
- * @since m2m
37
- */
38
- public function __construct(
39
- $trid, Toolset_Relationship_Definition $relationship_definition, $element_sources, $intermediary_source
40
- ) {
41
-
42
- parent::__construct( $trid, $relationship_definition );
43
-
44
- foreach( Toolset_Relationship_Role::parent_child_role_names() as $element_role ) {
45
- $element_source = toolset_getarr( $element_sources, $element_role, null );
46
-
47
- if( is_array( $element_source ) && 1 === count( $element_source ) ) {
48
- $element_source = array_pop( $element_source );
49
- }
50
-
51
- if( $element_source instanceof Toolset_Element ) {
52
- $this->element_ids[ $element_role ] = $element_source->get_id();
53
- $this->elements[ $element_role ] = $element_source;
54
- } elseif( Toolset_Utils::is_natural_numeric( $element_source ) ) {
55
- $this->element_ids[ $element_role ] = $element_source;
56
- } else {
57
- throw new InvalidArgumentException( 'Invalid or missing element source.' );
58
- }
59
- }
60
-
61
- if( is_array( $intermediary_source ) && 1 === count( $intermediary_source ) ) {
62
- $intermediary_source = array_pop( $intermediary_source );
63
- }
64
-
65
- // Intermediary posts needs special care, as always.
66
- if( Toolset_Utils::is_nonnegative_integer( $intermediary_source ) ) {
67
- $this->intermediary_id = (int) $intermediary_source;
68
- } elseif( $intermediary_source instanceof Toolset_Post ) {
69
- /** @var Toolset_Relationship_Driver $driver */
70
- $driver = $this->get_definition()->get_driver();
71
- if( $intermediary_source->get_type() != $driver->get_intermediary_post_type() ) {
72
- throw new InvalidArgumentException( 'Invalid post type of the intermediary post.');
73
- }
74
-
75
- $this->intermediary_id = $intermediary_source->get_id();
76
- $this->intermediary_post = $intermediary_source;
77
- } else {
78
- throw new InvalidArgumentException( 'Invalid intermediary post source.' );
79
- }
80
- }
81
-
82
-
83
- /**
84
- * Get an ID of an element in the associaton.
85
- *
86
- * @param string $element_role Must be a valid role.
87
- *
88
- * @return int
89
- * @since m2m
90
- */
91
- protected function get_element_id( $element_role ) {
92
- return $this->element_ids[ $element_role ];
93
- }
94
-
95
-
96
- /**
97
- * Get an association element.
98
- *
99
- * Instantiates an element from its ID if that hasn't been done yet.
100
- *
101
- * @param string $element_role
102
- * @return Toolset_Element
103
- * @throws InvalidArgumentException
104
- * @since m2m
105
- */
106
- public function get_element( $element_role ) {
107
- self::validate_element_role( $element_role );
108
- if( ! array_key_exists( $element_role, $this->elements ) ) {
109
- $this->elements[ $element_role ] = Toolset_Element::get_instance(
110
- $this->get_element_domain( $element_role ),
111
- $this->get_element_id( $element_role )
112
- );
113
- }
114
-
115
- return $this->elements[ $element_role ];
116
- }
117
-
118
-
119
- /**
120
- * @inheritdoc
121
- * @return null|Toolset_Post
122
- */
123
- protected function get_intermediary_post() {
124
- if( 0 === $this->intermediary_id ) {
125
- return null;
126
- }
127
-
128
- if( null === $this->intermediary_post ) {
129
- try {
130
- $this->intermediary_post = Toolset_Element::get_instance( Toolset_Field_Utils::DOMAIN_POSTS, $this->intermediary_id );
131
- } catch( Exception $e ) {
132
- // We couldn't load the post, it probably doesn't exist. Reset the ID to avoid checking again.
133
- $this->intermediary_id = 0;
134
- }
135
- }
136
-
137
- return $this->intermediary_post;
138
- }
139
-
140
-
141
- /**
142
- * @inheritdoc
143
- * @return bool|Toolset_Field_Instance[]
144
- */
145
- public function get_fields() {
146
- if( ! $this->has_fields() ) {
147
- return false;
148
- }
149
-
150
- return $this->intermediary_post->get_fields();
151
- }
152
-
153
-
154
- /**
155
- * @inheritdoc
156
- * @param string|Toolset_Field_Definition $field_source
157
- * @return bool|Toolset_Field_Instance
158
- */
159
- public function get_field( $field_source ) {
160
- if( ! $this->has_fields() ) {
161
- return false;
162
- }
163
-
164
- return $this->intermediary_post->get_field( $field_source );
165
- }
166
-
167
-
168
- /**
169
- * Get the ID of the intermediary post with association fields.
170
- *
171
- * Required for the [types] shortcode, but use with consideration.
172
- *
173
- * @return int Post ID or zero if no post exists.
174
- * @since m2m
175
- */
176
- public function get_intermediary_id() {
177
- return $this->intermediary_id;
178
- }
179
-
180
-
181
- /**
182
- * @return bool
183
- * @since m2m
184
- */
185
- public function has_intermediary_post() {
186
- return ( 0 != $this->get_intermediary_id() );
187
- }
188
-
189
-
190
-
191
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/toolset/toolset-common/inc/m2m/association/association.php ADDED
@@ -0,0 +1,472 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Translation-unaware m2m association between two elements.
5
+ *
6
+ * This can be used only when the multilingual mode is off/transitional
7
+ *
8
+ * Not to be used directly outside of the m2m API.
9
+ *
10
+ * @since m2m
11
+ * @refactoring!!!! Store intermediary ID and post object in the same way as the other elements.
12
+ */
13
+ class Toolset_Association implements IToolset_Association {
14
+
15
+
16
+ /**
17
+ * @var int[] IDs of elements, always complete.
18
+ *
19
+ * However, in case we deal with translatable elements, this will hold only the IDs
20
+ * of the default language versions, so these values can't be always used directly.
21
+ * get_element_id() will handle the translation if necessary.
22
+ */
23
+ private $element_ids = array();
24
+
25
+
26
+ /**
27
+ * @var int Intermediary post ID or zero if there is no intermediary post at all.
28
+ *
29
+ * See the note for $element_ids. Same goes here.
30
+ */
31
+ private $intermediary_id;
32
+
33
+
34
+ /** @var Toolset_Relationship_Definition */
35
+ private $relationship_definition;
36
+
37
+
38
+ /**
39
+ * @var Toolset_Element[] Actual elements, loaded on demand. Use self::get_element() to obtain them.
40
+ */
41
+ protected $elements = array();
42
+
43
+
44
+ /**
45
+ * @var int Translation group ID.
46
+ */
47
+ private $uid;
48
+
49
+
50
+ /**
51
+ * @var null|IToolset_Post
52
+ */
53
+ protected $intermediary_post;
54
+
55
+
56
+ /** @var Toolset_WPML_Compatibility */
57
+ private $wpml_service;
58
+
59
+
60
+ /** @var Toolset_Element_Factory */
61
+ private $_element_factory;
62
+
63
+
64
+ /** @noinspection PhpDocRedundantThrowsInspection */
65
+ /**
66
+ * Toolset_Association constructor.
67
+ *
68
+ * Note that no checks about elements with respect to the relationship definition are being performed here.
69
+ * The caller needs to ensure everything is valid (domains, types, other conditions). This is handled well in the
70
+ * association factory.
71
+ *
72
+ * It is assumed that the relationship definition uses the Toolset_Relationship_Driver driver.
73
+ *
74
+ * @param int $uid Unique association ID.
75
+ * @param Toolset_Relationship_Definition $relationship_definition
76
+ * @param array $element_sources Associative array with both element keys. Each item can be either an ID
77
+ * or a matching Toolset_Element instance.
78
+ * @param int|Toolset_Post $intermediary_source Intermediary post with association fields or its ID. If a
79
+ * Toolset_Post instance is provided, it must have the type matching with the relationship definition.
80
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
81
+ * @param Toolset_Element_Factory|null $element_factory_di
82
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
83
+ * @since m2m
84
+ */
85
+ public function __construct(
86
+ $uid,
87
+ Toolset_Relationship_Definition $relationship_definition,
88
+ $element_sources,
89
+ $intermediary_source,
90
+ Toolset_WPML_Compatibility $wpml_service_di = null,
91
+ Toolset_Element_Factory $element_factory_di = null
92
+ ) {
93
+ $this->wpml_service = ( null === $wpml_service_di ? Toolset_WPML_Compatibility::get_instance() : $wpml_service_di );
94
+ $this->_element_factory = ( null === $element_factory_di ? new Toolset_Element_Factory( null, $wpml_service_di ) : $element_factory_di );
95
+
96
+ if( ! Toolset_Utils::is_nonnegative_numeric( $uid ) ) {
97
+ throw new InvalidArgumentException();
98
+ }
99
+
100
+ $this->relationship_definition = $relationship_definition;
101
+ $this->uid = (int) $uid;
102
+
103
+ foreach( Toolset_Relationship_Role::parent_child_role_names() as $element_role ) {
104
+ $element_source = toolset_getarr( $element_sources, $element_role, null );
105
+ $this->store_element( $element_source, $element_role );
106
+ }
107
+
108
+ $this->store_element( $intermediary_source, Toolset_Relationship_Role::INTERMEDIARY );
109
+ }
110
+
111
+
112
+ /**
113
+ * Understand the element source and store it properly without wasting too much performance.
114
+ *
115
+ * Sometimes, the association is getting only element IDs, other times, it will get existing
116
+ * IToolset_Element instances, or a mix thereof. If possible, we wait with instantiating the
117
+ * elements as long as possible, to reduce memory and performance requirements.
118
+ *
119
+ * However, if WPML is active and there's a risk of some of those IDs or elements being
120
+ * translated, we need to make sure that we store only element IDs in the default language.
121
+ * In that case, we will have to instantiate the element and translate it.
122
+ *
123
+ * Note: For historical reasons, this will also survive an array with a single item,
124
+ * which is the actual element source.
125
+ *
126
+ * @param int|string|IToolset_Element|array $element_source
127
+ * @param string $role_name
128
+ *
129
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
130
+ */
131
+ private function store_element( $element_source, $role_name ) {
132
+ $is_intermediary = Toolset_Relationship_Role::INTERMEDIARY === $role_name;
133
+
134
+ if( is_array( $element_source ) && 1 === count( $element_source ) ) {
135
+ $element_source = array_pop( $element_source );
136
+ }
137
+
138
+ if(
139
+ $is_intermediary
140
+ && is_numeric( $element_source )
141
+ && 0 === (int) $element_source
142
+ ) {
143
+ // No intermediary post.
144
+ $this->intermediary_id = 0;
145
+ return;
146
+ }
147
+
148
+ if( $this->can_be_translated() ) {
149
+ // There's a chance we might need a translation.
150
+ try {
151
+ if( $element_source instanceof IToolset_Element ) {
152
+ $element = $element_source;
153
+ } else {
154
+ $element = $this->get_element_factory()->get_element(
155
+ $this->get_definition()->get_domain( Toolset_Relationship_Role::role_from_name( $role_name ) ),
156
+ (int) $element_source
157
+ );
158
+ }
159
+
160
+ $element_id = $element->translate( $this->wpml_service->get_default_language() )->get_id();
161
+
162
+ } catch( Toolset_Element_Exception_Element_Doesnt_Exist $e ) {
163
+ // We'll survive only a missing intermediary post.
164
+ if( ! $is_intermediary ) {
165
+ throw $e;
166
+ }
167
+
168
+ $element = null;
169
+ $element_id = 0;
170
+ }
171
+ } elseif( $element_source instanceof IToolset_Element ) {
172
+ // No translations from now on.
173
+
174
+ $element = $element_source;
175
+ $element_id = $element_source->get_id();
176
+ } elseif( Toolset_Utils::is_natural_numeric( $element_source ) ) {
177
+ $element = null;
178
+ $element_id = (int) $element_source;
179
+ } else {
180
+ throw new InvalidArgumentException( 'Invalid or missing element source.' );
181
+ }
182
+
183
+ if( $is_intermediary ) {
184
+ $this->intermediary_id = $element_id;
185
+ if( null !== $element ) {
186
+ $this->intermediary_post = $element;
187
+ }
188
+ } else {
189
+ $this->element_ids[ $role_name ] = $element_id;
190
+ if( null !== $element ) {
191
+ $this->elements[ $role_name ] = $element;
192
+ }
193
+ }
194
+
195
+ }
196
+
197
+
198
+ private function can_be_translated() {
199
+ return (
200
+ $this->wpml_service->is_wpml_active_and_configured()
201
+ && $this->get_definition()->is_translatable()
202
+ );
203
+ }
204
+
205
+
206
+ /**
207
+ * @return Toolset_Relationship_Definition
208
+ */
209
+ public function get_definition() { return $this->relationship_definition; }
210
+
211
+
212
+ /**
213
+ * Get domain of selected association element.
214
+ *
215
+ * @param string $element_role
216
+ *
217
+ * @return string Valid domain name as defined in Toolset_Field_Utils.
218
+ * @since m2m
219
+ */
220
+ protected function get_element_domain( $element_role ) {
221
+ $relationship_definition = $this->get_definition();
222
+ $element_type = $relationship_definition->get_element_type( $element_role );
223
+ return $element_type->get_domain();
224
+ }
225
+
226
+
227
+ /**
228
+ * Get an ID of an element in the associaton.
229
+ *
230
+ * @param string|IToolset_Relationship_Role $element_role Must be a valid role.
231
+ *
232
+ * @return int
233
+ * @since m2m
234
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
235
+ */
236
+ public function get_element_id( $element_role ) {
237
+ $element_role_name = Toolset_Relationship_Role::name_from_role( $element_role );
238
+
239
+ if( ! $this->can_be_translated() ) {
240
+ if( Toolset_Relationship_Role::INTERMEDIARY === $element_role_name ) {
241
+ return $this->intermediary_id;
242
+ }
243
+
244
+ return $this->element_ids[ $element_role_name ];
245
+ }
246
+
247
+ // We have to use the actual element because we might have to return
248
+ // a translated ID.
249
+ $element = $this->get_element( $element_role_name );
250
+
251
+ if( null === $element ) {
252
+ // Intermediary post which doesn't exist.
253
+ return 0;
254
+ }
255
+
256
+ return $element->get_id();
257
+ }
258
+
259
+
260
+ /**
261
+ * Get an association element.
262
+ *
263
+ * Instantiates an element from its ID if that hasn't been done yet.
264
+ *
265
+ * @param string $element_role
266
+ *
267
+ * @return IToolset_Element|null
268
+ * @throws InvalidArgumentException
269
+ * @since m2m
270
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
271
+ */
272
+ public function get_element( $element_role ) {
273
+ $element_role_name = Toolset_Relationship_Role::name_from_role( $element_role );
274
+
275
+ if( Toolset_Relationship_Role::INTERMEDIARY === $element_role_name ) {
276
+ return $this->get_intermediary_post();
277
+ }
278
+
279
+ if(
280
+ ! array_key_exists( $element_role_name, $this->elements )
281
+ || null === $this->elements[ $element_role_name ]
282
+ ) {
283
+ $this->elements[ $element_role_name ] = $this->get_element_factory()->get_element(
284
+ $this->get_element_domain( $element_role_name ),
285
+ $this->get_element_id( $element_role_name )
286
+ );
287
+ }
288
+
289
+ return $this->elements[ $element_role_name ];
290
+ }
291
+
292
+
293
+ /**
294
+ * Check that the element role is valid.
295
+ *
296
+ * @param string $element_role
297
+ *
298
+ * @throws InvalidArgumentException
299
+ * @since m2m
300
+ * @deprecated Use methods in Toolset_Relationship_Role instead.
301
+ */
302
+ public static function validate_element_role( $element_role ) {
303
+ if( ! in_array( $element_role, Toolset_Relationship_Role::parent_child_role_names() ) ) {
304
+ throw new InvalidArgumentException( 'Invalid element key.' );
305
+ }
306
+ }
307
+
308
+
309
+ /**
310
+ * Shortcut to the relationship driver.
311
+ *
312
+ * @return Toolset_Relationship_Driver_Base
313
+ */
314
+ public function get_driver() {
315
+ $relationship_definition = $this->get_definition();
316
+ return $relationship_definition->get_driver();
317
+ }
318
+
319
+
320
+ /**
321
+ * Get the unique identifier for the association.
322
+ *
323
+ * An integer value indicates that it's an ID from the associations table.
324
+ *
325
+ * It may be zero for associations that are not persisted yet.
326
+ *
327
+ * @return int
328
+ * @since m2m
329
+ */
330
+ public function get_uid() {
331
+ return $this->uid;
332
+ }
333
+
334
+
335
+ /**
336
+ * Get the translation group ID of the association.
337
+ *
338
+ * @return int Translation group ID or zero if not supported.
339
+ * @deprecated Use get_uid() instead.
340
+ */
341
+ public function get_trid() {
342
+ return $this->uid;
343
+ }
344
+
345
+
346
+
347
+ /**
348
+ * @inheritdoc
349
+ * @return null|IToolset_Post
350
+ */
351
+ protected function get_intermediary_post() {
352
+ if( 0 === $this->intermediary_id ) {
353
+ return null;
354
+ }
355
+
356
+ if( null === $this->intermediary_post ) {
357
+ try {
358
+ $this->intermediary_post = $this->get_element_factory()->get_post( $this->intermediary_id );
359
+ } catch( Exception $e ) {
360
+ // We couldn't load the post, it probably doesn't exist. Reset the ID to avoid checking again.
361
+ $this->intermediary_id = 0;
362
+ }
363
+ }
364
+
365
+ return $this->intermediary_post;
366
+ }
367
+
368
+
369
+ /**
370
+ * @inheritdoc
371
+ * @return bool|Toolset_Field_Instance[]
372
+ */
373
+ public function get_fields() {
374
+ if( ! $this->has_fields() ) {
375
+ return false;
376
+ }
377
+
378
+ return $this->get_intermediary_post()->get_fields();
379
+ }
380
+
381
+
382
+ /**
383
+ * @inheritdoc
384
+ * @param string|Toolset_Field_Definition $field_source
385
+ * @return bool|Toolset_Field_Instance
386
+ */
387
+ public function get_field( $field_source ) {
388
+ if( ! $this->has_fields() ) {
389
+ return false;
390
+ }
391
+
392
+ return $this->get_intermediary_post()->get_field( $field_source );
393
+ }
394
+
395
+
396
+ /**
397
+ * Get the ID of the intermediary post with association fields.
398
+ *
399
+ * Required for the [types] shortcode, but use with consideration.
400
+ *
401
+ * @return int Post ID or zero if no post exists.
402
+ * @since m2m
403
+ */
404
+ public function get_intermediary_id() {
405
+ if( ! $this->can_be_translated() ) {
406
+ return $this->intermediary_id;
407
+ }
408
+
409
+ // We have to go through the post object because it might be translated.
410
+ $intermediary_post = $this->get_intermediary_post();
411
+ if( null === $intermediary_post ) {
412
+ return 0;
413
+ }
414
+ return $intermediary_post->get_id();
415
+ }
416
+
417
+
418
+ /**
419
+ * @return bool
420
+ * @since m2m
421
+ */
422
+ public function has_intermediary_post() {
423
+ return ( 0 !== $this->get_intermediary_id() );
424
+ }
425
+
426
+
427
+ /**
428
+ * @return Toolset_Element_Factory
429
+ */
430
+ private function get_element_factory() {
431
+ if( null === $this->_element_factory ) {
432
+ $this->_element_factory = new Toolset_Element_Factory();
433
+ }
434
+
435
+ return $this->_element_factory;
436
+ }
437
+
438
+
439
+ /**
440
+ * @inheritdoc
441
+ *
442
+ * This needs to be called (internally) before accessing the intermediary post object.
443
+ *
444
+ * @return bool
445
+ * @since m2m
446
+ */
447
+ public function has_fields() {
448
+ $intermediary_post = $this->get_intermediary_post();
449
+
450
+ if ( null === $intermediary_post ) {
451
+ return false;
452
+ }
453
+
454
+ return ( $intermediary_post->get_field_count() > 0 );
455
+ }
456
+
457
+
458
+ /**
459
+ * @inheritdoc
460
+ *
461
+ * @param string|Toolset_Field_Definition $field_source
462
+ * @return bool
463
+ */
464
+ public function has_field( $field_source ) {
465
+ if( ! $this->has_fields() ) {
466
+ return false;
467
+ }
468
+
469
+ return $this->get_intermediary_post()->has_field( $field_source );
470
+ }
471
+
472
+ }
vendor/toolset/toolset-common/inc/m2m/association/cleanup/association.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Removes a single association from the database and cleans up after.
5
+ *
6
+ * That means also deleting the intermediary post, if it exists.
7
+ *
8
+ * @since 2.5.10
9
+ */
10
+ class Toolset_Association_Cleanup_Association extends Toolset_Wpdb_User {
11
+
12
+
13
+ /** @var Toolset_Relationship_Table_Name */
14
+ private $table_name;
15
+
16
+
17
+ /** @var Toolset_Association_Intermediary_Post_Persistence|null */
18
+ private $_intermediary_post_persistence;
19
+
20
+
21
+ /**
22
+ * Toolset_Association_Cleanup_Association constructor.
23
+ *
24
+ * @param Toolset_Relationship_Table_Name|null $table_name_di
25
+ * @param wpdb|null $wpdb_di
26
+ * @param Toolset_Association_Intermediary_Post_Persistence|null $intermediary_post_persistence_di
27
+ */
28
+ public function __construct(
29
+ Toolset_Relationship_Table_Name $table_name_di = null,
30
+ wpdb $wpdb_di = null,
31
+ Toolset_Association_Intermediary_Post_Persistence $intermediary_post_persistence_di = null
32
+ ) {
33
+ parent::__construct( $wpdb_di );
34
+ $this->table_name = $table_name_di ?: new Toolset_Relationship_Table_Name();
35
+ $this->_intermediary_post_persistence = $intermediary_post_persistence_di;
36
+ }
37
+
38
+
39
+ /**
40
+ * @return Toolset_Association_Intermediary_Post_Persistence
41
+ */
42
+ private function get_intermediary_post_persistence() {
43
+ if( null === $this->_intermediary_post_persistence ) {
44
+ $this->_intermediary_post_persistence = new Toolset_Association_Intermediary_Post_Persistence();
45
+ }
46
+ return $this->_intermediary_post_persistence;
47
+ }
48
+
49
+
50
+
51
+ /**
52
+ * Permanently delete the provided association.
53
+ *
54
+ * @param IToolset_Association $association Association to delete. Do not use the instance
55
+ * after passing it to this method.
56
+ *
57
+ * @return Toolset_Result
58
+ */
59
+ public function delete( IToolset_Association $association ) {
60
+ $this->get_intermediary_post_persistence()->maybe_delete_intermediary_post( $association );
61
+
62
+ $rows_updated = $this->wpdb->delete(
63
+ $this->table_name->association_table(),
64
+ array( 'id' => $association->get_uid() ),
65
+ '%d'
66
+ );
67
+
68
+ $is_success = ( false !== $rows_updated || 1 === $rows_updated );
69
+
70
+ return new Toolset_Result( $is_success );
71
+ }
72
+
73
+ }
vendor/toolset/toolset-common/inc/m2m/association/cleanup/cron_event.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A WP-Cron event definition.
5
+ *
6
+ * The event hook is added in Toolset_Relationship_Controller.
7
+ *
8
+ * This event should be scheduled when there are dangling intermediary posts that need to be removed.
9
+ *
10
+ * @since 2.5.10
11
+ */
12
+ class Toolset_Association_Cleanup_Cron_Event extends Toolset_Cron_Event {
13
+
14
+
15
+ /**
16
+ * @inheritdoc
17
+ *
18
+ * @return string
19
+ */
20
+ public function get_unique_slug() {
21
+ return 'cleanup_dangling_intermediary_posts';
22
+ }
23
+
24
+
25
+ /**
26
+ * @inheritdoc
27
+ *
28
+ * @return string
29
+ */
30
+ public function get_parent_plugin() {
31
+ return 'types';
32
+ }
33
+
34
+
35
+ /**
36
+ * @inheritdoc
37
+ *
38
+ * @return string
39
+ */
40
+ public function get_interval() {
41
+ return Toolset_Cron_Event::INTERVAL_HOURLY;
42
+ }
43
+
44
+
45
+ }
vendor/toolset/toolset-common/inc/m2m/association/cleanup/cron_handler.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handle the Toolset_Association_Cleanup_Cron_Event event.
5
+ *
6
+ * Perform the cleanup action and unschedule the event in case there are no dangling
7
+ * intermediary posts left.
8
+ *
9
+ * @since 2.5.10
10
+ */
11
+ class Toolset_Association_Cleanup_Cron_Handler {
12
+
13
+
14
+ /** @var Toolset_Association_Cleanup_Factory */
15
+ private $cleanup_factory;
16
+
17
+
18
+ /** @var Toolset_Cron */
19
+ private $cron;
20
+
21
+
22
+ /**
23
+ * Toolset_Association_Cleanup_Cron_Handler constructor.
24
+ *
25
+ * @param Toolset_Association_Cleanup_Factory $cleanup_factory
26
+ * @param Toolset_Cron|null $cron_di
27
+ */
28
+ public function __construct(
29
+ Toolset_Association_Cleanup_Factory $cleanup_factory,
30
+ Toolset_Cron $cron_di = null
31
+ ) {
32
+ $this->cleanup_factory = $cleanup_factory;
33
+ $this->cron = $cron_di ?: Toolset_Cron::get_instance();
34
+ }
35
+
36
+
37
+ /**
38
+ * Handle the WP-Cron event.
39
+ */
40
+ public function handle_event() {
41
+ $cleanup = $this->cleanup_factory->dangling_intermediary_posts();
42
+ $cleanup->do_batch();
43
+
44
+ if( ! $cleanup->has_remaining_posts() ) {
45
+ $this->unschedule_event();
46
+ }
47
+ }
48
+
49
+
50
+ private function unschedule_event() {
51
+ $event = $this->cleanup_factory->cron_event();
52
+ $this->cron->unschedule_event( $event );
53
+ }
54
+
55
+
56
+
57
+ }
vendor/toolset/toolset-common/inc/m2m/association/cleanup/dangling_intermediary_posts.php ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Delete a batch of dangling intermediary posts (DIP).
5
+ *
6
+ * A DIP is a post belonging to an intermediary post type that is not involved in an association
7
+ * and is not a translation of any such post. DIPs should not exist and this class queries
8
+ * and permanently deletes them.
9
+ *
10
+ * Only a single batch is deleted on each pass because this might be an expensive operation
11
+ * which can be called from various contexts like WP-Cron or an user-triggered batch process.
12
+ *
13
+ * @since 2.5.10
14
+ */
15
+ class Toolset_Association_Cleanup_Dangling_Intermediary_Posts extends Toolset_Wpdb_User {
16
+
17
+
18
+ /** @var Toolset_Relationship_Query_Factory */
19
+ private $query_factory;
20
+
21
+
22
+ /** @var bool After a batch is performed, this will be set to false if there are no more DIPs. */
23
+ private $has_remaining_posts = true;
24
+
25
+
26
+ /** @var Toolset_Relationship_Table_Name */
27
+ private $table_name;
28
+
29
+
30
+ /** @var Toolset_WPML_Compatibility */
31
+ private $wpml_service;
32
+
33
+
34
+ /** @var Toolset_Post_Type_Query_Factory */
35
+ private $post_type_query_factory;
36
+
37
+
38
+ private $deleted_posts = 0;
39
+
40
+
41
+ /**
42
+ * Toolset_Association_Cleanup_Dangling_Intermediary_Posts constructor.
43
+ *
44
+ * @param Toolset_Relationship_Query_Factory|null $query_factory_di
45
+ * @param wpdb|null $wpdb_di
46
+ * @param Toolset_Relationship_Table_Name|null $table_name_di
47
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
48
+ * @param Toolset_Post_Type_Query_Factory|null $post_type_query_factory_di
49
+ */
50
+ public function __construct(
51
+ Toolset_Relationship_Query_Factory $query_factory_di = null,
52
+ wpdb $wpdb_di = null,
53
+ Toolset_Relationship_Table_Name $table_name_di = null,
54
+ Toolset_WPML_Compatibility $wpml_service_di = null,
55
+ Toolset_Post_Type_Query_Factory $post_type_query_factory_di = null
56
+ ) {
57
+ parent::__construct( $wpdb_di );
58
+ $this->query_factory = $query_factory_di ?: new Toolset_Relationship_Query_Factory();
59
+ $this->table_name = $table_name_di ?: new Toolset_Relationship_Table_Name( $wpdb_di );
60
+ $this->wpml_service = $wpml_service_di ?: Toolset_WPML_Compatibility::get_instance();
61
+ $this->post_type_query_factory = $post_type_query_factory_di ?: new Toolset_Post_Type_Query_Factory();
62
+ }
63
+
64
+
65
+ /**
66
+ * Perform one batch of DIP deletions.
67
+ *
68
+ * @since 2.5.10
69
+ */
70
+ public function do_batch() {
71
+ $post_ids = array_map( 'intval', $this->get_post_ids() );
72
+ foreach( $post_ids as $post_to_delete ) {
73
+ add_filter( Toolset_Association_Cleanup_Post::IS_DELETING_FILTER, '__return_true' );
74
+ wp_delete_post( $post_to_delete, true );
75
+ remove_filter( Toolset_Association_Cleanup_Post::IS_DELETING_FILTER, '__return_true' );
76
+ }
77
+
78
+ $this->deleted_posts = count( $post_ids );
79
+ }
80
+
81
+
82
+ private function get_post_ids() {
83
+ $post_ids = $this->wpdb->get_col( $this->build_query() );
84
+
85
+ $found_rows = (int) $this->wpdb->get_var( 'SELECT FOUND_ROWS()' );
86
+ $this->has_remaining_posts = ( $found_rows > Toolset_Association_Cleanup_Post::DELETE_POSTS_PER_BATCH );
87
+
88
+ return $post_ids;
89
+ }
90
+
91
+
92
+ /**
93
+ * After a batch operation was performed, this will return false if there are no
94
+ * remaining DIPs to be deleted. Otherwise returns true.
95
+ *
96
+ * @return bool
97
+ */
98
+ public function has_remaining_posts() {
99
+ return $this->has_remaining_posts;
100
+ }
101
+
102
+
103
+ /**
104
+ * After a batch operation was performed, this will return the number of posts
105
+ * that have actually been deleted.
106
+ *
107
+ * @return int
108
+ */
109
+ public function get_deleted_posts() {
110
+ return $this->deleted_posts;
111
+ }
112
+
113
+
114
+ /**
115
+ * Build a query for DIPs depending on WPML status.
116
+ *
117
+ * @return string Valid and safe MySQL query string.
118
+ */
119
+ private function build_query() {
120
+ $ipts = '\'' . implode( '\', \'', esc_sql( $this->get_intermediary_post_types() ) ) . '\'';
121
+ $limit = (int) Toolset_Association_Cleanup_Post::DELETE_POSTS_PER_BATCH;
122
+
123
+ if( $this->wpml_service->is_wpml_active_and_configured() ) {
124
+ $icl_translations = $this->wpdb->prefix . 'icl_translations';
125
+ $default_language = esc_sql( $this->wpml_service->get_default_language() );
126
+
127
+ // Main goal: Query posts of given types that are neither used as intermediary posts directly
128
+ // nor as translations of intermediary posts.
129
+ // We achieve that by doing a LEFT JOINs and then checking if the columns in
130
+ // joined tables are NULL (no match).
131
+ $query = "
132
+ SELECT SQL_CALC_FOUND_ROWS post.ID
133
+ FROM {$this->wpdb->posts} AS post
134
+ LEFT JOIN {$this->table_name->association_table()} AS association
135
+ ON (post.ID = association.intermediary_id)
136
+ LEFT JOIN {$icl_translations} AS translation
137
+ ON (
138
+ post.ID = translation.element_id
139
+ AND translation.element_type LIKE 'post_%'
140
+ AND translation.language_code != '{$default_language}'
141
+ )
142
+ LEFT JOIN {$icl_translations} AS default_language_translation
143
+ ON (
144
+ translation.trid = default_language_translation.trid
145
+ AND default_language_translation.language_code = '{$default_language}'
146
+ )
147
+ LEFT JOIN {$this->table_name->association_table()} AS default_language_association
148
+ ON(
149
+ default_language_association.intermediary_id = default_language_translation.element_id
150
+ )
151
+ WHERE
152
+ association.intermediary_id IS NULL
153
+ AND default_language_association.intermediary_id IS NULL
154
+ AND post.post_type IN ({$ipts})
155
+ LIMIT {$limit}";
156
+
157
+ } else {
158
+ // Ditto but without the WPML part, as the icl_translations table probably doesn't
159
+ // even exist.
160
+ $query = "
161
+ SELECT SQL_CALC_FOUND_ROWS post.ID
162
+ FROM {$this->wpdb->posts} AS post
163
+ LEFT JOIN {$this->table_name->association_table()} AS association
164
+ ON (post.ID = association.intermediary_id)
165
+ WHERE
166
+ association.intermediary_id IS NULL
167
+ AND post.post_type IN ({$ipts})
168
+ LIMIT {$limit}";
169
+ }
170
+
171
+ return $query;
172
+ }
173
+
174
+
175
+ /**
176
+ * @return string[] IPT slugs.
177
+ */
178
+ private function get_intermediary_post_types() {
179
+ $query = $this->post_type_query_factory->create(
180
+ array(
181
+ 'is_intermediary' => true,
182
+ 'return' => 'slug'
183
+ )
184
+ );
185
+
186
+ return $query->get_results();
187
+ }
188
+
189
+ }
vendor/toolset/toolset-common/inc/m2m/association/cleanup/factory.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Factory for objects handling cleaning up and removing m2m-related data.
5
+ *
6
+ * @since 2.5.10
7
+ */
8
+ class Toolset_Association_Cleanup_Factory {
9
+
10
+
11
+ /**
12
+ * @return Toolset_Association_Cleanup_Post
13
+ */
14
+ public function post() {
15
+ return new Toolset_Association_Cleanup_Post(
16
+ null, null, null, null, null, $this
17
+ );
18
+ }
19
+
20
+
21
+ /**
22
+ * @return Toolset_Association_Cleanup_Association
23
+ */
24
+ public function association() {
25
+ return new Toolset_Association_Cleanup_Association();
26
+ }
27
+
28
+
29
+ /**
30
+ * @return Toolset_Association_Cleanup_Cron_Handler
31
+ */
32
+ public function cron_handler() {
33
+ return new Toolset_Association_Cleanup_Cron_Handler( $this );
34
+ }
35
+
36
+
37
+ /**
38
+ * @return Toolset_Association_Cleanup_Dangling_Intermediary_Posts
39
+ */
40
+ public function dangling_intermediary_posts() {
41
+ return new Toolset_Association_Cleanup_Dangling_Intermediary_Posts();
42
+ }
43
+
44
+
45
+ /**
46
+ * @return Toolset_Association_Cleanup_Cron_Event
47
+ */
48
+ public function cron_event() {
49
+ return new Toolset_Association_Cleanup_Cron_Event();
50
+ }
51
+
52
+
53
+ /**
54
+ * @return Toolset_Association_Cleanup_Troubleshooting_Section
55
+ */
56
+ public function troubeshooting_section() {
57
+ return new Toolset_Association_Cleanup_Troubleshooting_Section( $this );
58
+ }
59
+
60
+
61
+ }
vendor/toolset/toolset-common/inc/m2m/association/cleanup/post.php ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Perform a cleanup after a single post has been deleted.
5
+ *
6
+ * Needs to be hooked to the before_delete_post action.
7
+ *
8
+ * Short version:
9
+ *
10
+ * This situation is much more tricky than when just deleting a single association. One post
11
+ * can be involved in many associations and deleting those might trigger also deleting of
12
+ * intermediary posts and their translations.
13
+ *
14
+ * Long version:
15
+ *
16
+ * Associations themselves can be handled with a single MySQL query,
17
+ * but for deleting intermediary posts, we have to perform consecutive wp_delete_post() calls,
18
+ * which in turn may trigger further deletions if those intermediary posts are translated
19
+ * to more languages.
20
+ *
21
+ * We simply cannot afford to delete all intermediary posts at once, because that might be
22
+ * easily much more than the server can handle, and we can't immediately show a
23
+ * batch deletion dialog because we don't know in which context the initial post is deleted.
24
+ * It may be even during an AJAX call or whatnot.
25
+ *
26
+ * The problem is that we don't want to have lingering intermediary posts because the user
27
+ * might use them in a View, for example, and assume that an intermediary post == an association.
28
+ *
29
+ * Here, a compromise solution is implemented: We immediately delete a certain number of
30
+ * intermediary posts, which will cover 99% of these cases, and for the remaining 1%
31
+ * of big deletions, offer a clean-up routine on the Toolset Troubleshooting page.
32
+ *
33
+ * If we detect that such a cleanup is needed, we'll display a notice until the user goes
34
+ * to the troubleshooting page and clicks the button.
35
+ *
36
+ * On top of that, a CRON job will be created to complete the cleanup if the user doesn't
37
+ * take action soon enough.
38
+ *
39
+ * @since 2.5.10
40
+ */
41
+ class Toolset_Association_Cleanup_Post extends Toolset_Wpdb_User {
42
+
43
+
44
+ const DELETE_POSTS_PER_BATCH = 25;
45
+
46
+
47
+ const IS_DELETING_FILTER = 'toolset_is_deleting_intermediary_post';
48
+
49
+
50
+ /** @var Toolset_Element_Factory */
51
+ private $element_factory;
52
+
53
+
54
+ /** @var Toolset_Relationship_Query_Factory */
55
+ private $query_factory;
56
+
57
+
58
+ /** @var Toolset_Relationship_Table_Name */
59
+ private $table_name;
60
+
61
+
62
+ /** @var null|Toolset_Cron */
63
+ private $_cron;
64
+
65
+
66
+ /** @var null|Toolset_Association_Cleanup_Factory */
67
+ private $_cleanup_factory;
68
+
69
+
70
+ /** @var Toolset_WPML_Compatibility */
71
+ private $wpml_service;
72
+
73
+
74
+ /** @var null|Toolset_Association_Intermediary_Post_Persistence */
75
+ private $_ip_persistence;
76
+
77
+
78
+ /**
79
+ * Toolset_Association_Cleanup_Post constructor.
80
+ *
81
+ * @param Toolset_Element_Factory|null $element_factory_di
82
+ * @param Toolset_Relationship_Query_Factory|null $query_factory_di
83
+ * @param Toolset_Relationship_Table_Name|null $table_name_di
84
+ * @param wpdb|null $wpdb_di
85
+ * @param Toolset_Cron|null $cron_di
86
+ * @param Toolset_Association_Cleanup_Factory|null $cleanup_factory_di
87
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
88
+ * @param Toolset_Association_Intermediary_Post_Persistence|null $intermediary_post_persistence_di
89
+ */
90
+ public function __construct(
91
+ Toolset_Element_Factory $element_factory_di = null,
92
+ Toolset_Relationship_Query_Factory $query_factory_di = null,
93
+ Toolset_Relationship_Table_Name $table_name_di = null,
94
+ wpdb $wpdb_di = null,
95
+ Toolset_Cron $cron_di = null,
96
+ Toolset_Association_Cleanup_Factory $cleanup_factory_di = null,
97
+ Toolset_WPML_Compatibility $wpml_service_di = null,
98
+ Toolset_Association_Intermediary_Post_Persistence $intermediary_post_persistence_di = null
99
+ ) {
100
+ parent::__construct( null );
101
+ $this->element_factory = $element_factory_di ?: new Toolset_Element_Factory();
102
+ $this->query_factory = $query_factory_di ?: new Toolset_Relationship_Query_Factory();
103
+ $this->table_name = $table_name_di ?: new Toolset_Relationship_Table_Name();
104
+ $this->_cron = $cron_di;
105
+ $this->_cleanup_factory = $cleanup_factory_di;
106
+ $this->wpml_service = $wpml_service_di ?: Toolset_WPML_Compatibility::get_instance();
107
+ $this->_ip_persistence = $intermediary_post_persistence_di;
108
+ }
109
+
110
+
111
+ /**
112
+ * Clean up affected associations before a post is permanently deleted.
113
+ *
114
+ * @param int $post_id
115
+ */
116
+ public function cleanup( $post_id ) {
117
+ $is_deleting_association = apply_filters( self::IS_DELETING_FILTER, false );
118
+
119
+ if( $is_deleting_association ) {
120
+ // Prevent an infinite recursion if a single association is being deleted.
121
+ // If we got here, it means that the association's intermediary post is about to
122
+ // be deleted and everything else is already handled either
123
+ // in Toolset_Association_Cleanup_Association, or within this class.
124
+ return;
125
+ }
126
+
127
+ try {
128
+ $post = $this->element_factory->get_post_untranslated( $post_id );
129
+
130
+ } /** @noinspection PhpRedundantCatchClauseInspection */
131
+ catch( Toolset_Element_Exception_Element_Doesnt_Exist $e ) {
132
+ // The post is already gone, do nothing.
133
+ return;
134
+ }
135
+
136
+ if( $post->is_revision() ) {
137
+ // No need to handle revisions. They're not supposed to have any
138
+ // associations at all. Just let WordPress proceed with the deletion.
139
+ return;
140
+ }
141
+
142
+ if( ! $this->is_involved_in_association_directly( $post ) ) {
143
+ // A post may be a translation of another post that is involved in an association
144
+ // as a parent, a child or an intermediary post. But in any of these cases, we don't
145
+ // have to delete anything. Not even the intermediary post translation. We allow even such
146
+ // scenarios as having a translatable intermediary post type but non-translatable
147
+ // parent and child.
148
+ //
149
+ // Intermediary post translations will be deleted only when the whole association is deleted
150
+ // or they can be deleted manually, if the user cares about it.
151
+ return;
152
+ }
153
+
154
+ // The post was directly involved in an association - either it's non-translatable
155
+ // or in the default language. We delete the associations and we're done.
156
+ $this->delete_associations_involving_post( $post );
157
+ }
158
+
159
+
160
+ /**
161
+ * @param IToolset_Post $post
162
+ *
163
+ * @return bool
164
+ */
165
+ private function is_involved_in_association_directly( IToolset_Post $post ) {
166
+ $query = $this->query_factory->associations_v2();
167
+
168
+ $found_rows = $query
169
+ ->add( $query->element(
170
+ $post, null, true, false
171
+ ) )
172
+ ->do_not_add_default_conditions()
173
+ ->get_found_rows_directly();
174
+
175
+ return ( $found_rows > 0 );
176
+ }
177
+
178
+
179
+ /**
180
+ * @param IToolset_Post $post
181
+ */
182
+ private function delete_associations_involving_post( IToolset_Post $post ) {
183
+ $this->delete_involved_intermediary_posts( $post );
184
+ $this->delete_association_rows( $post );
185
+ }
186
+
187
+
188
+ /**
189
+ * Delete all the affected association rows from the database.
190
+ *
191
+ * @param IToolset_Post $post
192
+ *
193
+ * @return Toolset_Result
194
+ */
195
+ private function delete_association_rows( IToolset_Post $post ) {
196
+ $associations = $this->table_name->association_table();
197
+ $relationships = $this->table_name->relationship_table();
198
+
199
+ $query = $this->wpdb->prepare(
200
+ "DELETE association
201
+ FROM {$associations} AS association
202
+ JOIN {$relationships} AS relationship
203
+ ON ( association.relationship_id = relationship.id )
204
+ WHERE
205
+ ( relationship.parent_domain = 'posts' AND parent_id = %d )
206
+ OR ( relationship.child_domain = 'posts' AND child_id = %d )
207
+ OR ( intermediary_id = %d )",
208
+ $post->get_id(),
209
+ $post->get_id(),
210
+ $post->get_id()
211
+ );
212
+
213
+ $deleted_rows = $this->wpdb->query( $query );
214
+
215
+ return new Toolset_Result( $deleted_rows > 0 );
216
+ }
217
+
218
+
219
+ /**
220
+ * Delete a first batch of intermediary posts that should be removed together
221
+ * with the association. If some intermediary posts remain, set up a CRON job and an admin notice
222
+ * for the user.
223
+ *
224
+ * @param IToolset_Post $post
225
+ */
226
+ private function delete_involved_intermediary_posts( IToolset_Post $post ) {
227
+ $query = $this->query_factory->associations_v2();
228
+
229
+ $intermediary_post_ids = $query
230
+ ->add( $query->do_or(
231
+ // Not intermediary posts. If the element is an intermediary post,
232
+ // we need to exclude it (it's already being deleted) and we wouldn't get any other
233
+ // associations where it's involved.
234
+ $query->element( $post, new Toolset_Relationship_Role_Parent(), true, false ),
235
+ $query->element( $post, new Toolset_Relationship_Role_Child(), true, false )
236
+ ) )
237
+ ->do_not_add_default_conditions()
238
+ ->limit( self::DELETE_POSTS_PER_BATCH )
239
+ ->return_element_ids( new Toolset_Relationship_Role_Intermediary() )
240
+ ->need_found_rows()
241
+ ->get_results();
242
+
243
+ foreach( $intermediary_post_ids as $intermediary_post_id ) {
244
+ // This will also delete post translations.
245
+ $this->get_intermediary_post_persistence()->delete_intermediary_post( $intermediary_post_id );
246
+ }
247
+
248
+ if( $query->get_found_rows() > self::DELETE_POSTS_PER_BATCH ) {
249
+ // Some dangling posts are left, there's too much of them to be deleted at once.
250
+ // Schedule a WP-Cron event to delete them by batches until there are none left.
251
+ $this->schedule_dangling_post_removal();
252
+ }
253
+ }
254
+
255
+
256
+ /**
257
+ * @return Toolset_Association_Cleanup_Factory
258
+ */
259
+ private function get_cleanup_factory() {
260
+ if( null === $this->_cleanup_factory ) {
261
+ $this->_cleanup_factory = new Toolset_Association_Cleanup_Factory();
262
+ }
263
+ return $this->_cleanup_factory;
264
+ }
265
+
266
+
267
+ /**
268
+ * @return Toolset_Cron
269
+ */
270
+ private function get_cron() {
271
+ if( null === $this->_cron ) {
272
+ $this->_cron = Toolset_Cron::get_instance();
273
+ }
274
+ return $this->_cron;
275
+ }
276
+
277
+
278
+ private function schedule_dangling_post_removal() {
279
+ $cron_event = $this->get_cleanup_factory()->cron_event();
280
+ $this->get_cron()->schedule_event( $cron_event );
281
+ }
282
+
283
+
284
+ /**
285
+ * @return Toolset_Association_Intermediary_Post_Persistence
286
+ */
287
+ private function get_intermediary_post_persistence() {
288
+ if( null === $this->_ip_persistence ) {
289
+ $this->_ip_persistence = new Toolset_Association_Intermediary_Post_Persistence();
290
+ }
291
+ return $this->_ip_persistence;
292
+ }
293
+
294
+
295
+ }
vendor/toolset/toolset-common/inc/m2m/association/cleanup/troubleshooting_section.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Manage the troubleshooting section for manually deleting dangling intermediary posts.
5
+ *
6
+ * @since 2.5.10
7
+ */
8
+ class Toolset_Association_Cleanup_Troubleshooting_Section {
9
+
10
+
11
+ const TROUBLESHOOTING_SECTION_SLUG = 'cleanup_intermediary_posts';
12
+
13
+
14
+ /**
15
+ * @var Toolset_Association_Cleanup_Factory
16
+ */
17
+ private $cleanup_factory;
18
+
19
+
20
+ /**
21
+ * @var Toolset_Cron
22
+ */
23
+ private $cron;
24
+
25
+
26
+ /**
27
+ * Toolset_Association_Cleanup_Troubleshooting_Section constructor.
28
+ *
29
+ * @param Toolset_Association_Cleanup_Factory $cleanup_factory
30
+ * @param Toolset_Cron|null $cron_di
31
+ */
32
+ public function __construct(
33
+ Toolset_Association_Cleanup_Factory $cleanup_factory,
34
+ Toolset_Cron $cron_di = null
35
+ ) {
36
+ $this->cleanup_factory = $cleanup_factory;
37
+ $this->cron = $cron_di ?: Toolset_Cron::get_instance();
38
+ }
39
+
40
+
41
+ /**
42
+ * Find out whether there are posts to clean up.
43
+ *
44
+ * Instead of running the query, we just check whether the cleanup WP-Cron job is already scheduled.
45
+ *
46
+ * @return bool
47
+ */
48
+ public function is_cleanup_needed() {
49
+ $cron_event = $this->cleanup_factory->cron_event();
50
+
51
+ // Note: This may give us false positives: There may be a WP-Cron event executed later during this request,
52
+ // which will delete all remaining DIPs. Unfortunately, we have no way of predicting that reliably.
53
+ //
54
+ // This will be happening if there are exactly between ($x+1) and ($x*2) DIPs,
55
+ // where $x = Toolset_Association_Cleanup_Post::DELETE_POSTS_PER_BATCH.
56
+ return $this->cron->is_scheduled( $cron_event );
57
+ }
58
+
59
+
60
+ /**
61
+ * Register the troubleshooting section and a dismissable admin notice that will point towards it.
62
+ */
63
+ public function register() {
64
+ add_filter( 'toolset_get_troubleshooting_sections', array( $this, 'add_troubleshooting_section' ) );
65
+ add_action( 'toolset_admin_notices_manager_show_notices', array( $this, 'add_notice' ) );
66
+ }
67
+
68
+
69
+ /**
70
+ * Add new troubleshooting section definition.
71
+ *
72
+ * @param array $sections
73
+ *
74
+ * @return array
75
+ */
76
+ public function add_troubleshooting_section( $sections ) {
77
+ $sections[ self::TROUBLESHOOTING_SECTION_SLUG ] = array(
78
+ 'title' => __( 'Delete leftover intermediary posts', 'wpcf' ),
79
+ 'description' => __( 'After deleting a large number of associations, there are some intermediary posts left. It was not possible to delete them at once. You can either delete them manually or ignore the issue, and they will be gradually removed automatically. This is only important if you use intermediary posts on the front-end directly, for example in a View.', 'wpcf'),
80
+ 'button_label' => __( 'Delete leftover posts', 'wpcf' ),
81
+ 'is_dangerous' => false,
82
+ 'action_name' => Toolset_Ajax::get_instance()->get_action_js_name( Toolset_Ajax::CALLBACK_INTERMEDIARY_POST_CLEANUP ),
83
+ 'nonce' => wp_create_nonce( Toolset_Ajax::CALLBACK_INTERMEDIARY_POST_CLEANUP ),
84
+ 'ajax_arguments' => array( 'current_step' => 1 )
85
+ );
86
+ return $sections;
87
+ }
88
+
89
+
90
+ /**
91
+ * Show an admin notice if there are dangling intermediary posts.
92
+ *
93
+ * @param array $notices
94
+ *
95
+ * @return array
96
+ * @throws Exception
97
+ */
98
+ public function add_notice( $notices ) {
99
+ if( $this->is_cleanup_needed() ) {
100
+ $notices[] = new Toolset_Admin_Notice_Dismissible(
101
+ self::TROUBLESHOOTING_SECTION_SLUG,
102
+ sprintf(
103
+ __( 'There may be some leftover intermediary posts that need to be deleted. You can do it manually on the %s or ignore this message and wait until they\'re deleted automatically.', 'wpcf' ),
104
+ sprintf(
105
+ '<a href="%s">%s</a>',
106
+ esc_attr( add_query_arg( array( 'page' => Toolset_Menu::TROUBLESHOOTING_PAGE_SLUG ), admin_url( 'admin.php' ) ) ),
107
+ __( 'Troubleshooting Page', 'wpcf' )
108
+ )
109
+ )
110
+ );
111
+ }
112
+ return $notices;
113
+ }
114
+
115
+ }
vendor/toolset/toolset-common/inc/m2m/association/factory.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Factory for instantiating IToolset_Association objects.
5
+ *
6
+ * This should not be used from outside
7
+ * of the m2m API. Everything required for working with associations should be
8
+ * implemented on IToolset_Relationship_Definition.
9
+ *
10
+ * @since 2.5.8
11
+ */
12
+ class Toolset_Association_Factory {
13
+
14
+
15
+ /** @var Toolset_Relationship_Definition_Repository */
16
+ private $definition_repository;
17
+
18
+
19
+ /** @var Toolset_Element_Factory|null */
20
+ private $_element_factory;
21
+
22
+
23
+ /** @var null|Toolset_WPML_Compatibility */
24
+ private $_wpml_service;
25
+
26
+
27
+ /**
28
+ * Toolset_Association_Factory constructor.
29
+ *
30
+ * @param Toolset_Relationship_Definition_Repository|null $definition_repository_di
31
+ * @param Toolset_Element_Factory|null $element_factory_di
32
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
33
+ */
34
+ public function __construct(
35
+ Toolset_Relationship_Definition_Repository $definition_repository_di = null,
36
+ Toolset_Element_Factory $element_factory_di = null,
37
+ Toolset_WPML_Compatibility $wpml_service_di = null
38
+ ) {
39
+ $this->definition_repository = ( null === $definition_repository_di ? Toolset_Relationship_Definition_Repository::get_instance() : $definition_repository_di );
40
+ $this->_element_factory = $element_factory_di;
41
+ $this->_wpml_service = $wpml_service_di;
42
+ }
43
+
44
+
45
+ /**
46
+ * @param Toolset_Relationship_Definition $relationship
47
+ * @param int|IToolset_Element $parent_id
48
+ * @param int|IToolset_Element $child_id
49
+ * @param int|IToolset_Post $intermediary_id
50
+ * @param int $association_uid Can be zero for associations that are not stored in the database yet.
51
+ *
52
+ * @return IToolset_Association
53
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
54
+ */
55
+ public function create(
56
+ Toolset_Relationship_Definition $relationship,
57
+ $parent_id, $child_id, $intermediary_id, $association_uid = 0
58
+ ) {
59
+ return new Toolset_Association(
60
+ $association_uid,
61
+ $relationship,
62
+ array(
63
+ Toolset_Relationship_Role::PARENT => $parent_id,
64
+ Toolset_Relationship_Role::CHILD => $child_id
65
+ ),
66
+ $intermediary_id,
67
+ $this->_wpml_service,
68
+ $this->_element_factory
69
+ );
70
+ }
71
+
72
+
73
+ /**
74
+ * @param int $relationship_id
75
+ * @param int $parent_id
76
+ * @param int $child_id
77
+ * @param int $intermediary_id
78
+ * @param int $association_uid Can be zero for associations that are not stored in the database yet.
79
+ *
80
+ * @return IToolset_Association
81
+ * @throws RuntimeException Thrown if an invalid relationship slug is provided.
82
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
83
+ */
84
+ public function create_by_relationship_id(
85
+ $relationship_id,
86
+ $parent_id, $child_id, $intermediary_id, $association_uid = 0
87
+ ) {
88
+ $relationship = $this->definition_repository->get_definition_by_row_id( $relationship_id );
89
+ if( null === $relationship ) {
90
+ throw new RuntimeException( 'Relationship doesn\'t exist.' );
91
+ }
92
+
93
+ return $this->create( $relationship, $parent_id, $child_id, $intermediary_id, $association_uid );
94
+ }
95
+
96
+ }
vendor/toolset/toolset-common/inc/m2m/{i_association.php → association/interface.php} RENAMED
@@ -73,15 +73,30 @@ interface IToolset_Association {
73
  *
74
  * Instantiates an element from its ID if that hasn't been done yet.
75
  *
76
- * @param string $element_role
 
 
 
77
  *
78
- * @return Toolset_Element
79
  * @throws InvalidArgumentException
80
  * @since m2m
81
  */
82
  public function get_element( $element_role );
83
 
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  /**
86
  * Check that the element role is valid.
87
  *
@@ -100,4 +115,23 @@ interface IToolset_Association {
100
  */
101
  public function get_driver();
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  }
73
  *
74
  * Instantiates an element from its ID if that hasn't been done yet.
75
  *
76
+ * @param IToolset_Relationship_Role $element_role
77
+ *
78
+ * @return Toolset_Element|null Null can be returned for the intermediary role, if there is no
79
+ * intermediary post.
80
  *
 
81
  * @throws InvalidArgumentException
82
  * @since m2m
83
  */
84
  public function get_element( $element_role );
85
 
86
 
87
+ /**
88
+ * Get an ID of the association element.
89
+ *
90
+ * Note that if WPML is active and the element is translated, this will return the ID of the
91
+ * translation.
92
+ *
93
+ * @param IToolset_Relationship_Role $element_role
94
+ *
95
+ * @return int
96
+ */
97
+ public function get_element_id( $element_role );
98
+
99
+
100
  /**
101
  * Check that the element role is valid.
102
  *
115
  */
116
  public function get_driver();
117
 
118
+
119
+ /**
120
+ * Get the ID of the intermediary post with association fields.
121
+ *
122
+ * Use with consideration.
123
+ *
124
+ * @return int Post ID or zero if no post exists.
125
+ * @since 2.5.8
126
+ */
127
+ public function get_intermediary_id();
128
+
129
+
130
+ /**
131
+ * Check whether an intermediary post exists for this association.
132
+ *
133
+ * @return bool
134
+ * @since 2.5.10
135
+ */
136
+ public function has_intermediary_post();
137
  }
vendor/toolset/toolset-common/inc/m2m/association/intermediary_post_persistence.php ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Helper class for extra association operations
5
+ *
6
+ * @since m2m
7
+ */
8
+ class Toolset_Association_Intermediary_Post_Persistence {
9
+
10
+
11
+ /**
12
+ * Number of items handled each loop
13
+ */
14
+ const DEFAULT_LIMIT = 50;
15
+
16
+ /**
17
+ * Relationship definition, the associations depend on a relationship, that is why it is neccesary.
18
+ *
19
+ * @var IToolset_Relationship_Definition
20
+ * @since m2m
21
+ */
22
+ private $relationship;
23
+
24
+
25
+ /** @var Toolset_WPML_Compatibility */
26
+ private $wpml_service;
27
+
28
+
29
+ /**
30
+ * Class constructor
31
+ *
32
+ * @param IToolset_Relationship_Definition $relationship Relationship.
33
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
34
+ *
35
+ * @since m2m
36
+ */
37
+ public function __construct(
38
+ IToolset_Relationship_Definition $relationship = null,
39
+ Toolset_WPML_Compatibility $wpml_service_di = null
40
+ ) {
41
+ // todo Consider passing this specifically to methods that need it.
42
+ $this->relationship = $relationship;
43
+ $this->wpml_service = $wpml_service_di ?: Toolset_WPML_Compatibility::get_instance();
44
+ }
45
+
46
+
47
+ /**
48
+ * Create an intermediary post for a new association.
49
+ *
50
+ * @param int $parent_id Association parent id.
51
+ * @param int $child_id Association child id.
52
+ *
53
+ * @return int|null ID of the new post or null if the post creation failed.
54
+ * @since m2m
55
+ */
56
+ public function create_intermediary_post( $parent_id, $child_id ) {
57
+ $post_type = $this->relationship->get_intermediary_post_type();
58
+
59
+ if ( null === $post_type ) {
60
+ return null;
61
+ }
62
+
63
+
64
+ /**
65
+ * toolset_build_intermediary_post_title
66
+ *
67
+ * Allow for overriding the post title of an intermediary post.
68
+ *
69
+ * @param string $post_title Post title default value.
70
+ * @param string $relationship_slug
71
+ * @param int $parent_id
72
+ * @param int $child_id
73
+ *
74
+ * @since m2m
75
+ */
76
+ $post_title = wp_strip_all_tags(
77
+ apply_filters(
78
+ 'toolset_build_intermediary_post_title',
79
+ $this->get_default_intermediary_post_title( $parent_id, $child_id ),
80
+ $this->relationship->get_slug(),
81
+ $parent_id,
82
+ $child_id
83
+ )
84
+ );
85
+
86
+ /**
87
+ * toolset_build_intermediary_post_name
88
+ *
89
+ * Allow for overriding the post name (slug) of an intermediary post.
90
+ *
91
+ * @param string $post_slug Post slug default value.
92
+ * @param string $relationship_slug
93
+ * @param int $parent_id
94
+ * @param int $child_id
95
+ *
96
+ * @since m2m
97
+ */
98
+ $post_name = apply_filters(
99
+ 'toolset_build_intermediary_post_name',
100
+ $post_title,
101
+ $this->relationship->get_slug(),
102
+ $parent_id,
103
+ $child_id
104
+ );
105
+
106
+ // Intermediary posts need to be always created in the default language, even if the IPT
107
+ // is translatable. Otherwise, it will not be possible to persist the association
108
+ // (it requires a default language translation of all involved elements).
109
+ $needs_wpml_lang_switch = (
110
+ $this->wpml_service->is_wpml_active_and_configured()
111
+ && ! $this->wpml_service->is_current_language_default()
112
+ );
113
+
114
+ if( $needs_wpml_lang_switch ) {
115
+ $this->wpml_service->switch_language( $this->wpml_service->get_default_language() );
116
+ }
117
+
118
+ $result = wp_insert_post(
119
+ array(
120
+ 'post_type' => $post_type,
121
+ 'post_title' => $post_title,
122
+ 'post_name' => $post_name,
123
+ 'post_content' => '',
124
+ 'post_status' => 'publish'
125
+ ),
126
+ true
127
+ );
128
+
129
+ if( $needs_wpml_lang_switch ) {
130
+ $this->wpml_service->switch_language_back();
131
+ }
132
+
133
+ if ( $result instanceof WP_Error ) {
134
+ return null;
135
+ }
136
+
137
+ return $result;
138
+ }
139
+
140
+ /**
141
+ * Returns the default name for an association intermediary post.
142
+ *
143
+ * @param int $parent_id Association parent id.
144
+ * @param int $child_id Association child id.
145
+ *
146
+ * @return string
147
+ * @since m2m
148
+ */
149
+ private function get_default_intermediary_post_title( $parent_id, $child_id ) {
150
+ return sprintf(
151
+ '%s: %d - %d',
152
+ $this->relationship->get_display_name(),
153
+ $parent_id,
154
+ $child_id
155
+ );
156
+ }
157
+
158
+
159
+ /**
160
+ * It there are associations belonging to the definition, intermediary post without field values has to be created.
161
+ *
162
+ * @param int $limit The number of associations in a loop.
163
+ * @since 2.3
164
+ */
165
+ public function create_empty_associations_intermediary_posts( $limit = 0 ) {
166
+ if ( (int) $limit <= 0 ) {
167
+ $limit = self::DEFAULT_LIMIT;
168
+ }
169
+
170
+ $association_query = new Toolset_Association_Query_V2();
171
+ $association_query->add( $association_query->relationship( $this->relationship ) );
172
+ $association_query->add( new Toolset_Association_Query_Condition_Empty_Intermediary() );
173
+ $association_query->limit( $limit );
174
+ $associations = $association_query->get_results();
175
+ foreach ( $associations as $association ) {
176
+ if ( ! $association->get_intermediary_id() ) {
177
+ $this->create_empty_association_intermediary_post( $association );
178
+ }
179
+ }
180
+ }
181
+
182
+
183
+
184
+ /**
185
+ * Creates an empty association intermediary post
186
+ *
187
+ * @param IToolset_Association $association Association.
188
+ * @return int Post ID
189
+ * @since m2m
190
+ */
191
+ public function create_empty_association_intermediary_post( $association ) {
192
+ $intermediary_id = (int) $this->create_intermediary_post(
193
+ $association->get_element( new Toolset_Relationship_Role_Parent() )->get_id(),
194
+ $association->get_element( new Toolset_Relationship_Role_Child() )->get_id()
195
+ );
196
+ if ( $intermediary_id ) {
197
+ $database_operations = new Toolset_Relationship_Database_Operations();
198
+ $database_operations->update_association_intermediary_id( $association->get_uid(), $intermediary_id );
199
+ }
200
+ return $intermediary_id;
201
+ }
202
+
203
+
204
+ /**
205
+ * Delete the intermediary post if it exists and it's not disabled by a filter.
206
+ *
207
+ * This also deletes all its translations.
208
+ *
209
+ * @param IToolset_Association $association
210
+ */
211
+ public function maybe_delete_intermediary_post( IToolset_Association $association ) {
212
+ if ( $association->has_intermediary_post() ) {
213
+ $intermediary_id = $association->get_element( new Toolset_Relationship_Role_Intermediary() )
214
+ ->get_default_language_id();
215
+ $this->delete_intermediary_post( $intermediary_id );
216
+ }
217
+ }
218
+
219
+
220
+ /**
221
+ * Delete the intermediary post if it's not disabled by a filter.
222
+ *
223
+ * This also deletes all its translations.
224
+ *
225
+ * @param $post_id
226
+ */
227
+ public function delete_intermediary_post( $post_id ) {
228
+
229
+ /**
230
+ * toolset_deleting_association_intermediary_post
231
+ *
232
+ * Notify about deleting the intermediary post and allow avoiding it.
233
+ *
234
+ * @param bool $delete_post Whether the post should be deleted.
235
+ * @param int $intermediary_id ID of the intermediary post.
236
+ */
237
+ $delete_post = apply_filters(
238
+ 'toolset_deleting_association_intermediary_post',
239
+ true,
240
+ $post_id
241
+ );
242
+
243
+ if ( $delete_post ) {
244
+ add_filter( Toolset_Association_Cleanup_Post::IS_DELETING_FILTER, '__return_true' );
245
+
246
+ // We also need to delete post translations, because WPML doesn't handle that at all.
247
+ // This is out of the scope of the association query, so we'll query for translations
248
+ // individually, per post which we're deleting.
249
+ $this->delete_post_translations( $post_id );
250
+
251
+ wp_delete_post( $post_id );
252
+ remove_filter( Toolset_Association_Cleanup_Post::IS_DELETING_FILTER, '__return_true' );
253
+ }
254
+ }
255
+
256
+
257
+ /**
258
+ * Delete posts which are translations of the provided post.
259
+ *
260
+ * Thanks to the implementation of Toolset_WPML_Compatibility::get_post_translations_directly(), this
261
+ * is safe without WPML as well.
262
+ *
263
+ * @param int $post_id
264
+ */
265
+ private function delete_post_translations( $post_id ) {
266
+ $post_translations = $this->wpml_service->get_post_translations_directly( $post_id );
267
+ foreach( $post_translations as $post_translation_id ) {
268
+ wp_delete_post( $post_translation_id, true );
269
+ }
270
+ }
271
+
272
+
273
+ }
vendor/toolset/toolset-common/inc/m2m/association/persistence.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles the persistence of associations, from IToolset_Association object
5
+ * to a wpdb call and back.
6
+ *
7
+ * Like Toolset_Relationship_Definition_Persistence, this should not be used from outside
8
+ * of the m2m API. Everything required for working with associations should be
9
+ * implemented on IToolset_Relationship_Definition.
10
+ *
11
+ * @since 2.5.8
12
+ */
13
+ class Toolset_Association_Persistence {
14
+
15
+
16
+ /** @var Toolset_Association_Factory */
17
+ private $association_factory;
18
+
19
+
20
+ /** @var Toolset_Relationship_Table_Name */
21
+ private $table_name;
22
+
23
+
24
+ /** @var wpdb */
25
+ private $wpdb;
26
+
27
+
28
+ /** @var Toolset_Association_Translator */
29
+ private $association_translator;
30
+
31
+
32
+ /** @var null|Toolset_Association_Cleanup_Factory */
33
+ protected $_cleanup_factory;
34
+
35
+
36
+
37
+ /**
38
+ * Toolset_Association_Persistence constructor.
39
+ *
40
+ * @param Toolset_Association_Factory|null $association_factory_di
41
+ * @param Toolset_Relationship_Table_Name|null $table_name_di
42
+ * @param wpdb|null $wpdb_di
43
+ * @param Toolset_Association_Translator|null $association_translator_di
44
+ * @param Toolset_Association_Cleanup_Factory|null $cleanup_factory_di
45
+ */
46
+ public function __construct(
47
+ Toolset_Association_Factory $association_factory_di = null,
48
+ Toolset_Relationship_Table_Name $table_name_di = null,
49
+ wpdb $wpdb_di = null,
50
+ Toolset_Association_Translator $association_translator_di = null,
51
+ Toolset_Association_Cleanup_Factory $cleanup_factory_di = null
52
+ ) {
53
+ $this->association_factory = ( null === $association_factory_di ? new Toolset_Association_Factory() : $association_factory_di );
54
+ $this->table_name = ( null === $table_name_di ? new Toolset_Relationship_Table_Name() : $table_name_di );
55
+ $this->association_translator = ( null === $association_translator_di ? new Toolset_Association_Translator() : $association_translator_di );
56
+ global $wpdb;
57
+ $this->wpdb = ( null === $wpdb_di ? $wpdb : $wpdb_di );
58
+ $this->_cleanup_factory = $cleanup_factory_di;
59
+ }
60
+
61
+
62
+ /**
63
+ * Load a native association from the database.
64
+ *
65
+ * @param int $association_uid Association UID.
66
+ *
67
+ * @return null|IToolset_Association The association instance
68
+ * or null if it couln't have been loaded.
69
+ * @deprecated Do not use this outside of the m2m API, instead, use the association query.
70
+ */
71
+ public function load_association_by_uid( $association_uid ) {
72
+ $associations_table = $this->table_name->association_table();
73
+
74
+ $query = $this->wpdb->prepare(
75
+ "SELECT * FROM {$associations_table} WHERE trid = %d",
76
+ $association_uid
77
+ );
78
+
79
+ $row = $this->wpdb->get_row( $query );
80
+
81
+ if ( ! $row ) {
82
+ return null;
83
+ }
84
+
85
+ $relationship = Toolset_Relationship_Definition_Repository::get_instance()
86
+ ->get_definition_by_row_id( $row->relationship_id );
87
+
88
+ if ( null === $relationship ) {
89
+ return null;
90
+ }
91
+
92
+ try {
93
+ return $this->association_factory->create(
94
+ $relationship,
95
+ (int) $row->parent_id,
96
+ (int) $row->child_id,
97
+ (int) $row->intermediary_id,
98
+ (int) $row->id
99
+ );
100
+ } catch( Exception $e ) {
101
+ return null;
102
+ }
103
+ }
104
+
105
+
106
+ /**
107
+ * Insert a new association in the database.
108
+ *
109
+ * @param IToolset_Association $association
110
+ *
111
+ * @return IToolset_Association
112
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
113
+ */
114
+ public function insert_association( IToolset_Association $association ) {
115
+ $row = $this->association_translator->to_database_row( $association );
116
+
117
+ $this->wpdb->insert(
118
+ $this->table_name->association_table(),
119
+ $row,
120
+ $this->association_translator->get_database_row_formats()
121
+ );
122
+
123
+ $row['id'] = $this->wpdb->insert_id;
124
+
125
+ $updated_association = $this->association_translator->from_database_row( (object) $row );
126
+
127
+ return $updated_association;
128
+ }
129
+
130
+
131
+ /**
132
+ * Delete an association from the database.
133
+ *
134
+ * Also delete an intermediary post if it exists.
135
+ *
136
+ * @param IToolset_Association $association
137
+ *
138
+ * @return Toolset_Result
139
+ * @since m2m
140
+ */
141
+ public function delete_association( IToolset_Association $association ) {
142
+ $cleanup = $this->get_cleanup_factory()->association();
143
+ return $cleanup->delete( $association );
144
+ }
145
+
146
+
147
+ /**
148
+ * @return Toolset_Association_Cleanup_Factory
149
+ */
150
+ private function get_cleanup_factory() {
151
+ if( null === $this->_cleanup_factory ) {
152
+ $this->_cleanup_factory = new Toolset_Association_Cleanup_Factory();
153
+ }
154
+
155
+ return $this->_cleanup_factory;
156
+ }
157
+
158
+
159
+
160
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/association_query.php ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A class for querying associations and associated elements.
5
+ *
6
+ * Usage:
7
+ *
8
+ * $query = new Toolset_Association_Query( $args );
9
+ * $results = $query->get_results();
10
+ *
11
+ * Notes:
12
+ *
13
+ * - For now, it supports only the native associations (they're the only ones we have).
14
+ * - If you need to query by some parameters that are not supported, either create a feature request about it or
15
+ * submit a merge request rather than going around the query and touching the database directly.
16
+ *
17
+ * WARNING: This got deprecated and was turned into a complatibility layer for Toolset_Association_Query_V2.
18
+ *
19
+ * @since m2m
20
+ * @deprecated Since 2.5.8. Use Toolset_Association_Query instead.
21
+ */
22
+ class Toolset_Association_Query extends Toolset_Relationship_Query_Base {
23
+
24
+ /** @var string One of the RETURN_* constants determining what kind of output should be provided. */
25
+ private $return;
26
+
27
+ /** @var bool */
28
+ protected $dont_count_found_rows;
29
+
30
+ const OPTION_USE_CACHED_RESULTS = 'use_cached_results';
31
+ const OPTION_CACHE_RESULTS = 'cache_results';
32
+ const OPTION_RETURN = 'return';
33
+ const OPTION_DONT_COUNT_FOUND_ROWS = 'no_found_rows';
34
+ const QUERY_OFFSET = 'offset';
35
+ const QUERY_LIMIT = 'limit';
36
+ const QUERY_SELECT_FIELDS = 'select_fields';
37
+ const QUERY_RELATIONSHIP_SLUG = 'relationship_slug';
38
+ const QUERY_RELATIONSHIP_ID = 'relationship_id';
39
+ const QUERY_PARENT_ID = 'parent_id';
40
+ const QUERY_CHILD_ID = 'child_id';
41
+ const QUERY_PARENT_DOMAIN = 'parent_domain';
42
+ const QUERY_PARENT_QUERY = 'parent_query';
43
+ const QUERY_CHILD_DOMAIN = 'child_domain';
44
+ const QUERY_CHILD_QUERY = 'child_query';
45
+ const QUERY_LANGUAGE = 'language';
46
+ const QUERY_HAS_TRASHED_POSTS = 'has_trashed_posts';
47
+ const RETURN_ASSOCIATION_IDS = 'association_ids';
48
+ const RETURN_ASSOCIATIONS = 'associations';
49
+ const RETURN_PARENT_IDS = 'parent_ids';
50
+ const RETURN_CHILD_IDS = 'child_ids';
51
+ const RETURN_PARENTS = 'parents';
52
+ const RETURN_CHILDREN = 'children';
53
+ const LANGUAGE_ALL = 'all';
54
+ const GROUP_CONCAT_SEPARATOR = ',';
55
+
56
+
57
+ /**
58
+ * Parse query arguments, store them sanitized as options or in the $query_vars array.
59
+ *
60
+ * @param array $query
61
+ */
62
+ protected function parse_query( $query ) {
63
+
64
+ $this->use_cached_results = (bool) toolset_getarr( $query, self::OPTION_USE_CACHED_RESULTS, true );
65
+ $this->cache_results = (bool) toolset_getarr( $query, self::OPTION_CACHE_RESULTS, true );
66
+ $this->return = toolset_getarr( $query, self::OPTION_RETURN, self::RETURN_ASSOCIATIONS, $this->get_return_options() );
67
+ $this->dont_count_found_rows = (bool) toolset_getarr( $query, self::OPTION_DONT_COUNT_FOUND_ROWS, false );
68
+
69
+ // Default value of these needs to be null
70
+ $this->parse_query_arg( $query, self::QUERY_RELATIONSHIP_SLUG, 'strval' );
71
+ $this->parse_query_arg( $query, self::QUERY_RELATIONSHIP_ID, 'absint' );
72
+ $this->parse_query_arg( $query, self::QUERY_PARENT_ID, 'absint' );
73
+ $this->parse_query_arg( $query, self::QUERY_CHILD_ID, 'absint' );
74
+ $this->parse_query_arg( $query, self::QUERY_LIMIT, 'absint' );
75
+ $this->parse_query_arg( $query, self::QUERY_OFFSET, 'absint' );
76
+ $this->parse_query_arg( $query, self::QUERY_SELECT_FIELDS, null, array() );
77
+ $this->parse_query_arg( $query, self::QUERY_PARENT_DOMAIN, null, null, array( Toolset_Field_Utils::DOMAIN_POSTS ) );
78
+ $this->parse_query_arg( $query, self::QUERY_PARENT_QUERY, null );
79
+ $this->parse_query_arg( $query, self::QUERY_CHILD_DOMAIN, null, null, array( Toolset_Field_Utils::DOMAIN_POSTS ) );
80
+ $this->parse_query_arg( $query, self::QUERY_CHILD_QUERY, null );
81
+ $this->parse_query_arg( $query, self::QUERY_HAS_TRASHED_POSTS, 'boolval' );
82
+ }
83
+
84
+
85
+ /**
86
+ * Perform the query and get results.
87
+ *
88
+ * Depending on query arguments, the results may be cached.
89
+ *
90
+ * @return int[]|IToolset_Element[]|IToolset_Association[] Array of results, depending on query arguments.
91
+ */
92
+ public function get_results() {
93
+ $q = new Toolset_Association_Query_V2();
94
+
95
+ if ( $this->has_query_var( self::QUERY_RELATIONSHIP_SLUG ) ) {
96
+ $relationship_slug = $this->get_query_var( self::QUERY_RELATIONSHIP_SLUG );
97
+ $q->add( $q->relationship_slug( $relationship_slug ) );
98
+ }
99
+
100
+ if ( $this->has_query_var( self::QUERY_RELATIONSHIP_ID ) ) {
101
+ $relationship_id = $this->get_query_var( self::QUERY_RELATIONSHIP_ID );
102
+ $q->add( $q->relationship_id( $relationship_id ) );
103
+ }
104
+
105
+ if ( $this->has_query_var( self::QUERY_PARENT_ID ) ) {
106
+ $q->add( $q->parent_id( $this->get_query_var( self::QUERY_PARENT_ID ) ) );
107
+ }
108
+
109
+ if ( $this->has_query_var( self::QUERY_HAS_TRASHED_POSTS ) ) {
110
+ $include_trash = $this->get_query_var( self::QUERY_HAS_TRASHED_POSTS );
111
+ if ( $include_trash ) {
112
+ $q->add(
113
+ $q->do_and(
114
+ $q->element_status( 'any', new Toolset_Relationship_Role_Parent() ),
115
+ $q->element_status( 'any', new Toolset_Relationship_Role_Child() )
116
+ )
117
+ );
118
+ }
119
+ }
120
+
121
+ if ( $this->has_query_var( self::QUERY_CHILD_ID ) ) {
122
+ $q->add( $q->child_id( $this->get_query_var( self::QUERY_CHILD_ID ) ) );
123
+ }
124
+
125
+ if ( $this->has_query_var( self::QUERY_PARENT_DOMAIN ) ) {
126
+ $q->add( $q->has_domain( $this->get_query_var( self::QUERY_PARENT_DOMAIN ), new Toolset_Relationship_Role_Parent() ) );
127
+ }
128
+
129
+ if ( $this->has_query_var( self::QUERY_CHILD_DOMAIN ) ) {
130
+ $q->add( $q->has_domain( $this->get_query_var( self::QUERY_CHILD_DOMAIN ), new Toolset_Relationship_Role_Child() ) );
131
+ }
132
+
133
+ if( $this->has_query_var( self::QUERY_PARENT_QUERY ) ) {
134
+ $q->add( $q->wp_query( new Toolset_Relationship_Role_Parent(), $this->get_query_var( self::QUERY_PARENT_QUERY ), 'i_know_what_i_am_doing' ) );
135
+ }
136
+
137
+ if( $this->has_query_var( self::QUERY_CHILD_QUERY ) ) {
138
+ $q->add( $q->wp_query( new Toolset_Relationship_Role_Child(), $this->get_query_var( self::QUERY_CHILD_QUERY ), 'i_know_what_i_am_doing' ) );
139
+ }
140
+
141
+ if( $this->need_row_count() ) {
142
+ $q->need_found_rows();
143
+ }
144
+
145
+ if ( $this->has_query_var( self::QUERY_LIMIT ) ) {
146
+ $q->limit( $this->get_query_var( self::QUERY_LIMIT ) );
147
+ if ( $this->has_query_var( self::QUERY_OFFSET ) ) {
148
+ $q->offset( $this->get_query_var( self::QUERY_OFFSET ) );
149
+ }
150
+ } else {
151
+ // Toolset_Association_Query worked without a limit set by the user
152
+ // Toolset_Association_Query_V2 requires that the user sets a limit, otherwise FATAL ERROR
153
+ // For backward compatibility we're adding limit 1000 if no specific limit set by the user
154
+ $q->limit( 1000 );
155
+ }
156
+
157
+ switch( $this->return ) {
158
+ case self::RETURN_ASSOCIATION_IDS:
159
+ $q->return_association_uids();
160
+ break;
161
+ case self::RETURN_ASSOCIATIONS:
162
+ $q->return_association_instances();
163
+ break;
164
+ case self::RETURN_PARENT_IDS:
165
+ $q->return_element_ids( new Toolset_Relationship_Role_Parent() );
166
+ break;
167
+ case self::RETURN_CHILD_IDS:
168
+ $q->return_element_ids( new Toolset_Relationship_Role_Child() );
169
+ break;
170
+ case self::RETURN_PARENTS:
171
+ $q->return_element_instances( new Toolset_Relationship_Role_Parent() );
172
+ break;
173
+ case self::RETURN_CHILDREN:
174
+ $q->return_element_instances( new Toolset_Relationship_Role_Child() );
175
+ break;
176
+ }
177
+
178
+ return $q->get_results();
179
+ }
180
+
181
+
182
+
183
+ protected function get_subject_name_for_cache() {
184
+ return 'associations';
185
+ }
186
+
187
+
188
+ /**
189
+ * Build the MySQL statement for querying the data, depending on query variables.
190
+ *
191
+ * @return string MySQL query statement.
192
+ * @since m2m
193
+ */
194
+ protected function build_sql_statement() {
195
+ return '';
196
+ }
197
+
198
+
199
+ /**
200
+ * @inheritdoc
201
+ * @return string
202
+ */
203
+ protected function get_results_type() {
204
+ return ARRAY_A;
205
+ }
206
+
207
+
208
+ /**
209
+ * @return string[] Possible values for the 'return' query argument.
210
+ */
211
+ private function get_return_options() {
212
+ return array(
213
+ self::RETURN_ASSOCIATIONS,
214
+ self::RETURN_ASSOCIATION_IDS,
215
+ self::RETURN_CHILD_IDS,
216
+ self::RETURN_CHILDREN,
217
+ self::RETURN_PARENT_IDS,
218
+ self::RETURN_PARENTS
219
+ );
220
+ }
221
+
222
+
223
+ /**
224
+ * Determine if SQL_CALC_FOUND_ROWS should be part of the MySQL statement.
225
+ *
226
+ * @return bool
227
+ */
228
+ private function need_row_count() {
229
+ return ( ! $this->dont_count_found_rows && $this->has_query_var( self::QUERY_LIMIT ) );
230
+ }
231
+
232
+
233
+ /**
234
+ * Process raw output from $wpdb.
235
+ *
236
+ * @param array $rows
237
+ *
238
+ * @return array
239
+ */
240
+ protected function postprocess_results( $rows ) {
241
+ return array();
242
+ }
243
+
244
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/association_query_v2.php ADDED
@@ -0,0 +1,994 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Association query class with a more OOP/functional approach.
5
+ *
6
+ * Replaces Toolset_Association_Query.
7
+ *
8
+ * Allows for chaining query conditions and avoiding passing query arguments as associative arrays.
9
+ * It makes it also possible to build queries with nested AND & OR statements in an arbitrary way.
10
+ * The object model may be complex but all the complexity is hidden from the user, they need to know
11
+ * only the methods on this class.
12
+ *
13
+ * Example usage:
14
+ *
15
+ * $query = new Toolset_Association_Query_V2();
16
+ *
17
+ * $results = $query
18
+ * ->add(
19
+ * $query->has_domain( 'posts', new Toolset_Relationship_Role_Parent() )
20
+ * )
21
+ * ->add(
22
+ * $query->do_or(
23
+ * $query->has_type( 'attachment', new Toolset_Relationship_Role_Parent() ),
24
+ * $query->do_and(
25
+ * $query->has_type( 'page', new Toolset_Relationship_Role_Child() ),
26
+ * $query->has_type( 'post', new Toolset_Relationship_Role_Child() ),
27
+ * )
28
+ * )
29
+ * )
30
+ * ->add(
31
+ * $query->search( 'some string', new Toolset_Relationship_Role_Parent() )
32
+ * )
33
+ * ->order_by_field_value( $custom_field_definition )
34
+ * ->order( 'DESC' )
35
+ * ->limit( 50 )
36
+ * ->offset( 100 )
37
+ * ->return_association_instances()
38
+ * ->get_results();
39
+ *
40
+ * Note about default conditions:
41
+ * - If no element status (element_status() or has_available_elements()) condition is used when constructing the query,
42
+ * has_available_elements() is used.
43
+ * - If no has_active_relationship() condition is used when constructing the query, has_active_relationship(true)
44
+ * is used.
45
+ * - This mechanism doesn't recognize where, how and if these conditions are actually applied, so even
46
+ * $query->do_if( false, $query->has_active_relationship( true ) ) will disable the default
47
+ * has_active_relationship() condition.
48
+ * - You can prevent the adding of default conditions by $query->do_not_add_default_conditions().
49
+ *
50
+ * @since 2.5.8
51
+ */
52
+ class Toolset_Association_Query_V2 extends Toolset_Wpdb_User implements IToolset_Query {
53
+
54
+
55
+ /** @var IToolset_Association_Query_Condition[] */
56
+ private $conditions = array();
57
+
58
+ /** @var Toolset_Relationship_Database_Unique_Table_Alias */
59
+ private $unique_table_alias;
60
+
61
+ /** @var Toolset_Association_Query_Condition_Factory */
62
+ private $condition_factory;
63
+
64
+ /** @var Toolset_Association_Query_Sql_Expression_Builder */
65
+ private $expression_builder;
66
+
67
+ /** @var bool */
68
+ private $should_add_default_conditions = true;
69
+
70
+ /** @var bool */
71
+ private $has_active_relationship_condition = false;
72
+
73
+ /** @var bool */
74
+ private $has_element_status_condition = false;
75
+
76
+ /** @var Toolset_Association_Translator */
77
+ private $association_translator;
78
+
79
+ /** @var Toolset_Relationship_Definition_Repository|null */
80
+ private $_definition_repository;
81
+
82
+ /** @var Toolset_Association_Query_Table_Join_Manager */
83
+ private $join_manager;
84
+
85
+ /** @var IToolset_Association_Query_Result_Transformation */
86
+ private $result_transformation;
87
+
88
+ /** @var int|null */
89
+ private $limit = null;
90
+
91
+ /** @var int */
92
+ private $offset = 0;
93
+
94
+ /** @var IToolset_Association_Query_Orderby|null */
95
+ private $orderby = null;
96
+
97
+ /** @var string */
98
+ private $order = 'ASC';
99
+
100
+ /** @var bool */
101
+ private $need_found_rows = false;
102
+
103
+ /** @var int|null */
104
+ private $found_rows;
105
+
106
+ /** @var Toolset_Association_Query_Orderby_Factory */
107
+ private $orderby_factory;
108
+
109
+ /** @var bool Remember whether get_results() was called. */
110
+ private $was_used = false;
111
+
112
+ /** @var Toolset_Association_Query_Element_Selector_Provider */
113
+ private $element_selector_provider;
114
+
115
+ /** @var IToolset_Association_Query_Restriction[] */
116
+ private $restrictions = array();
117
+
118
+
119
+ /**
120
+ * Toolset_Association_Query_V2 constructor.
121
+ *
122
+ * @param wpdb|null $wpdb_di
123
+ * @param Toolset_Relationship_Database_Unique_Table_Alias|null $unique_table_alias_di
124
+ * @param Toolset_Association_Query_Sql_Expression_Builder|null $expression_builder_di
125
+ * @param Toolset_Association_Query_Condition_Factory|null $condition_factory_di
126
+ * @param Toolset_Association_Translator|null $association_translator_di
127
+ * @param Toolset_Relationship_Definition_Repository|null $definition_repository_di
128
+ * @param Toolset_Association_Query_Table_Join_Manager|null $join_manager_di
129
+ * @param Toolset_Association_Query_Orderby_Factory|null $orderby_factory_di
130
+ * @param Toolset_Association_Query_Element_Selector_Provider|null $element_selector_provider_di
131
+ */
132
+ public function __construct(
133
+ wpdb $wpdb_di = null,
134
+ Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias_di = null,
135
+ Toolset_Association_Query_Sql_Expression_Builder $expression_builder_di = null,
136
+ Toolset_Association_Query_Condition_Factory $condition_factory_di = null,
137
+ Toolset_Association_Translator $association_translator_di = null,
138
+ Toolset_Relationship_Definition_Repository $definition_repository_di = null,
139
+ Toolset_Association_Query_Table_Join_Manager $join_manager_di = null,
140
+ Toolset_Association_Query_Orderby_Factory $orderby_factory_di = null,
141
+ Toolset_Association_Query_Element_Selector_Provider $element_selector_provider_di = null
142
+ ) {
143
+ parent::__construct( $wpdb_di );
144
+ $this->unique_table_alias = $unique_table_alias_di ?: new Toolset_Relationship_Database_Unique_Table_Alias();
145
+ $this->condition_factory = $condition_factory_di ?: new Toolset_Association_Query_Condition_Factory();
146
+ $this->association_translator = $association_translator_di ?: new Toolset_Association_Translator();
147
+ $this->join_manager = $join_manager_di ?: new Toolset_Association_Query_Table_Join_Manager( $this->unique_table_alias );
148
+ $this->expression_builder = $expression_builder_di ?: new Toolset_Association_Query_Sql_Expression_Builder( $this->join_manager );
149
+ $this->orderby_factory = $orderby_factory_di ?: new Toolset_Association_Query_Orderby_Factory();
150
+ $this->element_selector_provider = $element_selector_provider_di ?: new Toolset_Association_Query_Element_Selector_Provider();
151
+ $this->_definition_repository = $definition_repository_di;
152
+ }
153
+
154
+
155
+
156
+ /**
157
+ * Add another condition to the query.
158
+ *
159
+ * @param IToolset_Association_Query_Condition $condition
160
+ * @return $this
161
+ */
162
+ public function add( IToolset_Association_Query_Condition $condition ) {
163
+ $this->conditions[] = $condition;
164
+ return $this;
165
+ }
166
+
167
+
168
+ /**
169
+ * Allow for adding query restrictions to reduce its complexity
170
+ * right after all conditions have been added.
171
+ *
172
+ * @param IToolset_Association_Query_Condition $root_condition
173
+ */
174
+ private function maybe_add_restrictions( IToolset_Association_Query_Condition $root_condition ) {
175
+ // Nothing to do yet.
176
+ }
177
+
178
+
179
+ /**
180
+ * Basically, this sets default query parameters.
181
+ *
182
+ * The method needs to stay idempotent.
183
+ */
184
+ private function add_default_conditions() {
185
+ if ( ! $this->should_add_default_conditions ) {
186
+ return;
187
+ }
188
+
189
+ if( ! $this->has_element_status_condition ) {
190
+ $this->add( $this->has_available_elements() );
191
+ }
192
+
193
+ if( ! $this->has_active_relationship_condition ) {
194
+ $this->add( $this->has_active_relationship() );
195
+ }
196
+ }
197
+
198
+
199
+ /**
200
+ * Prevent the query from adding any default conditions. WYSIWYG.
201
+ *
202
+ * @return $this
203
+ */
204
+ public function do_not_add_default_conditions() {
205
+ $this->should_add_default_conditions = false;
206
+ return $this;
207
+ }
208
+
209
+
210
+ /**
211
+ * @return IToolset_Association_Query_Condition MySQL WHERE clause for the query.
212
+ */
213
+ private function build_root_condition() {
214
+ $this->add_default_conditions();
215
+ return $this->condition_factory->do_and( $this->conditions );
216
+ }
217
+
218
+
219
+ /**
220
+ * Build a complete MySQL query from the conditions.
221
+ *
222
+ * @return string
223
+ * @throws RuntimeException If no query limit is set.
224
+ */
225
+ private function build_sql_query() {
226
+ $root_condition = $this->build_root_condition();
227
+ $this->maybe_add_restrictions( $root_condition );
228
+
229
+ if( null === $this->orderby ) {
230
+ $this->dont_order();
231
+ }
232
+
233
+ $this->orderby->set_order( $this->order );
234
+
235
+ if( null === $this->limit ) {
236
+ throw new RuntimeException(
237
+ 'The query limit has not been set. This is necessary to ensure the scalability.'
238
+ );
239
+ }
240
+
241
+ return $this->expression_builder->build(
242
+ $root_condition,
243
+ $this->offset,
244
+ $this->limit,
245
+ $this->orderby,
246
+ $this->element_selector_provider->get_selector(),
247
+ $this->need_found_rows,
248
+ $this->result_transformation
249
+ );
250
+ }
251
+
252
+
253
+
254
+ /**
255
+ * Apply stored conditions and perform the query.
256
+ *
257
+ * @return IToolset_Association[]|int[]|IToolset_Element[]
258
+ */
259
+ public function get_results() {
260
+
261
+ if( $this->was_used ) {
262
+ _doing_it_wrong(
263
+ __FUNCTION__,
264
+ 'The association query object should not be reused. Create a new instance if you need to run another query.',
265
+ TOOLSET_COMMON_VERSION
266
+ );
267
+ }
268
+
269
+ $this->was_used = true;
270
+
271
+ // Default value if no result transformation was selected.
272
+ if( null === $this->result_transformation ) {
273
+ $this->return_association_instances();
274
+ }
275
+
276
+ $this->apply_restrictions();
277
+
278
+ // We do this only after restrictions have been applied.
279
+ $this->element_selector_provider->create_selector(
280
+ $this->unique_table_alias, $this->join_manager, $this
281
+ );
282
+
283
+ $query = $this->build_sql_query();
284
+ $rows = toolset_ensarr( $this->wpdb->get_results( $query ) );
285
+
286
+ if( $this->need_found_rows ) {
287
+ $this->found_rows = (int) $this->wpdb->get_var( 'SELECT FOUND_ROWS()' );
288
+ }
289
+
290
+ $results = array();
291
+ foreach( $rows as $row ) {
292
+ $result = $this->result_transformation->transform( $row, $this->element_selector_provider->get_selector() );
293
+
294
+ if ( null !== $result ) {
295
+ $results[] = $result;
296
+ }
297
+ }
298
+
299
+ $this->clear_restrictions();
300
+
301
+ return $results;
302
+ }
303
+
304
+
305
+
306
+ /**
307
+ * Chain multiple conditions with OR.
308
+ *
309
+ * The whole statement will evaluate to true if at least one of provided conditions is true.
310
+ *
311
+ * @param IToolset_Association_Query_Condition[] [$condition1, $condition2, ...]
312
+ * @return IToolset_Association_Query_Condition
313
+ */
314
+ public function do_or() {
315
+ return $this->condition_factory->do_or( func_get_args() );
316
+ }
317
+
318
+
319
+ /**
320
+ * Chain multiple conditions with AND.
321
+ *
322
+ * The whole statement will evaluate to true if all provided conditions are true.
323
+ *
324
+ * @param IToolset_Association_Query_Condition[] [$condition1, $condition2, ...]
325
+ * @return IToolset_Association_Query_Condition
326
+ */
327
+ public function do_and() {
328
+ return $this->condition_factory->do_and( func_get_args() );
329
+ }
330
+
331
+
332
+ /**
333
+ * Choose a query condition depending on a boolean expression.
334
+ *
335
+ * @param bool $statement A boolean condition statement.
336
+ * @param IToolset_Association_Query_Condition $if_branch Query condition that will be used
337
+ * if the statement is true.
338
+ * @param IToolset_Association_Query_Condition|null $else_branch Query condition that will be
339
+ * used if the statement is false. If none is provided, a tautology is used (always true).
340
+ *
341
+ * @return IToolset_Association_Query_Condition
342
+ * @since 2.5.6
343
+ */
344
+ public function do_if(
345
+ $statement,
346
+ IToolset_Association_Query_Condition $if_branch,
347
+ IToolset_Association_Query_Condition $else_branch = null
348
+ ) {
349
+ if( $statement ) {
350
+ return $if_branch;
351
+ } elseif( null !== $else_branch ) {
352
+ return $else_branch;
353
+ } else {
354
+ return $this->condition_factory->tautology();
355
+ }
356
+ }
357
+
358
+
359
+ /**
360
+ * Query by a row ID of a relationship definition.
361
+ *
362
+ * @param int $relationship_id
363
+ * @return IToolset_Association_Query_Condition
364
+ */
365
+ public function relationship_id( $relationship_id ) {
366
+ return $this->condition_factory->relationship_id( $relationship_id );
367
+ }
368
+
369
+
370
+ /**
371
+ * Query by a relationship definition.
372
+ *
373
+ * @param IToolset_Relationship_Definition $relationship_definition
374
+ * @return IToolset_Association_Query_Condition
375
+ */
376
+ public function relationship( IToolset_Relationship_Definition $relationship_definition ) {
377
+ return $this->relationship_id( $relationship_definition->get_row_id() );
378
+ }
379
+
380
+
381
+ /**
382
+ * Query by a relationship definition slug.
383
+ *
384
+ * @param string $slug
385
+ * @return IToolset_Association_Query_Condition
386
+ */
387
+ public function relationship_slug( $slug ) {
388
+ $definition = $this->get_definition_repository()->get_definition( $slug );
389
+ if( null === $definition ) {
390
+ return $this->condition_factory->contradiction();
391
+ }
392
+
393
+ return $this->relationship( $definition );
394
+ }
395
+
396
+
397
+ /**
398
+ * @return Toolset_Relationship_Definition_Repository
399
+ */
400
+ private function get_definition_repository() {
401
+ if( null === $this->_definition_repository ) {
402
+ $this->_definition_repository = Toolset_Relationship_Definition_Repository::get_instance();
403
+ }
404
+
405
+ return $this->_definition_repository;
406
+ }
407
+
408
+
409
+ /**
410
+ * Query by an ID of an element in the selected role.
411
+ *
412
+ * Warning: This is an WPML-unaware query.
413
+ *
414
+ * @param int $element_id
415
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
416
+ * @param bool $need_wpml_unaware_query Set this to true to avoid a _doing_it_wrong notice.
417
+ *
418
+ * @return IToolset_Association_Query_Condition
419
+ */
420
+ public function element_id(
421
+ $element_id, IToolset_Relationship_Role_Parent_Child $for_role, $need_wpml_unaware_query = true
422
+ ) {
423
+ if( ! $need_wpml_unaware_query ) {
424
+ // This is to ensure a smooth transition from using element_id() everywhere to doing it only
425
+ // in cases where it's explicitly needed. We can remove this after the final release.
426
+ trigger_error(
427
+ 'You are using the element_id() condition in the association query. '
428
+ . 'However, this condition is WPML-unaware. Consider using element_id_and_domain() instead '
429
+ .'or, if you really need to ignore element translations, set the new $need_wpml_unaware_query to true.',
430
+ E_NOTICE
431
+ );
432
+ }
433
+ return $this->condition_factory->element_id( $element_id, $for_role, $this->element_selector_provider );
434
+ }
435
+
436
+
437
+ /**
438
+ * Query by an ID of an element in the selected role.
439
+ *
440
+ * @param int $element_id
441
+ * @param string $domain
442
+ * @param IToolset_Relationship_Role $for_role
443
+ * @param bool $query_original_element If true, the query will check the element ID in the original language
444
+ * as stored in the association table. Default is false.
445
+ * @param bool $translate_provided_id If true, this will try to translate the element ID (if
446
+ * applicable on the domain) and use the translated one in the final condition. Default is true.
447
+ *
448
+ * @return Toolset_Association_Query_Condition_Element_Id_And_Domain
449
+ * @since 2.5.10
450
+ */
451
+ public function element_id_and_domain(
452
+ $element_id,
453
+ $domain,
454
+ IToolset_Relationship_Role $for_role,
455
+ $query_original_element = false,
456
+ $translate_provided_id = true
457
+ ) {
458
+ return $this->condition_factory->element_id_and_domain(
459
+ $element_id,
460
+ $domain,
461
+ $for_role,
462
+ $this->element_selector_provider,
463
+ $query_original_element,
464
+ $translate_provided_id
465
+ );
466
+ }
467
+
468
+
469
+ /**
470
+ * Query by an element in the selected role.
471
+ *
472
+ * @param IToolset_Element $element
473
+ * @param IToolset_Relationship_Role|null $for_role If null is provided, the query will involve all roles.
474
+ * @param bool $query_original_element If true, the query will check the element ID in the original language
475
+ * as stored in the association table. Default is false.
476
+ * @param bool $translate_provided_id If true, this will try to translate the element ID (if
477
+ * applicable on the domain) and use the translated one in the final condition. Default is true.
478
+ *
479
+ * @return IToolset_Association_Query_Condition
480
+ */
481
+ public function element(
482
+ IToolset_Element $element,
483
+ IToolset_Relationship_Role $for_role = null,
484
+ $query_original_element = false,
485
+ $translate_provided_id = true
486
+ ) {
487
+
488
+ if( null === $for_role ) {
489
+ $conditions = array();
490
+ foreach( Toolset_Relationship_Role::all() as $role ) {
491
+ $conditions[] = $this->element(
492
+ $element, $role, $query_original_element, $translate_provided_id
493
+ );
494
+ }
495
+ return $this->do_or( $conditions );
496
+ }
497
+
498
+ return $this->element_id_and_domain(
499
+ $element->get_id(), $element->get_domain(), $for_role,
500
+ $query_original_element, $translate_provided_id
501
+ );
502
+ }
503
+
504
+
505
+ /**
506
+ * Exclude associations with a particular element in the selected role.
507
+ *
508
+ * @param IToolset_Element $element
509
+ * @param IToolset_Relationship_Role $for_role
510
+ * @param bool $query_original_element If true, the query will check the element ID in the original language
511
+ * as stored in the association table. Default is false.
512
+ * @param bool $translate_provided_id If true, this will try to translate the element ID (if
513
+ * applicable on the domain) and use the translated one in the final condition. Default is true.
514
+ *
515
+ * @return IToolset_Association_Query_Condition
516
+ */
517
+ public function exclude_element(
518
+ IToolset_Element $element,
519
+ IToolset_Relationship_Role $for_role,
520
+ $query_original_element = false,
521
+ $translate_provided_id = true
522
+ ) {
523
+ return $this->condition_factory->exclude_element(
524
+ $element->get_id(), $element->get_domain(), $for_role,
525
+ $this->element_selector_provider,
526
+ $query_original_element, $translate_provided_id
527
+ );
528
+ }
529
+
530
+
531
+ /**
532
+ * Query by a parent element.
533
+ *
534
+ * @param IToolset_Element $element_source
535
+ * @return IToolset_Association_Query_Condition
536
+ */
537
+ public function parent( IToolset_Element $element_source ) {
538
+ return $this->element( $element_source, new Toolset_Relationship_Role_Parent() );
539
+ }
540
+
541
+
542
+ /**
543
+ * Query by a parent element ID.
544
+ *
545
+ * @param int $parent_id
546
+ * @param string $domain
547
+ *
548
+ * @return IToolset_Association_Query_Condition
549
+ */
550
+ public function parent_id( $parent_id, $domain = Toolset_Element_Domain::POSTS ) {
551
+ return $this->element_id_and_domain( $parent_id, $domain, new Toolset_Relationship_Role_Parent() );
552
+ }
553
+
554
+
555
+ /**
556
+ * Query by a child element.
557
+ *
558
+ * @param IToolset_Element $element
559
+ * @return IToolset_Association_Query_Condition
560
+ */
561
+ public function child( IToolset_Element $element ) {
562
+ return $this->element( $element, new Toolset_Relationship_Role_Child() );
563
+ }
564
+
565
+
566
+ /**
567
+ * Query by a child element ID.
568
+ *
569
+ * @param int $child_id
570
+ * @param string $domain
571
+ *
572
+ * @return IToolset_Association_Query_Condition
573
+ */
574
+ public function child_id( $child_id, $domain = Toolset_Element_Domain::POSTS ) {
575
+ return $this->element_id_and_domain( $child_id, $domain, new Toolset_Relationship_Role_Child() );
576
+ }
577
+
578
+
579
+ /**
580
+ * Query by an element status.
581
+ *
582
+ * @param string $status 'any'|'is_available'|'is_public'. Meaning of these options
583
+ * is domain-dependant.
584
+ * @param IToolset_Relationship_Role $for_role
585
+ *
586
+ * @return IToolset_Association_Query_Condition
587
+ */
588
+ public function element_status( $status, IToolset_Relationship_Role $for_role ) {
589
+ $this->has_element_status_condition = true;
590
+
591
+ return $this->condition_factory->element_status(
592
+ $status, $for_role, $this->join_manager, $this->element_selector_provider
593
+ );
594
+ }
595
+
596
+
597
+ /**
598
+ * Query only associations that have both elements available (see element_status()).
599
+ *
600
+ * @return IToolset_Association_Query_Condition
601
+ */
602
+ public function has_available_elements() {
603
+ $conditions = array();
604
+
605
+ foreach( Toolset_Relationship_Role::parent_child() as $role ) {
606
+ $conditions[] = $this->element_status(
607
+ Toolset_Association_Query_Condition_Element_Status::STATUS_AVAILABLE,
608
+ $role
609
+ );
610
+ }
611
+
612
+ return $this->do_and( $conditions );
613
+ }
614
+
615
+
616
+ /**
617
+ * Query associations by the activity status of the relationship.
618
+ *
619
+ * @param bool $is_active
620
+ *
621
+ * @return IToolset_Association_Query_Condition
622
+ */
623
+ public function has_active_relationship( $is_active = true ) {
624
+ $this->has_active_relationship_condition = true;
625
+ return $this->condition_factory->has_active_relationship( $is_active, $this->join_manager );
626
+ }
627
+
628
+
629
+ /**
630
+ * Query associations by the fact whether the relationship was migrated from the legacy implementation.
631
+ *
632
+ * @param bool $needs_legacy_support
633
+ *
634
+ * @return IToolset_Association_Query_Condition
635
+ */
636
+ public function has_legacy_relationship( $needs_legacy_support = true ) {
637
+ return $this->condition_factory->has_legacy_relationship( $needs_legacy_support, $this->join_manager );
638
+ }
639
+
640
+
641
+ /**
642
+ * Query associations by the element domain on a specified role.
643
+ *
644
+ * @param string $domain
645
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
646
+ *
647
+ * @return IToolset_Association_Query_Condition
648
+ */
649
+ public function has_domain( $domain, IToolset_Relationship_Role_Parent_Child $for_role ) {
650
+ return $this->condition_factory->has_domain( $domain, $for_role, $this->join_manager );
651
+ }
652
+
653
+
654
+ /**
655
+ * Query associations based on element type.
656
+ *
657
+ * Warning: This doesn't query for the domain. Make sure you at least add
658
+ * a separate element domain condition. Otherwise, the results will be unpredictable.
659
+ *
660
+ * The best way is to use the has_domain_and_type() condition instead, which whill allow
661
+ * for some more advanced optimizations.
662
+ *
663
+ * @param string $type Element type.
664
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
665
+ *
666
+ * @return IToolset_Association_Query_Condition
667
+ */
668
+ public function has_type( $type, IToolset_Relationship_Role_Parent_Child $for_role ) {
669
+ return $this->condition_factory->has_type( $type, $for_role, $this->join_manager, $this->unique_table_alias );
670
+ }
671
+
672
+
673
+ /**
674
+ * Query associations based on element domain and type.
675
+ *
676
+ * @param string $domain Element domain.
677
+ * @param string $type Element type
678
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
679
+ *
680
+ * @return IToolset_Association_Query_Condition
681
+ */
682
+ public function has_domain_and_type( $domain, $type, IToolset_Relationship_Role_Parent_Child $for_role ) {
683
+ return $this->condition_factory->has_domain_and_type(
684
+ $domain, $type, $for_role, $this->join_manager, $this->unique_table_alias
685
+ );
686
+ }
687
+
688
+
689
+ /**
690
+ * Query by a WP_Query arguments applied on an element of a specified role.
691
+ *
692
+ * WARNING: It is important that you read the documentation of Toolset_Association_Query_Condition_Wp_Query
693
+ * before using this.
694
+ *
695
+ * @param IToolset_Relationship_Role $for_role
696
+ * @param array $query_args
697
+ * @param string|null $confirmation 'i_know_what_i_am_doing'
698
+ *
699
+ * @return IToolset_Association_Query_Condition
700
+ *
701
+ * @throws InvalidArgumentException Thrown if you don't know what you are doing.
702
+ */
703
+ public function wp_query( IToolset_Relationship_Role $for_role, $query_args, $confirmation = null ) {
704
+ if( 'i_know_what_i_am_doing' !== $confirmation ) {
705
+ throw new InvalidArgumentException();
706
+ }
707
+ return $this->condition_factory->wp_query( $for_role, $query_args, $this->join_manager, $this->unique_table_alias );
708
+ }
709
+
710
+
711
+ /**
712
+ * Query by a string search in elements of a selected role.
713
+ *
714
+ * Note that the behaviour may be different per domain.
715
+ *
716
+ * @param string $search_string
717
+ * @param IToolset_Relationship_Role $for_role
718
+ * @param bool $is_exact
719
+ *
720
+ * @return IToolset_Association_Query_Condition
721
+ */
722
+ public function search( $search_string, IToolset_Relationship_Role $for_role, $is_exact = false ) {
723
+ return $this->condition_factory->search( $search_string, $is_exact, $for_role, $this->join_manager );
724
+ }
725
+
726
+
727
+ /**
728
+ * Query by a specific association ID.
729
+ *
730
+ * This will also set the limit of the result count to one.
731
+ *
732
+ * @param int $association_id
733
+ *
734
+ * @return IToolset_Association_Query_Condition
735
+ */
736
+ public function association_id( $association_id ) {
737
+ $this->limit( 1 );
738
+ return $this->condition_factory->association_id( $association_id );
739
+ }
740
+
741
+
742
+ public function meta( $meta_key, $meta_value, $domain, IToolset_Relationship_Role $for_role = null, $comparison = Toolset_Query_Comparison_Operator::EQUALS ) {
743
+ if( Toolset_Element_Domain::POSTS !== $domain ) {
744
+ throw new RuntimeException( 'The meta query condition is supported only for the posts domain at the moment.' );
745
+ }
746
+
747
+ if( null === $for_role ) {
748
+ $queries_per_role = array();
749
+ foreach( Toolset_Relationship_Role::all() as $role ) {
750
+ $queries_per_role[] = $this->meta( $meta_key, $meta_value, $domain, $role, $comparison );
751
+ }
752
+ return $this->condition_factory->do_and( $queries_per_role );
753
+ }
754
+
755
+ return $this->condition_factory->postmeta( $meta_key, $meta_value, $comparison, $for_role, $this->join_manager );
756
+ }
757
+
758
+
759
+ /**
760
+ * Indicate that get_results() should return instances of IToolset_Association.
761
+ *
762
+ * @return $this
763
+ */
764
+ public function return_association_instances() {
765
+ $this->result_transformation = new Toolset_Association_Query_Result_Transformation_Association_Instance();
766
+ return $this;
767
+ }
768
+
769
+
770
+ /**
771
+ * Indicate that get_results() should return UIDs of associations.
772
+ *
773
+ * @return $this
774
+ */
775
+ public function return_association_uids() {
776
+ $this->result_transformation = new Toolset_Association_Query_Result_Transformation_Association_Uid();
777
+ return $this;
778
+ }
779
+
780
+
781
+ /**
782
+ * Indicate that get_results() should return element IDs from a selected role.
783
+ *
784
+ * @param IToolset_Relationship_Role $role
785
+ * @return $this
786
+ */
787
+ public function return_element_ids( IToolset_Relationship_Role $role ) {
788
+ $this->result_transformation = new Toolset_Association_Query_Result_Transformation_Element_Id( $role );
789
+ return $this;
790
+ }
791
+
792
+
793
+ /**
794
+ * Indicate that get_results() should return IToolset_Element instances from a selected role.
795
+ *
796
+ * @param IToolset_Relationship_Role $role
797
+ * @return $this
798
+ */
799
+ public function return_element_instances( IToolset_Relationship_Role $role ) {
800
+ $this->result_transformation = new Toolset_Association_Query_Result_Transformation_Element_Instance( $role );
801
+ return $this;
802
+ }
803
+
804
+
805
+ /**
806
+ * Set an offset for the query.
807
+ *
808
+ * @param int $value
809
+ *
810
+ * @return $this
811
+ * @throws InvalidArgumentException Thrown if an invalid value is provided.
812
+ */
813
+ public function offset( $value ) {
814
+ if( ! Toolset_Utils::is_nonnegative_numeric( $value ) ) {
815
+ throw new InvalidArgumentException( 'Invalid offset value.' );
816
+ }
817
+ $this->offset = (int) $value;
818
+ return $this;
819
+ }
820
+
821
+
822
+ /**
823
+ * Limit a number of results for the query.
824
+ *
825
+ * Note that by default, the limit is set at a certain value, and the query can never be unlimited.
826
+ *
827
+ * @param int $value
828
+ * @return $this
829
+ * @throws InvalidArgumentException Thrown if an invalid value is provided.
830
+ */
831
+ public function limit( $value ) {
832
+ if( ! Toolset_Utils::is_natural_numeric( $value ) ) {
833
+ throw new InvalidArgumentException( 'Invalid limit value.' );
834
+ }
835
+ $this->limit = (int) $value;
836
+ return $this;
837
+ }
838
+
839
+
840
+ /**
841
+ * Set the sorting order.
842
+ *
843
+ * @param string $value 'ASC'|'DESC'
844
+ * @return $this
845
+ */
846
+ public function order( $value ) {
847
+ $this->order = $value;
848
+ return $this;
849
+ }
850
+
851
+
852
+ /**
853
+ * Indicate whether the query should also retrieve the total number of results.
854
+ *
855
+ * This is required for get_found_rows() to work.
856
+ *
857
+ * @param bool $is_needed
858
+ * @return $this
859
+ */
860
+ public function need_found_rows( $is_needed = true ) {
861
+ $this->need_found_rows = (bool) $is_needed;
862
+ return $this;
863
+ }
864
+
865
+
866
+ /**
867
+ * Return the total number of found results after get_results() was called.
868
+ *
869
+ * For this to work, need_found_rows() needs to be called when building the query.
870
+ *
871
+ * @return int
872
+ * @throws RuntimeException
873
+ */
874
+ public function get_found_rows() {
875
+ if( null === $this->found_rows ) {
876
+ throw new RuntimeException(
877
+ 'Cannot return the number of found rows because the query was not instructed to obtain them.'
878
+ );
879
+ }
880
+
881
+ return $this->found_rows;
882
+ }
883
+
884
+
885
+ /**
886
+ * Indicate that no result ordering is needed.
887
+ *
888
+ * @return $this
889
+ */
890
+ public function dont_order() {
891
+ $this->orderby = $this->orderby_factory->nothing();
892
+ return $this;
893
+ }
894
+
895
+
896
+ /**
897
+ * Order results by a title of element of given role.
898
+ *
899
+ * Note that ordering by intermediary posts will cause the associations without those to be excluded from results.
900
+ *
901
+ * @param IToolset_Relationship_Role $for_role
902
+ * @return $this
903
+ */
904
+ public function order_by_title( IToolset_Relationship_Role $for_role ) {
905
+ $this->orderby = $this->orderby_factory->title( $for_role, $this->join_manager );
906
+ return $this;
907
+ }
908
+
909
+
910
+ /**
911
+ * Order results by a value of a certain custom field on a selected element role.
912
+ *
913
+ * @param Toolset_Field_Definition $field_definition
914
+ * @param IToolset_Relationship_Role $for_role
915
+ *
916
+ * @return $this
917
+ * @throws RuntimeException Thrown if the element domain is not supported.
918
+ */
919
+ public function order_by_field_value( Toolset_Field_Definition $field_definition, IToolset_Relationship_Role $for_role ) {
920
+ switch( $field_definition->get_domain() ) {
921
+ case Toolset_Element_Domain::POSTS:
922
+ $cast_to_numeric = $field_definition->get_type() instanceof Toolset_Field_Type_Definition_Numeric
923
+ ? 'SIGNED'
924
+ : null;
925
+ $this->orderby = $this->orderby_factory->postmeta(
926
+ $field_definition->get_meta_key(),
927
+ $for_role,
928
+ $this->join_manager,
929
+ $cast_to_numeric
930
+ );
931
+ break;
932
+ default:
933
+ throw new RuntimeException( 'Element domain not supported.' );
934
+ }
935
+
936
+ return $this;
937
+ }
938
+
939
+
940
+ /**
941
+ * Order results by a value of the element metadata.
942
+ *
943
+ * @param string $meta_key Meta key that should be used for ordering.
944
+ * @param string $domain Valid element domain. At the moment, only posts are supported.
945
+ * @param IToolset_Relationship_Role $for_role Role of the element whose metadata should be used for ordering.
946
+ * @param bool $is_numeric If true, numeric ordering will be used.
947
+ *
948
+ * @return $this
949
+ * @since 2.6.1
950
+ * @throws RuntimeException If unsupported element domain is used.
951
+ * @throws InvalidArgumentException
952
+ */
953
+ public function order_by_meta( $meta_key, $domain, IToolset_Relationship_Role $for_role, $is_numeric = false ) {
954
+ if( Toolset_Element_Domain::POSTS !== $domain ) {
955
+ throw new RuntimeException( 'Element domain not supported.' );
956
+ }
957
+
958
+ $cast_to = ( $is_numeric ? 'SIGNED' : null );
959
+
960
+ $this->orderby = $this->orderby_factory->postmeta( $meta_key, $for_role, $this->join_manager, $cast_to );
961
+
962
+ return $this;
963
+ }
964
+
965
+
966
+ private function apply_restrictions() {
967
+ foreach( $this->restrictions as $restriction ) {
968
+ $restriction->apply();
969
+ }
970
+ }
971
+
972
+
973
+ private function clear_restrictions() {
974
+ foreach( $this->restrictions as $restriction ) {
975
+ $restriction->clear();
976
+ }
977
+ }
978
+
979
+
980
+ /**
981
+ * Perform the query to only return the number of found rows, if we're not interested in
982
+ * the actual results.
983
+ *
984
+ * @return int Number of results matching the query.
985
+ */
986
+ public function get_found_rows_directly() {
987
+ $this->need_found_rows()
988
+ ->limit( 1 )
989
+ ->return_association_uids()
990
+ ->get_results();
991
+
992
+ return $this->get_found_rows();
993
+ }
994
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/abstract.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Condition for the Toolset_Association_Query_V2.
5
+ *
6
+ * Provides a wpdb instance to all its subclasses.
7
+ *
8
+ * @since 2.5.8
9
+ */
10
+ abstract class Toolset_Association_Query_Condition implements IToolset_Association_Query_Condition {
11
+
12
+
13
+ /**
14
+ * By default, there is nothing to join.
15
+ *
16
+ * @return string
17
+ */
18
+ public function get_join_clause() {
19
+ return '';
20
+ }
21
+
22
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/association_id.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Condition to query associations by a specific association ID.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Condition_Association_Id extends Toolset_Association_Query_Condition {
9
+
10
+
11
+ /** @var int */
12
+ private $association_id;
13
+
14
+
15
+ /**
16
+ * Toolset_Association_Query_Condition_Association_Id constructor.
17
+ *
18
+ * @param int $association_id
19
+ * @throws InvalidArgumentException
20
+ */
21
+ public function __construct( $association_id ) {
22
+ if( ! Toolset_Utils::is_natural_numeric( $association_id ) ) {
23
+ throw new InvalidArgumentException( 'Invalid association ID.' );
24
+ }
25
+
26
+ $this->association_id = (int) $association_id;
27
+ }
28
+
29
+
30
+ /**
31
+ * Get a part of the WHERE clause that applies the condition.
32
+ *
33
+ * @return string Valid part of a MySQL query, so that it can be
34
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
35
+ */
36
+ public function get_where_clause() {
37
+ return sprintf( 'associations.id = %d', $this->association_id );
38
+ }
39
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/element_id.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Condition to query associations by a particular element involved in a particular role.
5
+ *
6
+ * Warning: This is not WPML-aware query. It simply compares the provided ID with the ID in
7
+ * the correct column in the associations table. In most cases, you will need the translation
8
+ * mechanism to be involved and use Toolset_Association_Query_Condition_Element_Id_And_Domain
9
+ * instead.
10
+ *
11
+ * @since 2.5.8
12
+ */
13
+ class Toolset_Association_Query_Condition_Element_Id extends Toolset_Association_Query_Condition {
14
+
15
+
16
+ /** @var int */
17
+ private $element_id;
18
+
19
+
20
+ /** @var IToolset_Relationship_Role */
21
+ private $for_role;
22
+
23
+
24
+ /** @var Toolset_Association_Query_Element_Selector_Provider */
25
+ private $element_selector_provider;
26
+
27
+
28
+ /**
29
+ * Toolset_Association_Query_Condition_Element_Id constructor.
30
+ *
31
+ * @param int $element_id
32
+ * @param IToolset_Relationship_Role $for_role
33
+ * @param Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
34
+ * @throws InvalidArgumentException
35
+ */
36
+ public function __construct(
37
+ $element_id,
38
+ IToolset_Relationship_Role $for_role,
39
+ Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
40
+ ) {
41
+ if( ! Toolset_Utils::is_nonnegative_integer( $element_id ) ) {
42
+ throw new InvalidArgumentException();
43
+ }
44
+
45
+ $this->element_id = (int) $element_id;
46
+ $this->for_role = $for_role;
47
+ $this->element_selector_provider = $element_selector_provider;
48
+ }
49
+
50
+
51
+ /**
52
+ * Get a part of the WHERE clause that applies the condition.
53
+ *
54
+ * @return string Valid part of a MySQL query, so that it can be
55
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
56
+ */
57
+ public function get_where_clause() {
58
+ $column_name = $this->element_selector_provider
59
+ ->get_selector()
60
+ ->get_element_id_value( $this->for_role, false );
61
+
62
+ return sprintf( '%s = %d', $column_name, $this->element_id );
63
+ }
64
+
65
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/element_id_and_domain.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Condition to query associations by a particular element involved in a particular role.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Condition_Element_Id_And_Domain extends Toolset_Association_Query_Condition {
9
+
10
+
11
+ /** @var int */
12
+ private $element_id;
13
+
14
+
15
+ /** @var IToolset_Relationship_Role */
16
+ private $for_role;
17
+
18
+
19
+ /** @var Toolset_Association_Query_Element_Selector_Provider */
20
+ private $element_selector_provider;
21
+
22
+
23
+ /** @var bool */
24
+ private $translate_provided_id;
25
+
26
+
27
+ /** @var bool */
28
+ private $query_original_element;
29
+
30
+
31
+ /** @var string */
32
+ private $domain;
33
+
34
+
35
+ /**
36
+ * Toolset_Association_Query_Condition_Element_Id constructor.
37
+ *
38
+ * @param int $element_id
39
+ * @param string $domain
40
+ * @param IToolset_Relationship_Role $for_role
41
+ * @param Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
42
+ * @param $query_original_element
43
+ * @param $translate_provided_id
44
+ */
45
+ public function __construct(
46
+ $element_id,
47
+ $domain,
48
+ IToolset_Relationship_Role $for_role,
49
+ Toolset_Association_Query_Element_Selector_Provider $element_selector_provider,
50
+ $query_original_element,
51
+ $translate_provided_id
52
+ ) {
53
+ if(
54
+ ! Toolset_Utils::is_nonnegative_integer( $element_id )
55
+ || ! in_array( $domain, Toolset_Element_Domain::all(), true )
56
+ ) {
57
+ throw new InvalidArgumentException();
58
+ }
59
+
60
+ if(
61
+ $for_role instanceof Toolset_Relationship_Role_Intermediary
62
+ && Toolset_Element_Domain::POSTS !== $domain
63
+ ) {
64
+ throw new InvalidArgumentException( 'Querying by an intermediary post with a wrong element domain.' );
65
+ }
66
+
67
+ $this->element_id = (int) $element_id;
68
+ $this->domain = $domain;
69
+ $this->for_role = $for_role;
70
+ $this->element_selector_provider = $element_selector_provider;
71
+ $this->translate_provided_id = (bool) $translate_provided_id;
72
+ $this->query_original_element = (bool) $query_original_element;
73
+ }
74
+
75
+
76
+ /**
77
+ * Get a part of the WHERE clause that applies the condition.
78
+ *
79
+ * @return string Valid part of a MySQL query, so that it can be
80
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
81
+ */
82
+ public function get_where_clause() {
83
+ $column_name = $this->element_selector_provider
84
+ ->get_selector()
85
+ ->get_element_id_value(
86
+ $this->for_role, ! $this->query_original_element
87
+ );
88
+
89
+ return sprintf(
90
+ '%s %s %d', $column_name, $this->get_operator(), $this->get_element_id_to_query()
91
+ );
92
+ }
93
+
94
+
95
+ private function get_element_id_to_query() {
96
+ if( Toolset_Element_Domain::POSTS === $this->domain && $this->translate_provided_id ) {
97
+ $element_id = apply_filters( 'wpml_object_id', $this->element_id, 'any', true );
98
+ return $element_id;
99
+ }
100
+
101
+ return $this->element_id;
102
+ }
103
+
104
+
105
+ protected function get_operator() {
106
+ return '=';
107
+ }
108
+
109
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/element_status.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Condition to query associations by a status of an element in a particular role.
5
+ *
6
+ * Allows querying for a specific status or for a set of statuses that may be
7
+ * depending on other circumstances (e.g. capabilities of the current user).
8
+ *
9
+ * Note that the functionality may be different per each domain. Currently, only posts
10
+ * are supported.
11
+ *
12
+ * @since 2.5.8
13
+ */
14
+ class Toolset_Association_Query_Condition_Element_Status extends Toolset_Association_Query_Condition {
15
+
16
+ const STATUS_AVAILABLE = 'is_available';
17
+ const STATUS_PUBLIC = 'is_public';
18
+ const STATUS_ANY = 'any';
19
+
20
+
21
+ /** @var string */
22
+ private $status;
23
+
24
+
25
+ /** @var IToolset_Relationship_Role */
26
+ private $for_role;
27
+
28
+
29
+ /** @var Toolset_Association_Query_Table_Join_Manager */
30
+ private $join_manager;
31
+
32
+
33
+ /** @var Toolset_Association_Query_Element_Selector_Provider */
34
+ private $element_selector_provider;
35
+
36
+
37
+ /**
38
+ * Toolset_Association_Query_Condition_Element_Status constructor.
39
+ *
40
+ * @param string $status
41
+ * @param IToolset_Relationship_Role $for_role
42
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
43
+ * @param Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
44
+ * @throws InvalidArgumentException
45
+ */
46
+ public function __construct(
47
+ $status,
48
+ IToolset_Relationship_Role $for_role,
49
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
50
+ Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
51
+ ) {
52
+ if(
53
+ ! is_string( $status ) || empty( $status )
54
+ ) {
55
+ throw new InvalidArgumentException();
56
+ }
57
+
58
+ $this->status = $status;
59
+ $this->for_role = $for_role;
60
+ $this->join_manager = $join_manager;
61
+ $this->element_selector_provider = $element_selector_provider;
62
+ }
63
+
64
+
65
+ /**
66
+ * Get a part of the WHERE clause that applies the condition.
67
+ *
68
+ * @return string Valid part of a MySQL query, so that it can be
69
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
70
+ */
71
+ public function get_where_clause() {
72
+ return $this->get_where_clause_for_posts();
73
+ }
74
+
75
+
76
+ /**
77
+ * Get the WHERE clause if the domain is known to be posts.
78
+ *
79
+ * @return string
80
+ */
81
+ private function get_where_clause_for_posts() {
82
+
83
+ $accepted_statuses = array();
84
+
85
+ switch( $this->status ) {
86
+ case self::STATUS_PUBLIC:
87
+ $accepted_statuses[] = 'publish';
88
+ break;
89
+ case self::STATUS_AVAILABLE:
90
+ $accepted_statuses[] = 'publish';
91
+ $accepted_statuses[] = 'draft';
92
+ // FIXME make the logic complete (involving WP_Query business logic and Access)
93
+ if( current_user_can( 'read_private_posts' ) ) {
94
+ $accepted_statuses[] = 'private';
95
+ }
96
+ break;
97
+ case self::STATUS_ANY:
98
+ // Match anything, don't bother with adding a query.
99
+ return ' 1 = 1 ';
100
+ default:
101
+ // Use the status value directly.
102
+ $accepted_statuses[] = $this->status;
103
+ }
104
+
105
+ if( empty( $accepted_statuses ) ) {
106
+ // For some reason, we don't allow any post status. Match nothing.
107
+ return ' 1 = 0 ';
108
+ }
109
+
110
+ $clause = sprintf(
111
+ ' %s.post_status IN ( %s ) ',
112
+ $this->join_manager->wp_posts( $this->for_role ),
113
+ '\'' . implode( '\', \'', $accepted_statuses ) . '\''
114
+ );
115
+
116
+ return $clause;
117
+ }
118
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/empty_intermediary.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Condition to query associations without intermediary post. Needed when fields are added and association have to be updated.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Condition_Empty_Intermediary extends Toolset_Association_Query_Condition {
9
+
10
+
11
+ /**
12
+ * Get a part of the WHERE clause that applies the condition.
13
+ *
14
+ * @return string Valid part of a MySQL query, so that it can be
15
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
16
+ */
17
+ public function get_where_clause() {
18
+ return 'associations.intermediary_id = 0';
19
+ }
20
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/exclude_element.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Condition to exclude a particular element from the results.
5
+ *
6
+ * See the parent class for details.
7
+ *
8
+ * @since 2.5.10
9
+ */
10
+ class Toolset_Association_Query_Condition_Exclude_Element extends Toolset_Association_Query_Condition_Element_Id_And_Domain {
11
+
12
+ protected function get_operator() {
13
+ return '!=';
14
+ }
15
+
16
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/has_active_relationship.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Query associations by the is_active value of a relationship they belong to.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Condition_Has_Active_Relationship extends Toolset_Association_Query_Condition_Relationship_Flag {
9
+
10
+
11
+ /**
12
+ * @inheritdoc
13
+ * @return string
14
+ */
15
+ protected function get_flag_name() {
16
+ return 'is_active';
17
+ }
18
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/has_domain.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Query associations by the domain of selected role.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Condition_Has_Domain extends Toolset_Association_Query_Condition {
9
+
10
+
11
+ /** @var Toolset_Association_Query_Table_Join_Manager */
12
+ private $join_manager;
13
+
14
+
15
+ /** @var IToolset_Relationship_Role_Parent_Child */
16
+ private $for_role;
17
+
18
+
19
+ /** @var string */
20
+ private $domain;
21
+
22
+
23
+ /** @var null|Toolset_Relationship_Database_Operations */
24
+ private $database_operations;
25
+
26
+
27
+ /**
28
+ * Toolset_Association_Query_Condition_Has_Active_Relationship constructor.
29
+ *
30
+ * @param string $domain
31
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
32
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
33
+ * @param Toolset_Relationship_Database_Operations|null $database_operations_di
34
+ */
35
+ public function __construct(
36
+ $domain,
37
+ IToolset_Relationship_Role_Parent_Child $for_role,
38
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
39
+ Toolset_Relationship_Database_Operations $database_operations_di = null
40
+ ) {
41
+ if( ! in_array( $domain, Toolset_Element_Domain::all(), true ) ) {
42
+ throw new InvalidArgumentException();
43
+ }
44
+
45
+ $this->domain = $domain;
46
+ $this->for_role = $for_role;
47
+ $this->join_manager = $join_manager;
48
+ $this->database_operations = ( null === $database_operations_di ? new Toolset_Relationship_Database_Operations() : $database_operations_di );
49
+ }
50
+
51
+
52
+ /**
53
+ * Get a part of the WHERE clause that applies the condition.
54
+ *
55
+ * @return string Valid part of a MySQL query, so that it can be
56
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
57
+ */
58
+ public function get_where_clause() {
59
+ $relationships_table_alias = $this->join_manager->relationships();
60
+ $domain_column = $this->database_operations->role_to_column(
61
+ $this->for_role,
62
+ Toolset_Relationship_Database_Operations::COLUMN_DOMAIN
63
+ );
64
+
65
+ return sprintf(
66
+ "%s.%s = '%s'",
67
+ $relationships_table_alias,
68
+ $domain_column,
69
+ esc_sql( $this->domain )
70
+ );
71
+ }
72
+
73
+
74
+ /**
75
+ * @return string The element domain set on this condition.
76
+ * @since 2.5.10
77
+ */
78
+ public function get_domain() {
79
+ return $this->domain;
80
+ }
81
+
82
+
83
+ public function get_for_role() {
84
+ return $this->for_role;
85
+ }
86
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/has_domain_and_type.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Condition to filter results by element domain and type at the same time.
5
+ *
6
+ * Actually, this doesn't do anything but to tie those two together so that the association query
7
+ * can perform some more advanced optimizations.
8
+ *
9
+ * @since m2m
10
+ */
11
+ class Toolset_Association_Query_Condition_Has_Domain_And_Type extends Toolset_Association_Query_Condition {
12
+
13
+
14
+ /** @var string */
15
+ private $domain;
16
+
17
+
18
+ /** @var string */
19
+ private $type;
20
+
21
+
22
+ /** @var IToolset_Association_Query_Condition */
23
+ private $inner_condition;
24
+
25
+
26
+ /**
27
+ * Toolset_Association_Query_Condition_Has_Type constructor.
28
+ *
29
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
30
+ * @param string $domain
31
+ * @param string $type
32
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
33
+ * @param Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias
34
+ * @param Toolset_Association_Query_Condition_Factory $condition_factory
35
+ */
36
+ public function __construct(
37
+ IToolset_Relationship_Role_Parent_Child $for_role,
38
+ $domain,
39
+ $type,
40
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
41
+ Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias,
42
+ Toolset_Association_Query_Condition_Factory $condition_factory
43
+ ) {
44
+ if(
45
+ ! in_array( $domain, Toolset_Element_Domain::all(), true )
46
+ || ! is_string( $type ) || empty( $type )
47
+ ) {
48
+ throw new InvalidArgumentException();
49
+ }
50
+
51
+ $this->domain = $domain;
52
+ $this->type = $type;
53
+
54
+ $this->inner_condition = $condition_factory->do_and(
55
+ array(
56
+ $condition_factory->has_domain( $domain, $for_role, $join_manager ),
57
+ $condition_factory->has_type( $type, $for_role, $join_manager, $unique_table_alias )
58
+ )
59
+ );
60
+ }
61
+
62
+
63
+ /**
64
+ * Get a part of the WHERE clause that applies the condition.
65
+ *
66
+ * @return string Valid part of a MySQL query, so that it can be
67
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
68
+ */
69
+ public function get_where_clause() {
70
+ return $this->inner_condition->get_where_clause();
71
+ }
72
+
73
+
74
+ /**
75
+ * @inheritdoc
76
+ *
77
+ * @return string
78
+ */
79
+ public function get_join_clause() {
80
+ return $this->inner_condition->get_join_clause();
81
+ }
82
+
83
+
84
+ /**
85
+ * @return string The element domain set in this condition.
86
+ */
87
+ public function get_domain() {
88
+ return $this->domain;
89
+ }
90
+
91
+
92
+ /**
93
+ * @return string The element type set in this condition.
94
+ */
95
+ public function get_type() {
96
+ return $this->type;
97
+ }
98
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/has_legacy_relationship.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Query associations by the fact whether the relationship they belong to was migrated from the legacy implementation or not.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Condition_Has_Legacy_Relationship extends Toolset_Association_Query_Condition_Relationship_Flag {
9
+
10
+
11
+ /**
12
+ * @inheritdoc
13
+ * @return string
14
+ */
15
+ protected function get_flag_name() {
16
+ return 'needs_legacy_support';
17
+ }
18
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/has_type.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Condition to query associations by a type (not domain) of elements in the given role.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Condition_Has_Type extends Toolset_Association_Query_Condition {
9
+
10
+
11
+ /** @var IToolset_Relationship_Role_Parent_Child */
12
+ private $for_role;
13
+
14
+
15
+ /** @var string */
16
+ private $type;
17
+
18
+
19
+ /** @var Toolset_Association_Query_Table_Join_Manager */
20
+ private $join_manager;
21
+
22
+
23
+ /** @var Toolset_Relationship_Database_Operations */
24
+ private $database_operations;
25
+
26
+
27
+ /** @var Toolset_Relationship_Table_Name */
28
+ private $table_name;
29
+
30
+
31
+ /** @var Toolset_Relationship_Database_Unique_Table_Alias */
32
+ private $unique_table_alias;
33
+
34
+
35
+ /** @var string|null This needs to be set during get_join_clauses(). */
36
+ private $type_set_table_alias;
37
+
38
+
39
+ /**
40
+ * Toolset_Association_Query_Condition_Has_Type constructor.
41
+ *
42
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
43
+ * @param string $type
44
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
45
+ * @param Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias
46
+ * @param Toolset_Relationship_Database_Operations|null $database_operations_di
47
+ * @param Toolset_Relationship_Table_Name|null $table_name_di
48
+ * @throws InvalidArgumentException
49
+ */
50
+ public function __construct(
51
+ IToolset_Relationship_Role_Parent_Child $for_role,
52
+ $type,
53
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
54
+ Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias,
55
+ Toolset_Relationship_Database_Operations $database_operations_di = null,
56
+ Toolset_Relationship_Table_Name $table_name_di = null
57
+ ) {
58
+ if( ! is_string( $type ) || empty( $type ) ) {
59
+ throw new InvalidArgumentException();
60
+ }
61
+
62
+ $this->for_role = $for_role;
63
+ $this->type = $type;
64
+ $this->join_manager = $join_manager;
65
+ $this->unique_table_alias = $unique_table_alias;
66
+ $this->database_operations = ( null === $database_operations_di ? new Toolset_Relationship_Database_Operations() : $database_operations_di );
67
+ $this->table_name = ( null === $table_name_di ? new Toolset_Relationship_Table_Name() : $table_name_di );
68
+ }
69
+
70
+
71
+ /**
72
+ * @inheritdoc
73
+ * @return string
74
+ */
75
+ public function get_join_clause() {
76
+ $relationships_table = $this->join_manager->relationships();
77
+ $type_set_column = $this->database_operations->role_to_column(
78
+ $this->for_role->get_name(),
79
+ Toolset_Relationship_Database_Operations::COLUMN_TYPES
80
+ );
81
+ $type_set_table = $this->table_name->type_set_table();
82
+ $type_set_table_alias = $this->unique_table_alias->generate( $type_set_table, true );
83
+
84
+ $this->type_set_table_alias = $type_set_table_alias;
85
+
86
+ return " JOIN $type_set_table AS $type_set_table_alias ON ( $type_set_table_alias.set_id = $relationships_table.$type_set_column ) ";
87
+ }
88
+
89
+
90
+ /**
91
+ * Get a part of the WHERE clause that applies the condition.
92
+ *
93
+ * @return string Valid part of a MySQL query, so that it can be
94
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
95
+ */
96
+ public function get_where_clause() {
97
+ return sprintf( "%s.type = '%s'", $this->type_set_table_alias, esc_sql( $this->type ) );
98
+ }
99
+
100
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/interface.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Represents a single condition for the Tooset_Association_Query_V2.
5
+ *
6
+ * Note: It is very important that if an Toolset_Association_Query_Element_Selector_Provider instance
7
+ * is passed to the condition, it doesn't try to obtain the element selector object
8
+ * within its constructor.
9
+ *
10
+ * @since 2.5.8
11
+ */
12
+ interface IToolset_Association_Query_Condition extends IToolset_Query_Condition {
13
+
14
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/postmeta.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Query condition by a postmeta value of a selected element role.
5
+ *
6
+ * Note: Using this will immediately exclude all non-post elements.
7
+ *
8
+ * @since 2.6.1
9
+ */
10
+ class Toolset_Association_Query_Condition_Postmeta extends Toolset_Association_Query_Condition {
11
+
12
+
13
+ /** @var string */
14
+ private $meta_key;
15
+
16
+
17
+ /** @var string */
18
+ private $meta_value;
19
+
20
+
21
+ /** @var string */
22
+ private $comparison_operator;
23
+
24
+
25
+ /** @var IToolset_Relationship_Role */
26
+ private $for_role;
27
+
28
+
29
+ /** @var Toolset_Association_Query_Table_Join_Manager */
30
+ private $join_manager;
31
+
32
+
33
+ /**
34
+ * Toolset_Association_Query_Condition_Postmeta constructor.
35
+ *
36
+ * @param string $meta_key
37
+ * @param string $meta_value
38
+ * @param string $comparison_operator
39
+ * @param IToolset_Relationship_Role $for_role
40
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
41
+ * @throws InvalidArgumentException
42
+ */
43
+ public function __construct(
44
+ $meta_key,
45
+ $meta_value,
46
+ $comparison_operator,
47
+ IToolset_Relationship_Role $for_role,
48
+ Toolset_Association_Query_Table_Join_Manager $join_manager
49
+ ) {
50
+ if(
51
+ ! is_string( $meta_key ) || empty( $meta_key )
52
+ || ! is_string( $meta_value ) || empty( $meta_value )
53
+ || ! in_array( $comparison_operator, Toolset_Query_Comparison_Operator::all() )
54
+ ) {
55
+ throw new InvalidArgumentException();
56
+ }
57
+
58
+ $this->meta_key = $meta_key;
59
+ $this->meta_value = $meta_value;
60
+ $this->comparison_operator = $comparison_operator;
61
+ $this->for_role = $for_role;
62
+ $this->join_manager = $join_manager;
63
+ }
64
+
65
+ /**
66
+ * Get a part of the WHERE clause that applies the condition.
67
+ *
68
+ * @return string Valid part of a MySQL query, so that it can be
69
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
70
+ */
71
+ public function get_where_clause() {
72
+ $postmeta = $this->join_manager->wp_postmeta( $this->for_role, $this->meta_key );
73
+ $meta_value = esc_sql( $this->meta_value );
74
+
75
+ return "$postmeta $this->comparison_operator '$meta_value'";
76
+ }
77
+
78
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/relationship_flag.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Query associations by a flag of a relationship they belong to.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ abstract class Toolset_Association_Query_Condition_Relationship_Flag extends Toolset_Association_Query_Condition {
9
+
10
+
11
+ /** @var Toolset_Association_Query_Table_Join_Manager */
12
+ private $join_manager;
13
+
14
+
15
+ /** @var bool */
16
+ private $expected_value;
17
+
18
+
19
+ /**
20
+ * Toolset_Association_Query_Condition_Has_Active_Relationship constructor.
21
+ *
22
+ * @param bool $expected_value
23
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
24
+ */
25
+ public function __construct( $expected_value, Toolset_Association_Query_Table_Join_Manager $join_manager ) {
26
+ $this->expected_value = (bool) $expected_value;
27
+ $this->join_manager = $join_manager;
28
+ }
29
+
30
+
31
+ /**
32
+ * Get a part of the WHERE clause that applies the condition.
33
+ *
34
+ * @return string Valid part of a MySQL query, so that it can be
35
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
36
+ */
37
+ public function get_where_clause() {
38
+ $relationships_table = $this->join_manager->relationships();
39
+
40
+ return sprintf(
41
+ '%s.%s = %d',
42
+ $relationships_table,
43
+ $this->get_flag_name(),
44
+ $this->expected_value ? 1 : 0
45
+ );
46
+ }
47
+
48
+
49
+ /**
50
+ * Get the name of the column in the relationships table to query by.
51
+ *
52
+ * @return string
53
+ */
54
+ protected abstract function get_flag_name();
55
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/relationship_id.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Condition to query associations by a specific relationship (row) ID.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Condition_Relationship_Id extends Toolset_Association_Query_Condition {
9
+
10
+
11
+ /** @var int */
12
+ private $relationship_id;
13
+
14
+
15
+ /**
16
+ * Toolset_Association_Query_Condition_Relationship_Id constructor.
17
+ *
18
+ * @param int $relationship_id
19
+ * @throws InvalidArgumentException
20
+ */
21
+ public function __construct( $relationship_id ) {
22
+ if( ! Toolset_Utils::is_nonnegative_integer( $relationship_id ) ) {
23
+ throw new InvalidArgumentException();
24
+ }
25
+
26
+ $this->relationship_id = (int) $relationship_id;
27
+ }
28
+
29
+
30
+ /**
31
+ * Get a part of the WHERE clause that applies the condition.
32
+ *
33
+ * @return string Valid part of a MySQL query, so that it can be
34
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
35
+ */
36
+ public function get_where_clause() {
37
+ return sprintf( 'associations.relationship_id = %d', $this->relationship_id );
38
+ }
39
+
40
+
41
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/search.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Query by searching a text in elements of a given role.
5
+ *
6
+ * Note: This currently supports only posts, but in the future, it should be domain-agnostic.
7
+ *
8
+ * @since 2.5.8
9
+ */
10
+ class Toolset_Association_Query_Condition_Search extends Toolset_Association_Query_Condition {
11
+
12
+
13
+ /** @var string */
14
+ private $search_string;
15
+
16
+
17
+ /** @var bool */
18
+ private $is_exact_search;
19
+
20
+
21
+ /** @var IToolset_Relationship_Role */
22
+ private $for_role;
23
+
24
+
25
+ /** @var Toolset_Association_Query_Table_Join_Manager */
26
+ private $join_manager;
27
+
28
+
29
+ /** @var wpdb */
30
+ private $wpdb;
31
+
32
+
33
+ /**
34
+ * Toolset_Association_Query_Condition_Search constructor.
35
+ *
36
+ * @param string $search_string
37
+ * @param bool $is_exact_search
38
+ * @param IToolset_Relationship_Role $for_role
39
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
40
+ * @param wpdb|null $wpdb_di
41
+ * @throws InvalidArgumentException
42
+ */
43
+ public function __construct(
44
+ $search_string,
45
+ $is_exact_search,
46
+ IToolset_Relationship_Role $for_role,
47
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
48
+ wpdb $wpdb_di = null
49
+ ) {
50
+ if( ! is_string( $search_string ) || empty( $search_string ) ) {
51
+ throw new InvalidArgumentException( 'Invalid search string ' . $search_string );
52
+ }
53
+ $this->search_string = $search_string;
54
+ $this->join_manager = $join_manager;
55
+ $this->is_exact_search = (bool) $is_exact_search;
56
+ $this->for_role = $for_role;
57
+
58
+ global $wpdb;
59
+ $this->wpdb = ( null === $wpdb_di ? $wpdb : $wpdb_di );
60
+ }
61
+
62
+
63
+ /**
64
+ * Get a part of the WHERE clause that applies the condition.
65
+ *
66
+ * @return string Valid part of a MySQL query, so that it can be
67
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
68
+ */
69
+ public function get_where_clause() {
70
+ $wp_posts = $this->join_manager->wp_posts( $this->for_role );
71
+ $search_string = esc_sql( $this->get_sanitized_search_string() );
72
+
73
+ return "{$wp_posts}.post_title LIKE '{$search_string}'
74
+ OR {$wp_posts}.post_excerpt LIKE '{$search_string}'
75
+ OR {$wp_posts}.post_content LIKE '{$search_string}'";
76
+ }
77
+
78
+
79
+ /**
80
+ * Get a string prepared for using in the query.
81
+ *
82
+ * @return string
83
+ */
84
+ private function get_sanitized_search_string() {
85
+ $s = stripslashes( $this->search_string );
86
+ $s = str_replace( array( "\r", "\n", "\t" ), '', $s );
87
+ if( ! $this->is_exact_search ) {
88
+ $s = '%' . $this->wpdb->esc_like( $s ) . '%';
89
+ }
90
+ return $s;
91
+ }
92
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition/wp_query.php ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A WP_Query condition.
5
+ *
6
+ * It allows for filtering the results of the association query by a WP_Query being applied on
7
+ * elements (posts) of a selected association role.
8
+ *
9
+ * WARNINGS and limitations:
10
+ *
11
+ * - The process to generate the query abuses WP_Query and is rather expensive in terms of performance.
12
+ * - This is untested and highly experimental.
13
+ * The WP_Query hack is so ugly that it's beautiful, if you ask me. But let's see if we actually
14
+ * put this to an use.
15
+ * - If used on non-post elements, the results are unpredictable. Never assume you're dealing only
16
+ * with post relationships.
17
+ * - Only subsets of WP_Query arguments are supported. Basically, anything that requires joining other
18
+ * tables than wp_posts should be considered unreliable (in need of extra testing) and if you use
19
+ * this query condition multiple times inside one association query, overreaching wp_posts
20
+ * will most definitely cause a collision of table aliases.
21
+ * - If you intend to use this only for searching elements by a string, please don't.
22
+ * Use $query->search() instead, which is much lighter and will become domain-agnostic
23
+ * when another domains become supported.
24
+ * - This usage of WP_Query doesn't support sticky posts, filter suppressing and WPML language queries.
25
+ *
26
+ * @since 2.5.8
27
+ */
28
+ class Toolset_Association_Query_Condition_Wp_Query extends Toolset_Association_Query_Condition {
29
+
30
+
31
+ /** @var IToolset_Relationship_Role */
32
+ private $for_role;
33
+
34
+
35
+ /** @var array */
36
+ private $query_args;
37
+
38
+
39
+ /** @var Toolset_Association_Query_Table_Join_Manager */
40
+ private $join_manager;
41
+
42
+
43
+ /** @var Toolset_Relationship_Query_Factory */
44
+ private $query_factory;
45
+
46
+
47
+ /** @var array|null Clauses generated by the WP_Query class. */
48
+ private $wp_query_clauses;
49
+
50
+
51
+ /** @var wpdb */
52
+ private $wpdb;
53
+
54
+
55
+ /** @var Toolset_Relationship_Database_Unique_Table_Alias */
56
+ private $unique_table_alias;
57
+
58
+
59
+ /**
60
+ * Toolset_Association_Query_Condition_Wp_Query constructor.
61
+ *
62
+ * @param IToolset_Relationship_Role $for_role
63
+ * @param array $query_args
64
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
65
+ * @param Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias
66
+ * @param Toolset_Relationship_Query_Factory|null $query_factory_di
67
+ * @param wpdb|null $wpdb_di
68
+ * @throws InvalidArgumentException
69
+ */
70
+ public function __construct(
71
+ IToolset_Relationship_Role $for_role, $query_args,
72
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
73
+ Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias,
74
+ Toolset_Relationship_Query_Factory $query_factory_di = null,
75
+ wpdb $wpdb_di = null
76
+ ) {
77
+ if( ! is_array( $query_args ) ) {
78
+ throw new InvalidArgumentException();
79
+ }
80
+ $this->for_role = $for_role;
81
+ $this->query_args = $query_args;
82
+ $this->join_manager = $join_manager;
83
+ $this->query_factory = ( null === $query_factory_di ? new Toolset_Relationship_Query_Factory() : $query_factory_di );
84
+ $this->unique_table_alias = $unique_table_alias;
85
+ if( null === $wpdb_di ) {
86
+ global $wpdb;
87
+ $this->wpdb = $wpdb;
88
+ } else {
89
+ $this->wpdb = $wpdb_di;
90
+ }
91
+ }
92
+
93
+
94
+ /**
95
+ * Get a part of the WHERE clause that applies the condition.
96
+ *
97
+ * @return string Valid part of a MySQL query, so that it can be
98
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
99
+ */
100
+ public function get_where_clause() {
101
+ $query_clauses = $this->get_wp_query_clauses();
102
+
103
+ // The clause starts with AND. I'm not sure about the whitespaces, so this is easier than
104
+ // parsing and removing the keyword.
105
+ return ' 1 = 1 ' . $query_clauses['where'];
106
+ }
107
+
108
+
109
+ /**
110
+ * @inheritdoc
111
+ *
112
+ * @return string
113
+ */
114
+ public function get_join_clause() {
115
+ $query_clauses = $this->get_wp_query_clauses();
116
+ $join_clauses = $query_clauses['join'];
117
+
118
+ return $join_clauses;
119
+ }
120
+
121
+
122
+ /**
123
+ * Retrieve the generated clauses from WP_Query.
124
+ *
125
+ * @return string[]
126
+ */
127
+ private function get_wp_query_clauses() {
128
+ if( null === $this->wp_query_clauses ) {
129
+ $this->wp_query_clauses = $this->build_wp_query_clauses( $this->query_args );
130
+ }
131
+
132
+ return $this->wp_query_clauses;
133
+ }
134
+
135
+
136
+ /**
137
+ * Fool WP_Query into generating MySQL query clauses for given query arguments without actually executing the query.
138
+ *
139
+ * It also prevents WPML from modifying the query because filtering by language is handled elsewhere.
140
+ * It doesn't support sticky posts, filter suppressing and probably some complex use-cases.
141
+ *
142
+ * @param array $query_args Arguments for WP_Query.
143
+ * @return string[] MySQL clauses, for details see the posts_clauses filter.
144
+ * @since 2.5.8
145
+ */
146
+ private function build_wp_query_clauses( $query_args ) {
147
+
148
+ // Sticky posts are handled in a special way after the query takes place, so they would have no
149
+ // effect in any case. This is a performance optimalization.
150
+ $query_args['ignore_sticky_posts'] = true;
151
+
152
+ // Without this, we won't be able to get the clauses because the posts_clauses filter would not be applied.
153
+ $query_args['suppress_filters'] = false;
154
+
155
+ if( ! isset( $query_args['post_type'] ) ) {
156
+ // Get all associated post_types if none is defined
157
+ $query_args['post_type'] = 'any';
158
+ }
159
+
160
+ // This will hold the mysql clauses after WP_Query pushes them through the posts_pre_query filter.
161
+ $clauses_out = array();
162
+
163
+ $catch_clauses = function( $clauses_in ) use( &$clauses_out ) {
164
+ $clauses_out = $clauses_in;
165
+ };
166
+
167
+ // Filter priority
168
+ $very_late = 10000;
169
+
170
+ add_filter( 'posts_clauses', $catch_clauses, $very_late );
171
+
172
+ // Returning a non-null value on the posts_pre_query filter (since WP 4.6) causes that no actual
173
+ // mysql query takes place in WP_Query::get_posts().
174
+ $dont_query_anyting = function() { return array(); };
175
+ add_filter( 'posts_pre_query', $dont_query_anyting, $very_late );
176
+
177
+ // Avoid WPML messing with the results because we already know in which language we want to query
178
+ $current_language = apply_filters( 'wpml_current_language', '' );
179
+ do_action( 'wpml_switch_language', 'all' );
180
+
181
+ // Did you think it can't get any worse? Well... Now we have to override $wpdb
182
+ // because we need it to use a different name of the wp_posts table. The wrapper object will
183
+ // forward anything to the original $wpdb instance except the attempt to read the $posts
184
+ // property. In that case, it will use the join manager to get a proper table alias.
185
+ //
186
+ // This hack allows us to use this query condition (at least in a limited way) multiple times
187
+ // within a single query.
188
+ global $wpdb;
189
+ $original_wpdb_object = $wpdb;
190
+ $wpdb_wrapper = new Toolset_Association_Query_Wpdb_Wrapper(
191
+ $wpdb, $this->join_manager, $this->for_role
192
+ );
193
+ $wpdb = $wpdb_wrapper;
194
+
195
+ // This will immediately run the query.
196
+ $this->query_factory->wp_query( $query_args );
197
+
198
+ // Like nothing has ever happened.
199
+ $wpdb = $original_wpdb_object;
200
+
201
+ // Switch back to the current language so that we don't break anything else down the road.
202
+ do_action( 'wpml_switch_language', $current_language );
203
+
204
+ // Clean up
205
+ remove_filter( 'posts_clauses', $catch_clauses, $very_late );
206
+ remove_filter( 'posts_pre_query', $dont_query_anyting, $very_late );
207
+
208
+ return $this->adjust_table_aliases( $clauses_out );
209
+ }
210
+
211
+
212
+ /**
213
+ * Try to avoid table alias collisions if the WP_Query joins further tables.
214
+ *
215
+ * @param string[] $query_clauses Array with the query clauses coming from the WP_Query.
216
+ * @return string[] Updated query clauses array.
217
+ */
218
+ private function adjust_table_aliases( $query_clauses ) {
219
+
220
+ $join_clauses = $query_clauses['join'];
221
+ $where_clauses = $query_clauses['where'];
222
+
223
+ $matches = array();
224
+
225
+ // Match all JOINs - table name in the second capturing group and optionally also
226
+ // alias name in the fifth capturing group (it may not be present).
227
+ preg_match_all(
228
+ '/JOIN\s+(\w+)\s+(as\s+|AS\s+)?((\w+)\s+)?ON/',
229
+ $join_clauses, $matches, PREG_SET_ORDER
230
+ );
231
+
232
+ foreach( $matches as $match ) {
233
+ // Failsafe if something goes wrong.
234
+ if( ! is_array( $match ) || count( $match ) < 2 ) {
235
+ continue;
236
+ }
237
+
238
+ $table_name = $match[1];
239
+ $replace_table_name_in_where = true;
240
+
241
+ // wp_posts table needs special handling because its name has already been overridden
242
+ // (it's always used, while additional JOINs will not be so frequent).
243
+ if ( $table_name === $this->join_manager->wp_posts( $this->for_role ) ) {
244
+ $join_clauses = str_replace( $table_name, $this->wpdb->posts, $join_clauses );
245
+ $replace_table_name_in_where = false;
246
+ $table_name = $this->wpdb->posts;
247
+ }
248
+
249
+ // This is unique across the whole association query.
250
+ $unique_alias_name = $this->unique_table_alias->generate( $table_name, true );
251
+
252
+ $has_alias = ( count( $match ) === 5 );
253
+
254
+ if( $has_alias ) {
255
+ // We already have an alias, so we keep the original table name
256
+ // in the "JOIN $table_name AS..." as it is, and just replace the alias by
257
+ // an unique one.
258
+ $alias_name = $match[4];
259
+ $join_clauses = preg_replace( '/'.$table_name.'\s+'.$alias_name.'/', $table_name . ' ' . $unique_alias_name, $join_clauses );
260
+ $join_clauses = preg_replace( '/([^A-z\_])'.$alias_name.'\./', "$1$unique_alias_name.", $join_clauses );
261
+ $where_clauses = preg_replace( '/'.$table_name.'\s+'.$alias_name.'/', $table_name . ' ' . $unique_alias_name, $where_clauses );
262
+ $where_clauses = preg_replace( '/([^A-z\_])'.$alias_name.'\./', "$1$unique_alias_name.", $where_clauses );
263
+ } else {
264
+ // There is no alias the table name is used directly - we need to add it.
265
+ // First, replace the table name with the alias everywhere.
266
+ $join_clauses = str_replace( $table_name, $unique_alias_name, $join_clauses );
267
+ // And now, replace back the "JOIN $unique_alias_name" with the actual table name
268
+ // and add the "AS $unique_alias_name" string.
269
+ $join_clauses = preg_replace(
270
+ "/JOIN\s+$unique_alias_name\s+ON/",
271
+ "JOIN $table_name AS $unique_alias_name ON",
272
+ $join_clauses
273
+ );
274
+
275
+ // The table/alias usage in the WHERE clause needs to be adjusted as well.
276
+ // (unless we're dealing with a wp_posts alias)
277
+ if( $replace_table_name_in_where ) {
278
+ $where_clauses = str_replace( $table_name, $unique_alias_name, $where_clauses );
279
+ }
280
+ }
281
+ }
282
+
283
+ $query_clauses['join'] = $join_clauses;
284
+ $query_clauses['where'] = $where_clauses;
285
+ return $query_clauses;
286
+ }
287
+
288
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/condition_factory.php ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A factory for IToolset_Association_Query_Condition implementations.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Condition_Factory {
9
+
10
+
11
+ /**
12
+ * Chain multiple conditions with OR.
13
+ *
14
+ * The whole statement will evaluate to true if at least one of provided conditions is true.
15
+ *
16
+ * @param IToolset_Association_Query_Condition[] $operands
17
+ * @return IToolset_Association_Query_Condition
18
+ */
19
+ public function do_or( $operands ) {
20
+ return new Toolset_Query_Condition_Or( $operands );
21
+ }
22
+
23
+
24
+ /**
25
+ * Chain multiple conditions with AN.
26
+ *
27
+ * The whole statement will evaluate to true if all provided conditions are true.
28
+ *
29
+ * @param IToolset_Association_Query_Condition[] $operands
30
+ * @return IToolset_Association_Query_Condition
31
+ */
32
+ public function do_and( $operands ) {
33
+ return new Toolset_Query_Condition_And( $operands );
34
+ }
35
+
36
+
37
+ /**
38
+ * A condition that is always true.
39
+ *
40
+ * @return IToolset_Association_Query_Condition
41
+ */
42
+ public function tautology() {
43
+ return new Toolset_Query_Condition_Tautology();
44
+ }
45
+
46
+
47
+ /**
48
+ * A condition that is always false.
49
+ *
50
+ * @return IToolset_Association_Query_Condition
51
+ */
52
+ public function contradiction() {
53
+ return new Toolset_Query_Condition_Contradiction();
54
+ }
55
+
56
+
57
+ /**
58
+ * Condition to query associations by a specific relationship (row) ID.
59
+ *
60
+ * @param int $relationship_id
61
+ *
62
+ * @return IToolset_Association_Query_Condition
63
+ */
64
+ public function relationship_id( $relationship_id ) {
65
+ return new Toolset_Association_Query_Condition_Relationship_Id( $relationship_id );
66
+ }
67
+
68
+
69
+ /**
70
+ * Condition to query associations by a particular element involved in a particular role.
71
+ *
72
+ * Warning: WPML-unaware implementation.
73
+ *
74
+ * @param int $element_id
75
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
76
+ * @param Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
77
+ *
78
+ * @return IToolset_Association_Query_Condition
79
+ */
80
+ public function element_id(
81
+ $element_id, IToolset_Relationship_Role_Parent_Child $for_role,
82
+ Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
83
+ ) {
84
+ return new Toolset_Association_Query_Condition_Element_Id( $element_id, $for_role, $element_selector_provider );
85
+ }
86
+
87
+
88
+ /**
89
+ * Condition to query associations by a particular element involved in a particular role.
90
+ *
91
+ * @param int $element_id
92
+ * @param string $domain
93
+ * @param IToolset_Relationship_Role $for_role
94
+ * @param Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
95
+ * @param $query_original_element
96
+ * @param $translate_provided_id
97
+ *
98
+ * @return Toolset_Association_Query_Condition_Element_Id_And_Domain
99
+ */
100
+ public function element_id_and_domain(
101
+ $element_id,
102
+ $domain,
103
+ IToolset_Relationship_Role $for_role,
104
+ Toolset_Association_Query_Element_Selector_Provider $element_selector_provider,
105
+ $query_original_element,
106
+ $translate_provided_id
107
+ ) {
108
+ return new Toolset_Association_Query_Condition_Element_Id_And_Domain(
109
+ $element_id, $domain, $for_role, $element_selector_provider, $query_original_element, $translate_provided_id
110
+ );
111
+ }
112
+
113
+
114
+
115
+ /**
116
+ * Condition to query associations that do not contain a particular element in a particular role.
117
+ *
118
+ * @param int $element_id
119
+ * @param string $domain
120
+ * @param IToolset_Relationship_Role $for_role
121
+ * @param Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
122
+ * @param $query_original_element
123
+ * @param $translate_provided_id
124
+ *
125
+ * @return Toolset_Association_Query_Condition_Element_Id_And_Domain
126
+ */
127
+ public function exclude_element(
128
+ $element_id,
129
+ $domain,
130
+ IToolset_Relationship_Role $for_role,
131
+ Toolset_Association_Query_Element_Selector_Provider $element_selector_provider,
132
+ $query_original_element,
133
+ $translate_provided_id
134
+ ) {
135
+ return new Toolset_Association_Query_Condition_Exclude_Element(
136
+ $element_id, $domain, $for_role, $element_selector_provider, $query_original_element, $translate_provided_id
137
+ );
138
+ }
139
+
140
+
141
+ /**
142
+ * Condition to query associations by a status of an element in a particular role.
143
+ *
144
+ * @param string $status
145
+ * @param IToolset_Relationship_Role $for_role
146
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
147
+ * @param Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
148
+ *
149
+ * @return IToolset_Association_Query_Condition
150
+ */
151
+ public function element_status(
152
+ $status, IToolset_Relationship_Role $for_role,
153
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
154
+ Toolset_Association_Query_Element_Selector_Provider $element_selector_provider
155
+ ) {
156
+ return new Toolset_Association_Query_Condition_Element_Status(
157
+ $status, $for_role, $join_manager, $element_selector_provider
158
+ );
159
+ }
160
+
161
+
162
+ /**
163
+ * Query associations by the activity status of the relationship.
164
+ *
165
+ * @param bool $is_active
166
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
167
+ *
168
+ * @return IToolset_Association_Query_Condition
169
+ */
170
+ public function has_active_relationship( $is_active, Toolset_Association_Query_Table_Join_Manager $join_manager ) {
171
+ return new Toolset_Association_Query_Condition_Has_Active_Relationship( $is_active, $join_manager );
172
+ }
173
+
174
+
175
+ /**
176
+ * Query associations by the element domain on a specified role.
177
+ *
178
+ * @param string $domain Domain name.
179
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
180
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
181
+ *
182
+ * @return IToolset_Association_Query_Condition
183
+ */
184
+ public function has_domain(
185
+ $domain, IToolset_Relationship_Role_Parent_Child $for_role, Toolset_Association_Query_Table_Join_Manager $join_manager
186
+ ) {
187
+ return new Toolset_Association_Query_Condition_Has_Domain( $domain, $for_role, $join_manager );
188
+ }
189
+
190
+
191
+ /**
192
+ * @param bool $needs_legacy_support
193
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
194
+ *
195
+ * @return IToolset_Association_Query_Condition
196
+ */
197
+ public function has_legacy_relationship( $needs_legacy_support, Toolset_Association_Query_Table_Join_Manager $join_manager ) {
198
+ return new Toolset_Association_Query_Condition_Has_Legacy_Relationship( $needs_legacy_support, $join_manager );
199
+ }
200
+
201
+
202
+ /**
203
+ * Query associations by element type on a given role.
204
+ *
205
+ * Warning: This doesn't query for the domain. Make sure you at least add
206
+ * a separate element domain condition. Otherwise, the results will be unpredictable.
207
+ *
208
+ * The best way is to use the has_domain_and_type() condition instead, which whill allow
209
+ * for some more advanced optimizations.
210
+ *
211
+ * @param string $type
212
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
213
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
214
+ * @param Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias
215
+ *
216
+ * @return IToolset_Association_Query_Condition
217
+ */
218
+ public function has_type(
219
+ $type,
220
+ IToolset_Relationship_Role_Parent_Child $for_role,
221
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
222
+ Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias
223
+ ) {
224
+ return new Toolset_Association_Query_Condition_Has_Type( $for_role, $type, $join_manager, $unique_table_alias );
225
+ }
226
+
227
+
228
+ /**
229
+ * @param string $domain
230
+ * @param string $type
231
+ * @param IToolset_Relationship_Role_Parent_Child $for_role
232
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
233
+ * @param Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias
234
+ *
235
+ * @return Toolset_Association_Query_Condition_Has_Domain_And_Type
236
+ */
237
+ public function has_domain_and_type(
238
+ $domain,
239
+ $type,
240
+ IToolset_Relationship_Role_Parent_Child $for_role,
241
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
242
+ Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias
243
+ ) {
244
+ return new Toolset_Association_Query_Condition_Has_Domain_And_Type(
245
+ $for_role, $domain, $type, $join_manager, $unique_table_alias, $this
246
+ );
247
+ }
248
+
249
+
250
+ /**
251
+ * @param IToolset_Relationship_Role $for_role
252
+ * @param array $query_args
253
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
254
+ * @param Toolset_Relationship_Database_Unique_Table_Alias $table_alias
255
+ *
256
+ * @return IToolset_Association_Query_Condition
257
+ */
258
+ public function wp_query(
259
+ IToolset_Relationship_Role $for_role,
260
+ $query_args,
261
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
262
+ Toolset_Relationship_Database_Unique_Table_Alias $table_alias
263
+ ) {
264
+ return new Toolset_Association_Query_Condition_Wp_Query( $for_role, $query_args, $join_manager, $table_alias );
265
+ }
266
+
267
+
268
+ /**
269
+ * @param string $search_string
270
+ * @param bool $is_exact_search
271
+ * @param IToolset_Relationship_Role $for_role
272
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
273
+ *
274
+ * @return IToolset_Association_Query_Condition
275
+ */
276
+ public function search(
277
+ $search_string,
278
+ $is_exact_search,
279
+ IToolset_Relationship_Role $for_role,
280
+ Toolset_Association_Query_Table_Join_Manager $join_manager
281
+ ) {
282
+ return new Toolset_Association_Query_Condition_Search(
283
+ $search_string, $is_exact_search, $for_role, $join_manager
284
+ );
285
+ }
286
+
287
+
288
+ /**
289
+ * @param int $association_id
290
+ *
291
+ * @return IToolset_Association_Query_Condition
292
+ */
293
+ public function association_id( $association_id ) {
294
+ return new Toolset_Association_Query_Condition_Association_Id( $association_id );
295
+ }
296
+
297
+
298
+ /**
299
+ * @param string $meta_key
300
+ * @param string $meta_value
301
+ * @param string $comparison_operator
302
+ * @param IToolset_Relationship_Role $for_role
303
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
304
+ *
305
+ * @return Toolset_Association_Query_Condition_Postmeta
306
+ */
307
+ public function postmeta(
308
+ $meta_key,
309
+ $meta_value,
310
+ $comparison_operator,
311
+ IToolset_Relationship_Role $for_role,
312
+ Toolset_Association_Query_Table_Join_Manager $join_manager
313
+ ) {
314
+ return new Toolset_Association_Query_Condition_Postmeta(
315
+ $meta_key,
316
+ $meta_value,
317
+ $comparison_operator,
318
+ $for_role,
319
+ $join_manager
320
+ );
321
+ }
322
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/element_selector/abstract.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Shared functionality for all element selector implementations.
5
+ *
6
+ * @since 2.5.10
7
+ */
8
+ abstract class Toolset_Association_Query_Element_Selector_Abstract
9
+ implements IToolset_Association_Query_Element_Selector
10
+ {
11
+
12
+ /** @var Toolset_Relationship_Database_Operations */
13
+ protected $database_operations;
14
+
15
+
16
+ /** @var Toolset_Relationship_Database_Unique_Table_Alias */
17
+ protected $table_alias;
18
+
19
+
20
+ /** @var Toolset_Association_Query_Table_Join_Manager */
21
+ protected $join_manager;
22
+
23
+
24
+ /** @var wpdb */
25
+ protected $wpdb;
26
+
27
+
28
+ /** @var Toolset_WPML_Compatibility */
29
+ protected $wpml_service;
30
+
31
+
32
+ /** @var IToolset_Relationship_Role[] */
33
+ protected $requested_roles = array();
34
+
35
+
36
+ /**
37
+ * Toolset_Association_Query_Element_Selector_Abstract constructor.
38
+ *
39
+ * @param Toolset_Relationship_Database_Unique_Table_Alias $table_alias
40
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
41
+ * @param wpdb|null $wpdb_di
42
+ * @param Toolset_Relationship_Database_Operations|null $database_operations_di
43
+ * @param Toolset_WPML_Compatibility|null $wpml_compatibility_di
44
+ */
45
+ public function __construct(
46
+ Toolset_Relationship_Database_Unique_Table_Alias $table_alias,
47
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
48
+ wpdb $wpdb_di = null,
49
+ Toolset_Relationship_Database_Operations $database_operations_di = null,
50
+ Toolset_WPML_Compatibility $wpml_compatibility_di = null
51
+ ) {
52
+ $this->table_alias = $table_alias;
53
+ $this->join_manager = $join_manager;
54
+
55
+ $this->database_operations = ( null === $database_operations_di ? new Toolset_Relationship_Database_Operations() : $database_operations_di );
56
+ $this->wpml_service = ( null === $wpml_compatibility_di ? Toolset_WPML_Compatibility::get_instance() : $wpml_compatibility_di );
57
+
58
+ global $wpdb;
59
+ $this->wpdb = ( null === $wpdb_di ? $wpdb : $wpdb_di );
60
+ }
61
+
62
+
63
+ /**
64
+ * @inheritdoc
65
+ */
66
+ public function initialize() {
67
+ // Nothing to do here.
68
+ }
69
+
70
+
71
+ /**
72
+ * Get the element ID column name of the associations table.
73
+ *
74
+ * @param IToolset_Relationship_Role $for_role
75
+ *
76
+ * @return string
77
+ */
78
+ protected function get_id_column( IToolset_Relationship_Role $for_role ) {
79
+ return $this->database_operations->role_to_column(
80
+ $for_role, Toolset_Relationship_Database_Operations::COLUMN_ID
81
+ );
82
+ }
83
+
84
+
85
+ /**
86
+ * @inheritdoc
87
+ *
88
+ * @param IToolset_Relationship_Role $role
89
+ */
90
+ public function request_element_in_results( IToolset_Relationship_Role $role ) {
91
+ $this->requested_roles[ $role->get_name() ] = $role;
92
+ }
93
+
94
+
95
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/element_selector/default.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Trivial element selector that works in the standard mode,
5
+ * if there is no need to translate anything.
6
+ *
7
+ * @since 2.5.10
8
+ */
9
+ class Toolset_Association_Query_Element_Selector_Default
10
+ extends Toolset_Association_Query_Element_Selector_Abstract {
11
+
12
+
13
+ /**
14
+ * @inheritdoc
15
+ *
16
+ * @param IToolset_Relationship_Role $for_role
17
+ * @param bool $translate_if_possible
18
+ *
19
+ * @return string
20
+ */
21
+ public function get_element_id_alias(
22
+ IToolset_Relationship_Role $for_role, $translate_if_possible = true
23
+ ) {
24
+ return $this->get_id_column( $for_role );
25
+ }
26
+
27
+
28
+ /**
29
+ * @inheritdoc
30
+ *
31
+ * @param IToolset_Relationship_Role $for_role
32
+ * @param bool $translate_if_possible
33
+ *
34
+ * @return string
35
+ */
36
+ public function get_element_id_value(
37
+ IToolset_Relationship_Role $for_role, $translate_if_possible = true
38
+ ) {
39
+ return $this->get_element_id_alias( $for_role );
40
+ }
41
+
42
+
43
+ /**
44
+ * @inheritdoc
45
+ *
46
+ * @return string
47
+ */
48
+ public function get_select_clauses() {
49
+ $results = array();
50
+ foreach( $this->requested_roles as $role ) {
51
+ $results[] = $this->get_select_clause_for_role( $role );
52
+ }
53
+
54
+ return ' ' . implode( ', ', $results ) . ' ';
55
+ }
56
+
57
+
58
+ /**
59
+ * Generate a SELECT clause for a single role.
60
+ *
61
+ * @param IToolset_Relationship_Role $for_role
62
+ *
63
+ * @return string
64
+ */
65
+ protected function get_select_clause_for_role( IToolset_Relationship_Role $for_role ) {
66
+ return sprintf(
67
+ 'associations.%s AS %s',
68
+ $this->get_id_column( $for_role ),
69
+ $this->get_element_id_alias( $for_role )
70
+ );
71
+ }
72
+
73
+
74
+ /**
75
+ * @inheritdoc
76
+ *
77
+ * @return string
78
+ */
79
+ public function get_join_clauses() {
80
+ return '';
81
+ }
82
+
83
+
84
+ /**
85
+ * Tell whether there may be a different element ID value for the current and the default language.
86
+ *
87
+ * @param IToolset_Relationship_Role $role
88
+ *
89
+ * @return mixed
90
+ */
91
+ public function has_element_id_translated( IToolset_Relationship_Role $role ) {
92
+ return false;
93
+ }
94
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/element_selector/interface.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Manages the way element IDs are obtained when building the MySQL query for associations.
5
+ *
6
+ * Generates SELECT clauses for the element IDs. Allows for injecting additional JOIN clauses
7
+ * into the final query.
8
+ *
9
+ * @since 2.5.10
10
+ */
11
+ interface IToolset_Association_Query_Element_Selector {
12
+
13
+
14
+ /**
15
+ * The element selector needs to be initialized early so that it can interact
16
+ * with the join manager object, if needed.
17
+ *
18
+ * See Toolset_Association_Query_Sql_Expression_Builder::build() for detailed information.
19
+ *
20
+ * @return void
21
+ */
22
+ public function initialize();
23
+
24
+
25
+ /**
26
+ * Get an alias for an element ID that will be used in the SELECT clause.
27
+ *
28
+ * @param IToolset_Relationship_Role $for_role
29
+ * @param bool $translate_if_possible
30
+ *
31
+ * @return string
32
+ */
33
+ public function get_element_id_alias(
34
+ IToolset_Relationship_Role $for_role, $translate_if_possible = true
35
+ );
36
+
37
+
38
+ /**
39
+ * Tell whether there may be a different element ID value for the current and the default language.
40
+ *
41
+ * @param IToolset_Relationship_Role $role
42
+ *
43
+ * @return mixed
44
+ */
45
+ public function has_element_id_translated( IToolset_Relationship_Role $role );
46
+
47
+
48
+ /**
49
+ * Get a name of the table and the column that contains an element ID.
50
+ *
51
+ * This is different from the alias because it can be used within the query itself
52
+ * for other purposes.
53
+ *
54
+ * @param IToolset_Relationship_Role $for_role
55
+ * @param bool $translate_if_possible
56
+ *
57
+ * @return string Unambiguous "column" or "table.column" that contains ID of the element.
58
+ */
59
+ public function get_element_id_value(
60
+ IToolset_Relationship_Role $for_role, $translate_if_possible = true
61
+ );
62
+
63
+
64
+ /**
65
+ * Get all the select clauses for all the element IDs.
66
+ *
67
+ * Individual clauses must be connected with a comma, but there must not be
68
+ * a trailing comma present.
69
+ *
70
+ * @return string
71
+ */
72
+ public function get_select_clauses();
73
+
74
+
75
+ /**
76
+ * Get all JOIN clauses that need to be included in the query.
77
+ *
78
+ * The only assumption these JOINs can make is that there might be the relationships table joined
79
+ * first (if the element selector requires it). Anything else coming from the join manager
80
+ * will be joined after.
81
+ *
82
+ * @return string
83
+ */
84
+ public function get_join_clauses();
85
+
86
+
87
+ /**
88
+ * @param IToolset_Relationship_Role $role
89
+ *
90
+ * @return void
91
+ */
92
+ public function request_element_in_results( IToolset_Relationship_Role $role );
93
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/element_selector/provider.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Provider for the element selector.
5
+ *
6
+ * It creates the correct one depending on the state of WPML and the current language
7
+ * and then keeps providing the same instance every time.
8
+ *
9
+ * Together with the restriction that condition classes must not use the element selector
10
+ * in their constructor, this allows us to inject this dependency to query conditions
11
+ * but wait until all conditions are instantiated before we decide which element selector
12
+ * to actually use.
13
+ *
14
+ * @since 2.5.10
15
+ */
16
+ class Toolset_Association_Query_Element_Selector_Provider {
17
+
18
+
19
+ const FILTER_WPML_SELECTOR = 'toolset_association_query_use_wpml_element_selector';
20
+
21
+
22
+ /** @var Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured */
23
+ private $is_wpml_active;
24
+
25
+
26
+ /** @var Toolset_Condition_Plugin_Wpml_Is_Current_Language_Default */
27
+ private $is_current_language_default;
28
+
29
+
30
+ /** @var IToolset_Association_Query_Element_Selector|null */
31
+ private $selector;
32
+
33
+
34
+ /**
35
+ * Toolset_Association_Query_Element_Selector_Provider constructor.
36
+ *
37
+ * @param Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured|null $is_wpml_active_di
38
+ * @param Toolset_Condition_Plugin_Wpml_Is_Current_Language_Default|null $is_current_language_default_di
39
+ */
40
+ public function __construct(
41
+ Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured $is_wpml_active_di = null,
42
+ Toolset_Condition_Plugin_Wpml_Is_Current_Language_Default $is_current_language_default_di = null
43
+ ) {
44
+ $this->is_wpml_active = ( null === $is_wpml_active_di ? new Toolset_Condition_Plugin_Wpml_Is_Active_And_Configured() : $is_wpml_active_di );
45
+ $this->is_current_language_default = ( null === $is_current_language_default_di ? new Toolset_Condition_Plugin_Wpml_Is_Current_Language_Default() : $is_current_language_default_di );
46
+ }
47
+
48
+
49
+ /**
50
+ * Get the selector instance once it has been created.
51
+ *
52
+ * @return IToolset_Association_Query_Element_Selector|null
53
+ */
54
+ public function get_selector() {
55
+ return $this->selector;
56
+ }
57
+
58
+
59
+ /**
60
+ * Create an appropriate element selector.
61
+ *
62
+ * This can be called only once.
63
+ *
64
+ * @param Toolset_Relationship_Database_Unique_Table_Alias $table_alias
65
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
66
+ * @param Toolset_Association_Query_V2 $query
67
+ *
68
+ * @return IToolset_Association_Query_Element_Selector
69
+ *
70
+ * @throws InvalidArgumentException
71
+ */
72
+ public function create_selector(
73
+ Toolset_Relationship_Database_Unique_Table_Alias $table_alias,
74
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
75
+ Toolset_Association_Query_V2 $query
76
+ ) {
77
+ if( null !== $this->selector ) {
78
+ throw new RuntimeException( 'Element selector for the association query has already been created.' );
79
+ }
80
+
81
+ $this->selector = $this->instantiate_selector( $table_alias, $join_manager, $query );
82
+
83
+ return $this->selector;
84
+ }
85
+
86
+
87
+ /**
88
+ * @param Toolset_Relationship_Database_Unique_Table_Alias $table_alias
89
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
90
+ * @param Toolset_Association_Query_V2 $query
91
+ * @return IToolset_Association_Query_Element_Selector
92
+ */
93
+ private function instantiate_selector(
94
+ Toolset_Relationship_Database_Unique_Table_Alias $table_alias,
95
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
96
+ Toolset_Association_Query_V2 $query
97
+ ) {
98
+ if(
99
+ $this->is_wpml_active->is_met()
100
+ && ! $this->is_current_language_default->is_met()
101
+ ) {
102
+ $use_wpml_selector = apply_filters( self::FILTER_WPML_SELECTOR, true, $query );
103
+
104
+ if( $use_wpml_selector ) {
105
+ return new Toolset_Association_Query_Element_Selector_Wpml( $table_alias, $join_manager );
106
+ }
107
+ }
108
+
109
+ return new Toolset_Association_Query_Element_Selector_Default( $table_alias, $join_manager );
110
+ }
111
+
112
+
113
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/element_selector/wpml.php ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Element selector that translates post elements and chooses the best element ID
5
+ * (the translated one, but defaults to the original if the translation doesn't exist).
6
+ *
7
+ * @since 2.5.10
8
+ */
9
+ class Toolset_Association_Query_Element_Selector_Wpml
10
+ extends Toolset_Association_Query_Element_Selector_Abstract {
11
+
12
+
13
+ /** @var bool */
14
+ private $is_ready = false;
15
+
16
+
17
+ /** @var string[] Indexed by role names. */
18
+ private $select_clauses = array();
19
+
20
+
21
+ /** @var string[] Indexed by role names. */
22
+ private $join_clauses = array();
23
+
24
+
25
+ /**
26
+ * @var string[] Aliases for original element IDs that will be used in the SELECT clause.
27
+ * Indexed by role names.
28
+ */
29
+ private $original_element_id_select_aliases = array();
30
+
31
+
32
+ /**
33
+ * @var string[] Unambiguous column names for original element IDs that can be used
34
+ * within the rest of the MySQL query. Indexed by role names.
35
+ */
36
+ private $original_element_id_values = array();
37
+
38
+
39
+ /**
40
+ * @var string[] Aliases for translated element IDs that will be used in the SELECT clause.
41
+ * Indexed by role names.
42
+ */
43
+ private $translated_element_id_select_aliases = array();
44
+
45
+
46
+ /**
47
+ * @var string[] Expressions for translated element IDs that can be used
48
+ * within the rest of the MySQL query. Indexed by role names.
49
+ */
50
+ private $translated_element_id_values = array();
51
+
52
+
53
+ /** @var IToolset_Relationship_Role[] */
54
+ private $requested_roles_in_join = array();
55
+
56
+
57
+ /**
58
+ * @inheritdoc
59
+ */
60
+ public function initialize() {
61
+ if( $this->is_ready ) {
62
+ return;
63
+ }
64
+
65
+ foreach( Toolset_Relationship_Role::all() as $role ) {
66
+ $this->build_data_for_role( $role );
67
+ }
68
+
69
+ $this->is_ready = true;
70
+ }
71
+
72
+
73
+ /**
74
+ * Build all parts of the query and other values needed for a single element role.
75
+ *
76
+ * @param IToolset_Relationship_Role $for_role
77
+ */
78
+ private function build_data_for_role( IToolset_Relationship_Role $for_role ) {
79
+
80
+ // This is hardcoded across the association query classes.
81
+ $association_alias = 'associations';
82
+
83
+ $element_id_column = $this->get_id_column( $for_role );
84
+
85
+ // Require the JOIN of the relationships table.
86
+ $relationships_table_alias = $this->join_manager->relationships();
87
+
88
+ // Make sure that we translate only posts.
89
+ // No check for the intermediary ID because those are always posts by definition.
90
+ if( $for_role->is_parent_child() ) {
91
+ $element_domain_column = $this->database_operations->role_to_column(
92
+ $for_role, Toolset_Relationship_Database_Operations::COLUMN_DOMAIN
93
+ );
94
+ $posts_domain = esc_sql( Toolset_Element_Domain::POSTS );
95
+ // Note: Must end with "AND" so that another query can be concatenated immediately after.
96
+ $domain_query = "$relationships_table_alias.$element_domain_column = '$posts_domain' AND";
97
+ } else {
98
+ $domain_query = "";
99
+ }
100
+
101
+ $original_element_id_alias = 'original_' . $element_id_column;
102
+
103
+ // This is, however, usable only for the final SELECT clause as it will not an alias for
104
+ // an existing column, but for a COALESCE() result.
105
+ $translated_element_id_alias = 'translated_' . $element_id_column;
106
+
107
+ // Generate safe aliases for the icl_translations table.
108
+ // We need to JOIN it twice to get from the original element ID to the translated one.
109
+ $icl_translations = $this->wpdb->prefix . 'icl_translations';
110
+ $icl_translations_for_original = $this->table_alias->generate( $icl_translations, true );
111
+ $icl_translations_for_translation = $this->table_alias->generate( $icl_translations, true );
112
+
113
+ $current_language = esc_sql( $this->wpml_service->get_current_language() );
114
+
115
+ // Generate expressions with element IDs. The translated one will default to the original
116
+ // if no translation is available. This will be also extremely important for domains different
117
+ // than posts.
118
+ $translated_or_original_element_id = "COALESCE(
119
+ $icl_translations_for_translation.element_id, $association_alias.$element_id_column
120
+ )";
121
+ $original_element_id = "$association_alias.$element_id_column";
122
+
123
+ $this->select_clauses[ $for_role->get_name() ] =
124
+ "$original_element_id AS $original_element_id_alias,
125
+ $translated_or_original_element_id AS $translated_element_id_alias";
126
+
127
+ // LEFT joins are extremely important here.
128
+ $this->join_clauses[ $for_role->get_name() ] =
129
+ "LEFT JOIN $icl_translations AS $icl_translations_for_original
130
+ ON (
131
+ $domain_query
132
+ $icl_translations_for_original.element_id = $original_element_id
133
+ AND $icl_translations_for_original.element_type LIKE 'post_%'
134
+ )
135
+ LEFT JOIN $icl_translations AS $icl_translations_for_translation
136
+ ON (
137
+ $icl_translations_for_original.trid = $icl_translations_for_translation.trid
138
+ AND $icl_translations_for_translation.language_code = '$current_language'
139
+ )";
140
+
141
+ $this->original_element_id_select_aliases[ $for_role->get_name() ] = $original_element_id_alias;
142
+ $this->original_element_id_values[ $for_role->get_name() ] = $original_element_id;
143
+ $this->translated_element_id_select_aliases[ $for_role->get_name() ] = $translated_element_id_alias;
144
+ $this->translated_element_id_values[ $for_role->get_name() ] = $translated_or_original_element_id;
145
+ }
146
+
147
+
148
+ /**
149
+ * @inheritdoc
150
+ *
151
+ * @param IToolset_Relationship_Role $for_role
152
+ * @param bool $translate_if_possible
153
+ *
154
+ * @return string
155
+ */
156
+ public function get_element_id_alias(
157
+ IToolset_Relationship_Role $for_role, $translate_if_possible = true
158
+ ) {
159
+ $this->initialize();
160
+ $this->request_element_in_results( $for_role );
161
+
162
+ if( $translate_if_possible ) {
163
+ return $this->translated_element_id_select_aliases[ $for_role->get_name() ];
164
+ } else {
165
+ return $this->original_element_id_select_aliases[ $for_role->get_name() ];
166
+ }
167
+ }
168
+
169
+
170
+ /**
171
+ * @inheritdoc
172
+ *
173
+ * @param IToolset_Relationship_Role $for_role
174
+ * @param bool $translate_if_possible
175
+ *
176
+ * @return string
177
+ */
178
+ public function get_element_id_value(
179
+ IToolset_Relationship_Role $for_role, $translate_if_possible = true
180
+ ) {
181
+ $this->initialize();
182
+
183
+ // The element value is used only within the query itself, but not within the SELECT clause.
184
+ $this->request_element_in_join_only( $for_role );
185
+
186
+ if( $translate_if_possible ) {
187
+ return $this->translated_element_id_values[ $for_role->get_name() ];
188
+ } else {
189
+ return $this->original_element_id_values[ $for_role->get_name() ];
190
+ }
191
+ }
192
+
193
+
194
+ /**
195
+ * @inheritdoc
196
+ *
197
+ * @return string
198
+ */
199
+ public function get_join_clauses() {
200
+ $this->initialize();
201
+
202
+ $requested_join_clauses = array();
203
+ foreach( $this->requested_roles_in_join as $role ) {
204
+ $requested_join_clauses[] = $this->join_clauses[ $role->get_name() ];
205
+ }
206
+ return ' ' . implode( ' ', $requested_join_clauses ) . ' ';
207
+ }
208
+
209
+
210
+ /**
211
+ * @inheritdoc
212
+ *
213
+ * @return string
214
+ */
215
+ public function get_select_clauses() {
216
+ $this->initialize();
217
+
218
+ $requested_select_clauses = array();
219
+ foreach( $this->requested_roles as $role ) {
220
+ $requested_select_clauses[] = $this->select_clauses[ $role->get_name() ];
221
+ }
222
+ return ' ' . implode( ', ', $requested_select_clauses ) . ' ';
223
+ }
224
+
225
+
226
+ /**
227
+ * @inheritdoc
228
+ *
229
+ * @param IToolset_Relationship_Role $role
230
+ */
231
+ public function request_element_in_results( IToolset_Relationship_Role $role ) {
232
+ parent::request_element_in_results( $role );
233
+
234
+ // Make sure that requested elements in results are superset of those requested in JOINs.
235
+ $this->request_element_in_join_only( $role );
236
+ }
237
+
238
+
239
+ /**
240
+ * @param IToolset_Relationship_Role $role
241
+ */
242
+ public function request_element_in_join_only( IToolset_Relationship_Role $role ) {
243
+ $this->requested_roles_in_join[ $role->get_name() ] = $role;
244
+ }
245
+
246
+
247
+ /**
248
+ * Tell whether there may be a different element ID value for the current and the default language.
249
+ *
250
+ * @param IToolset_Relationship_Role $role
251
+ *
252
+ * @return mixed
253
+ */
254
+ public function has_element_id_translated( IToolset_Relationship_Role $role ) {
255
+ return true; // This can be optimized in the future.
256
+ }
257
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/orderby/abstract.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Shared functionality for most IToolset_Association_Query_Orderby classes.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ abstract class Toolset_Association_Query_Orderby implements IToolset_Association_Query_Orderby {
9
+
10
+
11
+ /** @var string */
12
+ protected $order = 'ASC';
13
+
14
+
15
+ /** @var Toolset_Association_Query_Table_Join_Manager */
16
+ protected $join_manager;
17
+
18
+
19
+ /**
20
+ * Toolset_Association_Query_Orderby constructor.
21
+ *
22
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
23
+ */
24
+ public function __construct( Toolset_Association_Query_Table_Join_Manager $join_manager ) {
25
+ $this->join_manager = $join_manager;
26
+ }
27
+
28
+
29
+ /**
30
+ * Set the direction of sorting.
31
+ *
32
+ * @param string $order 'ASC'|'DESC'
33
+ * @throws InvalidArgumentException
34
+ */
35
+ public function set_order( $order ) {
36
+ $normalized_value = strtoupper( $order );
37
+ if( ! in_array( $normalized_value, array( 'ASC', 'DESC' ), true ) ) {
38
+ throw new InvalidArgumentException( 'Invalid order value.' );
39
+ }
40
+
41
+ $this->order = $normalized_value;
42
+ }
43
+
44
+
45
+ /**
46
+ * @inheritdoc
47
+ */
48
+ public function register_joins() { }
49
+
50
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/orderby/interface.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface for objects that handle the ORDER BY clause when building the association query.
5
+ *
6
+ * A dedicated set of classes is needed because sometimes, this also involves joining additional tables.
7
+ *
8
+ * @since 2.5.8
9
+ */
10
+ interface IToolset_Association_Query_Orderby {
11
+
12
+
13
+ /**
14
+ * Set the order direction.
15
+ *
16
+ * @param string $order 'ASC'|'DESC'
17
+ * @return void
18
+ */
19
+ public function set_order( $order );
20
+
21
+
22
+ /**
23
+ * Build the ORDER BY clause (not including the "ORDER BY" keyword).
24
+ *
25
+ * @return string
26
+ */
27
+ public function get_orderby_clause();
28
+
29
+
30
+ /**
31
+ * If the class uses a join manager, request all needed joins now.
32
+ *
33
+ * @return void
34
+ */
35
+ public function register_joins();
36
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/orderby/nothing.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Don't order associations by anything.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Orderby_Nothing implements IToolset_Association_Query_Orderby {
9
+
10
+ public function get_orderby_clause() {
11
+ return '';
12
+ }
13
+
14
+ public function set_order( $order ) {
15
+ // Nothing to do here.
16
+ }
17
+
18
+ public function register_joins() {
19
+ // Nothing to do here.
20
+ }
21
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/orderby/postmeta.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Order associations by a postmeta value of an (post) element of given role.
5
+ *
6
+ * Note: Using this on an element of a wrong domain will exclude all associations from the results.
7
+ *
8
+ * @since 2.5.8
9
+ */
10
+ class Toolset_Association_Query_Orderby_Postmeta extends Toolset_Association_Query_Orderby {
11
+
12
+
13
+ /** @var IToolset_Relationship_Role */
14
+ private $for_role;
15
+
16
+
17
+ /** @var string */
18
+ private $meta_key;
19
+
20
+
21
+ /**
22
+ * If the metakey needs to be casted into a different type (UNSIGNED, DATE, ..)
23
+ *
24
+ * @var string
25
+ */
26
+ private $cast_to;
27
+
28
+
29
+ /**
30
+ * List of allowed casting types
31
+ *
32
+ * @var array
33
+ */
34
+ private $allowed_mysql_types = array( 'SIGNED', 'UNSIGNED', 'DATE', 'DATETIME', 'CHAR' );
35
+
36
+
37
+ /**
38
+ * Toolset_Association_Query_Orderby_Postmeta constructor.
39
+ *
40
+ * @param string $meta_key
41
+ * @param IToolset_Relationship_Role $role
42
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
43
+ * @param string $cast_to If the metakey needs to be casted into a different type
44
+ * @throws InvalidArgumentException
45
+ */
46
+ public function __construct(
47
+ $meta_key,
48
+ IToolset_Relationship_Role $role,
49
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
50
+ $cast_to = null
51
+ ) {
52
+ parent::__construct( $join_manager );
53
+
54
+ if ( ! is_string( $meta_key ) || empty( $meta_key ) ) {
55
+ throw new InvalidArgumentException();
56
+ }
57
+
58
+ $this->meta_key = $meta_key;
59
+ $this->for_role = $role;
60
+ if ( null !== $cast_to && ! in_array( strtoupper( $cast_to ), $this->allowed_mysql_types, true ) ) {
61
+ throw new InvalidArgumentException();
62
+ }
63
+ $this->cast_to = $cast_to;
64
+ }
65
+
66
+
67
+ /**
68
+ * @inheritdoc
69
+ */
70
+ public function register_joins() {
71
+ $this->join_manager->wp_postmeta( $this->for_role, $this->meta_key );
72
+ }
73
+
74
+
75
+ /**
76
+ * @inheritdoc
77
+ * @return string
78
+ */
79
+ public function get_orderby_clause() {
80
+ $postmeta_table_alias = $this->join_manager->wp_postmeta( $this->for_role, $this->meta_key );
81
+ if ( $this->cast_to ) {
82
+ return "CAST({$postmeta_table_alias}.meta_value AS {$this->cast_to}) {$this->order}";
83
+ } else {
84
+ return "{$postmeta_table_alias}.meta_value {$this->order}";
85
+ }
86
+ }
87
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/orderby/title.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Order associations by title of an element of given role.
5
+ *
6
+ * Note: Currently, only the posts domain is supported.
7
+ *
8
+ * Note: Ordering by intermediary posts will exclude associations that don't have one.
9
+ *
10
+ * @since 2.5.8
11
+ */
12
+ class Toolset_Association_Query_Orderby_Title extends Toolset_Association_Query_Orderby {
13
+
14
+
15
+ /** @var IToolset_Relationship_Role */
16
+ private $for_role;
17
+
18
+
19
+ /**
20
+ * Toolset_Association_Query_Orderby_Title constructor.
21
+ *
22
+ * @param IToolset_Relationship_Role $role
23
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
24
+ */
25
+ public function __construct(
26
+ IToolset_Relationship_Role $role,
27
+ Toolset_Association_Query_Table_Join_Manager $join_manager
28
+ ) {
29
+ parent::__construct( $join_manager );
30
+
31
+ $this->for_role = $role;
32
+ }
33
+
34
+
35
+ /**
36
+ * @inheritdoc
37
+ */
38
+ public function register_joins() {
39
+ $this->join_manager->wp_posts( $this->for_role );
40
+ }
41
+
42
+
43
+ /**
44
+ * @inheritdoc
45
+ * @return string
46
+ */
47
+ public function get_orderby_clause() {
48
+ $posts_table_alias = $this->join_manager->wp_posts( $this->for_role );
49
+
50
+ return "{$posts_table_alias}.post_title {$this->order}";
51
+ }
52
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/orderby_factory.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Factory for IToolset_Association_Query_Orderby.
5
+ */
6
+ class Toolset_Association_Query_Orderby_Factory {
7
+
8
+
9
+ /**
10
+ * @return IToolset_Association_Query_Orderby
11
+ */
12
+ public function nothing() {
13
+ return new Toolset_Association_Query_Orderby_Nothing();
14
+ }
15
+
16
+
17
+ /**
18
+ * @param IToolset_Relationship_Role $role
19
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
20
+ *
21
+ * @return IToolset_Association_Query_Orderby
22
+ */
23
+ public function title( IToolset_Relationship_Role $role, Toolset_Association_Query_Table_Join_Manager $join_manager ) {
24
+ return new Toolset_Association_Query_Orderby_Title( $role, $join_manager );
25
+ }
26
+
27
+
28
+ /**
29
+ * @param string $meta_key
30
+ * @param IToolset_Relationship_Role $role
31
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
32
+ * @param string|null $cast_to If the metakey needs to be casted into a different type
33
+ *
34
+ * @return IToolset_Association_Query_Orderby
35
+ */
36
+ public function postmeta( $meta_key, IToolset_Relationship_Role $role, Toolset_Association_Query_Table_Join_Manager $join_manager, $cast_to = null ) {
37
+ return new Toolset_Association_Query_Orderby_Postmeta( $meta_key, $role, $join_manager, $cast_to );
38
+ }
39
+
40
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/restriction/interface.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Represents an object that can restrict the association query in certain cases,
5
+ * making it less complex and more performant.
6
+ *
7
+ * Note: No implementation yet, but ideas:
8
+ * - disable the WPML version of element selector when it's not needed
9
+ * - the domain of all elements is known to be something non-translatable
10
+ * - the post types involved are all known and non-translatable
11
+ * - if the above is true only for one role, make the element selector use the non-WPML way
12
+ * only for that role
13
+ * - etc.
14
+ *
15
+ * @since 2.5.10
16
+ */
17
+ interface IToolset_Association_Query_Restriction {
18
+
19
+
20
+ /**
21
+ * Apply the restrictions.
22
+ *
23
+ * @return void
24
+ */
25
+ public function apply();
26
+
27
+
28
+ /**
29
+ * Clear the restrictions after the query has been run.
30
+ *
31
+ * @return void
32
+ */
33
+ public function clear();
34
+
35
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/result_transformation/association_instance.php ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Transform association query results into instances of IToolset_Association.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Result_Transformation_Association_Instance
9
+ implements IToolset_Association_Query_Result_Transformation {
10
+
11
+
12
+ /** @var Toolset_Association_Translator */
13
+ private $association_translator;
14
+
15
+
16
+ private $wpml_service;
17
+
18
+
19
+ /**
20
+ * Toolset_Association_Query_Result_Transformation_Association_Instance constructor.
21
+ *
22
+ * @param Toolset_Association_Translator|null $association_translator_di
23
+ * @param Toolset_WPML_Compatibility|null $wpml_service
24
+ * @param Toolset_Condition_Plugin_Wpml_Is_Current_Language_Default|null $is_current_language_default_di
25
+ */
26
+ public function __construct(
27
+ Toolset_Association_Translator $association_translator_di = null,
28
+ Toolset_WPML_Compatibility $wpml_service = null,
29
+ Toolset_Condition_Plugin_Wpml_Is_Current_Language_Default $is_current_language_default_di = null
30
+ ) {
31
+ $this->wpml_service = ( null === $wpml_service ? Toolset_WPML_Compatibility::get_instance() : $wpml_service );
32
+ $this->association_translator = ( null === $association_translator_di ? new Toolset_Association_Translator() : $association_translator_di );
33
+ }
34
+
35
+
36
+ /**
37
+ * @inheritdoc
38
+ *
39
+ * @param object $database_row
40
+ *
41
+ * @return IToolset_Association
42
+ */
43
+ public function transform( $database_row, IToolset_Association_Query_Element_Selector $element_selector ) {
44
+
45
+ try {
46
+ if (
47
+ $this->wpml_service->is_wpml_active_and_configured()
48
+ && $this->wpml_service->get_current_language() !== $this->wpml_service->get_default_language()
49
+ ) {
50
+ // There's a chance of having element translations among the results. Let's try.
51
+ return $this->transform_with_wpml( $database_row, $element_selector );
52
+ }
53
+
54
+ return $this->transform_without_wpml( $database_row, $element_selector );
55
+ } catch( Toolset_Element_Exception_Element_Doesnt_Exist $e ) {
56
+ return null;
57
+ }
58
+ }
59
+
60
+
61
+ /**
62
+ * Transform the database row to an association instance if we know that there are no
63
+ * element translations involved.
64
+ *
65
+ * @param object $database_row
66
+ * @param IToolset_Association_Query_Element_Selector $element_selector
67
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
68
+ * @return IToolset_Association
69
+ */
70
+ private function transform_without_wpml( $database_row, IToolset_Association_Query_Element_Selector $element_selector ) {
71
+ $id_column_map = array();
72
+ foreach( Toolset_Relationship_Role::all() as $role ) {
73
+ $id_column_map[ $role->get_name() ] = $element_selector->get_element_id_alias( $role );
74
+ }
75
+
76
+ $association = $this->association_translator->from_database_row( $database_row, $id_column_map );
77
+
78
+ return $association;
79
+
80
+ }
81
+
82
+
83
+ /**
84
+ * Transform the database row to an association instance if there may be element translations.
85
+ *
86
+ * @param object $database_row
87
+ * @param IToolset_Association_Query_Element_Selector $element_selector
88
+ *
89
+ * @return IToolset_Association
90
+ */
91
+ private function transform_with_wpml( $database_row, IToolset_Association_Query_Element_Selector $element_selector ) {
92
+
93
+ // The map must contain: role --> language code --> name of the column with element ID.
94
+ $id_column_map = array();
95
+
96
+ foreach( Toolset_Relationship_Role::all() as $role ) {
97
+
98
+ $default_language = $this->wpml_service->get_default_language();
99
+ $default_language_element_id_alias = $element_selector->get_element_id_alias( $role, false );
100
+
101
+ if ( $element_selector->has_element_id_translated( $role ) ) {
102
+ $current_language = $this->wpml_service->get_current_language();
103
+ $current_language_element_id_alias = $element_selector->get_element_id_alias( $role, true );
104
+
105
+ if( $database_row->$current_language_element_id_alias !== $database_row->$default_language_element_id_alias ) {
106
+ // We finally have two different element IDs - the default language and its translation.
107
+ $id_column_map[ $role->get_name() ] = array(
108
+ $current_language => $current_language_element_id_alias,
109
+ $default_language => $default_language_element_id_alias
110
+ );
111
+ continue;
112
+ }
113
+ }
114
+
115
+ // If we fall through to this point, there is only one (default) language version.
116
+ $id_column_map[ $role->get_name() ] = array(
117
+ $default_language => $default_language_element_id_alias,
118
+ );
119
+ }
120
+
121
+ $association = $this->association_translator->from_translated_database_row(
122
+ $database_row, $id_column_map
123
+ );
124
+
125
+ return $association;
126
+
127
+ }
128
+
129
+
130
+ /**
131
+ * Talk to the element selector so that it includes only elements that are actually needed.
132
+ *
133
+ * @param IToolset_Association_Query_Element_Selector $element_selector
134
+ *
135
+ * @return void
136
+ * @since 2.5.10
137
+ */
138
+ public function request_element_selection( IToolset_Association_Query_Element_Selector $element_selector ) {
139
+ // Request all element IDs so that we can instantiate the association object.
140
+ foreach( Toolset_Relationship_Role::all() as $role ) {
141
+ $element_selector->request_element_in_results( $role );
142
+ }
143
+ }
144
+
145
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/result_transformation/association_uid.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Transform association query results into association UIDs.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Result_Transformation_Association_Uid
9
+ implements IToolset_Association_Query_Result_Transformation {
10
+
11
+
12
+ /**
13
+ * @inheritdoc
14
+ *
15
+ * @param object $database_row
16
+ *
17
+ * @return int
18
+ */
19
+ public function transform(
20
+ $database_row, IToolset_Association_Query_Element_Selector $element_selector
21
+ ) {
22
+ return (int) $database_row->id;
23
+ }
24
+
25
+
26
+ /**
27
+ * Talk to the element selector so that it includes only elements that are actually needed.
28
+ *
29
+ * @param IToolset_Association_Query_Element_Selector $element_selector
30
+ *
31
+ * @return void
32
+ * @since 2.5.10
33
+ */
34
+ public function request_element_selection( IToolset_Association_Query_Element_Selector $element_selector ) {
35
+ // Nothing to do here, as we're only returing the association UID and don't care
36
+ // about its elements.
37
+ }
38
+
39
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/result_transformation/element_id.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Transform association query results into element IDs of chosen role.
5
+ *
6
+ * @since 2.5.8
7
+ */
8
+ class Toolset_Association_Query_Result_Transformation_Element_Id
9
+ implements IToolset_Association_Query_Result_Transformation {
10
+
11
+
12
+ /** @var IToolset_Relationship_Role */
13
+ private $role;
14
+
15
+
16
+ /**
17
+ * Toolset_Association_Query_Result_Transformation_Element_Id constructor.
18
+ *
19
+ * @param IToolset_Relationship_Role $role
20
+ */
21
+ public function __construct( IToolset_Relationship_Role $role ) {
22
+ $this->role = $role;
23
+ }
24
+
25
+
26
+ /**
27
+ * @inheritdoc
28
+ *
29
+ * @param object $database_row
30
+ *
31
+ * @return int
32
+ */
33
+ public function transform(
34
+ $database_row, IToolset_Association_Query_Element_Selector $element_selector
35
+ ) {
36
+ $column_name = $element_selector->get_element_id_alias( $this->role );
37
+ return (int) $database_row->$column_name;
38
+ }
39
+
40
+
41
+ /**
42
+ * Talk to the element selector so that it includes only elements that are actually needed.
43
+ *
44
+ * @param IToolset_Association_Query_Element_Selector $element_selector
45
+ *
46
+ * @since 2.5.10
47
+ */
48
+ public function request_element_selection( IToolset_Association_Query_Element_Selector $element_selector ) {
49
+ // We need only one element here.
50
+ $element_selector->request_element_in_results( $this->role );
51
+ }
52
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/result_transformation/element_instance.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Transform association query results into instances of elements of the chosen role.
5
+ *
6
+ * Note: At the moment, only the posts domain is supported.
7
+ *
8
+ * @since 2.5.8
9
+ */
10
+ class Toolset_Association_Query_Result_Transformation_Element_Instance
11
+ implements IToolset_Association_Query_Result_Transformation {
12
+
13
+
14
+ /** @var IToolset_Relationship_Role */
15
+ private $role;
16
+
17
+
18
+ /** @var Toolset_Element_Factory */
19
+ private $element_factory;
20
+
21
+
22
+ private $wpml_service;
23
+
24
+
25
+ /**
26
+ * Toolset_Association_Query_Result_Transformation_Element_Instance constructor.
27
+ *
28
+ * @param IToolset_Relationship_Role $role
29
+ * @param Toolset_Element_Factory|null $element_factory_di
30
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
31
+ */
32
+ public function __construct(
33
+ IToolset_Relationship_Role $role,
34
+ Toolset_Element_Factory $element_factory_di = null,
35
+ Toolset_WPML_Compatibility $wpml_service_di = null
36
+ ) {
37
+ $this->role = $role;
38
+ $this->wpml_service = ( null === $wpml_service_di ? Toolset_WPML_Compatibility::get_instance() : $wpml_service_di );
39
+ $this->element_factory = ( null === $element_factory_di ? new Toolset_Element_Factory() : $element_factory_di );
40
+ }
41
+
42
+
43
+ /**
44
+ * @inheritdoc
45
+ *
46
+ * Note: This will require some adjustments when other element domains are supported.
47
+ * The best course will be to instruct $element_selector to also include the relationships
48
+ * table in request_element_selection() and then obtain the domain information from there.
49
+ *
50
+ * @param object $database_row
51
+ * @return IToolset_Element
52
+ */
53
+ public function transform(
54
+ $database_row, IToolset_Association_Query_Element_Selector $element_selector
55
+ ) {
56
+ if(
57
+ $this->wpml_service->is_wpml_active_and_configured()
58
+ && $element_selector->has_element_id_translated( $this->role )
59
+ && $this->wpml_service->get_current_language() !== $this->wpml_service->get_default_language()
60
+ ) {
61
+ // There's a chance of getting two language versions of the element, let's try.
62
+ return $this->transform_with_wpml( $database_row, $element_selector );
63
+ }
64
+
65
+ $element_id = $this->get_element_id( $database_row, $element_selector, true );
66
+ return $this->element_factory->get_element( Toolset_Element_Domain::POSTS, $element_id );
67
+ }
68
+
69
+
70
+ /**
71
+ * Determine if the desired element has two language versions and if it does,
72
+ * pass both of them to the factory object when instantiating the IToolset_Element model.
73
+ *
74
+ * @param object $database_row
75
+ * @param IToolset_Association_Query_Element_Selector $element_selector
76
+ *
77
+ * @return IToolset_Element
78
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
79
+ */
80
+ private function transform_with_wpml(
81
+ $database_row, IToolset_Association_Query_Element_Selector $element_selector
82
+ ) {
83
+ $default_language_element_id = $this->get_element_id( $database_row, $element_selector, false );
84
+ $current_language_element_id = $this->get_element_id( $database_row, $element_selector, true );
85
+
86
+ if( $current_language_element_id === $default_language_element_id ) {
87
+ // Only a default language is available.
88
+ return $this->element_factory->get_element( Toolset_Element_Domain::POSTS, $current_language_element_id );
89
+ }
90
+
91
+ $element_ids = array(
92
+ $this->wpml_service->get_default_language() => $default_language_element_id,
93
+ $this->wpml_service->get_current_language() => $current_language_element_id
94
+ );
95
+
96
+ return $this->element_factory->get_element( Toolset_Element_Domain::POSTS, $element_ids );
97
+ }
98
+
99
+
100
+ /**
101
+ * Read an element ID from the database row.
102
+ *
103
+ * @param object $database_row
104
+ * @param IToolset_Association_Query_Element_Selector $element_selector
105
+ * @param bool $translate_if_possible Use the default language version or try using a translation?
106
+ *
107
+ * @return mixed
108
+ */
109
+ private function get_element_id(
110
+ $database_row, IToolset_Association_Query_Element_Selector $element_selector, $translate_if_possible
111
+ ) {
112
+ $column_name = $element_selector->get_element_id_alias( $this->role, $translate_if_possible );
113
+ return $database_row->$column_name;
114
+ }
115
+
116
+
117
+ /**
118
+ * Talk to the element selector so that it includes only elements that are actually needed.
119
+ *
120
+ * @param IToolset_Association_Query_Element_Selector $element_selector
121
+ *
122
+ * @since 2.5.10
123
+ */
124
+ public function request_element_selection( IToolset_Association_Query_Element_Selector $element_selector ) {
125
+ // We need only one element here.
126
+ $element_selector->request_element_in_results( $this->role );
127
+ }
128
+
129
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/result_transformation/interface.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface IToolset_Association_Query_Result_Transformation
5
+ *
6
+ * Object that performs a transformation of a single database row from the
7
+ * association query into a the desired result.
8
+ *
9
+ * @since 2.5.8
10
+ */
11
+ interface IToolset_Association_Query_Result_Transformation {
12
+
13
+
14
+ /**
15
+ * @param object $database_row It is safe to expect only properties that are always
16
+ * preset in results of a query from Toolset_Association_Query_Sql_Expression_Builder.
17
+ *
18
+ * @param IToolset_Association_Query_Element_Selector $element_selector
19
+ *
20
+ * @return mixed
21
+ */
22
+ public function transform( $database_row, IToolset_Association_Query_Element_Selector $element_selector );
23
+
24
+
25
+ /**
26
+ * Talk to the element selector so that it includes only elements that are actually needed.
27
+ *
28
+ * @param IToolset_Association_Query_Element_Selector $element_selector
29
+ *
30
+ * @return void
31
+ * @since 2.5.10
32
+ */
33
+ public function request_element_selection( IToolset_Association_Query_Element_Selector $element_selector );
34
+
35
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/sql_expression_builder.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Builds the MySQL expression for the association query.
5
+ *
6
+ * @since 2.5.10
7
+ */
8
+ class Toolset_Association_Query_Sql_Expression_Builder {
9
+
10
+
11
+ /** @var Toolset_Relationship_Database_Operations */
12
+ private $database_operations;
13
+
14
+
15
+ /** @var Toolset_Relationship_Table_Name */
16
+ private $table_name;
17
+
18
+
19
+ /** @var Toolset_Association_Query_Table_Join_Manager */
20
+ private $join_manager;
21
+
22
+
23
+ /**
24
+ * Toolset_Relationship_Query_Sql_Expression_Builder constructor.
25
+ *
26
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
27
+ * @param Toolset_Relationship_Table_Name|null $table_name_di
28
+ * @param Toolset_Relationship_Database_Operations|null $database_operations_di
29
+ */
30
+ public function __construct(
31
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
32
+ Toolset_Relationship_Table_Name $table_name_di = null,
33
+ Toolset_Relationship_Database_Operations $database_operations_di = null
34
+ ) {
35
+ $this->table_name = ( null === $table_name_di ? new Toolset_Relationship_Table_Name() : $table_name_di );
36
+
37
+ $this->database_operations = (
38
+ null === $database_operations_di
39
+ ? new Toolset_Relationship_Database_Operations()
40
+ : $database_operations_di
41
+ );
42
+
43
+ $this->join_manager = $join_manager;
44
+ }
45
+
46
+
47
+ /**
48
+ * Build a complete MySQL query from the conditions.
49
+ *
50
+ * @param IToolset_Association_Query_Condition $root_condition
51
+ * @param int $offset
52
+ * @param int $limit
53
+ * @param IToolset_Association_Query_Orderby $orderby
54
+ * @param IToolset_Association_Query_Element_Selector $element_selector
55
+ * @param bool $need_found_rows
56
+ * @param IToolset_Association_Query_Result_Transformation $result_transformation
57
+ *
58
+ * @return string
59
+ */
60
+ public function build(
61
+ IToolset_Association_Query_Condition $root_condition,
62
+ $offset,
63
+ $limit,
64
+ IToolset_Association_Query_Orderby $orderby,
65
+ IToolset_Association_Query_Element_Selector $element_selector,
66
+ $need_found_rows,
67
+ IToolset_Association_Query_Result_Transformation $result_transformation
68
+ ) {
69
+
70
+ $associations_table = $this->table_name->association_table();
71
+
72
+ // Before building JOIN clauses, allow the ORDERBY builder also to add its own.
73
+ $orderby->register_joins();
74
+ // Same for the element selector. Otherwise the initialization would run
75
+ // from inside of $this->join_manager->get_join_clause() which is too late.
76
+ $element_selector->initialize();
77
+
78
+ // Conditions can either use the JOIN manager object to share JOINed tables
79
+ // or handle it entirely on their own. We need to get results from both sources here.
80
+ //
81
+ // Timing is extra important here: First, we get the JOIN clauses, so that the conditions
82
+ // can create table aliases that are later used when building the WHERE clauses.
83
+ //
84
+ // Then come ORDER BY clauses.
85
+ //
86
+ // Then we ask the result transformation object to talk to the element selector,
87
+ // and tell it which elements it will need in the select clause. This will
88
+ // influence the following step as well and can't be done later.
89
+ //
90
+ // Then we collect the JOIN clauses from the join manager object, which may have been used also
91
+ // when building the WHERE or ORDER BY clauses. This also includes JOINs coming from
92
+ // the element selector.
93
+ //
94
+ // Finally, we already know what we're going to need in the results and we can
95
+ // obtain the optimized select clauses from the element selector.
96
+ $join_clause = $root_condition->get_join_clause();
97
+ $where_clause = $root_condition->get_where_clause();
98
+ $orderby_clause = $orderby->get_orderby_clause();
99
+ $result_transformation->request_element_selection( $element_selector );
100
+ $join_clause = $this->join_manager->get_join_clause( $element_selector ) . ' ' . ' ' . $join_clause;
101
+ $select_elements = $element_selector->get_select_clauses();
102
+ // End of the timing-critical part.
103
+
104
+ $sql_found_rows = ( $need_found_rows ? 'SQL_CALC_FOUND_ROWS' : '' );
105
+ if( ! empty( $orderby_clause ) ) {
106
+ $orderby_clause = "ORDER BY $orderby_clause";
107
+ }
108
+
109
+ $limit = (int) $limit;
110
+ $offset = (int) $offset;
111
+
112
+ // Make sure we glue the pieces together well and leave no extra comma at the end
113
+ // in case $select_elements is empty.
114
+ $final_select_elements = array(
115
+ 'associations.id AS id',
116
+ 'associations.relationship_id AS relationship_id'
117
+ );
118
+ $select_elements_trimmed = trim( $select_elements );
119
+ if( ! empty( $select_elements_trimmed ) ) {
120
+ $final_select_elements[] = $select_elements;
121
+ }
122
+ $final_select_elements = implode( ', ' . PHP_EOL, $final_select_elements );
123
+
124
+ // We rely on all the moving parts which are supposed to have provided properly escaped strings.
125
+ $query = "
126
+ SELECT
127
+ {$sql_found_rows}
128
+ {$final_select_elements}
129
+ FROM {$associations_table} AS associations {$join_clause}
130
+ WHERE {$where_clause}
131
+ {$orderby_clause}
132
+ LIMIT {$limit}
133
+ OFFSET {$offset}";
134
+
135
+ return $query;
136
+ }
137
+
138
+
139
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/table_join_manager.php ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Manages JOIN clauses shared between different conditions within one association query.
5
+ *
6
+ * Use methods in this class to obtain aliases for the tables you need. By doing that,
7
+ * those tables will be added to the final JOIN clause. There is no risk of alias
8
+ * conflicts as long as all conditions use the same instance of
9
+ * Toolset_Relationship_Database_Unique_Table_Alias as is provided here in the constructor.
10
+ *
11
+ * @since 2.5.8
12
+ */
13
+ class Toolset_Association_Query_Table_Join_Manager {
14
+
15
+
16
+ /** @var Toolset_Relationship_Database_Unique_Table_Alias */
17
+ private $unique_table_alias;
18
+
19
+
20
+ /** @var wpdb */
21
+ private $wpdb;
22
+
23
+
24
+ /** @var Toolset_Relationship_Database_Operations */
25
+ private $database_operations;
26
+
27
+
28
+ /** @var Toolset_Relationship_Table_Name */
29
+ private $table_name;
30
+
31
+
32
+ /** @var string[] Mapping of role names to aliases of JOINed wp_posts table. */
33
+ private $registered_wp_posts_joins = array();
34
+
35
+
36
+ /** @var string[][] Mapping of role names and meta_keys to aliases of JOINed wp_postmeta table. */
37
+ private $registered_wp_postmeta_joins = array();
38
+
39
+
40
+ /** @var bool Flag indicating that a relationships table also needs to be JOINed. */
41
+ private $join_relationships = false;
42
+
43
+
44
+ /**
45
+ * Toolset_Association_Query_Table_Join_Manager constructor.
46
+ *
47
+ * @param Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias
48
+ * @param Toolset_Relationship_Database_Operations|null $database_operations_di
49
+ * @param Toolset_Relationship_Table_Name|null $table_name_di
50
+ * @param wpdb|null $wpdb_di
51
+ */
52
+ public function __construct(
53
+ Toolset_Relationship_Database_Unique_Table_Alias $unique_table_alias,
54
+ Toolset_Relationship_Database_Operations $database_operations_di = null,
55
+ Toolset_Relationship_Table_Name $table_name_di = null,
56
+ wpdb $wpdb_di = null
57
+ ) {
58
+ $this->unique_table_alias = $unique_table_alias;
59
+
60
+ if( null === $wpdb_di ) {
61
+ global $wpdb;
62
+ $this->wpdb = $wpdb;
63
+ } else {
64
+ $this->wpdb = $wpdb_di;
65
+ }
66
+
67
+ $this->database_operations = ( null === $database_operations_di ? new Toolset_Relationship_Database_Operations() : $database_operations_di );
68
+ $this->table_name = ( null === $table_name_di ? new Toolset_Relationship_Table_Name() : $table_name_di );
69
+ }
70
+
71
+
72
+ /**
73
+ * Get an alias for a wp_posts table JOINed on a particular element role.
74
+ *
75
+ * @param IToolset_Relationship_Role $for_role
76
+ * @return string Table alias.
77
+ */
78
+ public function wp_posts( IToolset_Relationship_Role $for_role ) {
79
+ if( ! array_key_exists( $for_role->get_name(), $this->registered_wp_posts_joins ) ) {
80
+ $table_alias = $this->unique_table_alias->generate( $this->wpdb->posts, true );
81
+ $this->registered_wp_posts_joins[ $for_role->get_name() ] = $table_alias;
82
+ }
83
+
84
+ return $this->registered_wp_posts_joins[ $for_role->get_name() ];
85
+ }
86
+
87
+
88
+ /**
89
+ * Get an alias for a wp_postmeta table JOINed on a particular element role and a meta_key value.
90
+ *
91
+ * This creates LEFT JOIN clauses, so that even with missing postmeta, the end results are not affected.
92
+ *
93
+ * @param IToolset_Relationship_Role $for_role
94
+ * @param string $meta_key
95
+ *
96
+ * @return string
97
+ * @throws InvalidArgumentException
98
+ */
99
+ public function wp_postmeta( IToolset_Relationship_Role $for_role, $meta_key ) {
100
+ if( ! is_string( $meta_key ) || empty( $meta_key ) ) {
101
+ throw new InvalidArgumentException();
102
+ }
103
+
104
+ $role_name = $for_role->get_name();
105
+
106
+ if(
107
+ null === toolset_getnest(
108
+ $this->registered_wp_postmeta_joins, array( $role_name, $meta_key ), null
109
+ )
110
+ ) {
111
+ $table_alias = $this->unique_table_alias->generate( $this->wpdb->postmeta, true );
112
+
113
+ if( ! isset( $this->registered_wp_postmeta_joins[ $role_name ] ) ) {
114
+ $this->registered_wp_postmeta_joins[ $role_name ] = array();
115
+ }
116
+
117
+ $this->registered_wp_postmeta_joins[ $role_name ][ $meta_key ] = $table_alias;
118
+ }
119
+
120
+ return $this->registered_wp_postmeta_joins[ $role_name ][ $meta_key ];
121
+ }
122
+
123
+
124
+ /**
125
+ * Get an alias for a relationships table JOINed on the relationships_id column.
126
+ *
127
+ * @return string
128
+ */
129
+ public function relationships() {
130
+ $this->join_relationships = true;
131
+ return 'relationships';
132
+ }
133
+
134
+
135
+ /**
136
+ * Build the final MySQL query part containing all requested JOIN clauses.
137
+ *
138
+ * @param IToolset_Association_Query_Element_Selector $element_selector
139
+ *
140
+ * @return string
141
+ */
142
+ public function get_join_clause( IToolset_Association_Query_Element_Selector $element_selector ) {
143
+
144
+ // The order of JOINing is very important here:
145
+ //
146
+ // The JOINs coming from the element selector might reference the relationships table.
147
+ //
148
+ // Any other JOINs will be most probably referencing the elements, so they
149
+ // must be added only after the JOINs from the element selector.
150
+ //
151
+ // However, we first resolve those additional joins and only after that add the joins
152
+ // from the element selector. This way, the element selector will know exactly what
153
+ // element roles it can skip entirely (and save a lot of database performance if we have
154
+ // WPML active).
155
+ $results = array();
156
+
157
+ // JOINs that come after the relationships table and element selector JOINs
158
+ // but need to be determined in advance.
159
+ $additional_joins = array();
160
+
161
+ if( $this->join_relationships ) {
162
+ $results[] = sprintf(
163
+ ' JOIN %s AS relationships ON ( associations.relationship_id = relationships.id ) ',
164
+ $this->table_name->relationship_table()
165
+ );
166
+ }
167
+
168
+ foreach( $this->registered_wp_posts_joins as $role_name => $table_alias ) {
169
+ $id_column_alias = $element_selector->get_element_id_value(
170
+ Toolset_Relationship_Role::role_from_name( $role_name )
171
+ );
172
+
173
+ $additional_joins[] = sprintf(
174
+ ' JOIN %s AS %s ON (%s.ID = %s) ',
175
+ $this->wpdb->posts,
176
+ $table_alias,
177
+ $table_alias,
178
+ $id_column_alias
179
+ );
180
+ }
181
+
182
+ foreach( $this->registered_wp_postmeta_joins as $role_name => $postmeta_list ) {
183
+ foreach( $postmeta_list as $meta_key => $table_alias ) {
184
+ $id_column_alias = $element_selector->get_element_id_value(
185
+ Toolset_Relationship_Role::role_from_name( $role_name )
186
+ );
187
+
188
+ $additional_joins[] = sprintf(
189
+ " LEFT JOIN %s AS %s ON (%s.post_id = %s AND %s.meta_key = '%s') ",
190
+ $this->wpdb->postmeta,
191
+ $table_alias,
192
+ $table_alias,
193
+ $id_column_alias,
194
+ $table_alias,
195
+ esc_sql( $meta_key )
196
+ );
197
+ }
198
+ }
199
+
200
+ $results[] = $element_selector->get_join_clauses();
201
+
202
+ // Append the additonal JOINs after the relationships table and tables
203
+ // for the element ID resolution.
204
+ $results = array_merge( $results, $additional_joins );
205
+
206
+ return ' ' . implode( "\n", $results ) . ' ';
207
+ }
208
+
209
+ }
vendor/toolset/toolset-common/inc/m2m/association/query/wpdb_wrapper.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A wrapper class around a wpdb instance that redirects all calls to it, and
5
+ * allows to use all its properties, but overrides the value of $wpdb->posts to return
6
+ * an alias instead, that is specific for a selected element role.
7
+ *
8
+ * This is being used by Toolset_Association_Query_Condition_Wp_Query, check it for more information.
9
+ *
10
+ * @since 2.5.8
11
+ */
12
+ class Toolset_Association_Query_Wpdb_Wrapper {
13
+
14
+
15
+ /** @var wpdb */
16
+ private $wpdb;
17
+
18
+
19
+ /** @var Toolset_Association_Query_Table_Join_Manager */
20
+ private $join_manager;
21
+
22
+
23
+ /** @var IToolset_Relationship_Role */
24
+ private $for_role;
25
+
26
+
27
+ /**
28
+ * Toolset_Association_Query_Wpdb_Wrapper constructor.
29
+ *
30
+ * @param wpdb $wpdb
31
+ * @param Toolset_Association_Query_Table_Join_Manager $join_manager
32
+ * @param IToolset_Relationship_Role $for_role
33
+ */
34
+ public function __construct(
35
+ wpdb $wpdb,
36
+ Toolset_Association_Query_Table_Join_Manager $join_manager,
37
+ IToolset_Relationship_Role $for_role
38
+ ) {
39
+ $this->wpdb = $wpdb;
40
+ $this->join_manager = $join_manager;
41
+ $this->for_role = $for_role;
42
+ }
43
+
44
+
45
+ /**
46
+ * Get a $wpdb property name.
47
+ *
48
+ * Override $wpdb->posts.
49
+ *
50
+ * @param string $property_name
51
+ * @return mixed
52
+ */
53
+ public function __get( $property_name ) {
54
+ if( 'posts' === $property_name ) {
55
+ return $this->join_manager->wp_posts( $this->for_role );
56
+ }
57
+
58
+ return $this->wpdb->{$property_name};
59
+ }
60
+
61
+
62
+ /**
63
+ * Implement empty() and isset() checks for $wpdb properties.
64
+ *
65
+ * @param string $property_name
66
+ * @return bool
67
+ */
68
+ public function __isset( $property_name ) {
69
+ return isset( $this->wpdb->{$property_name} );
70
+ }
71
+
72
+
73
+ /**
74
+ * Call a method on $wpdb.
75
+ *
76
+ * @param string $method_name
77
+ * @param array $arguments
78
+ * @return mixed
79
+ */
80
+ public function __call( $method_name, $arguments ) {
81
+ return call_user_func_array( array( $this->wpdb, $method_name ), $arguments );
82
+ }
83
+
84
+ }
vendor/toolset/toolset-common/inc/m2m/association/translator.php ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Translate the association data between the IToolset_Association model and a database row.
5
+ *
6
+ * @since 2.5.9
7
+ */
8
+ class Toolset_Association_Translator {
9
+
10
+ /** @var Toolset_Relationship_Definition_Repository|null */
11
+ private $_definition_repository;
12
+
13
+ /** @var Toolset_Association_Factory|null */
14
+ private $_association_factory;
15
+
16
+ /** @var null|Toolset_Element_Factory */
17
+ private $_element_factory;
18
+
19
+
20
+ /** @var Toolset_WPML_Compatibility */
21
+ private $wpml_service;
22
+
23
+
24
+ /**
25
+ * Toolset_Association_Translator constructor.
26
+ *
27
+ * @param Toolset_Relationship_Definition_Repository|null $definition_repository_di
28
+ * @param Toolset_Association_Factory|null $association_factory_di
29
+ * @param Toolset_Element_Factory|null $element_factory_di
30
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
31
+ */
32
+ public function __construct(
33
+ Toolset_Relationship_Definition_Repository $definition_repository_di = null,
34
+ Toolset_Association_Factory $association_factory_di = null,
35
+ Toolset_Element_Factory $element_factory_di = null,
36
+ Toolset_WPML_Compatibility $wpml_service_di = null
37
+ ) {
38
+ $this->_definition_repository = $definition_repository_di;
39
+ $this->_association_factory = $association_factory_di;
40
+ $this->wpml_service = ( null === $wpml_service_di ? Toolset_WPML_Compatibility::get_instance() : $wpml_service_di );
41
+ $this->_element_factory = $element_factory_di;
42
+ }
43
+
44
+
45
+ private function get_definition_repository() {
46
+ if( null === $this->_definition_repository ) {
47
+ $this->_definition_repository = Toolset_Relationship_Definition_Repository::get_instance();
48
+ }
49
+
50
+ return $this->_definition_repository;
51
+ }
52
+
53
+
54
+ private function get_association_factory() {
55
+ if( null === $this->_association_factory ) {
56
+ $this->_association_factory = new Toolset_Association_Factory();
57
+ }
58
+
59
+ return $this->_association_factory;
60
+ }
61
+
62
+
63
+
64
+ /** @noinspection PhpDocRedundantThrowsInspection */
65
+ /**
66
+ * @param object $database_row Object returned from the wpdb->get_results() query.
67
+ * @param null|array $id_column_map Allows for overriding the names of the columns used to
68
+ * access element IDs. If not null, this must contain a map of columns for all three roles.
69
+ *
70
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
71
+ * @return IToolset_Association
72
+ */
73
+ public function from_database_row( $database_row, $id_column_map = null ) {
74
+ $relationship_definition = $this->get_definition_repository()->get_definition_by_row_id( $database_row->relationship_id );
75
+
76
+ if( null === $id_column_map ) {
77
+ $id_column_map = array(
78
+ Toolset_Relationship_Role::PARENT => 'parent_id',
79
+ Toolset_Relationship_Role::CHILD => 'child_id',
80
+ Toolset_Relationship_Role::INTERMEDIARY => 'intermediary_id',
81
+ );
82
+ }
83
+
84
+ return $this->get_association_factory()->create(
85
+ $relationship_definition,
86
+ (int) $database_row->{$id_column_map[ Toolset_Relationship_Role::PARENT ]},
87
+ (int) $database_row->{$id_column_map[ Toolset_Relationship_Role::CHILD ]},
88
+ (int) $database_row->{$id_column_map[ Toolset_Relationship_Role::INTERMEDIARY ]},
89
+ (int) $database_row->id
90
+ );
91
+ }
92
+
93
+
94
+ /**
95
+ * Translate a database row to an association instance if element translations are available.
96
+ *
97
+ * @param object $database_row
98
+ * @param array $id_column_map Nested associative array with:
99
+ * role --> language code --> name of the column with the element ID.
100
+ * In the database row, the IDs may be zero for translated (non-default language) parent
101
+ * or child or any intermediary posts.
102
+ *
103
+ * @return IToolset_Association
104
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
105
+ */
106
+ public function from_translated_database_row( $database_row, $id_column_map ) {
107
+ $relationship_definition = $this->get_definition_repository()->get_definition_by_row_id( $database_row->relationship_id );
108
+
109
+ $association = $this->get_association_factory()->create(
110
+ $relationship_definition,
111
+ $this->get_element_in_all_languages( $database_row, $id_column_map, $relationship_definition, new Toolset_Relationship_Role_Parent() ),
112
+ $this->get_element_in_all_languages( $database_row, $id_column_map, $relationship_definition, new Toolset_Relationship_Role_Child() ),
113
+ $this->get_element_in_all_languages( $database_row, $id_column_map, $relationship_definition, new Toolset_Relationship_Role_Intermediary() ),
114
+ (int) $database_row->id
115
+ );
116
+
117
+ return $association;
118
+ }
119
+
120
+
121
+ /**
122
+ * Get an element which contains all the available language information.
123
+ *
124
+ * @param $database_row
125
+ * @param array $id_column_map Map as described in from_translated_database_row().
126
+ * @param IToolset_Relationship_Definition $relationship_definition
127
+ * @param IToolset_Relationship_Role $for_role
128
+ *
129
+ * @return IToolset_Element|IToolset_Post|int Zero can be returned if there is no
130
+ * intermediary post at all.
131
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
132
+ */
133
+ private function get_element_in_all_languages(
134
+ $database_row,
135
+ $id_column_map,
136
+ IToolset_Relationship_Definition $relationship_definition,
137
+ IToolset_Relationship_Role $for_role
138
+ ) {
139
+ $element_ids = array();
140
+ foreach( $id_column_map[ $for_role->get_name() ] as $language => $column ) {
141
+ $element_id = (int) $database_row->{$column};
142
+ if( 0 !== $element_id ) {
143
+ $element_ids[ $language ] = $element_id;
144
+ }
145
+ }
146
+
147
+ if( empty( $element_ids ) ) {
148
+ // This can happen for an intermediary post - no element to instantiate, and
149
+ // the association will survive.
150
+ return 0;
151
+ }
152
+
153
+ $element = $this->get_element_factory()->get_element(
154
+ $relationship_definition->get_element_type( $for_role )->get_domain(),
155
+ $element_ids
156
+ );
157
+
158
+ return $element;
159
+ }
160
+
161
+
162
+ /**
163
+ * @param IToolset_Association $association
164
+ * @throws RuntimeException
165
+ * @return array Database row as an associative array.
166
+ */
167
+ public function to_database_row( IToolset_Association $association ) {
168
+ $row = array(
169
+ 'relationship_id' => $association->get_definition()->get_row_id(),
170
+ 'parent_id' => $this->get_default_language_element_id( $association, new Toolset_Relationship_Role_Parent() ),
171
+ 'child_id' => $this->get_default_language_element_id( $association, new Toolset_Relationship_Role_Child() ),
172
+ 'intermediary_id' => $this->get_default_language_element_id( $association, new Toolset_Relationship_Role_Intermediary() ),
173
+ );
174
+
175
+ return $row;
176
+ }
177
+
178
+
179
+ /**
180
+ * Obtain an element ID from the association for the purpose of saving it into database.
181
+ *
182
+ * If WPML is active, load the elements and make sure we're getting the ID
183
+ * of the default language version of the element.
184
+ *
185
+ * @param IToolset_Association $association
186
+ * @param IToolset_Relationship_Role $role
187
+ * @throws RuntimeException
188
+ *
189
+ * @return int
190
+ */
191
+ private function get_default_language_element_id(
192
+ IToolset_Association $association,
193
+ IToolset_Relationship_Role $role
194
+ ) {
195
+ if( ! $this->wpml_service->is_wpml_active_and_configured() ) {
196
+ return $association->get_element_id( $role );
197
+ }
198
+
199
+ $element = $association->get_element( $role );
200
+
201
+ if( null === $element ) {
202
+ // Intermediary post.
203
+ return 0;
204
+ }
205
+
206
+ $translation = $element->translate( $this->wpml_service->get_default_language(), true );
207
+
208
+ if( null === $translation ) {
209
+ throw new RuntimeException(
210
+ 'The default language version of an element involved in an association is missing.'
211
+ );
212
+ }
213
+
214
+ return $translation->get_id();
215
+ }
216
+
217
+
218
+ /**
219
+ * @return string[] Column formats for columns as returned by to_database_row().
220
+ */
221
+ public function get_database_row_formats() {
222
+ return array( '%d', '%d', '%d', '%d' );
223
+ }
224
+
225
+
226
+ /**
227
+ * @return Toolset_Element_Factory
228
+ */
229
+ private function get_element_factory() {
230
+ if( null === $this->_element_factory ) {
231
+ $this->_element_factory = new Toolset_Element_Factory();
232
+ }
233
+
234
+ return $this->_element_factory;
235
+ }
236
+ }
vendor/toolset/toolset-common/inc/m2m/association_base.php DELETED
@@ -1,193 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Represents a single m2m association between two elements.
5
- *
6
- * Encapsulates the intermediary post and exposes only the generic API for working with association fields.
7
- *
8
- * There are two implementations, one is translation-aware and one is not.
9
- * Both are to be instantiated exclusively through Toolset_Association_Repository.
10
- *
11
- * @since m2m
12
- */
13
- abstract class Toolset_Association_Base implements IToolset_Association {
14
-
15
-
16
- /** @var Toolset_Relationship_Definition */
17
- private $relationship_definition;
18
-
19
- /** @var Toolset_Element[] Actual elements, loaded on demand. Use self::get_element() to obtain them. */
20
- protected $elements = array();
21
-
22
- /** @var int Translation group ID. */
23
- private $trid;
24
-
25
- /** @var null|IToolset_Post */
26
- protected $intermediary_post = null;
27
-
28
-
29
-
30
- /**
31
- * Toolset_Association_Base constructor.
32
- *
33
- * Note that no checks about elements with respect to the relationship definition are being performed here.
34
- * The caller needs to ensure everything is valid (domains, types, other conditions). This is handled well in the
35
- * association factory.
36
- *
37
- * @param int $trid Association translation ID (acting as an unique identifier).
38
- * @param Toolset_Relationship_Definition $relationship_definition
39
- * @throws InvalidArgumentException
40
- * @since m2m
41
- */
42
- public function __construct( $trid, Toolset_Relationship_Definition $relationship_definition ) {
43
-
44
- if( ! Toolset_Utils::is_natural_numeric( $trid ) ) {
45
- throw new InvalidArgumentException();
46
- }
47
-
48
- $this->relationship_definition = $relationship_definition;
49
-
50
- $this->trid = (int) $trid;
51
-
52
- }
53
-
54
-
55
- /**
56
- * @return Toolset_Relationship_Definition
57
- */
58
- public function get_definition() { return $this->relationship_definition; }
59
-
60
-
61
- /**
62
- * Get domain of selected association element.
63
- *
64
- * @param string $element_role
65
- *
66
- * @return string Valid domain name as defined in Toolset_Field_Utils.
67
- * @since m2m
68
- */
69
- protected function get_element_domain( $element_role ) {
70
- $relationship_definition = $this->get_definition();
71
- $element_type = $relationship_definition->get_element_type( $element_role );
72
- return $element_type->get_domain();
73
- }
74
-
75
-
76
- /**
77
- * Get an association element.
78
- *
79
- * Instantiates an element if it hasn't been done yet.
80
- *
81
- * @param string $element_role
82
- * @return Toolset_Element
83
- * @throws InvalidArgumentException
84
- * @since m2m
85
- */
86
- public abstract function get_element( $element_role );
87
-
88
-
89
- /**
90
- * Check that the element role is valid.
91
- *
92
- * @param string $element_role
93
- *
94
- * @throws InvalidArgumentException
95
- * @since m2m
96
- * todo get rid of this, move to the enum
97
- */
98
- public static function validate_element_role( $element_role ) {
99
- if( ! in_array( $element_role, Toolset_Relationship_Role::parent_child_role_names() ) ) {
100
- throw new InvalidArgumentException( 'Invalid element key.' );
101
- }
102
- }
103
-
104
-
105
- /**
106
- * Shortcut to the relationship driver.
107
- *
108
- * @return Toolset_Relationship_Driver_Base
109
- */
110
- public function get_driver() {
111
- $relationship_definition = $this->get_definition();
112
- return $relationship_definition->get_driver();
113
- }
114
-
115
-
116
- /**
117
- * Get the unique identifier for the association.
118
- *
119
- * We can use a trid which is unique per translation group (and per association if WPML is not active).
120
- * If there's another implementation of associations in the future, it needs to use a string,
121
- * perhaps with some sort of a prefix.
122
- *
123
- * @return int|string
124
- * @since m2m
125
- */
126
- public function get_uid() {
127
- return $this->trid;
128
- }
129
-
130
-
131
- /**
132
- * Get the translation group ID of the association.
133
- *
134
- * @return int Translation group ID or zero if not supported.
135
- */
136
- public function get_trid() {
137
- return $this->trid;
138
- }
139
-
140
-
141
- /**
142
- * Get the intermediary post if it exists.
143
- *
144
- * @return null|Toolset_Post
145
- */
146
- protected abstract function get_intermediary_post();
147
-
148
-
149
-
150
- /**
151
- * @inheritdoc
152
- *
153
- * This needs to be called (internally) before accessing the intermediary post object.
154
- *
155
- * @return bool
156
- * @since m2m
157
- */
158
- public function has_fields() {
159
-
160
- $intermediary_post = $this->get_intermediary_post();
161
-
162
- if ( null === $intermediary_post ) {
163
- return false;
164
- }
165
-
166
- return ( $this->intermediary_post->get_field_count() > 0 );
167
- }
168
-
169
-
170
- /**
171
- * @inheritdoc
172
- *
173
- * @param string|Toolset_Field_Definition $field_source
174
- * @return bool
175
- */
176
- public function has_field( $field_source ) {
177
- if( ! $this->has_fields() ) {
178
- return false;
179
- }
180
-
181
- return $this->intermediary_post->has_field( $field_source );
182
- }
183
-
184
-
185
- /**
186
- * @return bool
187
- * @since m2m
188
- */
189
- public function has_intermediary_post() {
190
- return ( null !== $this->get_intermediary_post() );
191
- }
192
-
193
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/toolset/toolset-common/inc/m2m/association_query.php DELETED
@@ -1,932 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * A class for querying associations and associated elements.
5
- *
6
- * Arguments:
7
- * todo document
8
- *
9
- * Usage:
10
- *
11
- * $query = new Toolset_Association_Query( $args );
12
- * $results = $query->get_results();
13
- *
14
- * Notes:
15
- *
16
- * - For now, it supports only the native associations (they're the only ones we have).
17
- * - If you need to query by some parameters that are not supported, either create a feature request about it or
18
- * submit a merge request rather than going around the query and touching the database directly.
19
- *
20
- *
21
- * @since m2m
22
- */
23
- class Toolset_Association_Query extends Toolset_Relationship_Query_Base {
24
-
25
- /** @var string One of the RETURN_* constants determining what kind of output should be provided. */
26
- private $return;
27
-
28
- /** @var bool */
29
- protected $dont_count_found_rows;
30
-
31
- const OPTION_USE_CACHED_RESULTS = 'use_cached_results';
32
- const OPTION_CACHE_RESULTS = 'cache_results';
33
- const OPTION_RETURN = 'return';
34
- const OPTION_DONT_COUNT_FOUND_ROWS = 'no_found_rows';
35
-
36
- const QUERY_OFFSET = 'offset';
37
- const QUERY_LIMIT = 'limit';
38
- const QUERY_SELECT_FIELDS = 'select_fields';
39
- const QUERY_RELATIONSHIP_SLUG = 'relationship_slug';
40
- const QUERY_RELATIONSHIP_ID = 'relationship_id';
41
- const QUERY_PARENT_ID = 'parent_id';
42
- const QUERY_CHILD_ID = 'child_id';
43
- const QUERY_HAS_FIELDS = 'has_fields';
44
- const QUERY_PARENT_DOMAIN = 'parent_domain';
45
- const QUERY_PARENT_QUERY = 'parent_query';
46
- const QUERY_CHILD_DOMAIN = 'child_domain';
47
- const QUERY_CHILD_QUERY = 'child_query';
48
- const QUERY_LANGUAGE = 'language';
49
- const QUERY_HAS_TRASHED_POSTS = 'has_trashed_posts';
50
-
51
- const RETURN_ASSOCIATION_IDS = 'association_ids';
52
- const RETURN_ASSOCIATIONS = 'associations';
53
- const RETURN_PARENT_IDS = 'parent_ids';
54
- const RETURN_CHILD_IDS = 'child_ids';
55
- const RETURN_PARENTS = 'parents';
56
- const RETURN_CHILDREN = 'children';
57
-
58
- const LANGUAGE_ALL = 'all';
59
-
60
- const GROUP_CONCAT_SEPARATOR = ',';
61
-
62
-
63
- /**
64
- * Parse query arguments, store them sanitized as options or in the $query_vars array.
65
- *
66
- * @param array $query
67
- */
68
- protected function parse_query( $query ) {
69
-
70
- $this->use_cached_results = (bool) toolset_getarr( $query, self::OPTION_USE_CACHED_RESULTS, true );
71
- $this->cache_results = (bool) toolset_getarr( $query, self::OPTION_CACHE_RESULTS, true );
72
- $this->return = toolset_getarr( $query, self::OPTION_RETURN, self::RETURN_ASSOCIATIONS, $this->get_return_options() );
73
- $this->dont_count_found_rows = (bool) toolset_getarr( $query, self::OPTION_DONT_COUNT_FOUND_ROWS, false );
74
-
75
- // Default value of these needs to be null
76
- $this->parse_query_arg( $query, self::QUERY_RELATIONSHIP_SLUG, 'strval' );
77
- $this->parse_query_arg( $query, self::QUERY_RELATIONSHIP_ID, 'absint' );
78
- $this->parse_query_arg( $query, self::QUERY_PARENT_ID, 'absint' );
79
- $this->parse_query_arg( $query, self::QUERY_CHILD_ID, 'absint' );
80
- $this->parse_query_arg( $query, self::QUERY_LIMIT, 'absint' );
81
- $this->parse_query_arg( $query, self::QUERY_OFFSET, 'absint' );
82
- $this->parse_query_arg( $query, self::QUERY_SELECT_FIELDS, null, array() );
83
- $this->parse_query_arg( $query, self::QUERY_HAS_FIELDS, 'boolval' );
84
- $this->parse_query_arg( $query, self::QUERY_PARENT_DOMAIN, null, null, array( Toolset_Field_Utils::DOMAIN_POSTS ) );
85
- $this->parse_query_arg( $query, self::QUERY_PARENT_QUERY, null ); // todo sanitize?
86
- $this->parse_query_arg( $query, self::QUERY_CHILD_DOMAIN, null, null, array( Toolset_Field_Utils::DOMAIN_POSTS ) );
87
- $this->parse_query_arg( $query, self::QUERY_CHILD_QUERY, null ); // todo sanitize?
88
- $this->parse_query_arg( $query, self::QUERY_HAS_TRASHED_POSTS, 'boolval' );
89
- }
90
-
91
-
92
- /**
93
- * Perform the query and get results.
94
- *
95
- * Depending on query arguments, the results may be cached.
96
- *
97
- * @return int[]|IToolset_Element[]|IToolset_Association[] Array of results, depending on query arguments.
98
- */
99
- public function get_results() {
100
- return parent::get_results();
101
- }
102
-
103
-
104
- protected function get_subject_name_for_cache() {
105
- return 'associations';
106
- }
107
-
108
-
109
- /**
110
- * Build the MySQL statement for querying the data, depending on query variables.
111
- *
112
- * @return string MySQL query statement.
113
- * @since m2m
114
- */
115
- protected function build_sql_statement() {
116
-
117
- global $wpdb;
118
-
119
- /// Condition clauses to be joined with AND.
120
- $where_clauses = array();
121
-
122
- $groupby_clauses = array();
123
- $orderby_clauses = array();
124
-
125
- // JOIN statements to be concatenated (they need to start with the JOIN keyword and have padding spaces).
126
- // The original table to be joined to is the associations one (as 'association').
127
- $join_clauses = array();
128
-
129
- $having_clauses = array();
130
-
131
- /// Setting this to true will result in joining the relationships table (as 'relationship').
132
- $join_relationships = false;
133
-
134
- /// If this is set to a column name, that column will be used as an post ID to join the wp_posts table
135
- /// (as 'wp_posts'). Empty string means that the join is not needed.
136
- $join_wp_posts_on = '';
137
-
138
- $association_table = Toolset_Relationship_Table_Name::associations();
139
-
140
- // If we have a query that is not specific to a particular language (association translation),
141
- // we can avoid the self-join on the association table because we'll always have the whole
142
- // translation group (same trid) in the results, or none of it.
143
- //
144
- // For example, when querying for a particular relationship slug, we know it isn't language-specific.
145
- // On the other hand, querying for a specific parent_id will always get us only a single row for each trid.
146
- //
147
- // In that case, we must do the self-join in order to retrieve the information for all the relevant languages.
148
- $has_language_specific_query = (
149
- $this->has_query_var( self::QUERY_LANGUAGE )
150
- && self::LANGUAGE_ALL != $this->get_query_var( self::QUERY_LANGUAGE )
151
- );
152
-
153
- // Process individual query arguments.
154
- //
155
- //
156
- if( $this->has_query_var( self::QUERY_RELATIONSHIP_SLUG ) ) {
157
- $relationship_slug = $this->get_query_var( self::QUERY_RELATIONSHIP_SLUG );
158
- $relationship = Toolset_Relationship_Utils::get_relationship_definition( $relationship_slug );
159
-
160
- if( null === $relationship ) {
161
- // This will cause the query to return no results, as there can be no associations
162
- // for a non-existent relationship.
163
- $relationship_id = 0;
164
- } else {
165
- $relationship_id = $relationship->get_row_id();
166
- }
167
-
168
- $where_clauses[] = $wpdb->prepare(
169
- "association.relationship_id = %d",
170
- $relationship_id
171
- );
172
- }
173
-
174
- if( $this->has_query_var( self::QUERY_RELATIONSHIP_ID ) ) {
175
- $relationship_id = $this->get_query_var( self::QUERY_RELATIONSHIP_ID );
176
-
177
- $where_clauses[] = $wpdb->prepare(
178
- "association.relationship_id = %d",
179
- $relationship_id
180
- );
181
- }
182
-
183
- if( $this->has_query_var( self::QUERY_PARENT_ID ) ) {
184
- $where_clauses[] = $wpdb->prepare(
185
- "parent_id = %d",
186
- $this->get_query_var( self::QUERY_PARENT_ID )
187
- );
188
-
189
- $has_language_specific_query = true;
190
- }
191
-
192
- if( $this->has_query_var( self::QUERY_HAS_TRASHED_POSTS ) ) {
193
- // Note: This is not very nice from the performance point of view, but it's only a hotfix.
194
- // The query class will go through a refactoring very soon.
195
- $join_clauses[] = " JOIN {$wpdb->posts} as wp_parent_post ON ( wp_parent_post.ID = association.parent_id ) ";
196
- $join_clauses[] = " JOIN {$wpdb->posts} as wp_child_post ON ( wp_child_post.ID = association.child_id ) ";
197
-
198
- $operator = ( $this->get_query_var( self::QUERY_HAS_TRASHED_POSTS ) ? '=' : '!=' );
199
- $where_clauses[] = "wp_parent_post.post_status $operator 'trash'";
200
- $where_clauses[] = "wp_child_post.post_status $operator 'trash'";
201
- }
202
-
203
- if( $this->has_query_var( self::QUERY_CHILD_ID ) ) {
204
- $where_clauses[] = $wpdb->prepare(
205
- "child_id = %d",
206
- $this->get_query_var( self::QUERY_CHILD_ID )
207
- );
208
-
209
- $has_language_specific_query = true;
210
- }
211
-
212
- // Query only associations of relationships that have fields (that means they have an intermediary post type).
213
- // todo we might want to handle a situation when an intermediary post type is modified to have no fields.
214
- if( $this->has_query_var( self::QUERY_HAS_FIELDS ) ) {
215
- $join_relationships = true;
216
- $hasnt_fields_comparison = ( $this->get_query_var( self::QUERY_HAS_FIELDS ) ? 'NOT LIKE' : 'LIKE' );
217
- $where_clauses[] = "relationship.intermediary_type {$hasnt_fields_comparison} ''";
218
- }
219
-
220
- if( $this->has_query_var( self::QUERY_PARENT_DOMAIN ) ) {
221
- $join_relationships = true;
222
- $where_clauses[] = $wpdb->prepare( 'relationship.parent_domain LIKE %s', $this->get_query_var( self::QUERY_PARENT_DOMAIN ) );
223
- }
224
-
225
- if( $this->has_query_var( self::QUERY_CHILD_DOMAIN ) ) {
226
- $join_relationships = true;
227
- $where_clauses[] = $wpdb->prepare( 'relationship.child_domain LIKE %s', $this->get_query_var( self::QUERY_CHILD_DOMAIN ) );
228
- }
229
-
230
- // Filter results by a native WordPress query run on child/parent posts.
231
- //
232
- // Since currently only post relationships are supported, we're always using WP_Query.
233
- // We will obtain the list of MySQL clauses and merge them into our statement without actually querying anything yet.
234
- // See get_wp_query_clauses() for the details.
235
- $has_parent_query = $this->has_query_var( self::QUERY_PARENT_QUERY );
236
- $has_child_query = $this->has_query_var( self::QUERY_CHILD_QUERY );
237
-
238
- if( $has_parent_query && $has_child_query ) {
239
- throw new RuntimeException( 'A assocation query cannot join parent and child on a single query.' );
240
- }
241
-
242
- if( $has_parent_query || $has_child_query ) {
243
- $query_role = $has_child_query
244
- ? self::QUERY_CHILD_QUERY
245
- : self::QUERY_PARENT_QUERY;
246
-
247
- $join_wp_posts_on = $has_child_query
248
- ? 'child_id'
249
- : 'parent_id';
250
-
251
- $query_role = toolset_ensarr( $this->get_query_var( $query_role ) );
252
-
253
- $clauses = $this->get_wp_query_clauses( $query_role );
254
-
255
- // Include additional clauses to the final query.
256
- //
257
- // This should be safe because in WP_Query everything is properly referenced by table names
258
- // and we're joining only custom Toolset tables and wp_posts.
259
- //
260
- // We're ignoring these clauses:
261
- // - fields: because we have a custom mechanism of selecting them
262
- // - limits: because those are overridden by offset and limit query args
263
-
264
- // These clauses start with 'AND'
265
- $where_clauses[] = ' 1 = 1 ' . $clauses['where'];
266
- if( ! empty( $clauses['groupby'] ) ) {
267
- $groupby_clauses[] = $clauses['groupby'];
268
- }
269
-
270
- if( ! empty( $clauses['join'] ) ) {
271
- $join_clauses[] = $clauses['join'];
272
- }
273
-
274
- if( ! empty( $clauses['orderby'] ) ) {
275
- $orderby_clauses[] = $clauses['orderby'];
276
- }
277
-
278
- // most probably yes
279
- $has_language_specific_query = true;
280
- }
281
-
282
-
283
- // Determine if we're going to look for translations or not.
284
- //
285
- // With WPML inactive, the expected behaviour is to ignore all language-related information.
286
- //
287
- // Note that with the "transitional" multilingual mode, we are ignoring language information
288
- // in the associations table, but it is there, and some association translations might have "holes"
289
- // in them (missing element IDs where the element is not translated to a particular language).
290
- // But at this point, we don't mind. It will be handled as a special case in postprocess_results().
291
- if( Toolset_Relationship_Multilingual_Mode::is_on() ) {
292
-
293
- if( $has_language_specific_query ) {
294
-
295
- // Handle the query for a specific language.
296
- //
297
- // We will query for a single row within each translation group, then join the results with the
298
- // association table again in order to get the information in all the languages we need.
299
- if( $this->has_query_var( self::QUERY_LANGUAGE ) ) {
300
- $preferred_language = $this->get_query_var( self::QUERY_LANGUAGE );
301
- } else {
302
- $preferred_language = Toolset_Wpml_Utils::get_current_language();
303
- }
304
-
305
- if( self::LANGUAGE_ALL != $preferred_language ) {
306
-
307
- // Limit the result only for languages we care about.
308
- //
309
- // That is: specified language (or the current language), default site language and the
310
- // original language of the association.
311
-
312
- $language_clauses = array(
313
- $wpdb->prepare( "translation.lang = %s", $preferred_language ),
314
- "translation.translation_type IN ('none', 'original')"
315
- );
316
-
317
- $default_language = Toolset_Wpml_Utils::get_default_language();
318
- if( $default_language !== $preferred_language ) {
319
- $language_clauses[] = $wpdb->prepare( "translation.lang = %s", $default_language );
320
- }
321
-
322
- $language_clauses = sprintf(
323
- 'AND ( %s )',
324
- implode( ' OR ', $language_clauses )
325
- );
326
-
327
- } else {
328
- // This happens when specifically querying for all languages but there's another
329
- // query argument which is language-specific.
330
- $language_clauses = '';
331
- }
332
-
333
- $join_clauses[] = "
334
- JOIN $association_table AS translation
335
- ON (
336
- association.trid = translation.trid
337
- $language_clauses
338
- )
339
- ";
340
-
341
- $groupby_table = 'translation';
342
-
343
- } else {
344
-
345
- // We're not doing the self-join (there's no need for it because the query is not language-specific),
346
- // so we're going to get the data from the associations table directly.
347
- $groupby_table = 'association';
348
- }
349
-
350
- $groupby_clauses[] = "$groupby_table.trid";
351
-
352
- // Prepare fields for the SELECT clause.
353
- //
354
- // In this case, we'll be concatenating results for all selected languages within a translation group
355
- // in order to be able to use OFFSET and LIMIT consistently (one row == one actual result).
356
- $sep = self::GROUP_CONCAT_SEPARATOR;
357
- $select_fields = array(
358
- 'trid' => "$groupby_table.trid",
359
- 'relationship_id' => "GROUP_CONCAT($groupby_table.relationship_id SEPARATOR '$sep')",
360
- 'association_id' => "GROUP_CONCAT($groupby_table.id SEPARATOR '$sep')",
361
- 'lang' => "GROUP_CONCAT($groupby_table.lang SEPARATOR '$sep')",
362
- 'parent_id' => "GROUP_CONCAT($groupby_table.parent_id SEPARATOR '$sep')",
363
- 'child_id' => "GROUP_CONCAT($groupby_table.child_id SEPARATOR '$sep')",
364
- 'intermediary_id' => "GROUP_CONCAT($groupby_table.intermediary_id SEPARATOR '$sep')",
365
- );
366
-
367
- } else {
368
-
369
- // The simplest case, there's no need to deal with translations at all.
370
- $select_fields = array(
371
- 'trid' => 'association.trid',
372
- 'relationship_id' => 'association.relationship_id',
373
- 'association_id' => 'association.id',
374
- 'parent_id' => 'association.parent_id',
375
- 'child_id' => 'association.child_id',
376
- 'intermediary_id' => 'association.intermediary_id'
377
- );
378
- }
379
-
380
-
381
- // Aggregate the information into parts of the final sql statement.
382
- //
383
- //
384
- $sql_found_rows = ( $this->need_row_count() ? 'SQL_CALC_FOUND_ROWS' : '' );
385
-
386
- array_walk( $select_fields, function( &$value, $key ) {
387
- $value = $value . ' AS ' . $key;
388
- });
389
-
390
- // It could be necessary to add more fields to the select statement, for example due to the DISTINCT statement ORDER BY needs the field to be in the SELECT.
391
- $extra_select_fields = $this->get_query_var( self::QUERY_SELECT_FIELDS );
392
- if ( ! empty( $extra_select_fields ) ) {
393
- $select_fields = array_merge( $select_fields, $extra_select_fields );
394
- }
395
- $sql_select = implode( ', ', $select_fields );
396
-
397
- $sql_join = '';
398
- if( $join_relationships ) {
399
- $sql_join .= ' JOIN ' . Toolset_Relationship_Table_Name::relationships() . ' AS relationship
400
- ON ( association.relationship_id LIKE relationship.id ) ';
401
- }
402
- if( ! empty( $join_wp_posts_on ) ) {
403
- $sql_join .= " JOIN {$wpdb->posts} ON ( association.{$join_wp_posts_on} = {$wpdb->posts}.ID ) ";
404
- }
405
- $sql_join .= implode( $join_clauses );
406
-
407
- $sql_from = "$association_table AS association $sql_join";
408
-
409
- $sql_where = (
410
- empty( $where_clauses )
411
- ? ' 1=1 '
412
- : implode( ' AND ', $where_clauses )
413
- );
414
-
415
- if( $this->has_query_var( self::QUERY_LIMIT ) ) {
416
- $sql_limits = 'LIMIT ';
417
- if( $this->has_query_var( self::QUERY_OFFSET ) ) {
418
- $sql_limits .= $this->get_query_var( self::QUERY_OFFSET ) . ', ';
419
- }
420
- $sql_limits .= $this->get_query_var( self::QUERY_LIMIT );
421
- } else {
422
- $sql_limits = '';
423
- }
424
-
425
- $sql_groupby = '';
426
- if ( ! empty( $groupby_clauses ) ) {
427
- $sql_groupby = 'GROUP BY ' . join( ', ', $groupby_clauses );
428
- }
429
-
430
- $sql_orderby = '';
431
- if ( !empty( $orderby_clauses ) ) {
432
- $sql_orderby = 'ORDER BY ' . implode( ', ', $orderby_clauses );
433
- }
434
-
435
- $sql_having = '';
436
- if( ! empty( $having_clauses ) ) {
437
- $sql_having = 'HAVING ( ' . implode( ' ) AND ( ', $having_clauses ) . ' ) ';
438
- }
439
-
440
-
441
- // Finally, one query to bind them all...
442
- //
443
- //
444
- $query = "SELECT $sql_found_rows DISTINCT $sql_select FROM $sql_from WHERE $sql_where $sql_groupby $sql_having $sql_orderby $sql_limits";
445
-
446
- return $query;
447
- }
448
-
449
-
450
- /**
451
- * @inheritdoc
452
- * @return string
453
- */
454
- protected function get_results_type() {
455
- return ARRAY_A;
456
- }
457
-
458
-
459
- /**
460
- * Process raw output from $wpdb in a way defined by the 'return' query argument.
461
- *
462
- * @param $rows
463
- *
464
- * @return int[]|IToolset_Element[]|IToolset_Association[]
465
- */
466
- protected function postprocess_results( $rows ) {
467
-
468
- if( Toolset_Relationship_Multilingual_Mode::is_transitional() ) {
469
- $rows = $this->preprocess_results_in_transitional_mode( $rows );
470
- }
471
-
472
- switch( $this->return ) {
473
- case self::RETURN_ASSOCIATION_IDS:
474
- return $this->postprocess_association_ids( $rows );
475
- case self::RETURN_ASSOCIATIONS:
476
- return $this->postprocess_associations( $rows );
477
- case self::RETURN_PARENT_IDS:
478
- return $this->postprocess_element_ids( $rows, Toolset_Relationship_Role::PARENT );
479
- case self::RETURN_CHILD_IDS:
480
- return $this->postprocess_element_ids( $rows, Toolset_Relationship_Role::CHILD );
481
- case self::RETURN_PARENTS:
482
- return $this->postprocess_elements( $rows, Toolset_Relationship_Role::PARENT );
483
- case self::RETURN_CHILDREN:
484
- return $this->postprocess_elements( $rows, Toolset_Relationship_Role::CHILD );
485
- default:
486
- // will never happen
487
- return null;
488
- }
489
-
490
- }
491
-
492
-
493
- /**
494
- * Split single field's concatenated values by language.
495
- *
496
- * A database row from query results may contain more than one language version of the association,
497
- * in which case its values are going to be concatenated in individual fields.
498
- *
499
- * This method converts a selected field into an associative array of values where keys are language codes.
500
- * An empty string is used when there is no language defined.
501
- *
502
- * @param $row
503
- * @param string $field_name
504
- * @param null|string[] $language_codes Array of language codes if already extracted before. Must be an exact value.
505
- * @param bool $skip_zeros If true, (numeric) zero field values will be skipped.
506
- *
507
- * @return array Field values with language codes as keys.
508
- * @since m2m
509
- */
510
- private function get_field_by_language( $row, $field_name, $language_codes = null, $skip_zeros = false ) {
511
-
512
- if( null === $language_codes ) {
513
- $language_codes = explode( self::GROUP_CONCAT_SEPARATOR, toolset_getarr( $row, 'lang' ) );
514
- }
515
-
516
- $result_count = count( $language_codes );
517
- $field_values = explode( self::GROUP_CONCAT_SEPARATOR, toolset_getarr( $row, $field_name ) );
518
-
519
- $results = array();
520
- for( $i = 0; $i < $result_count; ++$i ) {
521
- $field_value = $field_values[ $i ];
522
-
523
- if( is_numeric( $field_value ) && 0 == $field_value && $skip_zeros ) {
524
- continue;
525
- }
526
-
527
- $results[ $language_codes[ $i ] ] = $field_value;
528
- }
529
-
530
- return $results;
531
- }
532
-
533
-
534
- /**
535
- * From raw query results, extract association IDs.
536
- *
537
- * If the associations are translated, the ID of the best translation is returned.
538
- *
539
- * @param $rows
540
- *
541
- * @return int[]
542
- * @since m2m
543
- */
544
- private function postprocess_association_ids( $rows ) {
545
-
546
- $selected_ids = array();
547
-
548
- foreach( $rows as $row ) {
549
-
550
- $association_ids_by_language = $this->get_field_by_language( $row, 'association_id' );
551
-
552
- $available_translations = array_keys( array_keys( $association_ids_by_language ) );
553
-
554
- // Here we asking to always return any value but the result should make sense - only
555
- // relevant languages should be queried by design (unless requesting 'all' languages,
556
- // but in that case returning a random translation makes sense).
557
- $selected_language = Toolset_Wpml_Utils::choose_best_translation( $available_translations, true );
558
-
559
- $selected_ids[] = (int) toolset_getarr( $association_ids_by_language[ $selected_language ], 'id', 0 );
560
- }
561
-
562
- return array_unique( $selected_ids );
563
- }
564
-
565
-
566
- /**
567
- * From raw query results, extract element IDs of chosen role.
568
- *
569
- * If the elements are translated, the ID of the best translation is returned for each of them.
570
- *
571
- * @param array $rows
572
- * @param string $role Toolset_Relationship_Role value.
573
- *
574
- * @return int[] Element IDs.
575
- * @since m2m
576
- */
577
- private function postprocess_element_ids( $rows, $role ) {
578
-
579
- $column_name = Toolset_Relationship_Database_Operations::get_instance()->role_to_column( $role );
580
-
581
- if( Toolset_Relationship_Multilingual_Mode::is_on() ) {
582
- $results = array();
583
- foreach( $rows as $row ) {
584
- $element_ids = $this->get_field_by_language( $row, $column_name, null, true );
585
- // todo handle empty result (which should never happen)
586
- $available_translations = array_keys( $element_ids );
587
- $selected_language = Toolset_Wpml_Utils::choose_best_translation( $available_translations, true );
588
- $results[] = $element_ids[ $selected_language ];
589
- }
590
- return $results;
591
- } else {
592
- return array_unique( wp_list_pluck( $rows, $column_name ) );
593
- }
594
-
595
- }
596
-
597
-
598
- /**
599
- * From raw query results, select elements with a certain role (parent or child are supported) and return them
600
- * as Toolset_Element instances.
601
- *
602
- * Posts will also get information about translations if it is part of the results.
603
- *
604
- * @param array $rows Query results from wpdb.
605
- * @param string $role ROLE_PARENT or ROLE_CHILD.
606
- *
607
- * @return Toolset_Element[]
608
- */
609
- private function postprocess_elements( $rows, $role ) {
610
-
611
- $column_name = Toolset_Relationship_Database_Operations::get_instance()->role_to_column( $role );
612
-
613
- $results = array();
614
- foreach( $rows as $row ) {
615
-
616
- if( Toolset_Relationship_Multilingual_Mode::is_on() ) {
617
- $relationship_slug = $this->get_field_by_language( $row, 'relationship' );
618
- $relationship_slug = array_pop( $relationship_slug );
619
- $element_source = $this->get_field_by_language( $row, $column_name );
620
- } else {
621
- $relationship_slug = toolset_getarr( $row, 'relationship' );
622
- $element_source = (int) toolset_getarr( $row, $column_name );
623
- }
624
-
625
- // We need the relationship definition for determining the element domain.
626
- $relationship_definition = Toolset_Relationship_Definition_Repository::get_instance()->get_definition( $relationship_slug );
627
-
628
- // todo handle errors
629
- try {
630
- $resuts[] = Toolset_Element::get_instance(
631
- $relationship_definition->get_domain( $role ),
632
- $element_source
633
- );
634
- } catch(Exception $e) {
635
- // skip missing post for now
636
- }
637
- }
638
-
639
- return $results;
640
- }
641
-
642
-
643
- /**
644
- * Use raw query results to return instances of Toolset_Association_Base.
645
- *
646
- * Even if multiple language variants are present, the associations will always be returned in an original
647
- * version.
648
- *
649
- * @param array $rows
650
- *
651
- * @return IToolset_Association[]
652
- */
653
- private function postprocess_associations( $rows ) {
654
-
655
- $association_repository = Toolset_Association_Repository::get_instance();
656
-
657
- $associations = array();
658
-
659
- foreach( $rows as $row ) {
660
-
661
- if( Toolset_Relationship_Multilingual_Mode::is_on() ) {
662
-
663
- // Prepare language codes to optimize field reading below.
664
- //
665
- // Note that the language codes need to be in the exact order as in the results
666
- // even with duplications.
667
- $language_codes = explode( self::GROUP_CONCAT_SEPARATOR, toolset_getarr( $row, 'lang' ) );
668
-
669
- $parent_source = $this->get_field_by_language( $row, 'parent_id', $language_codes, true );
670
- $child_source = $this->get_field_by_language( $row, 'child_id', $language_codes, true );
671
-
672
- $intermediary_source = $this->get_field_by_language( $row, 'intermediary_id', $language_codes, true );
673
- if( empty( $intermediary_source ) ) {
674
- $intermediary_source = 0;
675
- }
676
-
677
- // All relationship slugs should be the same, we just grab one of them.
678
- $relationship_ids = $this->get_field_by_language( $row, 'relationship_id', $language_codes, true );
679
- $relationship_id = (int) array_pop( $relationship_ids );
680
-
681
- } else {
682
-
683
- // Simple scenario, no GROUPBY_CONCAT results.
684
- $parent_source = (int) toolset_getarr( $row, 'parent_id' );
685
- $child_source = (int) toolset_getarr( $row, 'child_id' );
686
- $intermediary_source = (int) toolset_getarr( $row, 'intermediary_id' );
687
- $relationship_id = (int) toolset_getarr( $row, 'relationship_id' );
688
-
689
- }
690
-
691
- // todo sanitize, can be string
692
- $association_trid = toolset_getarr( $row, 'trid' );
693
-
694
- // Add the association to results.
695
- try {
696
- $association = $association_repository->instantiate(
697
- $relationship_id,
698
- $association_trid,
699
- array(
700
- Toolset_Relationship_Role::PARENT => $parent_source,
701
- Toolset_Relationship_Role::CHILD => $child_source,
702
- Toolset_Relationship_Role::INTERMEDIARY => $intermediary_source
703
- )
704
- );
705
-
706
- $associations[] = $association;
707
-
708
- } catch( Exception $e ) {
709
- // The association couldn't have been loaded for some reason, we just skip it.
710
- continue;
711
- }
712
- }
713
-
714
- return $associations;
715
- }
716
-
717
-
718
- /**
719
- * @return string[] Possible values for the 'return' query argument.
720
- */
721
- private function get_return_options() {
722
- return array(
723
- self::RETURN_ASSOCIATIONS,
724
- self::RETURN_ASSOCIATION_IDS,
725
- self::RETURN_CHILD_IDS,
726
- self::RETURN_CHILDREN,
727
- self::RETURN_PARENT_IDS,
728
- self::RETURN_PARENTS
729
- );
730
- }
731
-
732
-
733
- /**
734
- * Determine if SQL_CALC_FOUND_ROWS should be part of the MySQL statement.
735
- *
736
- * @return bool
737
- */
738
- private function need_row_count() {
739
- return ( ! $this->dont_count_found_rows && $this->has_query_var( self::QUERY_LIMIT ) );
740
- }
741
-
742
-
743
- /**
744
- * Fool WP_Query into generating MySQL query clauses for given query arguments without actually executing the query.
745
- *
746
- * It also prevents WPML from modifying the query because filtering by language is handled elsewhere.
747
- * It doesn't support sticky posts, filter suppressing and probably some complex use-cases.
748
- *
749
- * @param array $query_args Arguments for WP_Query.
750
- * @return string[] MySQL clauses, for details see the posts_clauses filter.
751
- * @since m2m
752
- */
753
- private function get_wp_query_clauses( $query_args ) {
754
-
755
- // Sticky posts are handled in a special way after the query takes place, so they would have no
756
- // effect in any case. This is a performance optimalization.
757
- $query_args['ignore_sticky_posts'] = true;
758
-
759
- // Without this, we won't be able to get the clauses because the posts_clauses filter would not be applied.
760
- $query_args['suppress_filters'] = false;
761
-
762
- if( ! isset( $query_args['post_type'] ) ) {
763
- // Get all associated post_types if none is defined
764
- $query_args['post_type'] = 'any';
765
- }
766
-
767
- // This will hold the mysql clauses after WP_Query pushes them through the posts_pre_query filter.
768
- $clauses_out = array();
769
-
770
- $catch_clauses = function( $clauses_in ) use( &$clauses_out ) {
771
- $clauses_out = $clauses_in;
772
- };
773
-
774
- // Filter priority
775
- $very_late = 10000;
776
-
777
- add_filter( 'posts_clauses', $catch_clauses, $very_late );
778
-
779
- // Returning a non-null value on the posts_pre_query filter (since WP 4.6) causes that no actual
780
- // mysql query takes place in WP_Query::get_posts().
781
- $dont_query_anyting = function() { return array(); };
782
- add_filter( 'posts_pre_query', $dont_query_anyting, $very_late );
783
-
784
- // Avoid WPML messing with the results because we already know in which language we want to query
785
- //$current_language = apply_filters( 'wpml_current_language', '' );
786
- //do_action( 'wpml_switch_language', 'all' );
787
-
788
- // This will immediately run the query.
789
- new WP_Query( $query_args );
790
-
791
- // Switch back to the current language so that we don't break anything else down the road.
792
- //do_action( 'wpml_switch_language', $current_language );
793
-
794
- // Clean up
795
- remove_filter( 'posts_clauses', $catch_clauses, $very_late );
796
- remove_filter( 'posts_pre_query', $dont_query_anyting, $very_late );
797
-
798
- return $clauses_out;
799
- }
800
-
801
-
802
- /**
803
- * Make sure that the query results contain the complete information and data integrity is maintained.
804
- *
805
- * When the multilingual mode is transitional (between switching WPML off and updating the associations
806
- * table), we need to behave like it's off (no language information is taken into account) but with
807
- * a database where we may have zero element IDs in any place (when a particular element translation
808
- * didn't exist).
809
- *
810
- * In order to fill these holes, we do another query to get the original translation and the row with
811
- * untranslatable element IDs (translation type "none"), merge this information and use it as a replacement
812
- * when a "hole" is encountered in the original results.
813
- *
814
- * Furthermore, trid is supposed to be unique for each association, but the transitional mode breaks
815
- * this invariant. In order to salvage it, we're going to construct a faux "trid" value which is unique.
816
- * This value can be broken down to the original trid and association_id.
817
- * Toolset_Association_Transitional was created to handle this rare difference.
818
- *
819
- * Finally, completing holes in results may lead to having duplicate results (with exactly the same
820
- * relationship, (original) trid and triplets of element IDs). We need to get rid of those.
821
- *
822
- * This approach is rather performance-heavy, but I believe that's acceptable because the transitional
823
- * mode is really supposed to be transitional, temporary, just a measure to avoid the site from
824
- * breaking when WPML is deactivated.
825
- *
826
- * @param array $rows Raw output from database.
827
- *
828
- * @return array Updated and valid results.
829
- *
830
- * @since m2m
831
- */
832
- private function preprocess_results_in_transitional_mode( $rows ) {
833
-
834
- // Get all trids that appear within results
835
- //
836
- //
837
- $trids = array();
838
- foreach( $rows as $row ) {
839
- $trids[] = (int) toolset_getarr( $row, 'trid' );
840
- }
841
- $trids = implode( ', ', array_unique( $trids ) );
842
-
843
- // Get original translations and untranslated content for each trid
844
- //
845
- //
846
- global $wpdb;
847
- $associations_table = Toolset_Relationship_Table_Name::associations();
848
- $trid_original_results = $wpdb->get_results(
849
- "SELECT trid, parent_id, child_id, intermediary_id FROM {$associations_table} AS association
850
- WHERE association.trid IN ({$trids})
851
- AND association.translation_type IN ('original', 'none')",
852
- ARRAY_A
853
- );
854
-
855
- // Merge nonzero element IDs from those translations
856
- //
857
- //
858
- $trid_completion = array();
859
- foreach( $trid_original_results as $row ) {
860
- $trid = (int) toolset_getarr( $row, 'trid' );
861
- $trid_completion[ $trid ] = $this->merge_rows(
862
- toolset_ensarr( toolset_getarr( $trid_completion, $trid ) ),
863
- $row
864
- );
865
- }
866
-
867
- // Fill holes in query results
868
- //
869
- //
870
- $results = array();
871
- foreach( $rows as $row ) {
872
- $trid = (int) toolset_getarr( $row, 'trid' );
873
- $row = $this->merge_rows( $row, $trid_completion[ $trid ] );
874
-
875
- // Avoid duplicating the same row (same meaning equal relationship, trid and element IDs)
876
- $row_hash = $this->calculate_row_hash( $row );
877
- if( array_key_exists( $row_hash, $results ) ) {
878
- continue;
879
- }
880
-
881
- // Generate an unique trid for the row since this is not guaranteed in the transitional mode.
882
- $id = (int) toolset_getarr( $row, 'association_id' );
883
- $row['trid'] = sprintf( '\transitional\%d\%d', $trid, $id );
884
-
885
- $results[ $row_hash ] = $row;
886
- }
887
-
888
- return $results;
889
- }
890
-
891
-
892
- /**
893
- * Merge element IDs from completion row into the main one if the ID in the main one is zero.
894
- *
895
- * @param $main
896
- * @param $completion
897
- *
898
- * @return array Main row, updated.
899
- */
900
- private function merge_rows( $main, $completion ) {
901
- foreach( Toolset_Relationship_Role::all_role_names() as $role ) {
902
- $column_name = Toolset_Relationship_Database_Operations::get_instance()->role_to_column( $role );
903
- $main_value = (int) toolset_getarr( $main, $column_name );
904
- if( 0 === $main_value ) {
905
- $main[ $column_name ] = (int) toolset_getarr( $completion, $column_name );
906
- }
907
- }
908
-
909
- return $main;
910
- }
911
-
912
-
913
- /**
914
- * Calculate a md5 hash of a database row, using relationship, trid and element IDs.
915
- *
916
- * @param $row
917
- * @return string md5 hash value.
918
- */
919
- private function calculate_row_hash( $row ) {
920
- $md5_source = sprintf(
921
- "%s_%d_%d_%d_%d",
922
- toolset_getarr( $row, 'relationship' ),
923
- (int) toolset_getarr( $row, 'trid' ),
924
- (int) toolset_getarr( $row, 'parent_id' ),
925
- (int) toolset_getarr( $row, 'child_id' ),
926
- (int) toolset_getarr( $row, 'intermediary_id' )
927
- );
928
-
929
- return md5( $md5_source );
930
- }
931
-
932
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/toolset/toolset-common/inc/m2m/association_repository.php DELETED
@@ -1,260 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Repository for associations.
5
- *
6
- * Outside m2m API, only this object should be used to obtain instances of the IToolset_Association.
7
- * Use it as a singleton in production code.
8
- *
9
- * @since m2m
10
- */
11
- class Toolset_Association_Repository {
12
-
13
- private static $instance;
14
-
15
- /** @var Toolset_Relationship_Database_Operations|null */
16
- private $_database_operations;
17
-
18
- /** @var IToolset_Association[] */
19
- private $associations_by_uid = array();
20
-
21
-
22
- public static function get_instance() {
23
- if( null === self::$instance ) {
24
- self::$instance = new self();
25
- }
26
-
27
- return self::$instance;
28
- }
29
-
30
-
31
- public function __construct( Toolset_Relationship_Database_Operations $database_operations_di = null ) {
32
- $this->_database_operations = $database_operations_di;
33
- }
34
-
35
-
36
- private function __clone() { }
37
-
38
-
39
- /**
40
- * Get an association by UID.
41
- *
42
- * Load it from database if needed.
43
- *
44
- * @param $association_uid
45
- *
46
- * @return null|IToolset_Association
47
- */
48
- public function get( $association_uid ) {
49
- if( $this->in_cache( $association_uid ) ) {
50
- return $this->from_cache( $association_uid );
51
- }
52
-
53
- /**
54
- * toolset_get_m2m_association_by_uid
55
- *
56
- * Allow for loading associations by UID by custom means.
57
- *
58
- * Note: To be enabled when actually needed.
59
- *
60
- * @param null $association Default value.
61
- * @param int|string $association_uid UID of the association.
62
- * @since m2m
63
- */
64
- // $association = apply_filters( 'toolset_get_m2m_association_by_uid', null, $association_uid );
65
- // if( ! $association instanceof IToolset_Association ) {
66
- $association = $this->load_association_by_uid( $association_uid );
67
- // }
68
-
69
- $this->to_cache( $association_uid, $association );
70
-
71
- return $association;
72
- }
73
-
74
-
75
- private function in_cache( $association_uid ) {
76
- return array_key_exists( $association_uid, $this->associations_by_uid );
77
- }
78
-
79
-
80
- private function from_cache( $association_uid ) {
81
- return $this->associations_by_uid[ $association_uid ];
82
- }
83
-
84
-
85
- private function to_cache( $association_uid, $association ) {
86
- $this->associations_by_uid[ $association_uid ] = $association;
87
- }
88
-
89
-
90
- /**
91
- * Load a native association from the database.
92
- *
93
- * @param int $association_uid Association UID.
94
- *
95
- * @return null|Toolset_Association The association instance or null if it couln't have been loaded.
96
- *
97
- * todo actually test this - maybe better use the query
98
- */
99
- private function load_association_by_uid( $association_uid ) {
100
- global $wpdb;
101
-
102
- $associations_tn = Toolset_Relationship_Table_Name::associations();
103
-
104
- $query = $wpdb->prepare( "SELECT * FROM {$associations_tn} WHERE trid = %d", $association_uid );
105
- $row = $wpdb->get_row( $query );
106
-
107
- if ( ! $row ) {
108
- return null;
109
- }
110
-
111
- $relationship_definition = Toolset_Relationship_Definition_Repository::get_instance()
112
- ->get_definition_by_row_id( $row->relationship_id );
113
-
114
- if ( null === $relationship_definition ) {
115
- return null;
116
- }
117
-
118
- try {
119
- $association = new Toolset_Association(
120
- $row->trid,
121
- $relationship_definition,
122
- array(
123
- Toolset_Relationship_Role::PARENT => $row->parent_id,
124
- Toolset_Relationship_Role::CHILD => $row->child_id
125
- ),
126
- $row->intermediary_id
127
- );
128
-
129
- } catch( Exception $e ) {
130
- $association = null;
131
- }
132
-
133
- return $association;
134
-
135
- }
136
-
137
-
138
- /**
139
- * Create an association instance from provided values.
140
- *
141
- * @param int|string|IToolset_Relationship_Definition $relationship_definition_source
142
- * @param int|string $association_trid
143
- * @param array $element_sources Elements indexed by role names - either Toolset_Element instances or ids (can be mixed).
144
- *
145
- * @return IToolset_Association
146
- * @since m2m
147
- */
148
- public function instantiate( $relationship_definition_source, $association_trid, $element_sources ) {
149
-
150
- if( $this->in_cache( $association_trid ) ) {
151
- return $this->from_cache( $association_trid );
152
- }
153
-
154
- $relationship_definition = Toolset_Relationship_Utils::get_relationship_definition( $relationship_definition_source );
155
- if ( ! $relationship_definition instanceof Toolset_Relationship_Definition ) {
156
- throw new InvalidArgumentException();
157
- }
158
-
159
- // todo Consider moving this part to the relationship driver.
160
- // todo That would allow for adding other drivers in the future, and the instantiation
161
- // todo and caching within this repository would work out of the box.
162
- if(
163
- Toolset_Relationship_Multilingual_Mode::is_on()
164
- && $relationship_definition->is_translatable() ) {
165
-
166
- $association = new Toolset_Association_Translation_Set(
167
- $association_trid,
168
- $relationship_definition,
169
- $element_sources
170
- );
171
-
172
- } elseif ( Toolset_Relationship_Multilingual_Mode::is_transitional() ) {
173
-
174
- $association = new Toolset_Association_Transitional(
175
- $association_trid,
176
- $relationship_definition,
177
- $element_sources,
178
- toolset_getarr( $element_sources, Toolset_Relationship_Role::INTERMEDIARY, 0 )
179
- );
180
-
181
- } else {
182
-
183
- $association = new Toolset_Association(
184
- $association_trid,
185
- $relationship_definition,
186
- $element_sources,
187
- toolset_getarr( $element_sources, Toolset_Relationship_Role::INTERMEDIARY, 0 )
188
- );
189
-
190
- }
191
-
192
- $this->to_cache( $association->get_uid(), $association );
193
-
194
- return $association;
195
- }
196
-
197
-
198
- /**
199
- * @return Toolset_Relationship_Database_Operations
200
- */
201
- private function get_database_operations() {
202
- if( null === $this->_database_operations ) {
203
- $this->_database_operations = new Toolset_Relationship_Database_Operations();
204
- }
205
-
206
- return $this->_database_operations;
207
- }
208
-
209
-
210
- /**
211
- * Delete all associations from given relationship.
212
- *
213
- * @param IToolset_Relationship_Definition $relationship_definition
214
- *
215
- * @return Toolset_Result_Updated
216
- */
217
- public function remove_by_relationship( IToolset_Relationship_Definition $relationship_definition ) {
218
-
219
- foreach( $this->associations_by_uid as $association_uid => $association ) {
220
- if( $association->get_definition()->get_slug() === $relationship_definition->get_slug() ) {
221
- unset( $this->associations_by_uid[ $association_uid ] );
222
- }
223
- }
224
-
225
- /** @var Toolset_Relationship_Definition $relationship_definition */
226
- return $this->get_database_operations()->delete_associations_by_relationship( $relationship_definition->get_row_id() );
227
- }
228
-
229
-
230
- /**
231
- * @param IToolset_Element $element
232
- */
233
- public function delete_associations_involving_element( $element ) {
234
-
235
- $query_parent = new Toolset_Association_Query( array(
236
- Toolset_Association_Query::QUERY_PARENT_DOMAIN => $element->get_domain(),
237
- Toolset_Association_Query::QUERY_PARENT_ID => $element->get_id(),
238
- Toolset_Association_Query::OPTION_RETURN => Toolset_Association_Query::RETURN_ASSOCIATIONS
239
- ) );
240
-
241
- $associations = $query_parent->get_results();
242
-
243
- $query_child = new Toolset_Association_Query( array(
244
- Toolset_Association_Query::QUERY_PARENT_DOMAIN => $element->get_domain(),
245
- Toolset_Association_Query::QUERY_PARENT_ID => $element->get_id(),
246
- Toolset_Association_Query::OPTION_RETURN => Toolset_Association_Query::RETURN_ASSOCIATIONS
247
- ) );
248
-
249
- /** @var Toolset_Association[] $associations */
250
- $associations = array_merge( $associations, $query_child->get_results() );
251
-
252
- foreach( $associations as $association ) {
253
- $definition = $association->get_definition();
254
- $driver = $definition->get_driver();
255
- $driver->delete_association( $association );
256
- }
257
-
258
- }
259
-
260
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/toolset/toolset-common/inc/m2m/association_transitional.php DELETED
@@ -1,61 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Represents a single, translation-unaware m2m association between two elements in the transitional
5
- * multilingual mode.
6
- *
7
- * The only difference is that in this mode, we get a string instead of a trid, and need to extract the
8
- * actual trid for the parent constructor, and use the string as an unique identifier.
9
- *
10
- * See Toolset_Association_Query::preprocess_results_in_transitional_mode() for more information.
11
- */
12
- class Toolset_Association_Transitional extends Toolset_Association {
13
-
14
-
15
- private $ttrid;
16
-
17
- /**
18
- * Unique identifier of the association.
19
- *
20
- * @return string
21
- */
22
- public function get_uid() {
23
- return $this->ttrid;
24
- }
25
-
26
-
27
- /**
28
- * Toolset_Association_Transitional constructor.
29
- *
30
- * @param string $ttrid Translation group ID or its string replacement.
31
- * @param Toolset_Relationship_Definition $relationship_definition
32
- * @param array $element_sources Associative array with both element keys. Each item can be either an ID
33
- * or a matching Toolset_Element instance.
34
- * @param int|Toolset_Post $intermediary_source Intermediary post with association fields or its ID. If a
35
- * Toolset_Post instance is provided, it must have the type matching with the relationship definition.
36
- *
37
- * @since m2m
38
- */
39
- public function __construct(
40
- $ttrid, Toolset_Relationship_Definition $relationship_definition, $element_sources, $intermediary_source
41
- ) {
42
-
43
- if( ! Toolset_Relationship_Multilingual_Mode::is_transitional() ) {
44
- throw new RuntimeException( 'Tried to instantiate Toolset_Association_Transitional in a non-transitional mode.' );
45
- }
46
-
47
- $ttrid_parts = explode( '\\', $ttrid );
48
- if( count( $ttrid_parts ) !== 4 ) {
49
- throw new InvalidArgumentException( 'Invalid transitional trid provided.' );
50
- }
51
-
52
- $this->ttrid = $ttrid;
53
-
54
- // In the extremely rare case someone explictly asks for a trid, they will get it (although it probably
55
- // won't be unique).
56
- $trid = (int) $ttrid_parts[2];
57
-
58
- parent::__construct( $trid, $relationship_definition, $element_sources, $intermediary_source );
59
- }
60
-
61
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/toolset/toolset-common/inc/m2m/association_translation_set.php DELETED
@@ -1,135 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Represents a translation set of an association between posts.
5
- *
6
- * Benefits:
7
- * - allows for specifying the preferred language in the rare cases it might be needed
8
- * - allows for storing element sources (IDs) with the complete language information but
9
- * without instantiating the elements immediately - that improves performance when
10
- * instantiating and prevents from a WPML interaction/database queries in the future
11
- *
12
- * You should never need to use this class directly outside of the m2m API.
13
- *
14
- * @since m2m
15
- */
16
- class Toolset_Association_Translation_Set extends Toolset_Association_Base {
17
-
18
- /**
19
- * @var array For each relationship role, there is an element source (something that will be
20
- * accepted by Toolset_Element::get_instance()).
21
- */
22
- private $element_sources = array();
23
-
24
-
25
- /**
26
- * Toolset_Association_Translation_Set constructor.
27
- *
28
- * @param int $trid
29
- * @param Toolset_Relationship_Definition $relationship_definition
30
- * @param array $element_sources
31
- */
32
- public function __construct(
33
- $trid, Toolset_Relationship_Definition $relationship_definition, $element_sources
34
- ) {
35
-
36
- if ( ! Toolset_Relationship_Multilingual_Mode::is_on() ) {
37
- throw new RuntimeException( 'Attempted to use an association translation set while WPML was inactive' );
38
- }
39
-
40
- parent::__construct( $trid, $relationship_definition );
41
-
42
- foreach( Toolset_Relationship_Role::all_role_names() as $role ) {
43
- $this->element_sources[ $role ] = toolset_getarr( $element_sources, $role, null );
44
- }
45
- }
46
-
47
-
48
- /**
49
- * Get an association element.
50
- *
51
- * Instantiates an element if it hasn't been done yet.
52
- *
53
- * @param string $element_role
54
- *
55
- * @return Toolset_Element|null
56
- * @throws InvalidArgumentException
57
- * @since m2m
58
- */
59
- public function get_element( $element_role ) {
60
-
61
- Toolset_Relationship_Role::validate( $element_role );
62
-
63
- if( ! array_key_exists( $element_role, $this->elements ) ) {
64
- $element_source = toolset_getarr( $this->element_sources, $element_role, null );
65
-
66
- try {
67
- $this->elements[ $element_role ] = Toolset_Element::get_instance(
68
- $this->get_element_domain( $element_role ),
69
- $element_source
70
- );
71
- } catch( Exception $e ) {
72
- $this->elements[ $element_role ] = null;
73
- }
74
- }
75
-
76
- return $this->elements[ $element_role ];
77
- }
78
-
79
-
80
- /**
81
- * @inheritdoc
82
- * @return null|Toolset_Post|Toolset_Post_Translation_Set
83
- */
84
- protected function get_intermediary_post() {
85
- /** @noinspection PhpIncompatibleReturnTypeInspection */
86
- return $this->get_element( Toolset_Relationship_Role::INTERMEDIARY );
87
- }
88
-
89
-
90
- /**
91
- * Determine whether the intermediary post exists and supports translations.
92
- *
93
- * @return bool
94
- */
95
- private function is_intermediary_post_translation_set() {
96
- return ( $this->has_fields() && $this->get_intermediary_post() instanceof Toolset_Post_Translation_Set );
97
- }
98
-
99
-
100
- /**
101
- * @inheritdoc
102
- *
103
- * @return bool|Toolset_Field_Instance[]
104
- */
105
- public function get_fields( $language_code = null ) {
106
- if( ! $this->has_fields() ) {
107
- return false;
108
- }
109
-
110
- if( $this->is_intermediary_post_translation_set() ) {
111
- return $this->get_intermediary_post()->get_fields( $language_code );
112
- }
113
-
114
- return $this->get_intermediary_post()->get_fields();
115
- }
116
-
117
-
118
- /**
119
- * @inheritdoc
120
- * @param string|Toolset_Field_Definition $field_source
121
- * @return bool|Toolset_Field_Instance
122
- */
123
- public function get_field( $field_source, $language_code = null ) {
124
- if( ! $this->has_fields() ) {
125
- return false;
126
- }
127
-
128
- if( $this->is_intermediary_post_translation_set() ) {
129
- return $this->get_intermediary_post()->get_field( $field_source, $language_code );
130
- }
131
-
132
- return $this->get_intermediary_post()->get_field( $field_source );
133
- }
134
-
135
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/toolset/toolset-common/inc/m2m/autoload_classmap.php CHANGED
@@ -1,75 +1,125 @@
1
  <?php
2
  // Generated by ZF2's ./bin/classmap_generator.php
3
  return array(
4
- 'IToolset_Association' => dirname( __FILE__ ) . '/i_association.php',
 
 
 
 
 
5
  'IToolset_Potential_Association_Query' => dirname( __FILE__ ) . '/potential_association/query_interface.php',
 
6
  'IToolset_Relationship_Database_Issue' => dirname( __FILE__ ) . '/database/issue/interface.php',
7
- 'IToolset_Relationship_Definition' => dirname( __FILE__ ) . '/definition/interface.php',
8
  'IToolset_Relationship_Origin' => dirname( __FILE__ ) . '/origin/interface.php',
9
- 'IToolset_Relationship_Query_Cardinality_Match' => dirname( __FILE__ ) . '/relationship_query/cardinality_match/interface.php',
10
- 'IToolset_Relationship_Query_Condition' => dirname( __FILE__ ) . '/relationship_query/condition/i_condition.php',
11
- 'IToolset_Relationship_Role' => dirname( __FILE__ ) . '/relationship_role/interface.php',
12
- 'IToolset_Relationship_Role_Parent_Child' => dirname( __FILE__ ) . '/relationship_role/parent_child_interface.php',
13
- 'Toolset_Association_Base' => dirname( __FILE__ ) . '/association_base.php',
14
- 'Toolset_Association' => dirname( __FILE__ ) . '/association.php',
15
- 'Toolset_Association_Query' => dirname( __FILE__ ) . '/association_query.php',
16
- 'Toolset_Association_Repository' => dirname( __FILE__ ) . '/association_repository.php',
17
- 'Toolset_Association_Transitional' => dirname( __FILE__ ) . '/association_transitional.php',
18
- 'Toolset_Association_Translation_Set' => dirname( __FILE__ ) . '/association_translation_set.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  'Toolset_Potential_Association_Query_Factory' => dirname( __FILE__ ) . '/potential_association/query_factory.php',
20
  'Toolset_Potential_Association_Query_Posts' => dirname( __FILE__ ) . '/potential_association/query_posts.php',
 
 
 
 
 
 
21
  'Toolset_Relationship_Cardinality' => dirname( __FILE__ ) . '/cardinality.php',
22
  'Toolset_Relationship_Controller' => dirname( __FILE__ ) . '/controller.php',
23
  'Toolset_Relationship_Database_Issue_Missing_Element' => dirname( __FILE__ ) . '/database/issue/missing_element.php',
24
  'Toolset_Relationship_Database_Operations' => dirname( __FILE__ ) . '/database/operations.php',
25
  'Toolset_Relationship_Database_Unique_Table_Alias' => dirname( __FILE__ ) . '/database/unique_table_alias.php',
26
- 'Toolset_Relationship_Definition' => dirname( __FILE__ ) . '/definition/definition.php',
27
- 'Toolset_Relationship_Definition_Factory' => dirname( __FILE__ ) . '/definition/factory.php',
28
- 'Toolset_Relationship_Definition_Persistence' => dirname( __FILE__ ) . '/definition/persistence.php',
29
- 'Toolset_Relationship_Definition_Repository' => dirname( __FILE__ ) . '/definition/repository.php',
30
- 'Toolset_Relationship_Definition_Translator' => dirname( __FILE__ ) . '/definition/translator.php',
31
  'Toolset_Relationship_Distinct_Post_Query' => dirname( __FILE__ ) . '/potential_association/distinct_post_query.php',
32
- 'Toolset_Relationship_Driver_Base' => dirname( __FILE__ ) . '/driver_base.php',
33
  'Toolset_Relationship_Driver' => dirname( __FILE__ ) . '/driver.php',
 
34
  'Toolset_Relationship_Element_Type' => dirname( __FILE__ ) . '/element_type.php',
35
- 'Toolset_Relationship_Migration_Associations' => dirname( __FILE__ ) . '/migration_associations.php',
36
- 'Toolset_Relationship_Migration' => dirname( __FILE__ ) . '/migration.php',
37
- 'Toolset_Relationship_Multilingual_Mode' => dirname( __FILE__ ) . '/multilingual_mode.php',
 
38
  'Toolset_Relationship_Origin_Post_Reference_Field' => dirname( __FILE__ ) . '/origin/post_reference_field.php',
39
  'Toolset_Relationship_Origin_Repeatable_Group' => dirname( __FILE__ ) . '/origin/repeatable_group.php',
40
  'Toolset_Relationship_Origin_Wizard' => dirname( __FILE__ ) . '/origin/wizard.php',
 
41
  'Toolset_Relationship_Query_Base' => dirname( __FILE__ ) . '/query_base.php',
42
  'Toolset_Relationship_Query_Cache' => dirname( __FILE__ ) . '/query_cache.php',
43
- 'Toolset_Relationship_Query_Cardinality_Match_Conjunction' => dirname( __FILE__ ) . '/relationship_query/cardinality_match/conjunction.php',
44
- 'Toolset_Relationship_Query_Cardinality_Match_Factory' => dirname( __FILE__ ) . '/relationship_query/cardinality_match/factory.php',
45
- 'Toolset_Relationship_Query_Cardinality_Match_Operators' => dirname( __FILE__ ) . '/relationship_query/cardinality_match/operators.php',
46
- 'Toolset_Relationship_Query_Cardinality_Match_Single' => dirname( __FILE__ ) . '/relationship_query/cardinality_match/single.php',
47
- 'Toolset_Relationship_Query_Condition_And' => dirname( __FILE__ ) . '/relationship_query/condition/and.php',
48
- 'Toolset_Relationship_Query_Condition' => dirname( __FILE__ ) . '/relationship_query/condition/abstract.php',
49
- 'Toolset_Relationship_Query_Condition_Factory' => dirname( __FILE__ ) . '/relationship_query/condition_factory.php',
50
- 'Toolset_Relationship_Query_Condition_Has_Active_Types' => dirname( __FILE__ ) . '/relationship_query/condition/has_active_types.php',
51
- 'Toolset_Relationship_Query_Condition_Has_Cardinality' => dirname( __FILE__ ) . '/relationship_query/condition/has_cardinality.php',
52
- 'Toolset_Relationship_Query_Condition_Has_Domain' => dirname( __FILE__ ) . '/relationship_query/condition/has_domain.php',
53
- 'Toolset_Relationship_Query_Condition_Is_Active' => dirname( __FILE__ ) . '/relationship_query/condition/is_active.php',
54
- 'Toolset_Relationship_Query_Condition_Is_Boolean_Flag' => dirname( __FILE__ ) . '/relationship_query/condition/is_boolean_flag.php',
55
- 'Toolset_Relationship_Query_Condition_Is_Legacy' => dirname( __FILE__ ) . '/relationship_query/condition/is_legacy.php',
56
- 'Toolset_Relationship_Query_Condition_Operator' => dirname( __FILE__ ) . '/relationship_query/condition/operator.php',
57
- 'Toolset_Relationship_Query_Condition_Or' => dirname( __FILE__ ) . '/relationship_query/condition/or.php',
58
- 'Toolset_Relationship_Query_Condition_Origin' => dirname( __FILE__ ) . '/relationship_query/condition/origin.php',
59
- 'Toolset_Relationship_Query_Condition_Tautology' => dirname( __FILE__ ) . '/relationship_query/condition/tautology.php',
60
- 'Toolset_Relationship_Query_Condition_Type' => dirname( __FILE__ ) . '/relationship_query/condition/type.php',
61
- 'Toolset_Relationship_Query' => dirname( __FILE__ ) . '/relationship_query/relationship_query.php',
62
- 'Toolset_Relationship_Query_Factory' => dirname( __FILE__ ) . '/query_factory.php',
63
- 'Toolset_Relationship_Query_Sql_Expression_Builder' => dirname( __FILE__ ) . '/relationship_query/sql_expression_builder.php',
64
- 'Toolset_Relationship_Query_V2' => dirname( __FILE__ ) . '/relationship_query/relationship_query_v2.php',
65
- 'Toolset_Relationship_Role_Abstract' => dirname( __FILE__ ) . '/relationship_role/abstract.php',
66
- 'Toolset_Relationship_Role_Child' => dirname( __FILE__ ) . '/relationship_role/child.php',
67
- 'Toolset_Relationship_Role' => dirname( __FILE__ ) . '/relationship_role/role.php',
68
- 'Toolset_Relationship_Role_Intermediary' => dirname( __FILE__ ) . '/relationship_role/intermediary.php',
69
- 'Toolset_Relationship_Role_Parent' => dirname( __FILE__ ) . '/relationship_role/parent.php',
70
- 'Toolset_Relationship_Scope' => dirname( __FILE__ ) . '/scope.php',
71
- 'Toolset_Relationship_Slug_Validator' => dirname( __FILE__ ) . '/slug_validator.php',
72
  'Toolset_Relationship_Table_Name' => dirname( __FILE__ ) . '/database/table_name.php',
73
  'Toolset_Relationship_Utils' => dirname( __FILE__ ) . '/utils.php',
74
- 'Toolset_Relationship_WPML_Interoperability' => dirname( __FILE__ ) . '/wpml_interoperability.php',
75
  );
1
  <?php
2
  // Generated by ZF2's ./bin/classmap_generator.php
3
  return array(
4
+ 'IToolset_Association' => dirname( __FILE__ ) . '/association/interface.php',
5
+ 'IToolset_Association_Query_Condition' => dirname( __FILE__ ) . '/association/query/condition/interface.php',
6
+ 'IToolset_Association_Query_Element_Selector' => dirname( __FILE__ ) . '/association/query/element_selector/interface.php',
7
+ 'IToolset_Association_Query_Orderby' => dirname( __FILE__ ) . '/association/query/orderby/interface.php',
8
+ 'IToolset_Association_Query_Restriction' => dirname( __FILE__ ) . '/association/query/restriction/interface.php',
9
+ 'IToolset_Association_Query_Result_Transformation' => dirname( __FILE__ ) . '/association/query/result_transformation/interface.php',
10
  'IToolset_Potential_Association_Query' => dirname( __FILE__ ) . '/potential_association/query_interface.php',
11
+ 'IToolset_Query_Condition' => dirname( __FILE__ ) . '/query/condition/interface.php',
12
  'IToolset_Relationship_Database_Issue' => dirname( __FILE__ ) . '/database/issue/interface.php',
13
+ 'IToolset_Relationship_Definition' => dirname( __FILE__ ) . '/relationship/definition/interface.php',
14
  'IToolset_Relationship_Origin' => dirname( __FILE__ ) . '/origin/interface.php',
15
+ 'IToolset_Relationship_Query_Cardinality_Match' => dirname( __FILE__ ) . '/relationship/query/cardinality_match/interface.php',
16
+ 'IToolset_Relationship_Query_Condition' => dirname( __FILE__ ) . '/relationship/query/condition/interface.php',
17
+ 'IToolset_Relationship_Role' => dirname( __FILE__ ) . '/relationship/role/interface.php',
18
+ 'IToolset_Relationship_Role_Parent_Child' => dirname( __FILE__ ) . '/relationship/role/parent_child_interface.php',
19
+ 'Toolset_Association' => dirname( __FILE__ ) . '/association/association.php',
20
+ 'Toolset_Association_Cleanup_Association' => dirname( __FILE__ ) . '/association/cleanup/association.php',
21
+ 'Toolset_Association_Cleanup_Cron_Event' => dirname( __FILE__ ) . '/association/cleanup/cron_event.php',
22
+ 'Toolset_Association_Cleanup_Cron_Handler' => dirname( __FILE__ ) . '/association/cleanup/cron_handler.php',
23
+ 'Toolset_Association_Cleanup_Dangling_Intermediary_Posts' => dirname( __FILE__ ) . '/association/cleanup/dangling_intermediary_posts.php',
24
+ 'Toolset_Association_Cleanup_Factory' => dirname( __FILE__ ) . '/association/cleanup/factory.php',
25
+ 'Toolset_Association_Cleanup_Post' => dirname( __FILE__ ) . '/association/cleanup/post.php',
26
+ 'Toolset_Association_Cleanup_Troubleshooting_Section' => dirname( __FILE__ ) . '/association/cleanup/troubleshooting_section.php',
27
+ 'Toolset_Association_Factory' => dirname( __FILE__ ) . '/association/factory.php',
28
+ 'Toolset_Association_Intermediary_Post_Persistence' => dirname( __FILE__ ) . '/association/intermediary_post_persistence.php',
29
+ 'Toolset_Association_Persistence' => dirname( __FILE__ ) . '/association/persistence.php',
30
+ 'Toolset_Association_Query' => dirname( __FILE__ ) . '/association/query/association_query.php',
31
+ 'Toolset_Association_Query_Condition' => dirname( __FILE__ ) . '/association/query/condition/abstract.php',
32
+ 'Toolset_Association_Query_Condition_Association_Id' => dirname( __FILE__ ) . '/association/query/condition/association_id.php',
33
+ 'Toolset_Association_Query_Condition_Element_Id' => dirname( __FILE__ ) . '/association/query/condition/element_id.php',
34
+ 'Toolset_Association_Query_Condition_Element_Id_And_Domain' => dirname( __FILE__ ) . '/association/query/condition/element_id_and_domain.php',
35
+ 'Toolset_Association_Query_Condition_Element_Status' => dirname( __FILE__ ) . '/association/query/condition/element_status.php',
36
+ 'Toolset_Association_Query_Condition_Empty_Intermediary' => dirname( __FILE__ ) . '/association/query/condition/empty_intermediary.php',
37
+ 'Toolset_Association_Query_Condition_Exclude_Element' => dirname( __FILE__ ) . '/association/query/condition/exclude_element.php',
38
+ 'Toolset_Association_Query_Condition_Factory' => dirname( __FILE__ ) . '/association/query/condition_factory.php',
39
+ 'Toolset_Association_Query_Condition_Has_Active_Relationship' => dirname( __FILE__ ) . '/association/query/condition/has_active_relationship.php',
40
+ 'Toolset_Association_Query_Condition_Has_Domain' => dirname( __FILE__ ) . '/association/query/condition/has_domain.php',
41
+ 'Toolset_Association_Query_Condition_Has_Domain_And_Type' => dirname( __FILE__ ) . '/association/query/condition/has_domain_and_type.php',
42
+ 'Toolset_Association_Query_Condition_Has_Legacy_Relationship' => dirname( __FILE__ ) . '/association/query/condition/has_legacy_relationship.php',
43
+ 'Toolset_Association_Query_Condition_Has_Type' => dirname( __FILE__ ) . '/association/query/condition/has_type.php',
44
+ 'Toolset_Association_Query_Condition_Postmeta' => dirname( __FILE__ ) . '/association/query/condition/postmeta.php',
45
+ 'Toolset_Association_Query_Condition_Relationship_Flag' => dirname( __FILE__ ) . '/association/query/condition/relationship_flag.php',
46
+ 'Toolset_Association_Query_Condition_Relationship_Id' => dirname( __FILE__ ) . '/association/query/condition/relationship_id.php',
47
+ 'Toolset_Association_Query_Condition_Search' => dirname( __FILE__ ) . '/association/query/condition/search.php',
48
+ 'Toolset_Association_Query_Condition_Wp_Query' => dirname( __FILE__ ) . '/association/query/condition/wp_query.php',
49
+ 'Toolset_Association_Query_Element_Selector_Abstract' => dirname( __FILE__ ) . '/association/query/element_selector/abstract.php',
50
+ 'Toolset_Association_Query_Element_Selector_Default' => dirname( __FILE__ ) . '/association/query/element_selector/default.php',
51
+ 'Toolset_Association_Query_Element_Selector_Provider' => dirname( __FILE__ ) . '/association/query/element_selector/provider.php',
52
+ 'Toolset_Association_Query_Element_Selector_Wpml' => dirname( __FILE__ ) . '/association/query/element_selector/wpml.php',
53
+ 'Toolset_Association_Query_Orderby' => dirname( __FILE__ ) . '/association/query/orderby/abstract.php',
54
+ 'Toolset_Association_Query_Orderby_Factory' => dirname( __FILE__ ) . '/association/query/orderby_factory.php',
55
+ 'Toolset_Association_Query_Orderby_Nothing' => dirname( __FILE__ ) . '/association/query/orderby/nothing.php',
56
+ 'Toolset_Association_Query_Orderby_Postmeta' => dirname( __FILE__ ) . '/association/query/orderby/postmeta.php',
57
+ 'Toolset_Association_Query_Orderby_Title' => dirname( __FILE__ ) . '/association/query/orderby/title.php',
58
+ 'Toolset_Association_Query_Result_Transformation_Association_Instance' => dirname( __FILE__ ) . '/association/query/result_transformation/association_instance.php',
59
+ 'Toolset_Association_Query_Result_Transformation_Association_Uid' => dirname( __FILE__ ) . '/association/query/result_transformation/association_uid.php',
60
+ 'Toolset_Association_Query_Result_Transformation_Element_Id' => dirname( __FILE__ ) . '/association/query/result_transformation/element_id.php',
61
+ 'Toolset_Association_Query_Result_Transformation_Element_Instance' => dirname( __FILE__ ) . '/association/query/result_transformation/element_instance.php',
62
+ 'Toolset_Association_Query_Sql_Expression_Builder' => dirname( __FILE__ ) . '/association/query/sql_expression_builder.php',
63
+ 'Toolset_Association_Query_Table_Join_Manager' => dirname( __FILE__ ) . '/association/query/table_join_manager.php',
64
+ 'Toolset_Association_Query_V2' => dirname( __FILE__ ) . '/association/query/association_query_v2.php',
65
+ 'Toolset_Association_Query_Wpdb_Wrapper' => dirname( __FILE__ ) . '/association/query/wpdb_wrapper.php',
66
+ 'Toolset_Association_Translator' => dirname( __FILE__ ) . '/association/translator.php',
67
  'Toolset_Potential_Association_Query_Factory' => dirname( __FILE__ ) . '/potential_association/query_factory.php',
68
  'Toolset_Potential_Association_Query_Posts' => dirname( __FILE__ ) . '/potential_association/query_posts.php',
69
+ 'Toolset_Query_Comparison_Operator' => dirname( __FILE__ ) . '/query/comparison_operator.php',
70
+ 'Toolset_Query_Condition_And' => dirname( __FILE__ ) . '/query/condition/and.php',
71
+ 'Toolset_Query_Condition_Contradiction' => dirname( __FILE__ ) . '/query/condition/contradiction.php',
72
+ 'Toolset_Query_Condition_Operator' => dirname( __FILE__ ) . '/query/condition/operator.php',
73
+ 'Toolset_Query_Condition_Or' => dirname( __FILE__ ) . '/query/condition/or.php',
74
+ 'Toolset_Query_Condition_Tautology' => dirname( __FILE__ ) . '/query/condition/tautology.php',
75
  'Toolset_Relationship_Cardinality' => dirname( __FILE__ ) . '/cardinality.php',
76
  'Toolset_Relationship_Controller' => dirname( __FILE__ ) . '/controller.php',
77
  'Toolset_Relationship_Database_Issue_Missing_Element' => dirname( __FILE__ ) . '/database/issue/missing_element.php',
78
  'Toolset_Relationship_Database_Operations' => dirname( __FILE__ ) . '/database/operations.php',
79
  'Toolset_Relationship_Database_Unique_Table_Alias' => dirname( __FILE__ ) . '/database/unique_table_alias.php',
80
+ 'Toolset_Relationship_Definition' => dirname( __FILE__ ) . '/relationship/definition/definition.php',
81
+ 'Toolset_Relationship_Definition_Factory' => dirname( __FILE__ ) . '/relationship/definition/factory.php',
82
+ 'Toolset_Relationship_Definition_Persistence' => dirname( __FILE__ ) . '/relationship/definition/persistence.php',
83
+ 'Toolset_Relationship_Definition_Repository' => dirname( __FILE__ ) . '/relationship/definition/repository.php',
84
+ 'Toolset_Relationship_Definition_Translator' => dirname( __FILE__ ) . '/relationship/definition/translator.php',
85
  'Toolset_Relationship_Distinct_Post_Query' => dirname( __FILE__ ) . '/potential_association/distinct_post_query.php',
 
86
  'Toolset_Relationship_Driver' => dirname( __FILE__ ) . '/driver.php',
87
+ 'Toolset_Relationship_Driver_Base' => dirname( __FILE__ ) . '/driver_base.php',
88
  'Toolset_Relationship_Element_Type' => dirname( __FILE__ ) . '/element_type.php',
89
+ 'Toolset_Relationship_Migration' => dirname( __FILE__ ) . '/migration/controller.php',
90
+ 'Toolset_Relationship_Migration_Associations' => dirname( __FILE__ ) . '/migration/associations.php',
91
+ 'Toolset_Relationship_Migration_Controller' => dirname( __FILE__ ) . '/migration/controller.php',
92
+ 'Toolset_Relationship_Migration_Post_Translation' => dirname( __FILE__ ) . '/migration/post_translation.php',
93
  'Toolset_Relationship_Origin_Post_Reference_Field' => dirname( __FILE__ ) . '/origin/post_reference_field.php',
94
  'Toolset_Relationship_Origin_Repeatable_Group' => dirname( __FILE__ ) . '/origin/repeatable_group.php',
95
  'Toolset_Relationship_Origin_Wizard' => dirname( __FILE__ ) . '/origin/wizard.php',
96
+ 'Toolset_Relationship_Query' => dirname( __FILE__ ) . '/relationship/query/relationship_query.php',
97
  'Toolset_Relationship_Query_Base' => dirname( __FILE__ ) . '/query_base.php',
98
  'Toolset_Relationship_Query_Cache' => dirname( __FILE__ ) . '/query_cache.php',
99
+ 'Toolset_Relationship_Query_Cardinality_Match_Conjunction' => dirname( __FILE__ ) . '/relationship/query/cardinality_match/conjunction.php',
100
+ 'Toolset_Relationship_Query_Cardinality_Match_Factory' => dirname( __FILE__ ) . '/relationship/query/cardinality_match/factory.php',
101
+ 'Toolset_Relationship_Query_Cardinality_Match_Operators' => dirname( __FILE__ ) . '/relationship/query/cardinality_match/operators.php',
102
+ 'Toolset_Relationship_Query_Cardinality_Match_Single' => dirname( __FILE__ ) . '/relationship/query/cardinality_match/single.php',
103
+ 'Toolset_Relationship_Query_Condition' => dirname( __FILE__ ) . '/relationship/query/condition/abstract.php',
104
+ 'Toolset_Relationship_Query_Condition_Factory' => dirname( __FILE__ ) . '/relationship/query/condition_factory.php',
105
+ 'Toolset_Relationship_Query_Condition_Has_Active_Types' => dirname( __FILE__ ) . '/relationship/query/condition/has_active_types.php',
106
+ 'Toolset_Relationship_Query_Condition_Has_Cardinality' => dirname( __FILE__ ) . '/relationship/query/condition/has_cardinality.php',
107
+ 'Toolset_Relationship_Query_Condition_Has_Domain' => dirname( __FILE__ ) . '/relationship/query/condition/has_domain.php',
108
+ 'Toolset_Relationship_Query_Condition_Is_Active' => dirname( __FILE__ ) . '/relationship/query/condition/is_active.php',
109
+ 'Toolset_Relationship_Query_Condition_Is_Boolean_Flag' => dirname( __FILE__ ) . '/relationship/query/condition/is_boolean_flag.php',
110
+ 'Toolset_Relationship_Query_Condition_Is_Legacy' => dirname( __FILE__ ) . '/relationship/query/condition/is_legacy.php',
111
+ 'Toolset_Relationship_Query_Condition_Origin' => dirname( __FILE__ ) . '/relationship/query/condition/origin.php',
112
+ 'Toolset_Relationship_Query_Condition_Type' => dirname( __FILE__ ) . '/relationship/query/condition/type.php',
113
+ 'Toolset_Relationship_Query_Factory' => dirname( __FILE__ ) . '/query/factory.php',
114
+ 'Toolset_Relationship_Query_Sql_Expression_Builder' => dirname( __FILE__ ) . '/relationship/query/sql_expression_builder.php',
115
+ 'Toolset_Relationship_Query_V2' => dirname( __FILE__ ) . '/relationship/query/relationship_query_v2.php',
116
+ 'Toolset_Relationship_Role' => dirname( __FILE__ ) . '/relationship/role/role.php',
117
+ 'Toolset_Relationship_Role_Abstract' => dirname( __FILE__ ) . '/relationship/role/abstract.php',
118
+ 'Toolset_Relationship_Role_Child' => dirname( __FILE__ ) . '/relationship/role/child.php',
119
+ 'Toolset_Relationship_Role_Intermediary' => dirname( __FILE__ ) . '/relationship/role/intermediary.php',
120
+ 'Toolset_Relationship_Role_Parent' => dirname( __FILE__ ) . '/relationship/role/parent.php',
121
+ 'Toolset_Relationship_Scope' => dirname( __FILE__ ) . '/relationship/scope.php',
122
+ 'Toolset_Relationship_Slug_Validator' => dirname( __FILE__ ) . '/relationship/slug_validator.php',
 
 
 
 
 
123
  'Toolset_Relationship_Table_Name' => dirname( __FILE__ ) . '/database/table_name.php',
124
  'Toolset_Relationship_Utils' => dirname( __FILE__ ) . '/utils.php',
 
125
  );
vendor/toolset/toolset-common/inc/m2m/cardinality.php CHANGED
@@ -113,7 +113,7 @@ class Toolset_Relationship_Cardinality {
113
  private function validiate_limits() {
114
 
115
  foreach( $this->limits as $element_role => $element_limits ) {
116
- Toolset_Association_Base::validate_element_role( $element_role );
117
 
118
  $min = toolset_getarr( $element_limits, self::MIN, self::INVALID_VALUE );
119
  $max = toolset_getarr( $element_limits, self::MAX, self::INVALID_VALUE );
@@ -157,7 +157,7 @@ class Toolset_Relationship_Cardinality {
157
  * @since m2m
158
  */
159
  public function get_limit( $element_role, $limit_key = self::MAX ) {
160
- Toolset_Association_Base::validate_element_role( $element_role );
161
  self::validate_limit_name( $limit_key );
162
 
163
  return $this->limits[ $element_role ][ $limit_key ];
113
  private function validiate_limits() {
114
 
115
  foreach( $this->limits as $element_role => $element_limits ) {
116
+ Toolset_Association::validate_element_role( $element_role );
117
 
118
  $min = toolset_getarr( $element_limits, self::MIN, self::INVALID_VALUE );
119
  $max = toolset_getarr( $element_limits, self::MAX, self::INVALID_VALUE );
157
  * @since m2m
158
  */
159
  public function get_limit( $element_role, $limit_key = self::MAX ) {
160
+ Toolset_Association::validate_element_role( $element_role );
161
  self::validate_limit_name( $limit_key );
162
 
163
  return $this->limits[ $element_role ][ $limit_key ];
vendor/toolset/toolset-common/inc/m2m/controller.php CHANGED
@@ -17,10 +17,21 @@ class Toolset_Relationship_Controller {
17
  private $_post_type_query_factory;
18
 
19
 
 
 
 
 
 
 
 
 
20
  /** @var Toolset_Relationship_Controller|null */
21
  private static $instance;
22
 
23
 
 
 
 
24
  public static function get_instance() {
25
  if( null == self::$instance ) {
26
  self::$instance = new self();
@@ -34,13 +45,26 @@ class Toolset_Relationship_Controller {
34
  * Toolset_Relationship_Controller constructor.
35
  *
36
  * @param Toolset_Post_Type_Query_Factory|null $post_type_query_factory_di
 
 
37
  */
38
- public function __construct( Toolset_Post_Type_Query_Factory $post_type_query_factory_di = null ) {
 
 
 
 
39
  $this->_post_type_query_factory = $post_type_query_factory_di;
 
 
40
  }
41
 
42
 
43
  const IS_M2M_ENABLED_OPTION = 'toolset_is_m2m_enabled';
 
 
 
 
 
44
 
45
 
46
  /**
@@ -73,10 +97,12 @@ class Toolset_Relationship_Controller {
73
 
74
  $is_enabled = get_option( self::IS_M2M_ENABLED_OPTION, null );
75
 
76
- if( null === $is_enabled ) {
 
 
77
  $is_enabled = $this->set_initial_m2m_state();
78
  } else {
79
- $is_enabled = ( 'no' == $is_enabled ? false : true );
80
  }
81
 
82
  /**
@@ -111,9 +137,8 @@ class Toolset_Relationship_Controller {
111
  return;
112
  }
113
 
114
- $this->is_core_initialized = true;
115
-
116
  $this->add_hooks();
 
117
  }
118
 
119
 
@@ -141,7 +166,8 @@ class Toolset_Relationship_Controller {
141
  // fixme: This is for the purpose of alpha and beta versions: If there's a database problem,
142
  // at least make it fail on every request. Otherwise, we'll just waste a little performance
143
  // on checking that the tables already exist.
144
- $migration = new Toolset_Relationship_Migration();
 
145
  $migration->do_native_dbdelta();
146
 
147
  $this->is_everything_initialized = true;
@@ -187,23 +213,9 @@ class Toolset_Relationship_Controller {
187
  return;
188
  }
189
 
190
- add_filter( 'before_delete_post', array( $this, 'on_before_delete_post' ) );
191
-
192
- // Intercept icl_translations table changes
193
- //
194
- //
195
 
196
- /**
197
- * toolset_use_default_m2m_wpml_interoperability_manager
198
- *
199
- * Allow for disabling the standard WPML interoperability manager if it's about to be overridden by
200
- * something else.
201
- *
202
- * @since m2m
203
- */
204
- if( true == apply_filters( 'toolset_use_default_m2m_wpml_interoperability_manager', true ) ) {
205
- // add_action( 'wpml_translation_update', array( $this, 'on_wpml_translation_update' ), 10 );
206
- }
207
 
208
  /**
209
  * toolset_relationship_query
@@ -233,19 +245,16 @@ class Toolset_Relationship_Controller {
233
  * @since 2.5.6
234
  */
235
  add_action( 'toolset_report_m2m_integrity_issue', array( $this, 'report_integrity_issue' ) );
236
- }
237
 
238
 
239
- /**
240
- * Intercept icl_translations table changes.
241
- *
242
- * @param $args
243
- * @since m2m
244
- */
245
- public function on_wpml_translation_update( $args ) {
246
- $this->initialize_full();
247
- $view_manager = Toolset_Relationship_WPML_Interoperability::get_instance();
248
- $view_manager->on_wpml_translation_update( $args );
249
  }
250
 
251
 
@@ -255,7 +264,7 @@ class Toolset_Relationship_Controller {
255
  * @param $ignored
256
  * @param $query_args
257
  *
258
- * @return int[]|Toolset_Association_Base[]|Toolset_Element[]
259
  */
260
  public function on_toolset_relationship_query( /** @noinspection PhpUnusedParameterInspection */ $ignored, $query_args ) {
261
  $this->initialize_full();
@@ -280,8 +289,7 @@ class Toolset_Relationship_Controller {
280
 
281
  $this->initialize_full();
282
 
283
- $database = new Toolset_Relationship_Database_Operations();
284
- $result = $database->update_type_on_type_sets( $new_slug, $old_slug );
285
 
286
  if( $result->is_error() ) {
287
  error_log( $result->get_message() );
@@ -323,8 +331,6 @@ class Toolset_Relationship_Controller {
323
  * Basically, that means checking if there are any associations with this post and delete them.
324
  * Note that that will also trigger deleting the intermediary post and possibly some owned elements.
325
  *
326
- * WIP
327
- *
328
  * @param int $post_id
329
  * @since m2m
330
  */
@@ -333,15 +339,12 @@ class Toolset_Relationship_Controller {
333
  $this->initialize_full();
334
 
335
  try {
336
- $post = Toolset_Post::get_instance( $post_id );
337
-
338
- $assocation_repository = Toolset_Association_Repository::get_instance();
339
- $assocation_repository->delete_associations_involving_element( $post );
340
-
341
- // todo Query all post's associations and delete them. That should trigger deleting the intermediary posts and owned elements.
342
-
343
  } catch( Exception $e ) {
344
-
 
 
345
  }
346
  }
347
 
@@ -360,20 +363,29 @@ class Toolset_Relationship_Controller {
360
  * @since m2m
361
  */
362
  private function set_initial_m2m_state() {
363
- $legacy_relationships = toolset_ensarr( get_option( 'wpcf_post_relationship', array() ) );
364
- $has_legacy_relationships = ! empty( $legacy_relationships );
365
-
366
  $is_ready_for_m2m = new Toolset_Condition_Plugin_Types_Ready_For_M2M();
367
 
368
- $enable_m2m = ( $is_ready_for_m2m->is_met() && ! $has_legacy_relationships );
 
 
 
 
369
 
370
  if( $enable_m2m ) {
371
  $this->force_autoloader_initialization();
372
- $migration = new Toolset_Relationship_Migration();
373
  $migration->do_native_dbdelta();
374
  }
375
 
376
- update_option( self::IS_M2M_ENABLED_OPTION, ( $enable_m2m ? 'yes' : 'no' ), true );
 
 
 
 
 
 
 
377
  return $enable_m2m;
378
  }
379
 
@@ -403,4 +415,53 @@ class Toolset_Relationship_Controller {
403
  $issue->handle();
404
  }
405
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  }
17
  private $_post_type_query_factory;
18
 
19
 
20
+ /** @var Toolset_Relationship_Database_Operations|null */
21
+ private $_database_operations;
22
+
23
+
24
+ /** @var null|Toolset_Association_Cleanup_Factory */
25
+ private $_cleanup_factory;
26
+
27
+
28
  /** @var Toolset_Relationship_Controller|null */
29
  private static $instance;
30
 
31
 
32
+ /**
33
+ * @return Toolset_Relationship_Controller
34
+ */
35
  public static function get_instance() {
36
  if( null == self::$instance ) {
37
  self::$instance = new self();
45
  * Toolset_Relationship_Controller constructor.
46
  *
47
  * @param Toolset_Post_Type_Query_Factory|null $post_type_query_factory_di
48
+ * @param Toolset_Relationship_Database_Operations|null $database_operations_di
49
+ * @param Toolset_Association_Cleanup_Factory|null $cleanup_factory_di
50
  */
51
+ public function __construct(
52
+ Toolset_Post_Type_Query_Factory $post_type_query_factory_di = null,
53
+ Toolset_Relationship_Database_Operations $database_operations_di = null,
54
+ Toolset_Association_Cleanup_Factory $cleanup_factory_di = null
55
+ ) {
56
  $this->_post_type_query_factory = $post_type_query_factory_di;
57
+ $this->_database_operations = $database_operations_di;
58
+ $this->_cleanup_factory = $cleanup_factory_di;
59
  }
60
 
61
 
62
  const IS_M2M_ENABLED_OPTION = 'toolset_is_m2m_enabled';
63
+ const IS_M2M_ENABLED_YES_VALUE = 'yes';
64
+
65
+ // This is not a typo. Initially, we had 'no', but then we changed the algorithm to determine the initial
66
+ // m2m state, and we have force re-checking.
67
+ const IS_M2M_ENABLED_NO_VALUE = 'noo';
68
 
69
 
70
  /**
97
 
98
  $is_enabled = get_option( self::IS_M2M_ENABLED_OPTION, null );
99
 
100
+ // We'll force the check again if 'no' is stored, because the algorithm for determining
101
+ // the initial state has changed since (now a different value for a negative result is used).
102
+ if( null === $is_enabled || 'no' === $is_enabled ) {
103
  $is_enabled = $this->set_initial_m2m_state();
104
  } else {
105
+ $is_enabled = ( self::IS_M2M_ENABLED_YES_VALUE === $is_enabled );
106
  }
107
 
108
  /**
137
  return;
138
  }
139
 
 
 
140
  $this->add_hooks();
141
+ $this->is_core_initialized = true;
142
  }
143
 
144
 
166
  // fixme: This is for the purpose of alpha and beta versions: If there's a database problem,
167
  // at least make it fail on every request. Otherwise, we'll just waste a little performance
168
  // on checking that the tables already exist.
169
+ // @refactoring
170
+ $migration = new Toolset_Relationship_Migration_Controller();
171
  $migration->do_native_dbdelta();
172
 
173
  $this->is_everything_initialized = true;
213
  return;
214
  }
215
 
216
+ add_action( 'admin_init', array( $this, 'on_admin_init' ) );
 
 
 
 
217
 
218
+ add_filter( 'before_delete_post', array( $this, 'on_before_delete_post' ) );
 
 
 
 
 
 
 
 
 
 
219
 
220
  /**
221
  * toolset_relationship_query
245
  * @since 2.5.6
246
  */
247
  add_action( 'toolset_report_m2m_integrity_issue', array( $this, 'report_integrity_issue' ) );
 
248
 
249
 
250
+ /**
251
+ * toolset_cron_cleanup_dangling_intermediary_posts
252
+ *
253
+ * A WP-Cron event hook defined as Toolset_Association_Cleanup_Cron_Event.
254
+ *
255
+ * @since 2.5.10
256
+ */
257
+ add_action( 'toolset_cron_cleanup_dangling_intermediary_posts', array( $this, 'cleanup_dangling_intermediary_posts' ) );
 
 
258
  }
259
 
260
 
264
  * @param $ignored
265
  * @param $query_args
266
  *
267
+ * @return int[]|Toolset_Association[]|Toolset_Element[]
268
  */
269
  public function on_toolset_relationship_query( /** @noinspection PhpUnusedParameterInspection */ $ignored, $query_args ) {
270
  $this->initialize_full();
289
 
290
  $this->initialize_full();
291
 
292
+ $result = $this->get_database_operations()->update_type_on_type_sets( $new_slug, $old_slug );
 
293
 
294
  if( $result->is_error() ) {
295
  error_log( $result->get_message() );
331
  * Basically, that means checking if there are any associations with this post and delete them.
332
  * Note that that will also trigger deleting the intermediary post and possibly some owned elements.
333
  *
 
 
334
  * @param int $post_id
335
  * @since m2m
336
  */
339
  $this->initialize_full();
340
 
341
  try {
342
+ $cleanup = $this->get_cleanup_factory()->post();
343
+ $cleanup->cleanup( $post_id );
 
 
 
 
 
344
  } catch( Exception $e ) {
345
+ // Silently do nothing and avoid disrupting the current process, whatever it is.
346
+ // In the worst case, any potential dangling db stuff can be sorted out
347
+ // later on the Troubleshooting page.
348
  }
349
  }
350
 
363
  * @since m2m
364
  */
365
  private function set_initial_m2m_state() {
366
+ $has_legacy_relationships = new Toolset_Condition_Plugin_Types_Has_Legacy_Relationships();
 
 
367
  $is_ready_for_m2m = new Toolset_Condition_Plugin_Types_Ready_For_M2M();
368
 
369
+ $enable_m2m = ( $is_ready_for_m2m->is_met() && ! $has_legacy_relationships->is_met() );
370
+
371
+ // If there are no relationships but Toolset is not ready for m2m yet (too old Types), we don't
372
+ // update the option, but keep trying until the update finally comes.
373
+ $store_m2m_state = $is_ready_for_m2m->is_met();
374
 
375
  if( $enable_m2m ) {
376
  $this->force_autoloader_initialization();
377
+ $migration = new Toolset_Relationship_Migration_Controller();
378
  $migration->do_native_dbdelta();
379
  }
380
 
381
+ if( $store_m2m_state ) {
382
+ update_option(
383
+ self::IS_M2M_ENABLED_OPTION,
384
+ ( $enable_m2m ? self::IS_M2M_ENABLED_YES_VALUE : self::IS_M2M_ENABLED_NO_VALUE ),
385
+ true
386
+ );
387
+ }
388
+
389
  return $enable_m2m;
390
  }
391
 
415
  $issue->handle();
416
  }
417
  }
418
+
419
+
420
+ /**
421
+ * @return Toolset_Relationship_Database_Operations
422
+ */
423
+ private function get_database_operations() {
424
+ if( null === $this->_database_operations ) {
425
+ $this->initialize_full();
426
+ $this->_database_operations = new Toolset_Relationship_Database_Operations();
427
+ }
428
+
429
+ return $this->_database_operations;
430
+ }
431
+
432
+
433
+ /**
434
+ * @return Toolset_Association_Cleanup_Factory
435
+ */
436
+ private function get_cleanup_factory() {
437
+ if( null === $this->_cleanup_factory ) {
438
+ $this->initialize_full();
439
+ $this->_cleanup_factory = new Toolset_Association_Cleanup_Factory();
440
+ }
441
+
442
+ return $this->_cleanup_factory;
443
+ }
444
+
445
+
446
+ /**
447
+ * Callback for the WP-Cron event defined as Toolset_Association_Cleanup_Cron_Event.
448
+ *
449
+ * @since 2.5.10
450
+ */
451
+ public function cleanup_dangling_intermediary_posts() {
452
+ $this->initialize_full();
453
+ $cron_handler = $this->get_cleanup_factory()->cron_handler();
454
+ $cron_handler->handle_event();
455
+ }
456
+
457
+
458
+ /**
459
+ * This will run on admin_init:10 if m2m is enabled.
460
+ *
461
+ * @since 2.5.10
462
+ */
463
+ public function on_admin_init() {
464
+ $this->initialize_full();
465
+ $this->get_cleanup_factory()->troubeshooting_section()->register();
466
+ }
467
  }
vendor/toolset/toolset-common/inc/m2m/database/operations.php CHANGED
@@ -6,7 +6,7 @@
6
  * Throughout m2m API, only these classes should directly touch the database:
7
  *
8
  * - Toolset_Relationship_Database_Operations
9
- * - Toolset_Relationship_Migration
10
  * - Toolset_Relationship_Driver
11
  * - Toolset_Relationship_Translation_View_Management
12
  * - Toolset_Association_Query
@@ -51,7 +51,6 @@ class Toolset_Relationship_Database_Operations {
51
  $this->wpdb = $wpdb_di;
52
  }
53
  $this->table_name = ( null === $table_name_di ? new Toolset_Relationship_Table_Name() : $table_name_di );
54
-
55
  }
56
 
57
 
@@ -85,6 +84,7 @@ class Toolset_Relationship_Database_Operations {
85
  *
86
  * @return IToolset_Association|Toolset_Result
87
  * @since m2m
 
88
  */
89
  public static function create_association( $relationship_definition_source, $parent_source, $child_source, $intermediary_id, $instantiate = true ) {
90
 
@@ -210,7 +210,7 @@ class Toolset_Relationship_Database_Operations {
210
  */
211
  private function create_associations_table() {
212
 
213
- $association_table_name = Toolset_Relationship_Table_Name::associations();
214
 
215
  if ( $this->table_exists( $association_table_name ) ) {
216
  return;
@@ -219,17 +219,14 @@ class Toolset_Relationship_Database_Operations {
219
  // Note that dbDelta is very sensitive about details, almost nothing here is arbitrary.
220
  $query = "CREATE TABLE {$association_table_name} (
221
  id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
222
- relationship_id bigint(20) UNSIGNED NOT NULL,
223
- parent_id bigint(20) UNSIGNED NOT NULL,
224
- child_id bigint(20) UNSIGNED NOT NULL,
225
- intermediary_id bigint(20) UNSIGNED NOT NULL,
226
- trid bigint(20) UNSIGNED NOT NULL,
227
- lang varchar(7) NOT NULL DEFAULT '',
228
- translation_type enum('original','translation','none') NOT NULL DEFAULT 'none',
229
- PRIMARY KEY id (id),
230
- KEY relationship_id (relationship_id),
231
  KEY parent_id (parent_id, relationship_id),
232
- KEY child_id (child_id, relationship_id)
233
  ) " . $this->get_charset_collate() . ";";
234
 
235
  self::dbdelta( $query );
@@ -253,36 +250,36 @@ class Toolset_Relationship_Database_Operations {
253
 
254
  // Note that dbDelta is very sensitive about details, almost nothing here is arbitrary.
255
  $query = "CREATE TABLE {$table_name} (
256
- id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
257
- slug varchar(" . self::MAXIMUM_RELATIONSHIP_SLUG_LENGTH . ") NOT NULL DEFAULT '',
258
- display_name_plural varchar(255) NOT NULL DEFAULT '',
259
- display_name_singular varchar(255) NOT NULL DEFAULT '',
260
- driver varchar(50) NOT NULL DEFAULT '',
261
- parent_domain varchar(20) NOT NULL DEFAULT '',
262
- parent_types bigint(20) UNSIGNED NOT NULL DEFAULT 0,
263
- child_domain varchar(20) NOT NULL DEFAULT '',
264
- child_types bigint(20) UNSIGNED NOT NULL DEFAULT 0,
265
- intermediary_type varchar(20) NOT NULL DEFAULT '',
266
- ownership enum('parent', 'child', 'none') NOT NULL DEFAULT 'none',
267
- cardinality_parent_max int(10) NOT NULL DEFAULT -1,
268
- cardinality_parent_min int(10) NOT NULL DEFAULT 0,
269
- cardinality_child_max int(10) NOT NULL DEFAULT -1,
270
- cardinality_child_min int(10) NOT NULL DEFAULT 0,
271
- is_distinct tinyint(1) NOT NULL DEFAULT 0,
272
- scope longtext NOT NULL DEFAULT '',
273
- origin varchar(50) NOT NULL DEFAULT '',
274
- role_name_parent varchar(255) NOT NULL DEFAULT '',
275
- role_name_child varchar(255) NOT NULL DEFAULT '',
276
- role_name_intermediary varchar(255) NOT NULL DEFAULT '',
277
- needs_legacy_support tinyint(1) NOT NULL DEFAULT 0,
278
- is_active tinyint(1) NOT NULL DEFAULT 0,
279
- PRIMARY KEY id (id),
280
- KEY slug (slug),
281
- KEY is_active (is_active),
282
- KEY needs_legacy_support (needs_legacy_support),
283
- KEY parent_type (parent_domain, parent_types),
284
- KEY child_type (child_domain, child_types)
285
- ) " . $this->get_charset_collate() . ";";
286
 
287
  self::dbdelta( $query );
288
 
@@ -297,44 +294,18 @@ class Toolset_Relationship_Database_Operations {
297
 
298
  // Note that dbDelta is very sensitive about details, almost nothing here is arbitrary.
299
  $query = "CREATE TABLE {$table_name} (
300
- id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
301
- set_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
302
- type varchar(20) NOT NULL DEFAULT '',
303
- PRIMARY KEY id (id),
304
- KEY set_id (set_id),
305
- KEY type (type)
306
- ) " . $this->get_charset_collate() . ";";
307
 
308
  self::dbdelta( $query );
309
  }
310
 
311
 
312
- /**
313
- * Get the next unused value for trid (translation ID, grouping different translations of
314
- * one association together).
315
- *
316
- * Assumes that this method will be always called before inserting a new trid, and that
317
- * the returned trid is always used.
318
- *
319
- * @return int
320
- */
321
- public static function get_next_trid() {
322
- static $next_trid = 0;
323
-
324
- if ( 0 === $next_trid ) {
325
- global $wpdb;
326
- $associations_table = Toolset_Relationship_Table_Name::associations();
327
- $last_trid = $wpdb->get_var( "SELECT MAX(trid) FROM {$associations_table}" );
328
-
329
- // It will be incremented and becomes unique in the next step
330
- $next_trid = $last_trid;
331
- }
332
-
333
- $next_trid++;
334
-
335
- return $next_trid;
336
- }
337
-
338
 
339
  /**
340
  * When a relationship definition slug is renamed, update the association table (where the slug is used as a foreign key).
@@ -429,31 +400,31 @@ class Toolset_Relationship_Database_Operations {
429
  $child_types_table_alias = 'child_types_table'
430
  ) {
431
  return "
432
- $relationships_table_alias.id AS id,
433
- $relationships_table_alias.slug AS slug,
434
- $relationships_table_alias.display_name_plural AS display_name_plural,
435
- $relationships_table_alias.display_name_singular AS display_name_singular,
436
- $relationships_table_alias.driver AS driver,
437
- $relationships_table_alias.parent_domain AS parent_domain,
438
- $relationships_table_alias.child_domain AS child_domain,
439
- $relationships_table_alias.intermediary_type AS intermediary_type,
440
- $relationships_table_alias.ownership AS ownership,
441
- $relationships_table_alias.cardinality_parent_max AS cardinality_parent_max,
442
- $relationships_table_alias.cardinality_parent_min AS cardinality_parent_min,
443
- $relationships_table_alias.cardinality_child_max AS cardinality_child_max,
444
- $relationships_table_alias.cardinality_child_min AS cardinality_child_min,
445
- $relationships_table_alias.is_distinct AS is_distinct,
446
- $relationships_table_alias.scope AS scope,
447
- $relationships_table_alias.origin AS origin,
448
- $relationships_table_alias.role_name_parent AS role_name_parent,
449
- $relationships_table_alias.role_name_child AS role_name_child,
450
- $relationships_table_alias.role_name_intermediary AS role_name_intermediary,
451
- $relationships_table_alias.needs_legacy_support AS needs_legacy_support,
452
- $relationships_table_alias.is_active AS is_active,
453
- $relationships_table_alias.parent_types AS parent_types_set_id,
454
- $relationships_table_alias.child_types AS child_types_set_id,
455
- GROUP_CONCAT(DISTINCT $parent_types_table_alias.type) AS parent_types,
456
- GROUP_CONCAT(DISTINCT $child_types_table_alias.type) AS child_types";
457
  }
458
 
459
 
@@ -475,9 +446,9 @@ class Toolset_Relationship_Database_Operations {
475
  $child_types_table_alias = 'child_types_table'
476
  ) {
477
  return "
478
- JOIN {$type_set_table_name} AS {$parent_types_table_alias}
479
  ON ({$relationships_table_alias}.parent_types = {$parent_types_table_alias}.set_id )
480
- JOIN {$type_set_table_name} AS {$child_types_table_alias}
481
  ON ({$relationships_table_alias}.child_types = {$child_types_table_alias}.set_id )";
482
  }
483
 
@@ -502,10 +473,10 @@ class Toolset_Relationship_Database_Operations {
502
  // The query is so complex because it needs to bring in data from the type set tables. But
503
  // those two joins are very cheap because we don't expect many records here.
504
  $query = "
505
- SELECT {$this->get_standard_relationships_select_clause()}
506
- FROM {$relationship_table} AS relationships
507
- {$this->get_standard_relationships_join_clause( $type_set_table )}
508
- GROUP BY {$this->get_standards_relationship_group_by_clause()}";
509
 
510
  $rows = toolset_ensarr( $this->wpdb->get_results( $query ) );
511
  return $rows;
@@ -545,4 +516,91 @@ class Toolset_Relationship_Database_Operations {
545
 
546
  return new Toolset_Result( $is_success, $message );
547
  }
548
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  * Throughout m2m API, only these classes should directly touch the database:
7
  *
8
  * - Toolset_Relationship_Database_Operations
9
+ * - Toolset_Relationship_Migration_Controller
10
  * - Toolset_Relationship_Driver
11
  * - Toolset_Relationship_Translation_View_Management
12
  * - Toolset_Association_Query
51
  $this->wpdb = $wpdb_di;
52
  }
53
  $this->table_name = ( null === $table_name_di ? new Toolset_Relationship_Table_Name() : $table_name_di );
 
54
  }
55
 
56
 
84
  *
85
  * @return IToolset_Association|Toolset_Result
86
  * @since m2m
87
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
88
  */
89
  public static function create_association( $relationship_definition_source, $parent_source, $child_source, $intermediary_id, $instantiate = true ) {
90
 
210
  */
211
  private function create_associations_table() {
212
 
213
+ $association_table_name = $this->table_name->association_table();
214
 
215
  if ( $this->table_exists( $association_table_name ) ) {
216
  return;
219
  // Note that dbDelta is very sensitive about details, almost nothing here is arbitrary.
220
  $query = "CREATE TABLE {$association_table_name} (
221
  id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
222
+ relationship_id bigint(20) UNSIGNED NOT NULL,
223
+ parent_id bigint(20) UNSIGNED NOT NULL,
224
+ child_id bigint(20) UNSIGNED NOT NULL,
225
+ intermediary_id bigint(20) UNSIGNED NOT NULL,
226
+ PRIMARY KEY id (id),
227
+ KEY relationship_id (relationship_id),
 
 
 
228
  KEY parent_id (parent_id, relationship_id),
229
+ KEY child_id (child_id, relationship_id)
230
  ) " . $this->get_charset_collate() . ";";
231
 
232
  self::dbdelta( $query );
250
 
251
  // Note that dbDelta is very sensitive about details, almost nothing here is arbitrary.
252
  $query = "CREATE TABLE {$table_name} (
253
+ id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
254
+ slug varchar(" . self::MAXIMUM_RELATIONSHIP_SLUG_LENGTH . ") NOT NULL DEFAULT '',
255
+ display_name_plural varchar(255) NOT NULL DEFAULT '',
256
+ display_name_singular varchar(255) NOT NULL DEFAULT '',
257
+ driver varchar(50) NOT NULL DEFAULT '',
258
+ parent_domain varchar(20) NOT NULL DEFAULT '',
259
+ parent_types bigint(20) UNSIGNED NOT NULL DEFAULT 0,
260
+ child_domain varchar(20) NOT NULL DEFAULT '',
261
+ child_types bigint(20) UNSIGNED NOT NULL DEFAULT 0,
262
+ intermediary_type varchar(20) NOT NULL DEFAULT '',
263
+ ownership enum('parent', 'child', 'none') NOT NULL DEFAULT 'none',
264
+ cardinality_parent_max int(10) NOT NULL DEFAULT -1,
265
+ cardinality_parent_min int(10) NOT NULL DEFAULT 0,
266
+ cardinality_child_max int(10) NOT NULL DEFAULT -1,
267
+ cardinality_child_min int(10) NOT NULL DEFAULT 0,
268
+ is_distinct tinyint(1) NOT NULL DEFAULT 0,
269
+ scope longtext NOT NULL DEFAULT '',
270
+ origin varchar(50) NOT NULL DEFAULT '',
271
+ role_name_parent varchar(255) NOT NULL DEFAULT '',
272
+ role_name_child varchar(255) NOT NULL DEFAULT '',
273
+ role_name_intermediary varchar(255) NOT NULL DEFAULT '',
274
+ needs_legacy_support tinyint(1) NOT NULL DEFAULT 0,
275
+ is_active tinyint(1) NOT NULL DEFAULT 0,
276
+ PRIMARY KEY id (id),
277
+ KEY slug (slug),
278
+ KEY is_active (is_active),
279
+ KEY needs_legacy_support (needs_legacy_support),
280
+ KEY parent_type (parent_domain, parent_types),
281
+ KEY child_type (child_domain, child_types)
282
+ ) " . $this->get_charset_collate() . ";";
283
 
284
  self::dbdelta( $query );
285
 
294
 
295
  // Note that dbDelta is very sensitive about details, almost nothing here is arbitrary.
296
  $query = "CREATE TABLE {$table_name} (
297
+ id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
298
+ set_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
299
+ type varchar(20) NOT NULL DEFAULT '',
300
+ PRIMARY KEY id (id),
301
+ KEY set_id (set_id),
302
+ KEY type (type)
303
+ ) " . $this->get_charset_collate() . ";";
304
 
305
  self::dbdelta( $query );
306
  }
307
 
308
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
 
310
  /**
311
  * When a relationship definition slug is renamed, update the association table (where the slug is used as a foreign key).
400
  $child_types_table_alias = 'child_types_table'
401
  ) {
402
  return "
403
+ $relationships_table_alias.id AS id,
404
+ $relationships_table_alias.slug AS slug,
405
+ $relationships_table_alias.display_name_plural AS display_name_plural,
406
+ $relationships_table_alias.display_name_singular AS display_name_singular,
407
+ $relationships_table_alias.driver AS driver,
408
+ $relationships_table_alias.parent_domain AS parent_domain,
409
+ $relationships_table_alias.child_domain AS child_domain,
410
+ $relationships_table_alias.intermediary_type AS intermediary_type,
411
+ $relationships_table_alias.ownership AS ownership,
412
+ $relationships_table_alias.cardinality_parent_max AS cardinality_parent_max,
413
+ $relationships_table_alias.cardinality_parent_min AS cardinality_parent_min,
414
+ $relationships_table_alias.cardinality_child_max AS cardinality_child_max,
415
+ $relationships_table_alias.cardinality_child_min AS cardinality_child_min,
416
+ $relationships_table_alias.is_distinct AS is_distinct,
417
+ $relationships_table_alias.scope AS scope,
418
+ $relationships_table_alias.origin AS origin,
419
+ $relationships_table_alias.role_name_parent AS role_name_parent,
420
+ $relationships_table_alias.role_name_child AS role_name_child,
421
+ $relationships_table_alias.role_name_intermediary AS role_name_intermediary,
422
+ $relationships_table_alias.needs_legacy_support AS needs_legacy_support,
423
+ $relationships_table_alias.is_active AS is_active,
424
+ $relationships_table_alias.parent_types AS parent_types_set_id,
425
+ $relationships_table_alias.child_types AS child_types_set_id,
426
+ GROUP_CONCAT(DISTINCT $parent_types_table_alias.type) AS parent_types,
427
+ GROUP_CONCAT(DISTINCT $child_types_table_alias.type) AS child_types";
428
  }
429
 
430
 
446
  $child_types_table_alias = 'child_types_table'
447
  ) {
448
  return "
449
+ JOIN {$type_set_table_name} AS {$parent_types_table_alias}
450
  ON ({$relationships_table_alias}.parent_types = {$parent_types_table_alias}.set_id )
451
+ JOIN {$type_set_table_name} AS {$child_types_table_alias}
452
  ON ({$relationships_table_alias}.child_types = {$child_types_table_alias}.set_id )";
453
  }
454
 
473
  // The query is so complex because it needs to bring in data from the type set tables. But
474
  // those two joins are very cheap because we don't expect many records here.
475
  $query = "
476
+ SELECT {$this->get_standard_relationships_select_clause()}
477
+ FROM {$relationship_table} AS relationships
478
+ {$this->get_standard_relationships_join_clause( $type_set_table )}
479
+ GROUP BY {$this->get_standards_relationship_group_by_clause()}";
480
 
481
  $rows = toolset_ensarr( $this->wpdb->get_results( $query ) );
482
  return $rows;
516
 
517
  return new Toolset_Result( $is_success, $message );
518
  }
519
+
520
+
521
+ /**
522
+ * Queries all post's associations and delete them.
523
+ *
524
+ * That should trigger deleting the intermediary posts and owned elements.
525
+ *
526
+ * @param IToolset_Element $element
527
+ * @deprecated Should be unused since 2.5.10. Replaced by Toolset_Association_Cleanup_Post.
528
+ */
529
+ public function delete_associations_involving_element( $element ) {
530
+
531
+ trigger_error(
532
+ 'Toolset_Relationship_Database_Operations::delete_associations_involving_element() is deprecated and should not be used anymore.',
533
+ E_USER_NOTICE
534
+ );
535
+
536
+ $query_parent = new Toolset_Association_Query( array(
537
+ Toolset_Association_Query::QUERY_PARENT_DOMAIN => $element->get_domain(),
538
+ Toolset_Association_Query::QUERY_PARENT_ID => $element->get_id(),
539
+ Toolset_Association_Query::OPTION_RETURN => Toolset_Association_Query::RETURN_ASSOCIATIONS
540
+ ) );
541
+
542
+ $associations = $query_parent->get_results();
543
+
544
+ $query_child = new Toolset_Association_Query( array(
545
+ Toolset_Association_Query::QUERY_PARENT_DOMAIN => $element->get_domain(),
546
+ Toolset_Association_Query::QUERY_PARENT_ID => $element->get_id(),
547
+ Toolset_Association_Query::OPTION_RETURN => Toolset_Association_Query::RETURN_ASSOCIATIONS
548
+ ) );
549
+
550
+ /** @var Toolset_Association[] $associations */
551
+ $associations = array_merge( $associations, $query_child->get_results() );
552
+
553
+ foreach( $associations as $association ) {
554
+ $definition = $association->get_definition();
555
+ $driver = $definition->get_driver();
556
+ $driver->delete_association( $association );
557
+ }
558
+
559
+ }
560
+
561
+
562
+ /**
563
+ * Updates association intermediary post
564
+ *
565
+ * @param int $association_id Association trID
566
+ * @param int $intermediary_id New intermediary ID
567
+ * @since m2m
568
+ */
569
+ public function update_association_intermediary_id( $association_id, $intermediary_id ) {
570
+ $this->wpdb->update(
571
+ $this->table_name->association_table(),
572
+ array(
573
+ 'intermediary_id' => $intermediary_id,
574
+ ),
575
+ array(
576
+ 'id' => $association_id,
577
+ ),
578
+ array( '%d' )
579
+ );
580
+ }
581
+
582
+
583
+ /**
584
+ * Returns the maximun number of associations of a relationship for a parent id and a child id
585
+ *
586
+ * @param int $relationship_id Relationship ID.
587
+ * @param string $role_name Role name.
588
+ * @return int
589
+ * @throws InvalidArgumentException In case of error.
590
+ */
591
+ public function count_max_associations( $relationship_id, $role_name ) {
592
+ if ( ! in_array( $role_name, Toolset_Relationship_Role::parent_child_role_names() ) ) {
593
+ throw new InvalidArgumentException( 'Wrong role name' );
594
+ }
595
+ $count = $this->wpdb->get_var(
596
+ $this->wpdb->prepare(
597
+ "SELECT max(n) count
598
+ FROM (
599
+ SELECT count(*) n
600
+ FROM `wp_toolset_associations`
601
+ WHERE relationship_id = %d
602
+ GROUP BY {$role_name}_id
603
+ ) count", $relationship_id ) );
604
+ return $count;
605
+ }
606
+ }
vendor/toolset/toolset-common/inc/m2m/driver.php CHANGED
@@ -21,19 +21,18 @@ class Toolset_Relationship_Driver extends Toolset_Relationship_Driver_Base {
21
  * @param int|Toolset_Element|WP_Post $child_source
22
  * @param array $args Association arguments:
23
  * - 'intermediary_id': ID of the intermediary post; defaults to zero.
24
- * - 'instantiate': bool Whether to return an association on success, or just a result. Default is false
25
  *
26
- * todo check that the intermediary post really exists, has the correct type, is not taken
27
- *
28
- * @return IToolset_Association|Toolset_Result ID of the new association on success or a result information with an error.
29
  */
30
  public function create_association( $parent_source, $child_source, $args = array() ) {
31
 
32
  $relationship_definition = $this->get_relationship_definition();
33
 
34
  // This will throw when the elements don't exist
35
- $parent = Toolset_Element::get_untranslated_instance( $relationship_definition->get_parent_domain(), $parent_source );
36
- $child = Toolset_Element::get_untranslated_instance( $relationship_definition->get_child_domain(), $child_source );
37
 
38
  // We need to make sure the association is allowed.
39
  $potential_association_query = $this->get_potential_association_query_factory()->create(
@@ -49,22 +48,26 @@ class Toolset_Relationship_Driver extends Toolset_Relationship_Driver_Base {
49
 
50
  $intermediary_id = (int) toolset_getarr( $args, 'intermediary_id', 0 );
51
 
52
- // Create intermediary post if the association should have some fields.
53
- $needs_fields = $relationship_definition->has_association_field_definitions();
54
- if ( 0 == $intermediary_id && $needs_fields ) {
55
- $intermediary_id = (int) $this->create_intermediary_post( $parent->get_id(), $child->get_id() );
56
  }
57
 
58
- // Insert the database records as needed, respecting the status of WPML and
59
- // existing translations of related items.
60
- $intermediary = ( 0 !== $intermediary_id ? Toolset_Post::get_instance( $intermediary_id ) : null );
61
  try {
62
- $insert_results = $this->translate_and_insert( $parent, $child, $intermediary );
 
 
 
 
 
 
 
63
  } catch( Exception $e ) {
64
  return new Toolset_Result(
65
  false,
66
  sprintf(
67
- __( 'Database error occurred when creating an association: %s', 'wpcf' ),
68
  $e->getMessage()
69
  )
70
  );
@@ -73,9 +76,7 @@ class Toolset_Relationship_Driver extends Toolset_Relationship_Driver_Base {
73
  // Get the association instance (in the best language available)
74
  $instantiate_association = (bool) toolset_getarr( $args, 'instantiate', false );
75
  if ( $instantiate_association ) {
76
- $association = $this->instantiate_after_insert( $insert_results, $relationship_definition );
77
-
78
- return $association;
79
  } else {
80
  return new Toolset_Result( true, __( 'Association created', 'wpcf' ) );
81
  }
@@ -83,255 +84,6 @@ class Toolset_Relationship_Driver extends Toolset_Relationship_Driver_Base {
83
  }
84
 
85
 
86
- /**
87
- * Return one instance of Toolset_Association, choosing the best language version.
88
- *
89
- * @param $insert_results
90
- * @param $relationship_definition
91
- *
92
- * @return IToolset_Association
93
- */
94
- private function instantiate_after_insert( $insert_results, $relationship_definition ) {
95
-
96
- // Prepare results into lang => ID arrays for each element.
97
- $element_sources = array(
98
- Toolset_Relationship_Role::PARENT => array(),
99
- Toolset_Relationship_Role::CHILD => array(),
100
- Toolset_Relationship_Role::INTERMEDIARY => array()
101
- );
102
-
103
- foreach ( $insert_results as $language_code => $insert_result ) {
104
- foreach ( Toolset_Relationship_Role::all_role_names() as $role_name ) {
105
- $element_sources[ $role_name ][ $language_code ] = $insert_result['elements'][ $role_name ];
106
- }
107
- }
108
-
109
- // Get a trid of the association (which is the same for all language versions).
110
- $single_language_version = array_slice( $insert_results, 0, 1 );
111
- $any_language_version = array_shift( $single_language_version );
112
- $trid = $any_language_version['trid'];
113
-
114
- $association = Toolset_Association_Repository::get_instance()->instantiate(
115
- $relationship_definition,
116
- $trid,
117
- $element_sources
118
- );
119
-
120
- return $association;
121
- }
122
-
123
-
124
- /**
125
- * Get all translations of given element.
126
- *
127
- * For non-posts, non-translatable posts or when WPML is not active, it will not attempt any translation.
128
- *
129
- * @param IToolset_Element|null $element
130
- *
131
- * @return int[] Associative array of post IDs, keys are language codes.
132
- */
133
- private function get_post_translations_or_default( $element ) {
134
- if ( ! $element instanceof Toolset_Element ) {
135
- return array( '' => 0 );
136
- } elseif (
137
- ! $element instanceof Toolset_Post
138
- || ! Toolset_Relationship_Multilingual_Mode::is_on()
139
- || ! $element->is_translatable()
140
- ) {
141
- return array( '' => $element->get_id() );
142
- }
143
-
144
- return Toolset_Wpml_Utils::get_post_translations_directly( $element->get_id() );
145
- }
146
-
147
-
148
- /**
149
- * Get the complete translation information for given elements, organized into triplets by language.
150
- *
151
- * If WPML is not active or the element is not translatable, it will have language '' (empty string).
152
- * If a particular element translation is missing, there will be a zero instead the translation ID.
153
- *
154
- * @param IToolset_Element $parent
155
- * @param IToolset_Element $child
156
- * @param Toolset_Post|null $intermediary
157
- *
158
- * @return array[string] Associative array of triplets, where keys are language codes and each
159
- * triplet always contains items for the parent, child and intermediary post IDs (or zero if
160
- * no translation is available).
161
- */
162
- private function get_translation_triplets( $parent, $child, $intermediary ) {
163
-
164
- $parent_translations = $this->get_post_translations_or_default( $parent );
165
- $child_translations = $this->get_post_translations_or_default( $child );
166
- $intermediary_translations = $this->get_post_translations_or_default( $intermediary );
167
-
168
- $present_languages = array_unique(
169
- array_merge(
170
- array_keys( $parent_translations ),
171
- array_keys( $child_translations ),
172
- array_keys( $intermediary_translations )
173
- )
174
- );
175
-
176
-
177
- $translations = array();
178
- foreach ( $present_languages as $language_code ) {
179
- $parent_id = toolset_getarr( $parent_translations, $language_code, 0 );
180
- $child_id = toolset_getarr( $child_translations, $language_code, 0 );
181
- $intermediary_id = toolset_getarr( $intermediary_translations, $language_code, 0 );
182
-
183
- if ( 0 === $parent_id && 0 === $child_id ) {
184
- // There are no actual elements to associate, skip this language
185
- continue;
186
- }
187
-
188
- $translations[ $language_code ] = array(
189
- Toolset_Relationship_Role::PARENT => $parent_id,
190
- Toolset_Relationship_Role::CHILD => $child_id,
191
- Toolset_Relationship_Role::INTERMEDIARY => $intermediary_id
192
- );
193
- }
194
-
195
- return $translations;
196
- }
197
-
198
-
199
- /**
200
- * Get all available translations of given elements and create the appropriate
201
- * records in the associations table.
202
- *
203
- * @param IToolset_Element $parent
204
- * @param IToolset_Element $child
205
- * @param Toolset_Post|null $intermediary
206
- *
207
- * @return array Translation results. Each key is a language code (can be an empty string if
208
- * the language information is not available) and the item is an associative array with
209
- * following elements:
210
- * - id: The association ID for this language.
211
- * - trid: Association trid (same for all languages).
212
- * - elements: A "translation triplet" of element IDs in this language (or 0 where no translation exists)
213
- * - translation_type: 'none'|'original'|'translation'
214
- *
215
- * @since m2m
216
- */
217
- private function translate_and_insert( $parent, $child, $intermediary ) {
218
-
219
- global $wpdb;
220
-
221
- $translations = $this->get_translation_triplets( $parent, $child, $intermediary );
222
-
223
- // We're going to need a unique trid to bind translations together.
224
- // Even if we don't use WPML, trid is still needed for grouping records in the associations table.
225
- $trid = Toolset_Relationship_Database_Operations::get_next_trid();
226
-
227
- $translation_type = 'none';
228
- $has_translations = ! ( 1 === count( $translations ) && array_key_exists( '', $translations ) );
229
-
230
- $insert_results = array();
231
- foreach ( $translations as $language_code => $elements ) {
232
-
233
- if ( $has_translations ) {
234
- $translation_type = $this->determine_translation_type( $elements, $parent, $child, $intermediary, $language_code );
235
- }
236
-
237
- $affected_rows = $wpdb->insert(
238
- Toolset_Relationship_Table_Name::associations(),
239
- array(
240
- 'relationship_id' => $this->get_relationship_definition()->get_row_id(),
241
- 'parent_id' => $elements[ Toolset_Relationship_Role::PARENT ],
242
- 'child_id' => $elements[ Toolset_Relationship_Role::CHILD ],
243
- 'intermediary_id' => $elements[ Toolset_Relationship_Role::INTERMEDIARY ],
244
- 'trid' => $trid,
245
- 'lang' => $language_code,
246
- 'translation_type' => $translation_type
247
- ),
248
- array(
249
- '%s',
250
- '%d',
251
- '%d',
252
- '%d',
253
- '%d',
254
- '%s',
255
- '%s'
256
- )
257
- );
258
-
259
- if ( false == $affected_rows ) {
260
- throw new RuntimeException( __( 'Error when inserting a row in the associations table.', 'wpcf' ) );
261
- }
262
-
263
- $association_id = $wpdb->insert_id;
264
-
265
- if ( ! Toolset_Utils::is_natural_numeric( $association_id ) ) {
266
- // Not an ID, fail
267
- throw new RuntimeException( __( 'Unable to obtain an ID of the newly created association.', 'wpcf' ) );
268
- }
269
-
270
- $insert_results[ $language_code ] = array(
271
- 'id' => $association_id,
272
- 'trid' => $trid,
273
- 'elements' => $elements,
274
- 'translation_type' => $translation_type
275
- );
276
-
277
- }
278
-
279
- return $insert_results;
280
- }
281
-
282
-
283
- /**
284
- * Compare elements from a particular language version with the original ones and decide the
285
- * translation type.
286
- *
287
- * The match of elements is required per each role, unless the original element is nontranslatable (
288
- * or missing). When no language code is provided, the translation type is automatically 'none'.
289
- *
290
- * @param int[] $elements Element IDs, indexed by role names.
291
- * @param IToolset_Element $original_parent
292
- * @param IToolset_Element $original_child
293
- * @param Toolset_Post|null $original_intermediary
294
- * @param string $language_code
295
- *
296
- * @return string 'none'|'original'|'translation'
297
- */
298
- private function determine_translation_type( $elements, $original_parent, $original_child, $original_intermediary, $language_code ) {
299
- if ( '' === $language_code ) {
300
- return 'none';
301
- }
302
-
303
- $is_original = (
304
- $this->is_element_original_or_untranslatable( $elements, Toolset_Relationship_Role::PARENT, $original_parent )
305
- && $this->is_element_original_or_untranslatable( $elements, Toolset_Relationship_Role::CHILD, $original_child )
306
- && $this->is_element_original_or_untranslatable( $elements, Toolset_Relationship_Role::INTERMEDIARY, $original_intermediary )
307
- );
308
-
309
- return ( $is_original ? 'original' : 'translation' );
310
- }
311
-
312
-
313
- /**
314
- * Check if a particular elements match IDs or are untranslatable.
315
- *
316
- * @param int[] $elements_to_check
317
- * @param string $role
318
- * @param IToolset_Element $original_element
319
- *
320
- * @return bool
321
- */
322
- private function is_element_original_or_untranslatable( $elements_to_check, $role, $original_element ) {
323
-
324
- $original_element_id = ( null === $original_element ? 0 : $original_element->get_id() );
325
-
326
- $result = (
327
- $elements_to_check[ $role ] == $original_element_id
328
- || ! $original_element->is_translatable()
329
- );
330
-
331
- return $result;
332
- }
333
-
334
-
335
  /**
336
  * Get the slug of the indermediary post type that holds association fields.
337
  *
@@ -483,173 +235,20 @@ class Toolset_Relationship_Driver extends Toolset_Relationship_Driver_Base {
483
  }
484
 
485
 
486
- /**
487
- * Create an intermediary post for a new association.
488
- *
489
- * @param int $parent_id
490
- * @param int $child_id
491
- *
492
- * @return int|null ID of the new post or null if the post creation failed.
493
- * @since m2m
494
- */
495
- private function create_intermediary_post( $parent_id, $child_id ) {
496
- $post_type = $this->get_intermediary_post_type();
497
-
498
- if ( null == $post_type ) {
499
- return null;
500
- }
501
-
502
- /**
503
- * toolset_build_intermediary_post_title
504
- *
505
- * Allow for overriding the post title of an intermediary post.
506
- *
507
- * @param string $post_title Post title default value.
508
- * @param string $relationship_slug
509
- * @param int $parent_id
510
- * @param int $child_id
511
- *
512
- * @since m2m
513
- */
514
- $post_title = wp_strip_all_tags(
515
- apply_filters(
516
- 'toolset_build_intermediary_post_title',
517
- $this->get_default_intermediary_post_title( $parent_id, $child_id ),
518
- $this->get_relationship_slug(),
519
- $parent_id,
520
- $child_id
521
- )
522
- );
523
-
524
- /**
525
- * toolset_build_intermediary_post_name
526
- *
527
- * Allow for overriding the post name (slug) of an intermediary post.
528
- *
529
- * @param string $post_slug Post slug default value.
530
- * @param string $relationship_slug
531
- * @param int $parent_id
532
- * @param int $child_id
533
- *
534
- * @since m2m
535
- */
536
- $post_name = apply_filters(
537
- 'toolset_build_intermediary_post_name',
538
- $post_title,
539
- $this->get_relationship_slug(),
540
- $parent_id,
541
- $child_id
542
- );
543
-
544
- $result = wp_insert_post(
545
- array(
546
- 'post_type' => $post_type,
547
- 'post_title' => $post_title,
548
- 'post_name' => $post_name,
549
- 'post_content' => '',
550
- 'post_status' => 'publish'
551
- ),
552
- true
553
- );
554
-
555
- if ( $result instanceof WP_Error ) {
556
- return null;
557
- } else {
558
- return $result;
559
- }
560
- }
561
-
562
-
563
- private function get_default_intermediary_post_title( $parent_id, $child_id ) {
564
- // Todo improve this - allow for specifying a default template in the relationship definition
565
- $relationship_definition = $this->get_relationship_definition();
566
-
567
- return sprintf(
568
- '%s: %d - %d',
569
- $relationship_definition->get_display_name(),
570
- $parent_id,
571
- $child_id
572
- );
573
- }
574
-
575
-
576
  /**
577
  * Delete an association from the database.
578
  *
579
  * Also delete an intermediary post if it exists.
580
  *
581
- * @param Toolset_Association $association
582
  *
583
  * @return Toolset_Result
 
 
584
  * @since m2m
585
  */
586
  public function delete_association( $association ) {
587
-
588
- if ( ! $this->is_association_match( $association ) ) {
589
- throw new InvalidArgumentException();
590
- }
591
-
592
- // Trigger the association translation view refresh.
593
- // fixme probably no longer needed
594
- $view_management = Toolset_Relationship_WPML_Interoperability::get_instance();
595
- $view_management->before_association_delete( $association );
596
-
597
- $this->maybe_delete_intermediary_post( $association );
598
-
599
- global $wpdb;
600
-
601
- $rows_updated = $wpdb->delete(
602
- Toolset_Relationship_Table_Name::associations(),
603
- // todo make this clearer - add a method to specifically query for trid
604
- array( 'trid' => $association->get_uid() ),
605
- '%d'
606
- );
607
-
608
- $is_success = ( false !== $rows_updated || 1 === $rows_updated );
609
-
610
- return new Toolset_Result( $is_success );
611
- }
612
-
613
-
614
- /**
615
- * Delete the intermediary post if it exists and it's not disabled by a filter.
616
- *
617
- * fixme probably need to delete its translations too (in that case, rename)
618
- *
619
- * @param Toolset_Association $association
620
- */
621
- private function maybe_delete_intermediary_post( $association ) {
622
-
623
- if ( $association->has_intermediary_post() ) {
624
- $intermediary_id = $association->get_intermediary_id();
625
-
626
- /**
627
- * toolset_deleting_association_intermediary_post
628
- *
629
- * Notify about deleting the intermediary post and allow avoiding it.
630
- *
631
- * @param bool $delete_post Whether the post should be deleted.
632
- * @param int $intermediary_id ID of the intermediary post.
633
- * @param int $association_uid Unique identifier of the (native) association that is removing it
634
- * @param Toolset_Association $association The association object.
635
- */
636
- $delete_post = apply_filters(
637
- 'toolset_deleting_association_intermediary_post',
638
- true,
639
- $intermediary_id,
640
- $association->get_uid(),
641
- $association
642
- );
643
-
644
- if ( $delete_post ) {
645
- wp_delete_post( $intermediary_id );
646
- }
647
- }
648
- }
649
-
650
-
651
- protected function is_association_match( $association ) {
652
- return ( parent::is_association_match( $association ) && $association instanceof Toolset_Association );
653
  }
654
 
655
  }
21
  * @param int|Toolset_Element|WP_Post $child_source
22
  * @param array $args Association arguments:
23
  * - 'intermediary_id': ID of the intermediary post; defaults to zero.
 
24
  *
25
+ * @return IToolset_Association|Toolset_Result ID of the new association on success or a result information with an
26
+ * error.
27
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
28
  */
29
  public function create_association( $parent_source, $child_source, $args = array() ) {
30
 
31
  $relationship_definition = $this->get_relationship_definition();
32
 
33
  // This will throw when the elements don't exist
34
+ $parent = $this->get_element_factory()->get_element( $relationship_definition->get_parent_domain(), $parent_source );
35
+ $child = $this->get_element_factory()->get_element( $relationship_definition->get_child_domain(), $child_source );
36
 
37
  // We need to make sure the association is allowed.
38
  $potential_association_query = $this->get_potential_association_query_factory()->create(
48
 
49
  $intermediary_id = (int) toolset_getarr( $args, 'intermediary_id', 0 );
50
 
51
+ // Create intermediary post if doesn't exist.
52
+ if ( 0 === $intermediary_id ) {
53
+ $association_helper = new Toolset_Association_Intermediary_Post_Persistence( $relationship_definition );
54
+ $intermediary_id = (int) $association_helper->create_intermediary_post( $parent->get_id(), $child->get_id() );
55
  }
56
 
 
 
 
57
  try {
58
+ $association = $this->association_factory->create(
59
+ $relationship_definition,
60
+ $parent->get_id(),
61
+ $child->get_id(),
62
+ $intermediary_id
63
+ );
64
+
65
+ $updated_association = $this->association_persistence->insert_association( $association );
66
  } catch( Exception $e ) {
67
  return new Toolset_Result(
68
  false,
69
  sprintf(
70
+ __( 'An error occurred when creating an association: %s', 'wpcf' ),
71
  $e->getMessage()
72
  )
73
  );
76
  // Get the association instance (in the best language available)
77
  $instantiate_association = (bool) toolset_getarr( $args, 'instantiate', false );
78
  if ( $instantiate_association ) {
79
+ return $updated_association;
 
 
80
  } else {
81
  return new Toolset_Result( true, __( 'Association created', 'wpcf' ) );
82
  }
84
  }
85
 
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  /**
88
  * Get the slug of the indermediary post type that holds association fields.
89
  *
235
  }
236
 
237
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  /**
239
  * Delete an association from the database.
240
  *
241
  * Also delete an intermediary post if it exists.
242
  *
243
+ * @param Toolset_Association|IToolset_Association $association
244
  *
245
  * @return Toolset_Result
246
+ *
247
+ * @deprecated Use Toolset_Association_Persistence::delete_association() instead.
248
  * @since m2m
249
  */
250
  public function delete_association( $association ) {
251
+ return $this->association_persistence->delete_association( $association );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  }
253
 
254
  }
vendor/toolset/toolset-common/inc/m2m/driver_base.php CHANGED
@@ -9,30 +9,56 @@
9
  */
10
  abstract class Toolset_Relationship_Driver_Base {
11
 
 
12
  /** @var Toolset_Relationship_Definition */
13
  private $definition;
14
 
 
15
  /** @var array Driver setup array provided by the relationship definition. */
16
  private $setup;
17
 
 
18
  /** @var null|Toolset_Potential_Association_Query_Factory */
19
  private $_potential_association_query_factory;
20
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  /**
22
  * Toolset_Relationship_Driver_Base constructor.
23
  *
24
  * @param Toolset_Relationship_Definition $definition Relationship definition that is going to be using this driver.
25
  * @param array $setup Driver setup array provided by the relationship definition.
26
  * @param Toolset_Potential_Association_Query_Factory|null $pa_query_factory_di
 
 
 
27
  *
28
  * @since m2m
29
  */
30
  public function __construct(
31
- Toolset_Relationship_Definition $definition, $setup, Toolset_Potential_Association_Query_Factory $pa_query_factory_di = null
 
 
 
 
 
32
  ) {
33
  $this->definition = $definition;
34
  $this->setup = toolset_ensarr( $setup );
35
  $this->_potential_association_query_factory = $pa_query_factory_di;
 
 
 
36
  }
37
 
38
 
@@ -58,7 +84,7 @@ abstract class Toolset_Relationship_Driver_Base {
58
  * @param int|Toolset_Element|WP_Post $child_source
59
  * @param array $args Optional arguments, implementation-specific
60
  *
61
- * @return Toolset_Association_Base|Toolset_Result ID of the new association on success or a result information with an error.
62
  */
63
  public abstract function create_association( $parent_source, $child_source, $args = array() );
64
 
@@ -66,7 +92,7 @@ abstract class Toolset_Relationship_Driver_Base {
66
  /**
67
  * Delete an association from the database.
68
  *
69
- * @param Toolset_Association_Base $association
70
  *
71
  * @return Toolset_Result
72
  * @since m2m
@@ -129,7 +155,7 @@ abstract class Toolset_Relationship_Driver_Base {
129
 
130
 
131
  protected function is_association_match( $association ) {
132
- return ( $association instanceof Toolset_Association_Base && $association->get_driver() === $this );
133
  }
134
 
135
 
@@ -144,4 +170,17 @@ abstract class Toolset_Relationship_Driver_Base {
144
 
145
  return $this->_potential_association_query_factory;
146
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  }
9
  */
10
  abstract class Toolset_Relationship_Driver_Base {
11
 
12
+
13
  /** @var Toolset_Relationship_Definition */
14
  private $definition;
15
 
16
+
17
  /** @var array Driver setup array provided by the relationship definition. */
18
  private $setup;
19
 
20
+
21
  /** @var null|Toolset_Potential_Association_Query_Factory */
22
  private $_potential_association_query_factory;
23
 
24
+
25
+ /** @var Toolset_Association_Persistence */
26
+ protected $association_persistence;
27
+
28
+
29
+ /** @var Toolset_Association_Factory */
30
+ protected $association_factory;
31
+
32
+ /** @var null|Toolset_Element_Factory */
33
+ private $_element_factory;
34
+
35
+
36
  /**
37
  * Toolset_Relationship_Driver_Base constructor.
38
  *
39
  * @param Toolset_Relationship_Definition $definition Relationship definition that is going to be using this driver.
40
  * @param array $setup Driver setup array provided by the relationship definition.
41
  * @param Toolset_Potential_Association_Query_Factory|null $pa_query_factory_di
42
+ * @param Toolset_Association_Persistence|null $association_persistence_di
43
+ * @param Toolset_Association_Factory|null $association_factory_di
44
+ * @param Toolset_Element_Factory|null $element_factory_di
45
  *
46
  * @since m2m
47
  */
48
  public function __construct(
49
+ Toolset_Relationship_Definition $definition,
50
+ $setup,
51
+ Toolset_Potential_Association_Query_Factory $pa_query_factory_di = null,
52
+ Toolset_Association_Persistence $association_persistence_di = null,
53
+ Toolset_Association_Factory $association_factory_di = null,
54
+ Toolset_Element_Factory $element_factory_di = null
55
  ) {
56
  $this->definition = $definition;
57
  $this->setup = toolset_ensarr( $setup );
58
  $this->_potential_association_query_factory = $pa_query_factory_di;
59
+ $this->association_persistence = $association_persistence_di ?: new Toolset_Association_Persistence();
60
+ $this->association_factory = $association_factory_di ?: new Toolset_Association_Factory();
61
+ $this->_element_factory = $element_factory_di;
62
  }
63
 
64
 
84
  * @param int|Toolset_Element|WP_Post $child_source
85
  * @param array $args Optional arguments, implementation-specific
86
  *
87
+ * @return Toolset_Association|Toolset_Result ID of the new association on success or a result information with an error.
88
  */
89
  public abstract function create_association( $parent_source, $child_source, $args = array() );
90
 
92
  /**
93
  * Delete an association from the database.
94
  *
95
+ * @param Toolset_Association $association
96
  *
97
  * @return Toolset_Result
98
  * @since m2m
155
 
156
 
157
  protected function is_association_match( $association ) {
158
+ return ( $association instanceof Toolset_Association && $association->get_driver() === $this );
159
  }
160
 
161
 
170
 
171
  return $this->_potential_association_query_factory;
172
  }
173
+
174
+
175
+ /**
176
+ * @return Toolset_Element_Factory
177
+ * @since 2.5.9
178
+ */
179
+ protected function get_element_factory() {
180
+ if( null === $this->_element_factory ) {
181
+ $this->_element_factory = new Toolset_Element_Factory();
182
+ }
183
+
184
+ return $this->_element_factory;
185
+ }
186
  }
vendor/toolset/toolset-common/inc/m2m/element_type.php CHANGED
@@ -84,7 +84,7 @@ class Toolset_Relationship_Element_Type {
84
  * @since m2m
85
  */
86
  private static function get_available_domains() {
87
- return array( self::DOMAIN_POSTS );
88
  }
89
 
90
 
@@ -132,7 +132,7 @@ class Toolset_Relationship_Element_Type {
132
  public static function build_for_post_type( $post_type_slug ) {
133
  return new self(
134
  array(
135
- self::DA_DOMAIN => self::DOMAIN_POSTS,
136
  self::DA_TYPES => array( $post_type_slug )
137
  )
138
  );
@@ -148,11 +148,11 @@ class Toolset_Relationship_Element_Type {
148
  */
149
  public function is_match( $element ) {
150
 
151
- if( ! $element instanceof Toolset_Element ) {
152
  throw new InvalidArgumentException( 'Invalid element provided.' );
153
  }
154
 
155
- if( $element->get_domain() != $this->get_domain() ) {
156
  return false;
157
  }
158
 
@@ -188,7 +188,7 @@ class Toolset_Relationship_Element_Type {
188
 
189
  $this->is_translatable = false;
190
 
191
- if( Toolset_Field_Utils::DOMAIN_POSTS == $this->get_domain() ) {
192
  foreach( $this->get_types() as $post_type_slug ) {
193
  if( Toolset_Wpml_Utils::is_post_type_translatable( $post_type_slug ) ) {
194
  $this->is_translatable = true;
84
  * @since m2m
85
  */
86
  private static function get_available_domains() {
87
+ return array( Toolset_Element_Domain::POSTS );
88
  }
89
 
90
 
132
  public static function build_for_post_type( $post_type_slug ) {
133
  return new self(
134
  array(
135
+ self::DA_DOMAIN => Toolset_Element_Domain::POSTS,
136
  self::DA_TYPES => array( $post_type_slug )
137
  )
138
  );
148
  */
149
  public function is_match( $element ) {
150
 
151
+ if( ! $element instanceof IToolset_Element ) {
152
  throw new InvalidArgumentException( 'Invalid element provided.' );
153
  }
154
 
155
+ if( $element->get_domain() !== $this->get_domain() ) {
156
  return false;
157
  }
158
 
188
 
189
  $this->is_translatable = false;
190
 
191
+ if( Toolset_Element_Domain::POSTS === $this->get_domain() ) {
192
  foreach( $this->get_types() as $post_type_slug ) {
193
  if( Toolset_Wpml_Utils::is_post_type_translatable( $post_type_slug ) ) {
194
  $this->is_translatable = true;
vendor/toolset/toolset-common/inc/m2m/migration/associations.php ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Helper class for migrating a single legacy association between two posts into m2m.
5
+ *
6
+ * Not to be used outside the m2m API.
7
+ *
8
+ * @since m2m
9
+ */
10
+ class Toolset_Relationship_Migration_Associations {
11
+
12
+
13
+ /** @var Toolset_Relationship_Definition_Repository */
14
+ private $definition_repository;
15
+
16
+
17
+ /** @var Toolset_Element_Factory */
18
+ private $element_factory;
19
+
20
+
21
+ /** @var Toolset_Potential_Association_Query_Factory */
22
+ private $potential_association_query_factory;
23
+
24
+
25
+ /** @var bool */
26
+ private $create_default_language_if_missing;
27
+
28
+
29
+ /** @var bool */
30
+ private $copy_post_content_when_creating;
31
+
32
+
33
+ /**
34
+ * Toolset_Relationship_Migration_Associations constructor.
35
+ *
36
+ * @param Toolset_Relationship_Definition_Repository $definition_repository
37
+ * @param bool $create_default_language_if_missing
38
+ * @param bool $copy_post_content_when_creating
39
+ * @param Toolset_Element_Factory|null $element_factory_di
40
+ * @param Toolset_Potential_Association_Query_Factory|null $potential_association_query_factory_di
41
+ */
42
+ public function __construct(
43
+ Toolset_Relationship_Definition_Repository $definition_repository,
44
+ $create_default_language_if_missing,
45
+ $copy_post_content_when_creating,
46
+ Toolset_Element_Factory $element_factory_di = null,
47
+ Toolset_Potential_Association_Query_Factory $potential_association_query_factory_di = null
48
+ ) {
49
+ $this->definition_repository = $definition_repository;
50
+ $this->create_default_language_if_missing = (bool) $create_default_language_if_missing;
51
+ $this->copy_post_content_when_creating = (bool) $copy_post_content_when_creating;
52
+ $this->element_factory = $element_factory_di ?: new Toolset_Element_Factory();
53
+ $this->potential_association_query_factory = $potential_association_query_factory_di ?: new Toolset_Potential_Association_Query_Factory();
54
+ }
55
+
56
+
57
+ /**
58
+ * @param int $parent_id
59
+ * @param int $child_id
60
+ * @param int $relationship_slug
61
+ *
62
+ * @return Toolset_Result
63
+ */
64
+ public function migrate_association( $parent_id, $child_id, $relationship_slug ) {
65
+
66
+ $relationship_definition = $this->definition_repository->get_definition( $relationship_slug );
67
+
68
+ if( null == $relationship_definition ) {
69
+ return new Toolset_Result( false, sprintf( __( 'Relationship definition "%s" not found.', 'wpcf' ), $relationship_slug ) );
70
+ }
71
+
72
+ try {
73
+ // We specifically require individual posts (element_factory->get_post_untranslated())
74
+ // and not translation sets (which we might get when using element_factory->get_post()).
75
+ //
76
+ // Here, we create an association between two specific posts, no matter their language.
77
+ // The m2m API always creates the association between default language posts, or fails if unable
78
+ // to do so.
79
+ //
80
+ // If these posts are non-default language versions of already associated posts,
81
+ // another association will not be created.
82
+ $parent = $this->element_factory->get_post_untranslated( $parent_id );
83
+ $child = $this->element_factory->get_post_untranslated( $child_id );
84
+
85
+ // Note: This might throw exceptions in some obscure cases, like trying to connect
86
+ // posts of type that don't belong to the correct relationship.
87
+ //
88
+ // Imagine the following situation:
89
+ // - post A of type "type-a" with ID "42"
90
+ // - post B of type "type-b"
91
+ // - post B has has a postmeta "_wpcf_belongs_type-x_id" with value "42"
92
+ //
93
+ // When migrating legacy relationships, we'll read post B and
94
+ // create a new relationship based on the combination of two post types: "type-b", which is the post type
95
+ // of the currently processed relationship, and "type-x", which is the parent post type, judging
96
+ // from the postmeta value. That will create a "type-x-type-b" relationship.
97
+ //
98
+ // Then, we will try to connect post B with a post with the ID "42" (post A) in a relationship "type-x-type-b".
99
+ // But this will not be accepted by the IToolset_Potential_Association_Query at all, because post A
100
+ // has a different post type than "type-x". And voilá... an exception.
101
+ $potential_association_query = $this->potential_association_query_factory->create(
102
+ $relationship_definition,
103
+ new Toolset_Relationship_Role_Child(),
104
+ $parent
105
+ );
106
+
107
+ // Specifically check whether the element is already associated. This can happen only when
108
+ // trying to create the same association for posts in different languages, and we want to skip
109
+ // those cases without triggering a warning.
110
+ if( $potential_association_query->is_element_already_associated( $child ) ) {
111
+ return new Toolset_Result(
112
+ true,
113
+ sprintf(
114
+ __( 'Skipping the association between posts #%d (%s) and #%d (%s), because these elements are already associated. This can happen when migrating post translations.', 'wpcf' ),
115
+ $parent_id,
116
+ esc_textarea( $parent->get_title() ),
117
+ $child_id,
118
+ esc_textarea( $child->get_title() )
119
+ )
120
+ );
121
+ }
122
+
123
+ $results = new Toolset_Result_Set();
124
+
125
+ // Handle posts without default language versions (if applicable).
126
+ //
127
+ // If the situation couldn't be handled according to user's choice, skip the current association
128
+ // and report the issue immediately.
129
+ //
130
+ // Otherwise, we'll print the (positive) output after the association is created successfully.
131
+ $parent_default_lang_check = $this->check_default_language_version( $parent, $parent, $child );
132
+ if( ! $parent_default_lang_check->is_success() ) {
133
+ return $parent_default_lang_check;
134
+ }
135
+ $results->add( $parent_default_lang_check );
136
+
137
+ $child_default_lang_check = $this->check_default_language_version( $child, $parent, $child );
138
+ if( ! $child_default_lang_check->is_success() ) {
139
+ return $child_default_lang_check;
140
+ }
141
+ $results->add( $child_default_lang_check );
142
+
143
+ // Check for other cases where it's not allowed to create this association.
144
+ // Those we will report as problems.
145
+ $can_associate = $potential_association_query->check_single_element( $child, false );
146
+ } catch( Exception $e ) {
147
+ $display_message = sprintf(
148
+ __( 'Unable to migrate an association from post #%d to #%d to a relationship "%s"', 'wpcf'),
149
+ $parent_id,
150
+ $child_id,
151
+ $relationship_slug
152
+ );
153
+ return new Toolset_Result( $e, $display_message );
154
+ }
155
+
156
+ if( ! $can_associate->is_success() ) {
157
+ return new Toolset_Result(
158
+ false,
159
+ sprintf(
160
+ __( 'The association between posts #%d (%s) and #%d (%s) in the relationship "%s" is not allowed: ', 'wpcf' ),
161
+ $parent->get_id(),
162
+ esc_textarea( $parent->get_title() ),
163
+ $child->get_id(),
164
+ esc_textarea( $child->get_title() ),
165
+ $relationship_slug
166
+ )
167
+ . $can_associate->get_message()
168
+ );
169
+ }
170
+
171
+ try {
172
+ $association = $relationship_definition->create_association( $parent_id, $child_id );
173
+ } catch( Exception $e ) {
174
+ return new Toolset_Result( $e );
175
+ }
176
+
177
+ if( $association instanceof Toolset_Result ) {
178
+ $message = ( $association->has_message() ? $association->get_message() : __( 'Error while saving an association to database', 'wpcf' ) );
179
+ return new Toolset_Result(
180
+ false,
181
+ sprintf( "%s\n\tparent: #%d (%s)\n\tchild: #%d (%s)\n\trelationship: \"%s\"",
182
+ $message,
183
+ $parent->get_id(),
184
+ esc_textarea( $parent->get_title() ),
185
+ $child->get_id(),
186
+ esc_textarea( $child->get_title() ),
187
+ $relationship_slug
188
+ )
189
+ );
190
+ }
191
+
192
+ // Happy end!
193
+ $results->add(
194
+ true,
195
+ sprintf(
196
+ __( 'Connected #%d (%s) and #%d (%s) in the relationship "%s".', 'wpcf' ),
197
+ $parent->get_id(),
198
+ $parent->get_title(),
199
+ $child->get_id(),
200
+ $child->get_title(),
201
+ $relationship_slug
202
+ )
203
+ );
204
+
205
+ return $results->aggregate( Toolset_Relationship_Migration_Controller::MESSAGE_SEPARATOR );
206
+ }
207
+
208
+
209
+ /**
210
+ * @param IToolset_Post $post The post to check.
211
+ * @param IToolset_Post $parent Parent post of the association (for logging purposes).
212
+ * @param IToolset_Post $child Child post of the association (for logging purposes).
213
+ *
214
+ * @return Toolset_Result
215
+ */
216
+ private function check_default_language_version( IToolset_Post $post, IToolset_Post $parent, IToolset_Post $child ) {
217
+ $translation_migration = new Toolset_Relationship_Migration_Post_Translation(
218
+ $post, $parent, $child, $this->create_default_language_if_missing, $this->copy_post_content_when_creating
219
+ );
220
+ return $translation_migration->run();
221
+ }
222
+ }
vendor/toolset/toolset-common/inc/m2m/{migration.php → migration/controller.php} RENAMED
@@ -7,17 +7,15 @@
7
  *
8
  * @since m2m
9
  */
10
- class Toolset_Relationship_Migration {
11
 
12
 
13
- /** @var wpdb */
14
- private $wpdb;
15
 
16
  /** @var Toolset_Relationship_Database_Operations */
17
  private $database_operations;
18
 
19
- /** @var Toolset_Relationship_Multilingual_Mode */
20
- private $multilingual_mode_manager;
21
 
22
  /**
23
  * This one needs to be initialized later because it will break when relationship tables don't exist yet.
@@ -26,48 +24,50 @@ class Toolset_Relationship_Migration {
26
  */
27
  private $_relationship_definition_repository;
28
 
 
29
  /** @var Toolset_Relationship_Migration_Associations|null */
30
  private $_association_migrator;
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  /**
33
- * Toolset_Relationship_Migration constructor.
34
  *
35
  * @param wpdb|null $wpdb_di
36
  * @param Toolset_Relationship_Database_Operations|null $database_operations_di
37
- * @param Toolset_Relationship_Multilingual_Mode|null $multilingual_mode_di
38
  * @param Toolset_Relationship_Definition_Repository|null $relationship_definition_repository_di
39
  * @param Toolset_Relationship_Migration_Associations|null $association_migrator_di
 
 
 
40
  */
41
  public function __construct(
42
  wpdb $wpdb_di = null,
43
  Toolset_Relationship_Database_Operations $database_operations_di = null,
44
- Toolset_Relationship_Multilingual_Mode $multilingual_mode_di = null,
45
  Toolset_Relationship_Definition_Repository $relationship_definition_repository_di = null,
46
- Toolset_Relationship_Migration_Associations $association_migrator_di = null
 
 
 
47
  ) {
48
-
49
- $this->wpdb = $wpdb_di;
50
- if( null === $this->wpdb ) {
51
- global $wpdb;
52
- $this->wpdb = $wpdb;
53
- }
54
-
55
- $this->database_operations = (
56
- null === $database_operations_di
57
- ? new Toolset_Relationship_Database_Operations()
58
- : $database_operations_di
59
- );
60
-
61
-
62
- $this->multilingual_mode_manager = (
63
- null === $multilingual_mode_di
64
- ? Toolset_Relationship_Multilingual_Mode::get_instance()
65
- : $multilingual_mode_di
66
- );
67
-
68
  $this->_relationship_definition_repository = $relationship_definition_repository_di;
69
-
70
  $this->_association_migrator = $association_migrator_di;
 
 
 
71
  }
72
 
73
 
@@ -80,9 +80,11 @@ class Toolset_Relationship_Migration {
80
  }
81
 
82
 
83
- private function get_association_migrator() {
84
  if( null === $this->_association_migrator ) {
85
- $this->_association_migrator = new Toolset_Relationship_Migration_Associations( $this->get_relationship_repository() );
 
 
86
  }
87
 
88
  return $this->_association_migrator;
@@ -96,7 +98,7 @@ class Toolset_Relationship_Migration {
96
  *
97
  * @since m2m
98
  *
99
- * TODO is it possible to reliably detect dbDelta failure?
100
  */
101
  public function do_native_dbdelta() {
102
  return $this->database_operations->do_native_dbdelta();
@@ -127,8 +129,9 @@ class Toolset_Relationship_Migration {
127
  }
128
 
129
  $m2m_tables = array(
130
- Toolset_Relationship_Table_Name::associations(),
131
- Toolset_Relationship_Table_Name::relationships(),
 
132
 
133
  // Obsolete table
134
  $this->wpdb->prefix . 'toolset_association_translations'
@@ -156,9 +159,6 @@ class Toolset_Relationship_Migration {
156
  $results->add( true, __( 'No tables had to be dropped.', 'wpcf' ) );
157
  }
158
 
159
- // Disable transitional mode if it was set previously.
160
- $this->multilingual_mode_manager->set_mode( Toolset_Relationship_Multilingual_Mode::MODE_OFF );
161
-
162
  return $results;
163
  }
164
 
@@ -187,17 +187,47 @@ class Toolset_Relationship_Migration {
187
  $child_post_type = $post_type_pair['child'];
188
  $relationship_slug = $post_type_pair['slug'];
189
 
 
 
 
190
  $result = $this->create_relationship_definition( $parent_post_type, $child_post_type, $relationship_slug );
191
  $results->add( $result );
192
  }
193
 
194
  // Now we need to persist everything
 
195
  $this->get_relationship_repository()->save_definitions();
196
 
197
  return $results;
198
  }
199
 
200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  /**
202
  * Read the legacy relationships data stored in an option and transform it into array that can be
203
  * processed more easily.
@@ -225,14 +255,17 @@ class Toolset_Relationship_Migration {
225
  $results = array();
226
 
227
  foreach ( $relationships as $parent_post_type => $relationships_per_post_type ) {
228
-
229
  $relationships_per_post_type = toolset_ensarr( $relationships_per_post_type );
230
 
231
  foreach ( $relationships_per_post_type as $child_post_type => $temporarily_ignored ) {
 
232
  $results[] = array(
233
  'parent' => $parent_post_type,
234
  'child' => $child_post_type,
235
- 'slug' => $this->derive_relationship_slug( $parent_post_type, $child_post_type )
 
 
236
  );
237
  }
238
  }
@@ -255,18 +288,19 @@ class Toolset_Relationship_Migration {
255
  */
256
  private function create_relationship_definition( $parent_post_type, $child_post_type, $relationship_slug ) {
257
 
258
- $factory = $this->get_relationship_repository();
259
 
260
  // Overwrite the definition if it already exists.
261
- if( $factory->definition_exists( $relationship_slug ) ) {
262
- $factory->remove_definition( $relationship_slug );
263
  }
264
 
265
  try {
266
  $parent_type = Toolset_Relationship_Element_Type::build_for_post_type( $parent_post_type );
267
  $child_type = Toolset_Relationship_Element_Type::build_for_post_type( $child_post_type );
268
 
269
- $definition = $factory->create_definition( $relationship_slug, $parent_type, $child_type );
 
270
 
271
  // All legacy relationships are one-to-many
272
  $cardinality = new Toolset_Relationship_Cardinality( 1, Toolset_Relationship_Cardinality::INFINITY );
@@ -321,10 +355,14 @@ class Toolset_Relationship_Migration {
321
  *
322
  * @param int $offset
323
  * @param int $limit
 
 
324
  *
325
  * @return Toolset_Result_Updated|Toolset_Result_Set
326
  */
327
- public function migrate_associations( $offset, $limit ) {
 
 
328
 
329
  $associations_to_migrate = $this->get_associations_to_migrate( $offset, $limit );
330
 
@@ -336,7 +374,9 @@ class Toolset_Relationship_Migration {
336
  $results = new Toolset_Result_Set();
337
 
338
  foreach( $associations_to_migrate as $association_to_migrate ) {
339
- $result = $this->get_association_migrator()->migrate_association(
 
 
340
  $association_to_migrate['parent_id'],
341
  $association_to_migrate['child_id'],
342
  $association_to_migrate['relationship_slug']
@@ -345,7 +385,7 @@ class Toolset_Relationship_Migration {
345
  }
346
 
347
  if( $results->is_complete_success() ) {
348
- return new Toolset_Result_Updated( true, count( $associations_to_migrate ) );
349
  } else {
350
  return $results;
351
  }
@@ -419,14 +459,15 @@ class Toolset_Relationship_Migration {
419
  * @since m2m
420
  */
421
  public function finish() {
422
-
423
  update_option( Toolset_Relationship_Controller::IS_M2M_ENABLED_OPTION, 'yes', true );
424
-
425
- // todo this needs a review
426
- // There is no need to update the translation view because we've just properly imported everything.
427
- //$wpml_interop = Toolset_Relationship_WPML_Interoperability::get_instance();
428
- //$wpml_interop->is_full_refresh_needed( false );
429
  }
430
 
431
  }
432
 
 
 
 
 
 
 
 
7
  *
8
  * @since m2m
9
  */
10
+ class Toolset_Relationship_Migration_Controller extends Toolset_Wpdb_User {
11
 
12
 
13
+ const MESSAGE_SEPARATOR = "\n> ";
14
+
15
 
16
  /** @var Toolset_Relationship_Database_Operations */
17
  private $database_operations;
18
 
 
 
19
 
20
  /**
21
  * This one needs to be initialized later because it will break when relationship tables don't exist yet.
24
  */
25
  private $_relationship_definition_repository;
26
 
27
+
28
  /** @var Toolset_Relationship_Migration_Associations|null */
29
  private $_association_migrator;
30
 
31
+
32
+ /** @var Toolset_Post_Type_Repository */
33
+ private $post_type_repository;
34
+
35
+
36
+ /** @var Toolset_Relationship_Table_Name */
37
+ private $table_name;
38
+
39
+
40
+ /** @var Toolset_WPML_Compatibility */
41
+ private $wpml_compatibility;
42
+
43
+
44
  /**
45
+ * Toolset_Relationship_Migration_Controller constructor.
46
  *
47
  * @param wpdb|null $wpdb_di
48
  * @param Toolset_Relationship_Database_Operations|null $database_operations_di
 
49
  * @param Toolset_Relationship_Definition_Repository|null $relationship_definition_repository_di
50
  * @param Toolset_Relationship_Migration_Associations|null $association_migrator_di
51
+ * @param Toolset_Relationship_Table_Name|null $table_name_di
52
+ * @param Toolset_Post_Type_Repository|null $post_type_repository
53
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
54
  */
55
  public function __construct(
56
  wpdb $wpdb_di = null,
57
  Toolset_Relationship_Database_Operations $database_operations_di = null,
 
58
  Toolset_Relationship_Definition_Repository $relationship_definition_repository_di = null,
59
+ Toolset_Relationship_Migration_Associations $association_migrator_di = null,
60
+ Toolset_Relationship_Table_Name $table_name_di = null,
61
+ Toolset_Post_Type_Repository $post_type_repository = null,
62
+ Toolset_WPML_Compatibility $wpml_service_di = null
63
  ) {
64
+ parent::__construct( $wpdb_di );
65
+ $this->database_operations = $database_operations_di ?: new Toolset_Relationship_Database_Operations();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  $this->_relationship_definition_repository = $relationship_definition_repository_di;
 
67
  $this->_association_migrator = $association_migrator_di;
68
+ $this->table_name = $table_name_di ?: new Toolset_Relationship_Table_Name();
69
+ $this->wpml_compatibility = $wpml_service_di ?: Toolset_WPML_Compatibility::get_instance();
70
+ $this->post_type_repository = $post_type_repository ? $post_type_repository : Toolset_Post_Type_Repository::get_instance();
71
  }
72
 
73
 
80
  }
81
 
82
 
83
+ private function get_association_migrator( $create_default_language_if_missing, $copy_post_content_when_creating ) {
84
  if( null === $this->_association_migrator ) {
85
+ $this->_association_migrator = new Toolset_Relationship_Migration_Associations(
86
+ $this->get_relationship_repository(), $create_default_language_if_missing, $copy_post_content_when_creating
87
+ );
88
  }
89
 
90
  return $this->_association_migrator;
98
  *
99
  * @since m2m
100
  *
101
+ * @refactoring TODO is it possible to reliably detect dbDelta failure?
102
  */
103
  public function do_native_dbdelta() {
104
  return $this->database_operations->do_native_dbdelta();
129
  }
130
 
131
  $m2m_tables = array(
132
+ $this->table_name->association_table(),
133
+ $this->table_name->relationship_table(),
134
+ $this->table_name->type_set_table(),
135
 
136
  // Obsolete table
137
  $this->wpdb->prefix . 'toolset_association_translations'
159
  $results->add( true, __( 'No tables had to be dropped.', 'wpcf' ) );
160
  }
161
 
 
 
 
162
  return $results;
163
  }
164
 
187
  $child_post_type = $post_type_pair['child'];
188
  $relationship_slug = $post_type_pair['slug'];
189
 
190
+ $results->add( $this->check_post_type_translation_mode( $parent_post_type ) );
191
+ $results->add( $this->check_post_type_translation_mode( $child_post_type ) );
192
+
193
  $result = $this->create_relationship_definition( $parent_post_type, $child_post_type, $relationship_slug );
194
  $results->add( $result );
195
  }
196
 
197
  // Now we need to persist everything
198
+ /** @noinspection PhpDeprecationInspection */
199
  $this->get_relationship_repository()->save_definitions();
200
 
201
  return $results;
202
  }
203
 
204
 
205
+ /**
206
+ * If WPML is active and the given post type has the standard translation mode, switch it to "display as translated".
207
+ *
208
+ * @param string $post_type_slug
209
+ *
210
+ * @return Toolset_Result
211
+ * @since 2.5.11
212
+ */
213
+ private function check_post_type_translation_mode( $post_type_slug ) {
214
+ if( Toolset_WPML_Compatibility::MODE_TRANSLATE !== $this->wpml_compatibility->get_post_type_translation_mode( $post_type_slug ) ) {
215
+ // This will happen also if WPML is not active at all.
216
+ return new Toolset_Result( true );
217
+ }
218
+
219
+ // Fix the wrong translation mode.
220
+ $this->wpml_compatibility->set_post_type_translation_mode( $post_type_slug, Toolset_WPML_Compatibility::MODE_DISPLAY_AS_TRANSLATED );
221
+ return new Toolset_Result(
222
+ true,
223
+ sprintf(
224
+ __( 'Adjusted the translation mode of the post type "%s" to "display as translated".', 'wpcf' ),
225
+ sanitize_title( $post_type_slug )
226
+ )
227
+ );
228
+ }
229
+
230
+
231
  /**
232
  * Read the legacy relationships data stored in an option and transform it into array that can be
233
  * processed more easily.
255
  $results = array();
256
 
257
  foreach ( $relationships as $parent_post_type => $relationships_per_post_type ) {
258
+ $parent_post_type_obj = $this->post_type_repository->get( $parent_post_type );
259
  $relationships_per_post_type = toolset_ensarr( $relationships_per_post_type );
260
 
261
  foreach ( $relationships_per_post_type as $child_post_type => $temporarily_ignored ) {
262
+ $child_post_type_obj = $this->post_type_repository->get( $child_post_type );
263
  $results[] = array(
264
  'parent' => $parent_post_type,
265
  'child' => $child_post_type,
266
+ 'slug' => $this->derive_relationship_slug( $parent_post_type, $child_post_type ),
267
+ 'parent_can_be_used_in_relationship' => $parent_post_type_obj->can_be_used_in_relationship() ? 1 : 0,
268
+ 'child_can_be_used_in_relationship' => $child_post_type_obj->can_be_used_in_relationship() ? 1 : 0,
269
  );
270
  }
271
  }
288
  */
289
  private function create_relationship_definition( $parent_post_type, $child_post_type, $relationship_slug ) {
290
 
291
+ $definition_repository = $this->get_relationship_repository();
292
 
293
  // Overwrite the definition if it already exists.
294
+ if( $definition_repository->definition_exists( $relationship_slug ) ) {
295
+ $definition_repository->remove_definition( $relationship_slug );
296
  }
297
 
298
  try {
299
  $parent_type = Toolset_Relationship_Element_Type::build_for_post_type( $parent_post_type );
300
  $child_type = Toolset_Relationship_Element_Type::build_for_post_type( $child_post_type );
301
 
302
+ /** @var Toolset_Relationship_Definition $definition */
303
+ $definition = $definition_repository->create_definition( $relationship_slug, $parent_type, $child_type );
304
 
305
  // All legacy relationships are one-to-many
306
  $cardinality = new Toolset_Relationship_Cardinality( 1, Toolset_Relationship_Cardinality::INFINITY );
355
  *
356
  * @param int $offset
357
  * @param int $limit
358
+ * @param bool $create_default_language_if_missing
359
+ * @param bool $copy_post_content_when_creating
360
  *
361
  * @return Toolset_Result_Updated|Toolset_Result_Set
362
  */
363
+ public function migrate_associations(
364
+ $offset, $limit, $create_default_language_if_missing, $copy_post_content_when_creating
365
+ ) {
366
 
367
  $associations_to_migrate = $this->get_associations_to_migrate( $offset, $limit );
368
 
374
  $results = new Toolset_Result_Set();
375
 
376
  foreach( $associations_to_migrate as $association_to_migrate ) {
377
+ $result = $this->get_association_migrator(
378
+ $create_default_language_if_missing, $copy_post_content_when_creating
379
+ )->migrate_association(
380
  $association_to_migrate['parent_id'],
381
  $association_to_migrate['child_id'],
382
  $association_to_migrate['relationship_slug']
385
  }
386
 
387
  if( $results->is_complete_success() ) {
388
+ return new Toolset_Result_Updated( true, count( $associations_to_migrate ), $results->concat_messages( self::MESSAGE_SEPARATOR ) );
389
  } else {
390
  return $results;
391
  }
459
  * @since m2m
460
  */
461
  public function finish() {
 
462
  update_option( Toolset_Relationship_Controller::IS_M2M_ENABLED_OPTION, 'yes', true );
 
 
 
 
 
463
  }
464
 
465
  }
466
 
467
+
468
+ /**
469
+ * @deprecated Fallback after class renaming. Use Toolset_Relationship_Migration_Controller instead.
470
+ */
471
+ class Toolset_Relationship_Migration extends Toolset_Relationship_Migration_Controller {
472
+
473
+ }
vendor/toolset/toolset-common/inc/m2m/migration/post_translation.php ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handle the creation of a default languge post translation during the m2m migration.
5
+ *
6
+ * The behaviour depends on user's settings passed to the constructor.
7
+ *
8
+ * @since 2.5.11
9
+ */
10
+ class Toolset_Relationship_Migration_Post_Translation {
11
+
12
+
13
+ /** @var IToolset_Post */
14
+ private $post;
15
+
16
+
17
+ /** @var IToolset_Post */
18
+ private $parent;
19
+
20
+
21
+ /** @var IToolset_Post */
22
+ private $child;
23
+
24
+
25
+ /** @var bool */
26
+ private $create_default_language_if_missing;
27
+
28
+
29
+ /** @var Toolset_WPML_Compatibility */
30
+ private $wpml_service;
31
+
32
+
33
+ /** @var bool */
34
+ private $copy_post_content_when_creating;
35
+
36
+
37
+ /**
38
+ * Toolset_Relationship_Migration_Post_Translation constructor.
39
+ *
40
+ * @param IToolset_Post $post
41
+ * @param IToolset_Post $parent
42
+ * @param IToolset_Post $child
43
+ * @param $create_default_language_if_missing
44
+ * @param $copy_post_content_when_creating
45
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
46
+ */
47
+ public function __construct(
48
+ IToolset_Post $post, IToolset_Post $parent, IToolset_Post $child,
49
+ $create_default_language_if_missing,
50
+ $copy_post_content_when_creating,
51
+ Toolset_WPML_Compatibility $wpml_service_di = null
52
+ ) {
53
+ $this->post = $post;
54
+ $this->parent = $parent;
55
+ $this->child = $child;
56
+ $this->create_default_language_if_missing = (bool) $create_default_language_if_missing;
57
+ $this->copy_post_content_when_creating = (bool) $copy_post_content_when_creating;
58
+ $this->wpml_service = $wpml_service_di ?: Toolset_WPML_Compatibility::get_instance();
59
+ }
60
+
61
+
62
+ /**
63
+ * Check for the missing translation and either create it or report a failure, depending
64
+ * on the user's choice.
65
+ *
66
+ * @return Toolset_Result
67
+ */
68
+ public function run() {
69
+ if( ! $this->is_missing_default_language_version( $this->post ) ) {
70
+ return new Toolset_Result( true );
71
+ }
72
+
73
+ if( ! $this->create_default_language_if_missing ) {
74
+ return new Toolset_Result(
75
+ false,
76
+ sprintf(
77
+ __( 'Skipping the association between posts #%d (%s) and #%d (%s) because #%d doesn\'t have a default language version and you chose to skip such associations.', 'wpcf' ),
78
+ $this->parent->get_id(),
79
+ $this->parent->get_title(),
80
+ $this->child->get_id(),
81
+ $this->child->get_title(),
82
+ $this->post->get_id()
83
+ )
84
+ );
85
+ }
86
+
87
+ return $this->create_default_language_version( $this->post );
88
+ }
89
+
90
+
91
+ /**
92
+ * @param IToolset_Post $post
93
+ * @return bool
94
+ */
95
+ private function is_missing_default_language_version( IToolset_Post $post ) {
96
+ if( ! $post->is_translatable() ) {
97
+ return false;
98
+ }
99
+ $default_language_id = $post->get_default_language_id();
100
+ return ( 0 === $default_language_id );
101
+ }
102
+
103
+
104
+ /**
105
+ * @param IToolset_Post $post
106
+ * @return Toolset_Result
107
+ */
108
+ private function create_default_language_version( IToolset_Post $post ) {
109
+ if( $this->copy_post_content_when_creating ) {
110
+ return $this->create_duplicate_default_language_version( $post );
111
+ }
112
+
113
+ return $this->create_clean_default_language_version( $post );
114
+ }
115
+
116
+
117
+ /**
118
+ * @param IToolset_Post $post
119
+ *
120
+ * @return Toolset_Result
121
+ */
122
+ private function create_clean_default_language_version( IToolset_Post $post ) {
123
+ // Create the new post, an empty draft with a similar title as the original.
124
+ $result = wp_insert_post(
125
+ array(
126
+ 'post_title' => sprintf(
127
+ '[%s] %s',
128
+ $this->wpml_service->get_default_language(),
129
+ $post->get_title()
130
+ ),
131
+ 'post_content' => '',
132
+ 'post_status' => 'draft',
133
+ 'post_author' => $post->get_author(),
134
+ 'post_type' => $post->get_type()
135
+ ),
136
+ true
137
+ );
138
+
139
+ if( $result instanceof WP_Error ) {
140
+ return new Toolset_Result( $result );
141
+ }
142
+
143
+ $default_lang_post_id = (int) $result;
144
+
145
+ // Set the language of the new post and connect it to the original.
146
+ $this->wpml_service->add_post_translation( $post, $default_lang_post_id, $this->wpml_service->get_default_language() );
147
+
148
+ // Unfortunately, there is no return value from the WPML hook (it's an action), we have to assume it went through.
149
+ return new Toolset_Result(
150
+ true,
151
+ sprintf(
152
+ __( 'Created a default language translation for post #%d (%s) in draft mode.', 'wpcf' ),
153
+ $post->get_id(),
154
+ $post->get_title()
155
+ )
156
+ );
157
+ }
158
+
159
+
160
+ /**
161
+ * @param IToolset_Post $post
162
+ *
163
+ * @return Toolset_Result
164
+ */
165
+ private function create_duplicate_default_language_version( IToolset_Post $post ) {
166
+
167
+ // First, create the duplicate (but don't mark it as an actual WPML duplicate to prevent value synchronization)
168
+ $duplicate_id = $this->wpml_service->create_post_duplicate(
169
+ $post, $this->wpml_service->get_default_language(), false
170
+ );
171
+
172
+ if( ! $duplicate_id ) {
173
+ return new Toolset_Result(
174
+ false,
175
+ sprintf(
176
+ __( 'Unable to create a default language translation for post #%d (%s).', 'wpcf' ),
177
+ $post->get_id(),
178
+ $post->get_title()
179
+ )
180
+ );
181
+ }
182
+
183
+ // Adjust the title and turn it into a draft.
184
+ $result = wp_update_post(
185
+ array(
186
+ 'ID' => $duplicate_id,
187
+ 'post_title' => sprintf(
188
+ '[%s] %s',
189
+ $this->wpml_service->get_default_language(),
190
+ $post->get_title()
191
+ ),
192
+ 'post_status' => 'draft',
193
+ ),
194
+ true
195
+ );
196
+
197
+
198
+ if( $result instanceof WP_Error ) {
199
+ return new Toolset_Result( $result );
200
+ }
201
+
202
+ return new Toolset_Result(
203
+ true,
204
+ sprintf(
205
+ __( 'Created a default language translation for post #%d (%s) in draft mode.', 'wpcf' ),
206
+ $post->get_id(),
207
+ $post->get_title()
208
+ )
209
+ );
210
+ }
211
+
212
+
213
+ }
vendor/toolset/toolset-common/inc/m2m/migration_associations.php DELETED
@@ -1,119 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Helper class for migrating a single legacy association between two posts into m2m.
5
- *
6
- * Not to be used outside the m2m API.
7
- *
8
- * @since m2m
9
- */
10
- class Toolset_Relationship_Migration_Associations {
11
-
12
- /** @var Toolset_Relationship_Definition_Repository */
13
- private $definition_repository;
14
-
15
- /** @var Toolset_Element_Factory */
16
- private $element_factory;
17
-
18
-
19
- /**
20
- * Toolset_Relationship_Migration_Associations constructor.
21
- *
22
- * @param Toolset_Relationship_Definition_Repository $definition_repository
23
- * @param Toolset_Element_Factory|null $element_factory_di
24
- */
25
- public function __construct(
26
- Toolset_Relationship_Definition_Repository $definition_repository,
27
- Toolset_Element_Factory $element_factory_di = null
28
- ) {
29
-
30
- $this->definition_repository = $definition_repository;
31
-
32
- $this->element_factory = (
33
- null === $element_factory_di
34
- ? new Toolset_Element_Factory()
35
- : $element_factory_di
36
- );
37
- }
38
-
39
-
40
- /**
41
- * @param int $parent_id
42
- * @param int $child_id
43
- * @param int $relationship_slug
44
- *
45
- * @return Toolset_Result
46
- */
47
- public function migrate_association( $parent_id, $child_id, $relationship_slug ) {
48
-
49
- $relationship_definition = $this->definition_repository->get_definition( $relationship_slug );
50
-
51
- if( null == $relationship_definition ) {
52
- return new Toolset_Result( false, sprintf( __( 'Relationship definition "%s" not found.', 'wpcf' ), $relationship_slug ) );
53
- }
54
-
55
- try {
56
- // We specifically require posts (element_factory->get_post()) and not translation sets (which we might
57
- // get when using element_factory->get_element()).
58
- //
59
- // Here, we create an association between two specific posts. When the WPML/m2m interop is fully
60
- // implemented, this will be enough to track associations between all translations of these posts.
61
- $parent = $this->element_factory->get_post( $parent_id );
62
- $child = $this->element_factory->get_post( $child_id );
63
- } catch( Exception $e ) {
64
- $display_message = sprintf(
65
- __( 'Unable to migrate an association from post #%d to #%d to a relationship "%s"', 'wpcf'),
66
- $parent_id,
67
- $child_id,
68
- $relationship_slug
69
- );
70
- return new Toolset_Result( $e, $display_message );
71
- }
72
-
73
- $potential_association_query_factory = new Toolset_Potential_Association_Query_Factory();
74
- $potential_association = $potential_association_query_factory->create(
75
- $relationship_definition,
76
- new Toolset_Relationship_Role_Child(),
77
- $parent
78
- );
79
-
80
- if( ! $potential_association->check_single_element( $child ) ) {
81
- return new Toolset_Result(
82
- false,
83
- sprintf(
84
- __( 'The association between posts %d and %d is not allowed (maybe it already exists).', 'wpcf' ),
85
- $parent->get_id(),
86
- $child->get_id()
87
- )
88
- );
89
- }
90
-
91
- try {
92
- $association = Toolset_Relationship_Database_Operations::create_association(
93
- $relationship_slug,
94
- $parent_id,
95
- $child_id,
96
- 0 // no intermediary post
97
- );
98
- } catch( Exception $e ) {
99
- return new Toolset_Result( $e );
100
- }
101
-
102
- if( $association instanceof Toolset_Result ) {
103
- return new Toolset_Result(
104
- false,
105
- sprintf( "%s\n\t%s",
106
- __( 'Error while saving an association to database.', 'wpcf' ),
107
- print_r(
108
- array( 'parent_id' => $parent_id, 'child_id' => $child_id, 'relationship_slug' => $relationship_slug ),
109
- true
110
- )
111
- )
112
- );
113
- } else {
114
- return new Toolset_Result( true );
115
- }
116
-
117
- }
118
-
119
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/toolset/toolset-common/inc/m2m/multilingual_mode.php DELETED
@@ -1,236 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Determine (and cache) the m2m multilingual mode.
5
- *
6
- * m2m API needs to recognize three "multilingual modes" internally:
7
- *
8
- * 1. off - no support for language filtering (internally: each database row has its own trid and
9
- * no other language information is stored)
10
- * 2. on - with WPML, results are filtered by language and associations are basically made between
11
- * translation groups (internally: rows in the associations of translatable relationships are grouped by
12
- * trid, the translation_type is correctly set and such rows can have zeros instead of element IDs if
13
- * a translation is missing)
14
- * 3. transitional - after WPML is deactivated (internally: database structure is same as for on,
15
- * but the behaviour of association query matches off; new associations are created without
16
- * translation information)
17
- *
18
- * The transitional mode is required so that the site can keep working when WPML is deactivated
19
- * (even temporarily). Switching from transitional to off needs to be done manually because it requires
20
- * a large database update (similar to the migration from legacy post relationships to m2m).
21
- *
22
- * Most of the m2m API doesn't need to know about the transitional mode, it's the same as "off" in most cases.
23
- * The only difference would be Toolset_Association_Query which needs to understand the database structure
24
- * of pre-existing records after WPML was deactivated.
25
- *
26
- * Outside of m2m API, this should never be needed at all.
27
- *
28
- * @since m2m
29
- */
30
- class Toolset_Relationship_Multilingual_Mode {
31
-
32
- private static $instance;
33
-
34
- public static function get_instance() {
35
- if( null === self::$instance ) {
36
- self::$instance = new self();
37
- }
38
- return self::$instance;
39
- }
40
-
41
- private function __construct() { }
42
-
43
- private function __clone() { }
44
-
45
-
46
- /**
47
- * Is m2m in the multilingual mode?
48
- *
49
- * This is mostly important for the API internals, there should be no need to use this outside.
50
- *
51
- * @return bool
52
- * @since m2m
53
- */
54
- public static function is_on() {
55
- return ( self::get_instance()->get_multilingual_mode() === self::MODE_ON );
56
- }
57
-
58
-
59
- /** @var null|string Cache for get_multilingual_mode(), 'on'|'off'|'transitional'. */
60
- private $current_multilingual_mode = null;
61
-
62
-
63
- private $translatable_relationships_exist = null;
64
-
65
-
66
- const MULTILINGUAL_MODE_OPTION = 'toolset_m2m_multilingual_mode';
67
- //const HAS_TRANSLARABLE_RELATIONSHIPS_OPTION = 'toolset_m2m_has_translatable_relationships';
68
-
69
- const MODE_ON = 'on';
70
- const MODE_OFF = 'off';
71
- const MODE_TRANSITIONAL = 'transitional';
72
-
73
-
74
- private static function allowed_modes() {
75
- return array( self::MODE_OFF, self::MODE_ON, self::MODE_TRANSITIONAL );
76
- }
77
-
78
-
79
- /**
80
- * Flush the cache of current multilingual mode.
81
- *
82
- * This needs to be done after a relationship definition or post type translation settings are updated
83
- * (unless reloading a page immediately after).
84
- */
85
- public static function flush_cache() {
86
- $instance = self::get_instance();
87
- $instance->current_multilingual_mode = null;
88
- $instance->translatable_relationships_exist = null;
89
- }
90
-
91
-
92
- /**
93
- * Determine the exact multilingual mode.
94
- *
95
- * To be used only by the m2m API and only when the transitional mode needs to be handled separately.
96
- * Otherwise, is_multilingual_mode_on() is preferred.
97
- *
98
- * @return string
99
- * @since m2m
100
- */
101
- public static function get() {
102
- return self::get_instance()->get_multilingual_mode();
103
- }
104
-
105
-
106
- /**
107
- * Is m2m in the transitional mode?
108
- *
109
- * @return bool
110
- */
111
- public static function is_transitional() {
112
- return ( self::get() === self::MODE_TRANSITIONAL );
113
- }
114
-
115
-
116
- private function get_multilingual_mode() {
117
-
118
- // Allways off since this functionality is about to be removed.
119
- return self::MODE_OFF;
120
-
121
- if( null === $this->current_multilingual_mode ) {
122
-
123
- $stored_mode = $this->load_multilingual_mode_option();
124
- $current_mode = $this->calculate_multilingual_mode();
125
-
126
- if( $stored_mode !== $current_mode ) {
127
- update_option( self::MULTILINGUAL_MODE_OPTION, $current_mode, true );
128
- }
129
-
130
- $this->current_multilingual_mode = $current_mode;
131
-
132
- }
133
-
134
- return $this->current_multilingual_mode;
135
- }
136
-
137
-
138
- private function load_multilingual_mode_option() {
139
-
140
- $stored_mode = get_option( self::MULTILINGUAL_MODE_OPTION );
141
- if( ! in_array( $stored_mode, self::allowed_modes() ) ) {
142
- $stored_mode = 'off';
143
- }
144
-
145
- return $stored_mode;
146
- }
147
-
148
-
149
- /**
150
- * Calculate what the current multilingual mode should be, based on WPML state,
151
- * existence of translatable relationships and previous mode.
152
- *
153
- * @return string New multilingual mode.
154
- * @since m2m
155
- */
156
- private function calculate_multilingual_mode() {
157
-
158
- $wpml_interop = Toolset_WPML_Compatibility::get_instance();
159
- $is_wpml_active = $wpml_interop->is_wpml_active_and_configured();
160
-
161
- // Note: This can be true only when WPML is active, otherwise it's not possible
162
- // to get the translatability status.
163
- $translatable_relationships_exist = $this->translatable_relationships_exist();
164
-
165
- // https://code2flow.com/0TjdqR
166
- if ( $is_wpml_active && $translatable_relationships_exist && $this->is_wpml_version_supported() ) {
167
- $mode = self::MODE_ON;
168
- } elseif ( self::MODE_OFF !== $this->load_multilingual_mode_option() ) {
169
- // This means that the previous condition was true before (WPML active + translatable relationships).
170
- // So we don't need to check for the relationships anymore (which we can't do now anyway) and
171
- // at the same time we're not risking switching into transitional mode without having
172
- // translatable relationships.
173
- $mode = self::MODE_TRANSITIONAL;
174
-
175
- // todo add a notice via Toolset_Admin_Notices_Manager
176
- } else {
177
- $mode = self::MODE_OFF;
178
- }
179
-
180
- return $mode;
181
- }
182
-
183
-
184
- private function is_wpml_version_supported() {
185
- $wpml_interop = Toolset_WPML_Compatibility::get_instance();
186
- return version_compare( $wpml_interop->get_wpml_version(), Toolset_Relationship_Controller::MINIMAL_WPML_VERSION, '>=' );
187
- }
188
-
189
-
190
- /**
191
- * Check if there are any relationship definitions that are translatable.
192
- *
193
- * @return bool
194
- */
195
- private function translatable_relationships_exist() {
196
-
197
- if( null === $this->translatable_relationships_exist ) {
198
-
199
- if ( ! Toolset_WPML_Compatibility::get_instance()->is_wpml_active_and_configured() ) {
200
-
201
- $this->translatable_relationships_exist = false;
202
-
203
- } else {
204
-
205
- // In order to do this, we'd need to reset the value when any relationship definition
206
- // is created, updated or removed, or any post type's translation preferences changed.
207
- // Seems like an overkill at this point.
208
- //$this->translatable_relationships_exist = get_option( self::HAS_TRANSLARABLE_RELATIONSHIPS_OPTION, null );
209
-
210
- if ( null === $this->translatable_relationships_exist ) {
211
- $relationship_query = new Toolset_Relationship_Query( array(
212
- Toolset_Relationship_Query::QUERY_IS_TRANSLATABLE => true
213
- ) );
214
-
215
- $results = $relationship_query->get_results();
216
-
217
- $this->translatable_relationships_exist = ( ! empty( $results ) );
218
-
219
- //update_option( self::HAS_TRANSLARABLE_RELATIONSHIPS_OPTION, $this->translatable_relationships_exist, true );
220
- }
221
- }
222
- }
223
-
224
- return $this->translatable_relationships_exist;
225
- }
226
-
227
-
228
- public function set_mode( $new_mode ) {
229
- if( ! in_array( $new_mode, self::allowed_modes() ) ) {
230
- throw new InvalidArgumentException();
231
- }
232
-
233
- update_option( self::MULTILINGUAL_MODE_OPTION, $new_mode, true );
234
- }
235
-
236
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/toolset/toolset-common/inc/m2m/potential_association/distinct_post_query.php CHANGED
@@ -13,11 +13,11 @@
13
  */
14
  class Toolset_Relationship_Distinct_Post_Query {
15
 
16
- /** @var Toolset_Relationship_Definition */
17
  private $relationship;
18
 
19
- /** @var int */
20
- private $for_element_id;
21
 
22
  /** @var IToolset_Relationship_Role_Parent_Child */
23
  private $target_role;
@@ -28,27 +28,33 @@ class Toolset_Relationship_Distinct_Post_Query {
28
  /** @var null|wpdb */
29
  private $_wpdb;
30
 
 
 
 
31
 
32
  /**
33
  * Toolset_Relationship_Distinct_Post_Query constructor.
34
  *
35
- * @param Toolset_Relationship_Definition $relationship
36
  * @param IToolset_Relationship_Role_Parent_Child $target_role Target role of the relationships (future role of
37
  * the posts that are being queried)
38
- * @param int $for_element_id ID of the element to check against.
39
  * @param Toolset_Relationship_Table_Name|null $table_names_di
40
  * @param wpdb|null $wpdb_di
 
41
  */
42
  public function __construct(
43
- Toolset_Relationship_Definition $relationship,
44
  IToolset_Relationship_Role_Parent_Child $target_role,
45
- $for_element_id,
46
  Toolset_Relationship_Table_Name $table_names_di = null,
47
- wpdb $wpdb_di = null
 
48
  ) {
49
  $this->relationship = $relationship;
50
- $this->for_element_id = $for_element_id;
51
  $this->target_role = $target_role;
 
52
 
53
  $this->_table_names = $table_names_di;
54
  $this->_wpdb = $wpdb_di;
@@ -69,8 +75,12 @@ class Toolset_Relationship_Distinct_Post_Query {
69
  }
70
 
71
  add_filter( 'posts_join', array( $this, 'add_join_clauses' ) );
72
-
73
  add_filter( 'posts_where', array( $this, 'add_where_clauses' ) );
 
 
 
 
 
74
  }
75
 
76
 
@@ -83,8 +93,9 @@ class Toolset_Relationship_Distinct_Post_Query {
83
  }
84
 
85
  remove_filter( 'posts_join', array( $this, 'add_join_clauses' ) );
86
-
87
  remove_filter( 'posts_where', array( $this, 'add_where_clauses' ) );
 
 
88
  }
89
 
90
 
@@ -115,6 +126,9 @@ class Toolset_Relationship_Distinct_Post_Query {
115
  *
116
  * Otherwise, those columns will be NULL, because we're doing a LEFT JOIN here.
117
  *
 
 
 
118
  * @param string $join
119
  *
120
  * @return string
@@ -132,9 +146,31 @@ class Toolset_Relationship_Distinct_Post_Query {
132
  AND toolset_associations.{$for_element_column} = %d
133
  ) ",
134
  $this->relationship->get_row_id(),
135
- $this->for_element_id
136
  );
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  return $join;
139
  }
140
 
@@ -146,6 +182,9 @@ class Toolset_Relationship_Distinct_Post_Query {
146
  * column with $for_element: That means there's no association between the queried
147
  * post and $for_element, and we can offer the post as a result.
148
  *
 
 
 
149
  * @param string $where
150
  *
151
  * @return string
@@ -153,6 +192,11 @@ class Toolset_Relationship_Distinct_Post_Query {
153
  public function add_where_clauses( $where ) {
154
  $for_element_column = $this->target_role->other() . '_id';
155
  $where .= " AND ( toolset_associations.{$for_element_column} IS NULL ) ";
 
 
 
 
 
156
  return $where;
157
  }
158
 
13
  */
14
  class Toolset_Relationship_Distinct_Post_Query {
15
 
16
+ /** @var IToolset_Relationship_Definition */
17
  private $relationship;
18
 
19
+ /** @var IToolset_Element */
20
+ private $for_element;
21
 
22
  /** @var IToolset_Relationship_Role_Parent_Child */
23
  private $target_role;
28
  /** @var null|wpdb */
29
  private $_wpdb;
30
 
31
+ /** @var Toolset_WPML_Compatibility */
32
+ private $wpml_service;
33
+
34
 
35
  /**
36
  * Toolset_Relationship_Distinct_Post_Query constructor.
37
  *
38
+ * @param IToolset_Relationship_Definition $relationship
39
  * @param IToolset_Relationship_Role_Parent_Child $target_role Target role of the relationships (future role of
40
  * the posts that are being queried)
41
+ * @param IToolset_Element $for_element ID of the element to check against.
42
  * @param Toolset_Relationship_Table_Name|null $table_names_di
43
  * @param wpdb|null $wpdb_di
44
+ * @param Toolset_WPML_Compatibility|null $wpml_service_di
45
  */
46
  public function __construct(
47
+ IToolset_Relationship_Definition $relationship,
48
  IToolset_Relationship_Role_Parent_Child $target_role,
49
+ IToolset_Element $for_element,
50
  Toolset_Relationship_Table_Name $table_names_di = null,
51
+ wpdb $wpdb_di = null,
52
+ Toolset_WPML_Compatibility $wpml_service_di = null
53
  ) {
54
  $this->relationship = $relationship;
55
+ $this->for_element = $for_element;
56
  $this->target_role = $target_role;
57
+ $this->wpml_service = $wpml_service_di ?: Toolset_WPML_Compatibility::get_instance();
58
 
59
  $this->_table_names = $table_names_di;
60
  $this->_wpdb = $wpdb_di;
75
  }
76
 
77
  add_filter( 'posts_join', array( $this, 'add_join_clauses' ) );
 
78
  add_filter( 'posts_where', array( $this, 'add_where_clauses' ) );
79
+
80
+ // WPML in the back-end filters strictly by the current language by default,
81
+ // but we need it to include default language posts, too, if the translation to the current language
82
+ // doesn't exist. This needs to behave consistently in all contexts.
83
+ add_filter( 'wpml_should_use_display_as_translated_snippet', '__return_true' );
84
  }
85
 
86
 
93
  }
94
 
95
  remove_filter( 'posts_join', array( $this, 'add_join_clauses' ) );
 
96
  remove_filter( 'posts_where', array( $this, 'add_where_clauses' ) );
97
+
98
+ remove_filter( 'wpml_should_use_display_as_translated_snippet', '__return_true' );
99
  }
100
 
101
 
126
  *
127
  * Otherwise, those columns will be NULL, because we're doing a LEFT JOIN here.
128
  *
129
+ * If WPML is active, we also do the same comparison for the default language version of the
130
+ * queried post, if it exists.
131
+ *
132
  * @param string $join
133
  *
134
  * @return string
146
  AND toolset_associations.{$for_element_column} = %d
147
  ) ",
148
  $this->relationship->get_row_id(),
149
+ $this->for_element->get_default_language_id()
150
  );
151
 
152
+ if( $this->wpml_service->is_wpml_active_and_configured() ) {
153
+ $icl_translations = $this->get_wpdb()->prefix . 'icl_translations';
154
+ $default_language = esc_sql( $this->wpml_service->get_default_language() );
155
+ $join .= $this->get_wpdb()->prepare(
156
+ " LEFT JOIN {$icl_translations} AS element_lang_info ON (
157
+ {$posts_table_name}.ID = element_lang_info.element_id
158
+ AND element_lang_info.element_type LIKE %s
159
+ ) LEFT JOIN {$icl_translations} AS default_lang_translation ON (
160
+ element_lang_info.trid = default_lang_translation.trid
161
+ AND default_lang_translation.language_code = %s
162
+ ) LEFT JOIN {$association_table} AS default_lang_association ON (
163
+ default_lang_association.relationship_id = %d
164
+ AND default_lang_translation.element_id = default_lang_association.{$target_element_column}
165
+ AND default_lang_association.{$for_element_column} = %d
166
+ ) ",
167
+ 'post_%',
168
+ $default_language,
169
+ $this->relationship->get_row_id(),
170
+ $this->for_element->get_default_language_id()
171
+ );
172
+ }
173
+
174
  return $join;
175
  }
176
 
182
  * column with $for_element: That means there's no association between the queried
183
  * post and $for_element, and we can offer the post as a result.
184
  *
185
+ * If WPML is active, we also have to check that there's no default language translation
186
+ * of the queried post that would be part of such an association.
187
+ *
188
  * @param string $where
189
  *
190
  * @return string
192
  public function add_where_clauses( $where ) {
193
  $for_element_column = $this->target_role->other() . '_id';
194
  $where .= " AND ( toolset_associations.{$for_element_column} IS NULL ) ";
195
+
196
+ if( $this->wpml_service->is_wpml_active_and_configured() ) {
197
+ $where .= " AND ( default_lang_association.{$for_element_column} IS NULL ) ";
198
+ }
199
+
200
  return $where;
201
  }
202
 
vendor/toolset/toolset-common/inc/m2m/potential_association/query_interface.php CHANGED
@@ -46,10 +46,12 @@ interface IToolset_Potential_Association_Query extends IToolset_Query {
46
  * The relationship, target role and the other element are those provided in the constructor.
47
  *
48
  * @param IToolset_Element $association_candidate Element that wants to be associated.
 
 
49
  * @return Toolset_Result Result with an user-friendly message in case the association is denied.
50
  * @since 2.5.6
51
  */
52
- public function check_single_element( IToolset_Element $association_candidate );
53
 
54
 
55
  /**
@@ -60,4 +62,17 @@ interface IToolset_Potential_Association_Query extends IToolset_Query {
60
  */
61
  public function can_connect_another_element();
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  }
46
  * The relationship, target role and the other element are those provided in the constructor.
47
  *
48
  * @param IToolset_Element $association_candidate Element that wants to be associated.
49
+ * @param bool $check_is_already_associated Perform the check that the element is already associated for distinct
50
+ * relationships. Default is true. Set to false only if the check was performed manually before.
51
  * @return Toolset_Result Result with an user-friendly message in case the association is denied.
52
  * @since 2.5.6
53
  */
54
+ public function check_single_element( IToolset_Element $association_candidate, $check_is_already_associated = true );
55
 
56
 
57
  /**
62
  */
63
  public function can_connect_another_element();
64
 
65
+
66
+ /**
67
+ * Check whether there already exists an association between the the target element and the provided one.
68
+ *
69
+ * Note that it doesn't always have to be a problem, it depends on whether the relationship is distinct or not.
70
+ * This was made public to optimize performance during the m2m migration process.
71
+ *
72
+ * @param IToolset_Element $element
73
+ *
74
+ * @return bool
75
+ */
76
+ public function is_element_already_associated( IToolset_Element $element );
77
+
78
  }
vendor/toolset/toolset-common/inc/m2m/potential_association/query_posts.php CHANGED
@@ -34,6 +34,9 @@ class Toolset_Potential_Association_Query_Posts implements IToolset_Potential_As
34
  private $query_factory;
35
 
36
 
 
 
 
37
  /**
38
  * Toolset_Potential_Association_Query constructor.
39
  *
@@ -47,13 +50,15 @@ class Toolset_Potential_Association_Query_Posts implements IToolset_Potential_As
47
  * - page: int
48
  * - wp_query_override: array
49
  * @param Toolset_Relationship_Query_Factory|null $query_factory_di
 
50
  */
51
  public function __construct(
52
  IToolset_Relationship_Definition $relationship,
53
  IToolset_Relationship_Role_Parent_Child $target_role,
54
  IToolset_Element $for_element,
55
  $args,
56
- Toolset_Relationship_Query_Factory $query_factory_di = null
 
57
  ) {
58
  $this->relationship = $relationship;
59
  $this->for_element = $for_element;
@@ -65,11 +70,13 @@ class Toolset_Potential_Association_Query_Posts implements IToolset_Potential_As
65
  }
66
 
67
  $this->query_factory = ( null === $query_factory_di ? new Toolset_Relationship_Query_Factory() : $query_factory_di );
 
68
  }
69
 
70
 
71
  /**
72
  * @return IToolset_Post[]
 
73
  */
74
  public function get_results() {
75
 
@@ -110,7 +117,7 @@ class Toolset_Potential_Association_Query_Posts implements IToolset_Potential_As
110
  $augment_query_for_distinct_relationships = $this->query_factory->distinct_relationship_posts(
111
  $this->relationship,
112
  $this->target_role,
113
- $this->for_element->get_id()
114
  );
115
 
116
  $augment_query_for_distinct_relationships->before_query();
@@ -164,14 +171,12 @@ class Toolset_Potential_Association_Query_Posts implements IToolset_Potential_As
164
  * @param WP_Post[] $wp_posts
165
  *
166
  * @return IToolset_Post[]
 
167
  */
168
  private function transform_results( $wp_posts ) {
169
  $results = array();
170
  foreach( $wp_posts as $wp_post ) {
171
- $results[] = Toolset_Element::get_instance(
172
- Toolset_Field_Utils::DOMAIN_POSTS,
173
- $wp_post
174
- );
175
  }
176
 
177
  return $results;
@@ -195,16 +200,22 @@ class Toolset_Potential_Association_Query_Posts implements IToolset_Potential_As
195
  * The relationship, target role and the other element are those provided in the constructor.
196
  *
197
  * @param IToolset_Element $association_candidate Element that wants to be associated.
 
 
 
198
  * @return Toolset_Result Result with an user-friendly message in case the association is denied.
199
  * @since 2.5.6
200
  */
201
- public function check_single_element( IToolset_Element $association_candidate ) {
202
 
203
  if( ! $this->relationship->get_element_type( $this->target_role )->is_match( $association_candidate ) ) {
204
  return new Toolset_Result( false, __( 'The element has a wrong type or a domain for this relationship.', 'wpcf' ) );
205
  }
206
 
207
- if( $this->relationship->is_distinct() && $this->is_element_already_associated( $association_candidate ) ) {
 
 
 
208
  return new Toolset_Result( false,
209
  __( 'These two elements are already associated and the relationship doesn\'t allow non-distinct associations.', 'wpcf' )
210
  );
@@ -259,21 +270,32 @@ class Toolset_Potential_Association_Query_Posts implements IToolset_Potential_As
259
  }
260
 
261
 
262
- private function is_element_already_associated( IToolset_Element $element ) {
 
 
 
 
 
 
 
263
 
264
  /** @var IToolset_Element[] $parent_and_child */
265
  $parent_and_child = Toolset_Relationship_Role::sort_elements( $element, $this->for_element, $this->target_role );
266
 
267
- $query = $this->query_factory->associations( array(
268
- Toolset_Association_Query::QUERY_RELATIONSHIP_SLUG => $this->relationship->get_slug(),
269
- Toolset_Association_Query::QUERY_PARENT_ID => $parent_and_child[0]->get_id(),
270
- Toolset_Association_Query::QUERY_CHILD_ID => $parent_and_child[1]->get_id(),
271
- Toolset_Association_Query::QUERY_LIMIT => 1,
272
- ) );
 
 
 
 
273
 
274
- $results = $query->get_results();
275
 
276
- return ( count( $results ) > 0 );
277
  }
278
 
279
 
@@ -307,20 +329,19 @@ class Toolset_Potential_Association_Query_Posts implements IToolset_Potential_As
307
  private function get_number_of_already_associated_elements(
308
  IToolset_Relationship_Role_Parent_Child $role, IToolset_Element $element
309
  ) {
310
- $for_element_role_query = (
311
- $role instanceof Toolset_Relationship_Role_Parent
312
- ? Toolset_Association_Query::QUERY_PARENT_ID
313
- : Toolset_Association_Query::QUERY_CHILD_ID
314
- );
315
-
316
- $query = $this->query_factory->associations( array(
317
- Toolset_Association_Query::QUERY_RELATIONSHIP_SLUG => $this->relationship->get_slug(),
318
- $for_element_role_query => $element->get_id()
319
- ) );
320
-
321
- $results = $query->get_results();
322
-
323
- return count( $results );
324
  }
325
 
326
  /**
34
  private $query_factory;
35
 
36
 
37
+ private $element_factory;
38
+
39
+
40
  /**
41
  * Toolset_Potential_Association_Query constructor.
42
  *
50
  * - page: int
51
  * - wp_query_override: array
52
  * @param Toolset_Relationship_Query_Factory|null $query_factory_di
53
+ * @param Toolset_Element_Factory|null $element_factory_di
54
  */
55
  public function __construct(
56
  IToolset_Relationship_Definition $relationship,
57
  IToolset_Relationship_Role_Parent_Child $target_role,
58
  IToolset_Element $for_element,
59
  $args,
60
+ Toolset_Relationship_Query_Factory $query_factory_di = null,
61
+ Toolset_Element_Factory $element_factory_di = null
62
  ) {
63
  $this->relationship = $relationship;
64
  $this->for_element = $for_element;
70
  }
71
 
72
  $this->query_factory = ( null === $query_factory_di ? new Toolset_Relationship_Query_Factory() : $query_factory_di );
73
+ $this->element_factory = ( null === $element_factory_di ? new Toolset_Element_Factory() : $element_factory_di );
74
  }
75
 
76
 
77
  /**
78
  * @return IToolset_Post[]
79
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
80
  */
81
  public function get_results() {
82
 
117
  $augment_query_for_distinct_relationships = $this->query_factory->distinct_relationship_posts(
118
  $this->relationship,
119
  $this->target_role,
120
+ $this->for_element
121
  );
122
 
123
  $augment_query_for_distinct_relationships->before_query();
171
  * @param WP_Post[] $wp_posts
172
  *
173
  * @return IToolset_Post[]
174
+ * @throws Toolset_Element_Exception_Element_Doesnt_Exist
175
  */
176
  private function transform_results( $wp_posts ) {
177
  $results = array();
178
  foreach( $wp_posts as $wp_post ) {
179
+ $results[] = $this->element_factory->get_post( $wp_post );
 
 
 
180
  }
181
 
182
  return $results;
200
  * The relationship, target role and the other element are those provided in the constructor.
201
  *
202
  * @param IToolset_Element $association_candidate Element that wants to be associated.
203
+ * @param bool $check_is_already_associated Perform the check that the element is already associated for distinct
204
+ * relationships. Default is true. Set to false only if the check was performed manually before.
205
+ *
206
  * @return Toolset_Result Result with an user-friendly message in case the association is denied.
207
  * @since 2.5.6
208
  */
209
+ public function check_single_element( IToolset_Element $association_candidate, $check_is_already_associated = true ) {
210
 
211
  if( ! $this->relationship->get_element_type( $this->target_role )->is_match( $association_candidate ) ) {
212
  return new Toolset_Result( false, __( 'The element has a wrong type or a domain for this relationship.', 'wpcf' ) );
213
  }
214
 
215
+ if( $check_is_already_associated
216
+ && $this->relationship->is_distinct()
217
+ && $this->is_element_already_associated( $association_candidate )
218
+ ) {
219
  return new Toolset_Result( false,
220
  __( 'These two elements are already associated and the relationship doesn\'t allow non-distinct associations.', 'wpcf' )
221
  );
270
  }
271
 
272
 
273
+ /**
274
+ * @inheritdoc
275
+ *
276
+ * @param IToolset_Element $element
277
+ *
278
+ * @return bool
279
+ */
280
+ public function is_element_already_associated( IToolset_Element $element ) {
281
 
282
  /** @var IToolset_Element[] $parent_and_child */
283
  $parent_and_child = Toolset_Relationship_Role::sort_elements( $element, $this->for_element, $this->target_role );
284
 
285
+ $query = $this->query_factory->associations_v2();
286
+
287
+ $query->add( $query->relationship( $this->relationship ) )
288
+ ->add( $query->parent( $parent_and_child[0] ) )
289
+ ->add( $query->child( $parent_and_child[1] ) )
290
+ ->do_not_add_default_conditions() // include all existing associations
291
+ ->limit( 1 ) // because we're not interested in the actual resuls
292
+ ->need_found_rows()
293
+ ->return_association_uids() // ditto
294
+ ->get_results();
295
 
296
+ $result_count = $query->get_found_rows();
297
 
298
+ return ( $result_count > 0 );
299
  }
300
 
301
 
329
  private function get_number_of_already_associated_elements(
330
  IToolset_Relationship_Role_Parent_Child $role, IToolset_Element $element
331
  ) {
332
+ $query = $this->query_factory->associations_v2();
333
+ $query
334
+ ->add( $query->relationship_slug( $this->relationship->get_slug() ) )
335
+ ->add( $query->element( $element, $role ) )
336
+ ->do_not_add_default_conditions() // include all existing associations
337
+ ->need_found_rows()
338
+ ->limit( 1 ) // because we're not interested in the actual resuls
339
+ ->return_association_uids() // ditto
340
+ ->get_results();
341
+
342
+ $row_count = $query->get_found_rows();
343
+
344
+ return $row_count;
 
345
  }
346
 
347
  /**
vendor/toolset/toolset-common/inc/m2m/query/comparison_operator.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pseudo-enum that holds possible comparison operators.
5
+ *
6
+ * Used, for example, on the meta() query condition.
7
+ * Can be further extended.
8
+ *
9
+ * @since 2.6.1
10
+ */
11
+ class Toolset_Query_Comparison_Operator {
12
+
13
+
14
+ // These need to be valid MySQL operators.
15
+ const EQUALS = '=';
16
+ const LIKE = 'LIKE';
17
+
18
+
19
+ /**
20
+ * All accepted values.
21
+ *
22
+ * @return string[]
23
+ */
24
+ public static function all() {
25
+ return array( self::EQUALS, self::LIKE );
26
+ }
27
+
28
+ }
vendor/toolset/toolset-common/inc/m2m/{relationship_query → query}/condition/and.php RENAMED
@@ -1,11 +1,11 @@
1
  <?php
2
 
3
  /**
4
- * Chains multiple IToolset_Relationship_Query_Condition with AND.
5
  *
6
  * @since m2m
7
  */
8
- class Toolset_Relationship_Query_Condition_And extends Toolset_Relationship_Query_Condition_Operator {
9
 
10
 
11
  /**
@@ -33,11 +33,16 @@ class Toolset_Relationship_Query_Condition_And extends Toolset_Relationship_Quer
33
  /**
34
  * @inheritdoc
35
  *
36
- * @param IToolset_Relationship_Query_Condition[] $conditions
37
  *
38
- * @return Toolset_Relationship_Query_Condition_And
39
  */
40
  protected function instantiate_self( $conditions ) {
41
  return new self( $conditions );
42
  }
 
 
 
 
 
43
  }
1
  <?php
2
 
3
  /**
4
+ * Chains multiple IToolset_Query_Condition with AND.
5
  *
6
  * @since m2m
7
  */
8
+ class Toolset_Query_Condition_And extends Toolset_Query_Condition_Operator {
9
 
10
 
11
  /**
33
  /**
34
  * @inheritdoc
35
  *
36
+ * @param IToolset_Query_Condition[] $conditions
37
  *
38
+ * @return Toolset_Query_Condition_And
39
  */
40
  protected function instantiate_self( $conditions ) {
41
  return new self( $conditions );
42
  }
43
+
44
+
45
+ public function get_inner_conditions() {
46
+ return $this->conditions;
47
+ }
48
  }
vendor/toolset/toolset-common/inc/m2m/query/condition/contradiction.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A condition that is always false.
5
+ *
6
+ * It can be useful in situations where we need to make sure that the query will produce no results
7
+ * (e.g. querying for something that clearly isn't there).
8
+ *
9
+ * @since 2.5.8
10
+ */
11
+ class Toolset_Query_Condition_Contradiction
12
+ implements IToolset_Relationship_Query_Condition, IToolset_Association_Query_Condition
13
+ {
14
+
15
+
16
+ public function get_join_clause() {
17
+ return '';
18
+ }
19
+
20
+
21
+ /**
22
+ * Get a part of the WHERE clause that applies the condition.
23
+ *
24
+ * @return string Valid part of a MySQL query, so that it can be
25
+ * used in WHERE ( $condition1 ) AND ( $condition2 ) AND ( $condition3 ) ...
26
+ */
27
+ public function get_where_clause() {
28
+ return ' 1 = 0 ';
29
+ }
30
+ }
vendor/toolset/toolset-common/inc/m2m/{relationship_query/condition/i_condition.php → query/condition/interface.php} RENAMED
@@ -1,11 +1,6 @@
1
  <?php
2
 
3
- /**
4
- * Represents a single condition for the Tooset_Relationship_Query_V2.
5
- *
6
- * @since m2m
7
- */
8
- interface IToolset_Relationship_Query_Condition {
9
 
10
  /**
11
  * Get a part of the WHERE clause that applies the condition.
@@ -25,4 +20,5 @@ interface IToolset_Relationship_Query_Condition {
25
  */
26
  public function get_join_clause();
27
 
 
28
  }
1
  <?php
2
 
3
+ interface IToolset_Query_Condition {
 
 
 
 
 
4
 
5
  /**
6
  * Get a part of the WHERE clause that applies the condition.
20
  */
21
  public function get_join_clause();
22
 
23
+
24
  }
vendor/toolset/toolset-common/inc/m2m/{relationship_query → query}/condition/operator.php RENAMED
@@ -5,17 +5,19 @@
5
  *
6
  * @since 2.5.4
7
  */
8
- abstract class Toolset_Relationship_Query_Condition_Operator implements IToolset_Relationship_Query_Condition {
 
 
9
 
10
 
11
- /** @var IToolset_Relationship_Query_Condition[] */
12
  protected $conditions = array();
13
 
14
 
15
  /**
16
- * Toolset_Relationship_Query_Condition_Operator constructor.
17
  *
18
- * @param IToolset_Relationship_Query_Condition[]|array $conditions If a nested array of conditions
19
  * is provided, it will be handled as a nested $op ($op is the operation):
20
  * ( $condition1 ) $op ( ( $condition2_1 ) $op ( $condition2_2 ) ) $op ...etc.
21
  */
@@ -25,11 +27,11 @@ abstract class Toolset_Relationship_Query_Condition_Operator implements IToolset
25
 
26
 
27
  /**
28
- * @param IToolset_Relationship_Query_Condition[]|array $conditions
29
  */
30
  private function add_conditions( $conditions ) {
31
  foreach( $conditions as $condition ) {
32
- if( $condition instanceof IToolset_Relationship_Query_Condition ) {
33
  $this->conditions[] = $condition;
34
  } elseif( is_array( $condition ) ) {
35
  if( count( $condition ) === 1 ) {
5
  *
6
  * @since 2.5.4
7
  */
8
+ abstract class Toolset_Query_Condition_Operator
9
+ implements IToolset_Relationship_Query_Condition, IToolset_Association_Query_Condition
10
+ {
11
 
12
 
13
+ /** @var IToolset_Query_Condition[] */
14
  protected $conditions = array();
15
 
16
 
17
  /**
18
+ * Toolset_Query_Condition_Operator constructor.
19
  *
20
+ * @param IToolset_Query_Condition[]|array $conditions If a nested array of conditions
21
  * is provided, it will be handled as a nested $op ($op is the operation):
22
  * ( $condition1 ) $op ( ( $condition2_1 ) $op ( $condition2_2 ) ) $op ...etc.
23
  */
27
 
28
 
29
  /**
30
+ * @param IToolset_Query_Condition[]|array $conditions
31
  */
32
  private function add_conditions( $conditions ) {
33
  foreach( $conditions as $condition ) {
34
+ if( $condition instanceof IToolset_Query_Condition ) {
35
  $this->conditions[] = $condition;
36
  } elseif( is_array( $condition ) ) {
37
  if( count( $condition ) === 1 ) {
vendor/toolset/toolset-common/inc/m2m/{relationship_query → query}/condition/or.php RENAMED
@@ -1,11 +1,11 @@
1
  <?php
2
 
3
  /**
4
- * Chains multiple IToolset_Relationship_Query_Condition with OR.
5
  *
6
  * @since m2m
7
  */
8
- class Toolset_Relationship_Query_Condition_Or extends Toolset_Relationship_Query_Condition_Operator {
9
 
10
 
11
  /**
@@ -32,9 +32,9 @@ class Toolset_Relationship_Query_Condition_Or extends Toolset_Relationship_Query
32
 
33
  /**
34
  * @inheritdoc
35
- * @param IToolset_Relationship_Query_Condition[] $conditions
36
  *
37
- * @return Toolset_Relationship_Query_Condition_Or
38
  */
39
  protected function instantiate_self( $conditions ) {
40
  return new self( $conditions );
1
  <?php
2
 
3
  /**
4
+ * Chains multiple IToolset_Query_Condition with OR.
5
  *
6
  * @since m2m
7
  */
8
+ class Toolset_Query_Condition_Or extends Toolset_Query_Condition_Operator {
9
 
10
 
11
  /**
32
 
33
  /**
34
  * @inheritdoc
35
+ * @param IToolset_Query_Condition[] $conditions
36
  *
37
+ * @return IToolset_Query_Condition
38
  */
39
  protected function instantiate_self( $conditions ) {
40
  return new self( $conditions );
vendor/toolset/toolset-common/inc/m2m/{relationship_query → query}/condition/tautology.php RENAMED
@@ -9,8 +9,17 @@
9
  * Remember, the first rule of the Tautology Club is the first rule of the Tautology Club!
10
  *
11
  * @since 2.5.6
 
12
  */
13
- class Toolset_Relationship_Query_Condition_Tautology extends Toolset_Relationship_Query_Condition {
 
 
 
 
 
 
 
 
14
 
15
  /**
16
  * Get a part of the WHERE clause that applies the condition.
9
  * Remember, the first rule of the Tautology Club is the first rule of the Tautology Club!
10
  *
11
  * @since 2.5.6
12
+ * @since 2.5.8 Adjusted for usage in Toolset_Association_Query_V2 as well.
13
  */
14
+ class Toolset_Query_Condition_Tautology
15
+ implements IToolset_Relationship_Query_Condition, IToolset_Association_Query_Condition
16
+ {
17
+
18
+
19
+ public function get_join_clause() {
20
+ return '';
21
+ }
22
+
23
 
24
  /**
25
  * Get a part of the WHERE clause that applies the condition.
vendor/toolset/toolset-common/inc/m2m/{query_factory.php → query/factory.php} RENAMED
@@ -13,7 +13,7 @@ class Toolset_Relationship_Query_Factory {
13
  * @param $args
14
  *
15
  * @return Toolset_Relationship_Query
16
- * @deprecated
17
  */
18
  public function relationships( $args ) {
19
  return new Toolset_Relationship_Query( $args );
@@ -34,7 +34,7 @@ class Toolset_Relationship_Query_Factory {
34
  * @param IToolset_Relationship_Definition $relationship
35
  * @param IToolset_Relationship_Role_Parent_Child $target_role Target role of the relationships (future role of
36
  * the posts that are being queried)
37
- * @param int $for_element_id ID of the element to check against.
38
  * @param Toolset_Relationship_Table_Name|null $table_names_di
39
  * @param wpdb|null $wpdb_di
40
  *
@@ -43,14 +43,14 @@ class Toolset_Relationship_Query_Factory {
43
  public function distinct_relationship_posts(
44
  IToolset_Relationship_Definition $relationship,
45
  IToolset_Relationship_Role_Parent_Child $target_role,
46
- $for_element_id,
47
  Toolset_Relationship_Table_Name $table_names_di = null,
48
  wpdb $wpdb_di = null
49
  ) {
50
  return new Toolset_Relationship_Distinct_Post_Query(
51
  $relationship,
52
  $target_role,
53
- $for_element_id,
54
  $table_names_di,
55
  $wpdb_di
56
  );
@@ -71,9 +71,17 @@ class Toolset_Relationship_Query_Factory {
71
  * @param $args
72
  *
73
  * @return Toolset_Association_Query
 
74
  */
75
  public function associations( $args ) {
76
  return new Toolset_Association_Query( $args );
77
  }
78
 
 
 
 
 
 
 
 
79
  }
13
  * @param $args
14
  *
15
  * @return Toolset_Relationship_Query
16
+ * @deprecated Use Toolset_Relationship_Query_V2 instead.
17
  */
18
  public function relationships( $args ) {
19
  return new Toolset_Relationship_Query( $args );
34
  * @param IToolset_Relationship_Definition $relationship
35
  * @param IToolset_Relationship_Role_Parent_Child $target_role Target role of the relationships (future role of
36
  * the posts that are being queried)
37
+ * @param IToolset_Element $for_element ID of the element to check against.
38
  * @param Toolset_Relationship_Table_Name|null $table_names_di
39
  * @param wpdb|null $wpdb_di
40
  *
43
  public function distinct_relationship_posts(
44
  IToolset_Relationship_Definition $relationship,
45
  IToolset_Relationship_Role_Parent_Child $target_role,
46
+ IToolset_Element $for_element,
47
  Toolset_Relationship_Table_Name $table_names_di = null,
48
  wpdb $wpdb_di = null
49
  ) {
50
  return new Toolset_Relationship_Distinct_Post_Query(
51
  $relationship,
52
  $target_role,
53
+ $for_element,
54
  $table_names_di,
55
  $wpdb_di
56
  );
71
  * @param $args
72
  *
73
  * @return Toolset_Association_Query
74
+ * @deprecated Use associations_v2() instead.
75
  */
76
  public function associations( $args ) {
77
  return new Toolset_Association_Query( $args );
78
  }
79
 
80
+
81
+ /**
82
+ * @return Toolset_Association_Query_V2
83
+ */
84
+ public function associations_v2() {
85
+ return new Toolset_Association_Query_V2();
86
+ }
87
  }
vendor/toolset/toolset-common/inc/m2m/query_base.php CHANGED
@@ -6,6 +6,7 @@
6
  * Contains shared methods, mainly related to query argument processing.
7
  *
8
  * @since m2m
 
9
  */
10
  abstract class Toolset_Relationship_Query_Base {
11
 
6
  * Contains shared methods, mainly related to query argument processing.
7
  *
8
  * @since m2m
9
+ * @deprecated Needed only for old association and relationship query classes. Remove when those are removed.
10
  */
11
  abstract class Toolset_Relationship_Query_Base {
12
 
vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/definition.php RENAMED
@@ -37,7 +37,7 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
37
 
38
  /** @var string */
39
  private $driver_name;
40
-
41
  /** @var Toolset_Relationship_Element_Type */
42
  private $parent_type;
43
 
@@ -129,11 +129,7 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
129
  public function __construct( $definition_array, Toolset_Potential_Association_Query_Factory $potential_association_query_factory_di = null ) {
130
  $this->read_definition_array( $definition_array );
131
 
132
- $this->potential_association_query_factory = (
133
- null === $potential_association_query_factory_di
134
- ? new Toolset_Potential_Association_Query_Factory()
135
- : $potential_association_query_factory_di
136
- );
137
  }
138
 
139
 
@@ -145,7 +141,7 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
145
  * @since m2m
146
  */
147
  private function read_definition_array( $definition_array ) {
148
-
149
  $this->slug = sanitize_title( toolset_getarr( $definition_array, self::DA_SLUG ) );
150
 
151
  $this->row_id = (int) toolset_getarr( $definition_array, self::DA_ROW_ID );
@@ -166,9 +162,9 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
166
  // All we know is that it's an array that will be passed to the driver when instantiating it.
167
  // From that point it's driver's business.
168
  $this->driver_setup = toolset_ensarr( toolset_getarr( $definition_array, self::DA_DRIVER_SETUP, null ) );
169
-
170
  $this->parent_type = new Toolset_Relationship_Element_Type( toolset_getarr( $definition_array, self::DA_PARENT_TYPE ) );
171
-
172
  $this->child_type = new Toolset_Relationship_Element_Type( toolset_getarr( $definition_array, self::DA_CHILD_TYPE ) );
173
 
174
  // Defaults to "infinity"
@@ -318,7 +314,7 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
318
 
319
  /**
320
  * Get the parent entity type definition.
321
- *
322
  * @return Toolset_Relationship_Element_Type
323
  * @since m2m
324
  */
@@ -327,7 +323,7 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
327
 
328
  /**
329
  * Get the child entity type definition.
330
- *
331
  * @return Toolset_Relationship_Element_Type
332
  * @since m2m
333
  */
@@ -371,6 +367,10 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
371
  return $this->get_child_type();
372
  case Toolset_Relationship_Role::PARENT:
373
  return $this->get_parent_type();
 
 
 
 
374
  default:
375
  throw new InvalidArgumentException();
376
  }
@@ -434,12 +434,12 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
434
 
435
  /**
436
  * Build a definition array for persisting the definition.
437
- *
438
- * @return array
439
  * @since m2m
440
  */
441
  public function get_definition_array() {
442
-
443
  return array(
444
  self::DA_SLUG => $this->get_slug(),
445
  self::DA_DRIVER => $this->get_driver_name(),
@@ -455,20 +455,20 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
455
  self::DA_DISPLAY_NAME_SINGULAR => $this->get_display_name_singular()
456
  );
457
  }
458
-
459
-
460
  /** @var Toolset_Relationship_Driver_Base|null */
461
  private $driver = null;
462
 
463
 
464
  /**
465
  * Get the relationship driver. Initialize it if called for the first time.
466
- *
467
  * @return Toolset_Relationship_Driver
468
  * @since m2m
469
  */
470
  public function get_driver() {
471
-
472
  if( null === $this->driver ) {
473
  switch( $this->get_driver_name() ) {
474
  case self::DRIVER_NATIVE:
@@ -476,7 +476,7 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
476
  break;
477
  default:
478
  // fail miserably
479
- //
480
  // But really - this should never happen because we have a validation
481
  // in read_definition_array().
482
  throw new RuntimeException( 'Unsupported relationship driver.' );
@@ -494,7 +494,7 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
494
 
495
  /**
496
  * Update the relationship cardinality.
497
- *
498
  * @param Toolset_Relationship_Cardinality $value
499
  * @throws InvalidArgumentException
500
  * @since m2m
@@ -503,7 +503,7 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
503
  if( ! $value instanceof Toolset_Relationship_Cardinality ) {
504
  throw new InvalidArgumentException();
505
  }
506
-
507
  $this->cardinality = $value;
508
  }
509
 
@@ -612,7 +612,7 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
612
  * @param int|WP_Post|Toolset_Element $parent Parent element (of matching domain, type and other conditions)
613
  * @param int|WP_Post|Toolset_Element $child Child element (of matching domain, type and other conditions)
614
  *
615
- * @return Toolset_Result|Toolset_Association_Base The newly created association or a negative Toolset_Result when it could not have been created.
616
  * @throws RuntimeException when the association cannot be created because of a known reason. The exception would
617
  * contain a displayable error message.
618
  * @throws InvalidArgumentException when the method is used improperly.
@@ -633,7 +633,7 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
633
 
634
 
635
  /**
636
- * Determine or set whether the relationship is distinct, which means that only one association between
637
  * each two elements can exist.
638
  *
639
  * @param null|bool $new_value If a boolean value is provided, it will be set.
@@ -859,4 +859,17 @@ class Toolset_Relationship_Definition implements IToolset_Relationship_Definitio
859
  return $this->row_id;
860
  }
861
 
862
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
  /** @var string */
39
  private $driver_name;
40
+
41
  /** @var Toolset_Relationship_Element_Type */
42
  private $parent_type;
43
 
129
  public function __construct( $definition_array, Toolset_Potential_Association_Query_Factory $potential_association_query_factory_di = null ) {
130
  $this->read_definition_array( $definition_array );
131
 
132
+ $this->potential_association_query_factory = ( null === $potential_association_query_factory_di ? new Toolset_Potential_Association_Query_Factory() : $potential_association_query_factory_di );
 
 
 
 
133
  }
134
 
135
 
141
  * @since m2m
142
  */
143
  private function read_definition_array( $definition_array ) {
144
+
145
  $this->slug = sanitize_title( toolset_getarr( $definition_array, self::DA_SLUG ) );
146
 
147
  $this->row_id = (int) toolset_getarr( $definition_array, self::DA_ROW_ID );
162
  // All we know is that it's an array that will be passed to the driver when instantiating it.
163
  // From that point it's driver's business.
164
  $this->driver_setup = toolset_ensarr( toolset_getarr( $definition_array, self::DA_DRIVER_SETUP, null ) );
165
+
166
  $this->parent_type = new Toolset_Relationship_Element_Type( toolset_getarr( $definition_array, self::DA_PARENT_TYPE ) );
167
+
168
  $this->child_type = new Toolset_Relationship_Element_Type( toolset_getarr( $definition_array, self::DA_CHILD_TYPE ) );
169
 
170
  // Defaults to "infinity"
314
 
315
  /**
316
  * Get the parent entity type definition.
317
+ *
318
  * @return Toolset_Relationship_Element_Type
319
  * @since m2m
320
  */
323
 
324
  /**
325
  * Get the child entity type definition.
326
+ *
327
  * @return Toolset_Relationship_Element_Type
328
  * @since m2m
329
  */
367
  return $this->get_child_type();
368
  case Toolset_Relationship_Role::PARENT:
369
  return $this->get_parent_type();
370
+ case Toolset_Relationship_Role::INTERMEDIARY:
371
+ return Toolset_Relationship_Element_Type::build_for_post_type(
372
+ $this->get_intermediary_post_type()
373
+ );
374
  default:
375
  throw new InvalidArgumentException();
376
  }
434
 
435
  /**
436
  * Build a definition array for persisting the definition.
437
+ *
438
+ * @return array
439
  * @since m2m
440
  */
441
  public function get_definition_array() {
442
+
443
  return array(
444
  self::DA_SLUG => $this->get_slug(),
445
  self::DA_DRIVER => $this->get_driver_name(),
455
  self::DA_DISPLAY_NAME_SINGULAR => $this->get_display_name_singular()
456
  );
457
  }
458
+
459
+
460
  /** @var Toolset_Relationship_Driver_Base|null */
461
  private $driver = null;
462
 
463
 
464
  /**
465
  * Get the relationship driver. Initialize it if called for the first time.
466
+ *
467
  * @return Toolset_Relationship_Driver
468
  * @since m2m
469
  */
470
  public function get_driver() {
471
+
472
  if( null === $this->driver ) {
473
  switch( $this->get_driver_name() ) {
474
  case self::DRIVER_NATIVE:
476
  break;
477
  default:
478
  // fail miserably
479
+ //
480
  // But really - this should never happen because we have a validation
481
  // in read_definition_array().
482
  throw new RuntimeException( 'Unsupported relationship driver.' );
494
 
495
  /**
496
  * Update the relationship cardinality.
497
+ *
498
  * @param Toolset_Relationship_Cardinality $value
499
  * @throws InvalidArgumentException
500
  * @since m2m
503
  if( ! $value instanceof Toolset_Relationship_Cardinality ) {
504
  throw new InvalidArgumentException();
505
  }
506
+
507
  $this->cardinality = $value;
508
  }
509
 
612
  * @param int|WP_Post|Toolset_Element $parent Parent element (of matching domain, type and other conditions)
613
  * @param int|WP_Post|Toolset_Element $child Child element (of matching domain, type and other conditions)
614
  *
615
+ * @return Toolset_Result|IToolset_Association The newly created association or a negative Toolset_Result when it could not have been created.
616
  * @throws RuntimeException when the association cannot be created because of a known reason. The exception would
617
  * contain a displayable error message.
618
  * @throws InvalidArgumentException when the method is used improperly.
633
 
634
 
635
  /**
636
+ * Determine or set whether the relationship is distinct, which means that only one association between
637
  * each two elements can exist.
638
  *
639
  * @param null|bool $new_value If a boolean value is provided, it will be set.
859
  return $this->row_id;
860
  }
861
 
862
+
863
+ /**
864
+ * Return the number of existing associations belonging to the relationships
865
+ *
866
+ * @param string|IToolset_Relationship_Role $role Role.
867
+ * @return int
868
+ * @since m2m
869
+ */
870
+ public function get_max_associations( $role ) {
871
+ $db_operations = Toolset_Relationship_Database_Operations::get_instance();
872
+ $role_name = $this->role_to_role_name( $role );
873
+ return $db_operations->count_max_associations( $this->get_row_id(), $role_name );
874
+ }
875
+ }
vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/factory.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/interface.php RENAMED
@@ -172,7 +172,7 @@ interface IToolset_Relationship_Definition {
172
  * @param int|WP_Post|IToolset_Element $parent Parent element (of matching domain, type and other conditions)
173
  * @param int|WP_Post|IToolset_Element $child Child element (of matching domain, type and other conditions)
174
  *
175
- * @return Toolset_Result|Toolset_Association_Base The newly created association or a negative Toolset_Result when it could not have been created.
176
  * @throws RuntimeException when the association cannot be created because of a known reason. The exception would
177
  * contain a displayable error message.
178
  * @throws InvalidArgumentException when the method is used improperly.
@@ -273,8 +273,34 @@ interface IToolset_Relationship_Definition {
273
  * Can be set by using the origin keyword or the class
274
  *
275
  * @param IToolset_Relationship_Origin|string $origin
276
- *
277
  * @since m2m
278
  */
279
  public function set_origin( $origin );
280
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  * @param int|WP_Post|IToolset_Element $parent Parent element (of matching domain, type and other conditions)
173
  * @param int|WP_Post|IToolset_Element $child Child element (of matching domain, type and other conditions)
174
  *
175
+ * @return Toolset_Result|IToolset_Association The newly created association or a negative Toolset_Result when it could not have been created.
176
  * @throws RuntimeException when the association cannot be created because of a known reason. The exception would
177
  * contain a displayable error message.
178
  * @throws InvalidArgumentException when the method is used improperly.
273
  * Can be set by using the origin keyword or the class
274
  *
275
  * @param IToolset_Relationship_Origin|string $origin
276
+ * @return void
277
  * @since m2m
278
  */
279
  public function set_origin( $origin );
280
+
281
+
282
+ /**
283
+ * @return int
284
+ */
285
+ public function get_row_id();
286
+
287
+
288
+ /**
289
+ * Return the number of existing associations belonging to the relationships
290
+ *
291
+ * @param string|IToolset_Relationship_Role $role Role.
292
+ * @return int
293
+ * @since m2m
294
+ */
295
+ public function get_max_associations( $role );
296
+
297
+
298
+ /**
299
+ * Get the intermediary post type, if it exists.
300
+ *
301
+ * Note that its existence doesn't necessarily mean that there are association fields.
302
+ *
303
+ * @return null|string
304
+ */
305
+ public function get_intermediary_post_type();
306
+ }
vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/persistence.php RENAMED
@@ -21,11 +21,14 @@ class Toolset_Relationship_Definition_Persistence {
21
  /** @var Toolset_Relationship_Table_Name */
22
  private $table_name;
23
 
 
 
24
 
25
  public function __construct(
26
  wpdb $wpdb_di = null,
27
  Toolset_Relationship_Definition_Translator $definition_translator_di = null,
28
- Toolset_Relationship_Table_Name $table_name_di = null
 
29
  ) {
30
 
31
  if( null === $wpdb_di ) {
@@ -47,6 +50,12 @@ class Toolset_Relationship_Definition_Persistence {
47
  : $table_name_di
48
  );
49
 
 
 
 
 
 
 
50
  }
51
 
52
 
@@ -57,6 +66,8 @@ class Toolset_Relationship_Definition_Persistence {
57
  * @param Toolset_Relationship_Definition $relationship_definition
58
  */
59
  public function persist_definition( Toolset_Relationship_Definition $relationship_definition ) {
 
 
60
  $row = $this->definition_translator->to_database_row( $relationship_definition );
61
  $row = $this->update_definition_type_sets( $relationship_definition, $row );
62
  $this->wpdb->update(
@@ -77,6 +88,8 @@ class Toolset_Relationship_Definition_Persistence {
77
  * @return null|Toolset_Relationship_Definition
78
  */
79
  public function insert_definition( Toolset_Relationship_Definition $relationship_definition ) {
 
 
80
  $row = $this->definition_translator->to_database_row( $relationship_definition );
81
  $row = $this->update_definition_type_sets( $relationship_definition, $row );
82
 
@@ -232,4 +245,66 @@ class Toolset_Relationship_Definition_Persistence {
232
  }
233
 
234
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  }
21
  /** @var Toolset_Relationship_Table_Name */
22
  private $table_name;
23
 
24
+ /** @var Toolset_Post_Type_Repository */
25
+ private $post_type_repository;
26
 
27
  public function __construct(
28
  wpdb $wpdb_di = null,
29
  Toolset_Relationship_Definition_Translator $definition_translator_di = null,
30
+ Toolset_Relationship_Table_Name $table_name_di = null,
31
+ Toolset_Post_Type_Repository $post_type_repository = null
32
  ) {
33
 
34
  if( null === $wpdb_di ) {
50
  : $table_name_di
51
  );
52
 
53
+ $this->post_type_repository = (
54
+ null === $post_type_repository
55
+ ? Toolset_Post_Type_Repository::get_instance()
56
+ : $post_type_repository
57
+ );
58
+
59
  }
60
 
61
 
66
  * @param Toolset_Relationship_Definition $relationship_definition
67
  */
68
  public function persist_definition( Toolset_Relationship_Definition $relationship_definition ) {
69
+ $this->abort_if_invalid_element_types_used( $relationship_definition );
70
+
71
  $row = $this->definition_translator->to_database_row( $relationship_definition );
72
  $row = $this->update_definition_type_sets( $relationship_definition, $row );
73
  $this->wpdb->update(
88
  * @return null|Toolset_Relationship_Definition
89
  */
90
  public function insert_definition( Toolset_Relationship_Definition $relationship_definition ) {
91
+ $this->abort_if_invalid_element_types_used( $relationship_definition );
92
+
93
  $row = $this->definition_translator->to_database_row( $relationship_definition );
94
  $row = $this->update_definition_type_sets( $relationship_definition, $row );
95
 
245
  }
246
 
247
 
248
+ /**
249
+ * This method proofs that the element types are valid for a new relationship. If not: FATAL ERROR is thrown.
250
+ *
251
+ * The decision to check it as late as possible is for better backwards compatiblity and possible edge cases.
252
+ * "Correctly" this check should be done on the contructor of Toolset_Relationship_Element_Type.
253
+ * BUT it's not impossible to create an invalid relationship just by using the GUI, for example:
254
+ * Activate Types, create Relationship, deactivate Types, activate WPML, select for previously used post types
255
+ * "Translatable - only show translated items", activate Types again and you would get an fatal error if this check
256
+ * would be on the constrcutor of Toolset_Relationship_Element_Type.
257
+ *
258
+ * @param Toolset_Relationship_Definition $relationship_definition
259
+ */
260
+ private function abort_if_invalid_element_types_used( Toolset_Relationship_Definition $relationship_definition ) {
261
+ /**
262
+ * @var $element_types Toolset_Relationship_Element_Type[]
263
+ */
264
+ $element_types = array(
265
+ $relationship_definition->get_parent_type(),
266
+ $relationship_definition->get_child_type()
267
+ );
268
+
269
+ $rfg_involved = false;
270
+ $error = false;
271
+
272
+ foreach( $element_types as $element_type ) {
273
+ switch( $element_type->get_domain() ) {
274
+ case Toolset_Element_Domain::POSTS:
275
+ foreach( $element_type->get_types() as $post_type_string ) {
276
+ $post_type = $this->post_type_repository->get( $post_type_string );
277
+ if( null === $post_type ) {
278
+ throw new RuntimeException(
279
+ 'The post type "' . sanitize_text_field( $post_type_string ) . '" was not found, so it cannot be used in '
280
+ . 'a relationship, post reference field or in a repeatable field group.'
281
+ );
282
+ }
283
+
284
+ if( $post_type->is_repeating_field_group() ) {
285
+ $rfg_involved = true;
286
+ continue;
287
+ }
288
+
289
+ if( ! $rfg_involved && ! $post_type->can_be_used_in_relationship() ) {
290
+ $error =
291
+ 'The post type "'.$post_type_string.'" uses the "Translatable - only show translated '
292
+ . 'items" WPML translation mode. In order to use it in a relationship, switch to '
293
+ . '"Translatable - use translation if available or fallback to default language mode".';
294
+ }
295
+ }
296
+ break;
297
+ case Toolset_Element_Domain::TERMS:
298
+ case Toolset_Element_Domain::USERS:
299
+ // no restrictions
300
+ break;
301
+ }
302
+ }
303
+
304
+ if( ! $rfg_involved && $error ) {
305
+ // We allow a relationship between RFG and wrong translation mode
306
+ // This exception should never been thrown, while using the GUI of Types to create Relationships
307
+ throw new RuntimeException( $error );
308
+ }
309
+ }
310
  }
vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/repository.php RENAMED
@@ -33,15 +33,9 @@ class Toolset_Relationship_Definition_Repository {
33
  }
34
 
35
 
36
- /** @var Toolset_Association_Repository|null */
37
- private $_association_repository;
38
-
39
  /** @var Toolset_Relationship_Database_Operations|null */
40
  private $_database_operations;
41
 
42
- /** @var Toolset_Relationship_Definition_Factory|null */
43
- private $_definition_factory;
44
-
45
  /** @var Toolset_Relationship_Definition_Persistence */
46
  private $_definition_persistence;
47
 
@@ -50,15 +44,11 @@ class Toolset_Relationship_Definition_Repository {
50
 
51
 
52
  public function __construct(
53
- Toolset_Association_Repository $association_repository_di = null,
54
  Toolset_Relationship_Database_Operations $database_operations_di = null,
55
- Toolset_Relationship_Definition_Factory $definition_factory_di = null,
56
  Toolset_Relationship_Definition_Persistence $definition_persistence_di = null,
57
  Toolset_Relationship_Definition_Translator $definition_translator_di = null
58
  ) {
59
- $this->_association_repository = $association_repository_di;
60
  $this->_database_operations = $database_operations_di;
61
- $this->_definition_factory = $definition_factory_di;
62
  $this->_definition_persistence = $definition_persistence_di;
63
 
64
  $this->definition_translator = (
@@ -139,7 +129,7 @@ class Toolset_Relationship_Definition_Repository {
139
  // fixme: abstract this away
140
  if( $do_cleanup ) {
141
  // delete associations of relationship
142
- $toolset_results[] = $this->get_association_repository()->remove_by_relationship( $definition );
143
 
144
  $intermediary_post_type = $definition->get_intermediary_post_type();
145
  if( null !== $intermediary_post_type ) {
@@ -407,15 +397,6 @@ class Toolset_Relationship_Definition_Repository {
407
  }
408
 
409
 
410
- private function get_association_repository() {
411
- if( null === $this->_association_repository ) {
412
- $this->_association_repository = Toolset_Association_Repository::get_instance();
413
- }
414
-
415
- return $this->_association_repository;
416
- }
417
-
418
-
419
  private function get_database_operations() {
420
  if( null === $this->_database_operations ) {
421
  $this->_database_operations = new Toolset_Relationship_Database_Operations();
@@ -424,14 +405,6 @@ class Toolset_Relationship_Definition_Repository {
424
  return $this->_database_operations;
425
  }
426
 
427
- private function get_definition_factory() {
428
- if( null === $this->_definition_factory ) {
429
- $this->_definition_factory = new Toolset_Relationship_Definition_Factory();
430
- }
431
-
432
- return $this->_definition_factory;
433
- }
434
-
435
 
436
  private function get_definition_persistence() {
437
  if( null === $this->_definition_persistence ) {
33
  }
34
 
35
 
 
 
 
36
  /** @var Toolset_Relationship_Database_Operations|null */
37
  private $_database_operations;
38
 
 
 
 
39
  /** @var Toolset_Relationship_Definition_Persistence */
40
  private $_definition_persistence;
41
 
44
 
45
 
46
  public function __construct(
 
47
  Toolset_Relationship_Database_Operations $database_operations_di = null,
 
48
  Toolset_Relationship_Definition_Persistence $definition_persistence_di = null,
49
  Toolset_Relationship_Definition_Translator $definition_translator_di = null
50
  ) {
 
51
  $this->_database_operations = $database_operations_di;
 
52
  $this->_definition_persistence = $definition_persistence_di;
53
 
54
  $this->definition_translator = (
129
  // fixme: abstract this away
130
  if( $do_cleanup ) {
131
  // delete associations of relationship
132
+ $toolset_results[] = $this->get_database_operations()->delete_associations_by_relationship( $definition->get_row_id() );
133
 
134
  $intermediary_post_type = $definition->get_intermediary_post_type();
135
  if( null !== $intermediary_post_type ) {
397
  }
398
 
399
 
 
 
 
 
 
 
 
 
 
400
  private function get_database_operations() {
401
  if( null === $this->_database_operations ) {
402
  $this->_database_operations = new Toolset_Relationship_Database_Operations();
405
  return $this->_database_operations;
406
  }
407
 
 
 
 
 
 
 
 
 
408
 
409
  private function get_definition_persistence() {
410
  if( null === $this->_definition_persistence ) {
vendor/toolset/toolset-common/inc/m2m/{definition → relationship/definition}/translator.php RENAMED
@@ -97,7 +97,7 @@ class Toolset_Relationship_Definition_Translator {
97
  Toolset_Relationship_Role::CHILD => array(
98
  Toolset_Relationship_Cardinality::MAX => (int) $row->cardinality_child_max,
99
  Toolset_Relationship_Cardinality::MIN => (int) $row->cardinality_child_min
100
- )
101
  ),
102
  Toolset_Relationship_Definition::DA_DRIVER_SETUP => array(
103
  Toolset_Relationship_Driver::DA_INTERMEDIARY_POST_TYPE => $row->intermediary_type
97
  Toolset_Relationship_Role::CHILD => array(
98
  Toolset_Relationship_Cardinality::MAX => (int) $row->cardinality_child_max,
99
  Toolset_Relationship_Cardinality::MIN => (int) $row->cardinality_child_min
100
+ ),
101
  ),
102
  Toolset_Relationship_Definition::DA_DRIVER_SETUP => array(
103
  Toolset_Relationship_Driver::DA_INTERMEDIARY_POST_TYPE => $row->intermediary_type
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/cardinality_match/conjunction.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/cardinality_match/factory.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/cardinality_match/interface.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/cardinality_match/operators.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/cardinality_match/single.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/abstract.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/has_active_types.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/has_cardinality.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/has_domain.php RENAMED
@@ -26,13 +26,14 @@ class Toolset_Relationship_Query_Condition_Has_Domain extends Toolset_Relationsh
26
  * @param string $domain_name One of the Toolset_Field_Utils::DOMAIN_* values.
27
  * @param IToolset_Relationship_Role_Parent_Child $role
28
  * @param Toolset_Relationship_Database_Operations|null $database_operations_di
 
29
  */
30
  public function __construct(
31
  $domain_name, IToolset_Relationship_Role_Parent_Child $role,
32
  Toolset_Relationship_Database_Operations $database_operations_di = null
33
  ) {
34
  if( ! is_string( $domain_name ) || ! in_array( $domain_name, Toolset_Element_Domain::all() ) ) {
35
- throw new InvalidArgumentException();
36
  }
37
 
38
  $this->domain_name = $domain_name;
26
  * @param string $domain_name One of the Toolset_Field_Utils::DOMAIN_* values.
27
  * @param IToolset_Relationship_Role_Parent_Child $role
28
  * @param Toolset_Relationship_Database_Operations|null $database_operations_di
29
+ * @throws InvalidArgumentException
30
  */
31
  public function __construct(
32
  $domain_name, IToolset_Relationship_Role_Parent_Child $role,
33
  Toolset_Relationship_Database_Operations $database_operations_di = null
34
  ) {
35
  if( ! is_string( $domain_name ) || ! in_array( $domain_name, Toolset_Element_Domain::all() ) ) {
36
+ throw new InvalidArgumentException( 'Invalid element domain provided: ' . sanitize_title( $domain_name ) );
37
  }
38
 
39
  $this->domain_name = $domain_name;
vendor/toolset/toolset-common/inc/m2m/relationship/query/condition/interface.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Represents a single condition for the Tooset_Relationship_Query_V2.
5
+ *
6
+ * @since m2m
7
+ */
8
+ interface IToolset_Relationship_Query_Condition extends IToolset_Query_Condition {
9
+
10
+ }
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/is_active.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/is_boolean_flag.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/is_legacy.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/origin.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition/type.php RENAMED
@@ -24,7 +24,7 @@ class Toolset_Relationship_Query_Condition_Type extends Toolset_Relationship_Que
24
  public function __construct(
25
  $type, IToolset_Relationship_Role_Parent_Child $role
26
  ) {
27
- if( ! is_string( $type ) || empty( $type ) || sanitize_text_field( $type ) !== $type ) {
28
  throw new InvalidArgumentException();
29
  }
30
 
24
  public function __construct(
25
  $type, IToolset_Relationship_Role_Parent_Child $role
26
  ) {
27
+ if( ( ! is_string( $type ) && ! is_int( $type ) ) || empty( $type ) || sanitize_text_field( $type ) != $type ) {
28
  throw new InvalidArgumentException();
29
  }
30
 
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/condition_factory.php RENAMED
@@ -16,7 +16,7 @@ class Toolset_Relationship_Query_Condition_Factory {
16
  * @return IToolset_Relationship_Query_Condition
17
  */
18
  public function do_or( $operands ) {
19
- return new Toolset_Relationship_Query_Condition_Or( $operands );
20
  }
21
 
22
 
@@ -29,7 +29,7 @@ class Toolset_Relationship_Query_Condition_Factory {
29
  * @return IToolset_Relationship_Query_Condition
30
  */
31
  public function do_and( $operands ) {
32
- return new Toolset_Relationship_Query_Condition_And( $operands );
33
  }
34
 
35
 
@@ -101,7 +101,7 @@ class Toolset_Relationship_Query_Condition_Factory {
101
  * @param bool $has_active_post_types
102
  * @param IToolset_Relationship_Role_Parent_Child $in_role
103
  *
104
- * @return IToolset_Relationship_Query_Condition|Toolset_Relationship_Query_Condition_Has_Active_Types
105
  */
106
  public function has_active_post_types( $has_active_post_types, IToolset_Relationship_Role_Parent_Child $in_role ) {
107
  return new Toolset_Relationship_Query_Condition_Has_Active_Types( $has_active_post_types, $in_role );
@@ -113,7 +113,7 @@ class Toolset_Relationship_Query_Condition_Factory {
113
  *
114
  * @param IToolset_Relationship_Query_Cardinality_Match $cardinality_match
115
  *
116
- * @return Toolset_Relationship_Query_Condition_Has_Cardinality
117
  */
118
  public function has_cardinality( IToolset_Relationship_Query_Cardinality_Match $cardinality_match ) {
119
  return new Toolset_Relationship_Query_Condition_Has_Cardinality( $cardinality_match );
@@ -124,10 +124,10 @@ class Toolset_Relationship_Query_Condition_Factory {
124
  * A condition that is always true.
125
  *
126
  * @since 2.5.6
127
- * @return Toolset_Relationship_Query_Condition_Tautology
128
  */
129
  public function tautology() {
130
- return new Toolset_Relationship_Query_Condition_Tautology();
131
  }
132
 
133
 
16
  * @return IToolset_Relationship_Query_Condition
17
  */
18
  public function do_or( $operands ) {
19
+ return new Toolset_Query_Condition_Or( $operands );
20
  }
21
 
22
 
29
  * @return IToolset_Relationship_Query_Condition
30
  */
31
  public function do_and( $operands ) {
32
+ return new Toolset_Query_Condition_And( $operands );
33
  }
34
 
35
 
101
  * @param bool $has_active_post_types
102
  * @param IToolset_Relationship_Role_Parent_Child $in_role
103
  *
104
+ * @return IToolset_Relationship_Query_Condition
105
  */
106
  public function has_active_post_types( $has_active_post_types, IToolset_Relationship_Role_Parent_Child $in_role ) {
107
  return new Toolset_Relationship_Query_Condition_Has_Active_Types( $has_active_post_types, $in_role );
113
  *
114
  * @param IToolset_Relationship_Query_Cardinality_Match $cardinality_match
115
  *
116
+ * @return IToolset_Relationship_Query_Condition
117
  */
118
  public function has_cardinality( IToolset_Relationship_Query_Cardinality_Match $cardinality_match ) {
119
  return new Toolset_Relationship_Query_Condition_Has_Cardinality( $cardinality_match );
124
  * A condition that is always true.
125
  *
126
  * @since 2.5.6
127
+ * @return IToolset_Relationship_Query_Condition
128
  */
129
  public function tautology() {
130
+ return new Toolset_Query_Condition_Tautology();
131
  }
132
 
133
 
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/relationship_query.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/relationship_query_v2.php RENAMED
@@ -74,6 +74,25 @@ class Toolset_Relationship_Query_V2 implements IToolset_Query {
74
  private $_cardinality_match_factory;
75
 
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  /**
78
  * Toolset_Relationship_Query_V2 constructor.
79
  *
@@ -168,6 +187,11 @@ class Toolset_Relationship_Query_V2 implements IToolset_Query {
168
  */
169
  private function build_root_condition() {
170
  $this->add_default_conditions();
 
 
 
 
 
171
  return $this->condition_factory->do_and( $this->conditions );
172
  }
173
 
@@ -190,9 +214,23 @@ class Toolset_Relationship_Query_V2 implements IToolset_Query {
190
  */
191
  public function get_results() {
192
 
 
 
 
 
 
 
 
 
 
 
193
  $query = $this->build_sql_query();
194
  $rows = toolset_ensarr( $this->wpdb->get_results( $query ) );
195
 
 
 
 
 
196
  $results = array();
197
  foreach( $rows as $row ) {
198
  $definition = $this->definition_translator->from_database_row( $row );
@@ -213,7 +251,7 @@ class Toolset_Relationship_Query_V2 implements IToolset_Query {
213
  */
214
  private function build_sql_query() {
215
  $root_condition = $this->build_root_condition();
216
- return $this->expression_builder->build( $root_condition );
217
  }
218
 
219
 
@@ -231,7 +269,7 @@ class Toolset_Relationship_Query_V2 implements IToolset_Query {
231
 
232
 
233
  /**
234
- * Chain multiple conditions with AN.
235
  *
236
  * The whole statement will evaluate to true if all provided conditions are true.
237
  *
@@ -424,4 +462,41 @@ class Toolset_Relationship_Query_V2 implements IToolset_Query {
424
  }
425
  }
426
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
427
  }
74
  private $_cardinality_match_factory;
75
 
76
 
77
+ /** @var bool Remember whether get_results() was called. */
78
+ private $was_used = false;
79
+
80
+
81
+ /**
82
+ * @var bool Determines whether the SQL query should also calculate found rows.
83
+ * @since 2.5.8
84
+ */
85
+ private $need_found_rows = false;
86
+
87
+
88
+ /**
89
+ * @var int|null Number of total found rows that will be set in get_results() if there was a request
90
+ * to calculate these, null otherwise.
91
+ * @since 2.5.8
92
+ */
93
+ private $found_rows;
94
+
95
+
96
  /**
97
  * Toolset_Relationship_Query_V2 constructor.
98
  *
187
  */
188
  private function build_root_condition() {
189
  $this->add_default_conditions();
190
+
191
+ if( empty( $this->conditions ) ) {
192
+ return $this->condition_factory->tautology();
193
+ }
194
+
195
  return $this->condition_factory->do_and( $this->conditions );
196
  }
197
 
214
  */
215
  public function get_results() {
216
 
217
+ if( $this->was_used ) {
218
+ _doing_it_wrong(
219
+ __FUNCTION__,
220
+ 'The relationship query object should not be reused. Create a new instance if you need to run another query.',
221
+ TOOLSET_COMMON_VERSION
222
+ );
223
+ }
224
+
225
+ $this->was_used = true;
226
+
227
  $query = $this->build_sql_query();
228
  $rows = toolset_ensarr( $this->wpdb->get_results( $query ) );
229
 
230
+ if( $this->need_found_rows ) {
231
+ $this->found_rows = (int) $this->wpdb->get_var( 'SELECT FOUND_ROWS()' );
232
+ }
233
+
234
  $results = array();
235
  foreach( $rows as $row ) {
236
  $definition = $this->definition_translator->from_database_row( $row );
251
  */
252
  private function build_sql_query() {
253
  $root_condition = $this->build_root_condition();
254
+ return $this->expression_builder->build( $root_condition, $this->need_found_rows );
255
  }
256
 
257
 
269
 
270
 
271
  /**
272
+ * Chain multiple conditions with AND.
273
  *
274
  * The whole statement will evaluate to true if all provided conditions are true.
275
  *
462
  }
463
  }
464
 
465
+
466
+ /**
467
+ * Indicate that the query should also determine the total number of found rows.
468
+ *
469
+ * This has to be set to true if you plan using get_found_rows().
470
+ *
471
+ * @param bool $is_needed
472
+ *
473
+ * @since 2.5.8
474
+ * @return Toolset_Relationship_Query_V2
475
+ */
476
+ public function need_found_rows( $is_needed = true ) {
477
+ $this->need_found_rows = (bool) $is_needed;
478
+ return $this;
479
+ }
480
+
481
+
482
+ /**
483
+ * Return a number of found rows.
484
+ *
485
+ * This can be called only after get_results() if need_found_rows() was set to true
486
+ * while building the query. Otherwise, an exception will be thrown.
487
+ *
488
+ * @return int
489
+ * @throws RuntimeException
490
+ * @since 2.5.8
491
+ */
492
+ public function get_found_rows() {
493
+ if( null === $this->found_rows ) {
494
+ throw new RuntimeException(
495
+ 'Cannot return the number of found rows because the query was not instructed to obtain them.'
496
+ );
497
+ }
498
+
499
+ return (int) $this->found_rows;
500
+ }
501
+
502
  }
vendor/toolset/toolset-common/inc/m2m/{relationship_query → relationship/query}/sql_expression_builder.php RENAMED
@@ -27,12 +27,7 @@ class Toolset_Relationship_Query_Sql_Expression_Builder {
27
  Toolset_Relationship_Database_Operations $database_operations_di = null
28
  ) {
29
  $this->table_name = ( null === $table_name_di ? new Toolset_Relationship_Table_Name() : $table_name_di );
30
-
31
- $this->database_operations = (
32
- null === $database_operations_di
33
- ? new Toolset_Relationship_Database_Operations()
34
- : $database_operations_di
35
- );
36
  }
37
 
38
 
@@ -42,10 +37,11 @@ class Toolset_Relationship_Query_Sql_Expression_Builder {
42
  * Also make sure that the query results will be easily recognizable by Toolset_Relationship_Definition_Translator.
43
  *
44
  * @param IToolset_Relationship_Query_Condition $root_condition
45
- *
46
  * @return string
 
47
  */
48
- public function build( IToolset_Relationship_Query_Condition $root_condition ) {
49
 
50
  $relationship_table = $this->table_name->relationship_table();
51
  $type_set_table = $this->table_name->type_set_table();
@@ -59,8 +55,10 @@ class Toolset_Relationship_Query_Sql_Expression_Builder {
59
  $root_condition->get_join_clause()
60
  ) );
61
  $group_by_clause = $this->database_operations->get_standards_relationship_group_by_clause();
 
62
 
63
- return "SELECT {$select_clause} FROM {$relationship_table} AS relationships {$join_clause}
 
64
  WHERE {$where_clause} GROUP BY {$group_by_clause}";
65
 
66
  }
27
  Toolset_Relationship_Database_Operations $database_operations_di = null
28
  ) {
29
  $this->table_name = ( null === $table_name_di ? new Toolset_Relationship_Table_Name() : $table_name_di );
30
+ $this->database_operations = ( null === $database_operations_di ? new Toolset_Relationship_Database_Operations() : $database_operations_di );
 
 
 
 
 
31
  }
32
 
33
 
37
  * Also make sure that the query results will be easily recognizable by Toolset_Relationship_Definition_Translator.
38
  *
39
  * @param IToolset_Relationship_Query_Condition $root_condition
40
+ * @param bool $need_found_rows
41
  * @return string
42
+ * @since 2.5.8 Can calculate found rows.
43
  */
44
+ public function build( IToolset_Relationship_Query_Condition $root_condition, $need_found_rows ) {
45
 
46
  $relationship_table = $this->table_name->relationship_table();
47
  $type_set_table = $this->table_name->type_set_table();
55
  $root_condition->get_join_clause()
56
  ) );
57
  $group_by_clause = $this->database_operations->get_standards_relationship_group_by_clause();
58
+ $sql_found_rows = ( $need_found_rows ? 'SQL_CALC_FOUND_ROWS' : '' );
59
 
60
+ return "SELECT {$sql_found_rows} {$select_clause}
61
+ FROM {$relationship_table} AS relationships {$join_clause}
62
  WHERE {$where_clause} GROUP BY {$group_by_clause}";
63
 
64
  }
vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/abstract.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/child.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/interface.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/intermediary.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/parent.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/parent_child_interface.php RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{relationship_role → relationship/role}/role.php RENAMED
@@ -68,6 +68,7 @@ abstract class Toolset_Relationship_Role {
68
  return in_array( $role_name, self::all_role_names() );
69
  }
70
 
 
71
  /**
72
  * Throw an exception if a given role name isn't valid.
73
  *
@@ -137,4 +138,67 @@ abstract class Toolset_Relationship_Role {
137
  }
138
 
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
68
  return in_array( $role_name, self::all_role_names() );
69
  }
70
 
71
+
72
  /**
73
  * Throw an exception if a given role name isn't valid.
74
  *
138
  }
139
 
140
 
141
+ /**
142
+ * @param string $role_name
143
+ *
144
+ * @return IToolset_Relationship_Role
145
+ */
146
+ public static function role_from_name( $role_name ) {
147
+ if( $role_name instanceof IToolset_Relationship_Role ) {
148
+ return $role_name;
149
+ }
150
+
151
+ switch( $role_name ) {
152
+ case self::PARENT:
153
+ return new Toolset_Relationship_Role_Parent();
154
+ case self::CHILD:
155
+ return new Toolset_Relationship_Role_Child();
156
+ case self::INTERMEDIARY:
157
+ return new Toolset_Relationship_Role_Intermediary();
158
+ default:
159
+ throw new InvalidArgumentException( 'Invalid element role name.' );
160
+ }
161
+ }
162
+
163
+
164
+ /**
165
+ * @param string $role_name
166
+ *
167
+ * @return IToolset_Relationship_Role_Parent_Child
168
+ * @since 2.5.10
169
+ */
170
+ public static function parent_or_child_from_name( $role_name ) {
171
+ $role = self::role_from_name( $role_name );
172
+
173
+ if( $role instanceof Toolset_Relationship_Role_Intermediary ) {
174
+ throw new InvalidArgumentException( 'Invalid element role name.' );
175
+ }
176
+
177
+ /** @noinspection PhpIncompatibleReturnTypeInspection */
178
+ return $role;
179
+ }
180
+
181
+
182
+ /**
183
+ * @param string|IToolset_Relationship_Role $role_or_name
184
+ *
185
+ * @return string
186
+ */
187
+ public static function name_from_role( $role_or_name ) {
188
+ if( is_string( $role_or_name ) ) {
189
+ if( ! in_array( $role_or_name, self::all_role_names(), true ) ) {
190
+ throw new InvalidArgumentException( 'Invalid element role name.' );
191
+ }
192
+
193
+ return $role_or_name;
194
+ }
195
+
196
+ if( ! $role_or_name instanceof IToolset_Relationship_Role ) {
197
+ throw new InvalidArgumentException();
198
+ }
199
+
200
+ return $role_or_name->get_name();
201
+ }
202
+
203
+
204
  }
vendor/toolset/toolset-common/inc/m2m/{scope.php → relationship/scope.php} RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/{slug_validator.php → relationship/slug_validator.php} RENAMED
File without changes
vendor/toolset/toolset-common/inc/m2m/utils.php CHANGED
@@ -28,4 +28,30 @@ class Toolset_Relationship_Utils {
28
  return null;
29
  }
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
28
  return null;
29
  }
30
 
31
+ /**
32
+ * This method returns all relationships, which includes at least one translated post type
33
+ *
34
+ * @param Toolset_Relationship_Definition_Repository|null $relationship_definition_repository
35
+ *
36
+ * @return IToolset_Relationship_Definition[]
37
+ */
38
+ public static function get_all_translated_relationships( Toolset_Relationship_Definition_Repository $relationship_definition_repository = null ) {
39
+ $relationships = $relationship_definition_repository
40
+ ? $relationship_definition_repository->get_definitions()
41
+ : Toolset_Relationship_Definition_Repository::get_instance()->get_definitions();
42
+
43
+ // collect all relationships which include at least one translatable element
44
+ $relationships_with_translatable_type = array();
45
+
46
+ foreach( $relationships as $relationship ) {
47
+ if( $relationship->get_parent_type()->is_translatable()
48
+ || $relationship->get_child_type()->is_translatable() ) {
49
+ // parent and/or child type is translatable
50
+ $relationships_with_translatable_type[] = $relationship;
51
+ }
52
+ }
53
+
54
+ // return collections
55
+ return $relationships_with_translatable_type;
56
+ }
57
  }
vendor/toolset/toolset-common/inc/m2m/wpml_interoperability.php DELETED
@@ -1,645 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Keeps the associations table up-to-date with post translations.
5
- *
6
- * Encapsulates everything that makes changes in the aforementioned table.
7
- *
8
- * Note that the implementation is quite performance-heavy because the of the extreme importancy of its stability.
9
- * It is open for improvements in the future.
10
- *
11
- * fixme this needs complete review
12
- *
13
- * @since m2m
14
- */
15
- class Toolset_Relationship_WPML_Interoperability {
16
-
17
- private static $instance;
18
-
19
- public static function get_instance() {
20
-
21
- if ( null == self::$instance ) {
22
- self::$instance = new self();
23
- }
24
-
25
- return self::$instance;
26
- }
27
-
28
-
29
- private function __construct() {
30
- }
31
-
32
- private function __clone() {
33
- }
34
-
35
-
36
- const IS_INTEROP_UP_TO_DATE_OPTION = 'toolset_m2m_is_wpml_interop_up_to_date';
37
-
38
-
39
- /**
40
- * Check for the active WPML interoperability support.
41
- *
42
- * That means, as this returns true, we're going to try to support association translations.
43
- *
44
- * @return bool
45
- */
46
- public function is_interop_active() {
47
-
48
- // todo check WPML plugin versions
49
-
50
- //$is_wpml_active = Toolset_Wpml_Utils::is_wpml_active();
51
-
52
- /**
53
- * toolset_is_m2m_wpml_interop_active
54
- *
55
- * Allows to disable m2m-WPML interoperability (updates of the translation table).
56
- *
57
- * @since m2m
58
- */
59
- return (bool) apply_filters( 'toolset_is_m2m_wpml_interop_active', false );
60
- }
61
-
62
-
63
- /**
64
- * Determine whether a full translation view refresh is needed.
65
- *
66
- * If needed, it updates the underlying WordPress option to properly handle WPML deactivation and re-activation.
67
- *
68
- * @param null|bool $new_value If a boolean value is provided, it will be used to overwrite the current state.
69
- *
70
- * @return bool
71
- * @since 2.3
72
- */
73
- public function is_full_refresh_needed( $new_value = null ) {
74
-
75
- if ( null === $new_value ) {
76
- $is_up_to_date = get_option( self::IS_INTEROP_UP_TO_DATE_OPTION, 'no' );
77
- $is_up_to_date = ( 'yes' == $is_up_to_date );
78
-
79
- $is_interop_active = $this->is_interop_active();
80
-
81
- if ( $is_up_to_date && ! $is_interop_active ) {
82
- // We still think that we're up-to-date with WPML but it has been deactivated
83
- // in the meantime.
84
- //
85
- // When (or if) it is re-activated, we are going to require full refresh.
86
- update_option( self::IS_INTEROP_UP_TO_DATE_OPTION, 'no', true );
87
- }
88
-
89
- return ( $is_up_to_date && $is_interop_active );
90
- } else {
91
- update_option( self::IS_INTEROP_UP_TO_DATE_OPTION, ( $new_value ? 'no' : 'yes' ), true );
92
-
93
- return (bool) $new_value;
94
- }
95
- }
96
-
97
-
98
- /**
99
- * An event that should be triggered whenever an association is inserted in the database.
100
- *
101
- * @param Toolset_Association $association
102
- *
103
- * @return Toolset_Result
104
- */
105
- public function after_association_insert( $association ) {
106
-
107
- if ( ! $association instanceof Toolset_Association ) {
108
- // Nothing to do here
109
- return new Toolset_Result( true );
110
- }
111
-
112
- if ( ! $this->is_interop_active() ) {
113
- return new Toolset_Result( true );
114
- }
115
-
116
- $result = $this->refresh_view_for_single_association(
117
- $association->get_id(),
118
- $association->get_definition(),
119
- $association->get_element( Toolset_Relationship_Role::PARENT )->get_id(),
120
- $association->get_element( Toolset_Relationship_Role::CHILD )->get_id(),
121
- $association->get_intermediary_id()
122
- );
123
-
124
- return $result->aggregate();
125
-
126
- }
127
-
128
-
129
- /**
130
- * An event that should be triggered before an association is deleted from the database.
131
- *
132
- * @param Toolset_Association $association
133
- *
134
- * @return Toolset_Result
135
- */
136
- public function before_association_delete( $association ) {
137
-
138
- if ( ! $association instanceof Toolset_Association ) {
139
- // Nothing to do here
140
- return new Toolset_Result( true );
141
- }
142
-
143
- if ( ! $this->is_interop_active() ) {
144
- return new Toolset_Result( true );
145
- }
146
-
147
-
148
- return $this->delete_translation_views_for_single_association( $association->get_id() );
149
-
150
- }
151
-
152
-
153
- /**
154
- * An event that should be triggered when an association is updated in the database (meaning the
155
- * record in the associations table).
156
- *
157
- * @param Toolset_Association $association
158
- *
159
- * @return Toolset_Result
160
- */
161
- public function after_association_update( $association ) {
162
-
163
- if ( ! $association instanceof Toolset_Association ) {
164
- // Nothing to do here
165
- return new Toolset_Result( true );
166
- }
167
-
168
- if ( ! $this->is_interop_active() ) {
169
- return new Toolset_Result( true );
170
- }
171
-
172
- $results = new Toolset_Result_Set();
173
-
174
- // Here we simply reset everything related to an association and then generate it again.
175
- // It could be probably optimized in the future.
176
- $results->add(
177
- $this->before_association_delete( $association )
178
- );
179
-
180
- $results->add(
181
- $this->after_association_insert( $association )
182
- );
183
-
184
- return $results->aggregate();
185
- }
186
-
187
-
188
- /**
189
- * Deletes all translation views related to a single association.
190
- *
191
- * For handling multiple associations at once, delete_translation_views_for_associations() is preferred.
192
- *
193
- * @param int $association_id
194
- *
195
- * @return Toolset_Result
196
- * @since m2m
197
- */
198
- private function delete_translation_views_for_single_association( $association_id ) {
199
-
200
- global $wpdb;
201
-
202
- $result = $wpdb->delete(
203
- Toolset_Relationship_Table_Name::association_translations(),
204
- array( 'association_id' => $association_id ),
205
- array( '%d ' )
206
- );
207
-
208
- return new Toolset_Result( $result !== false );
209
- }
210
-
211
-
212
- /**
213
- * Delete view rows for specific associations.
214
- *
215
- * @param int[] $association_ids
216
- *
217
- * @since m2m
218
- */
219
- private function delete_translation_views_for_associations( $association_ids ) {
220
- global $wpdb;
221
-
222
- $view_tn = Toolset_Relationship_Table_Name::association_translations();
223
- $query = "DELETE FROM `{$view_tn}`
224
- WHERE association_id IN ( " . Toolset_Utils::prepare_mysql_in( $association_ids, '%d' ) . " )";
225
-
226
- $wpdb->query( $query );
227
- }
228
-
229
-
230
- /**
231
- * Refresh the association translation MV for a given association between original posts.
232
- *
233
- * It will scan the icl_translations table for translations of posts (but only where the elements in the associations
234
- * actually are posts) and insert one row in the MV for each of them.
235
- *
236
- * If there are no rows in the icl_translations table for any affected post, which would otherwise result
237
- * in doing nothing, we'll insert the row with the original ID manually with empty language code.
238
- * That way it will still be possible to query the data.
239
- *
240
- * @param int $association_id
241
- * @param string|Toolset_Relationship_Definition $relationship_source
242
- * @param int $original_parent_id
243
- * @param int $original_child_id
244
- * @param int $original_intermediary_id
245
- *
246
- * @return Toolset_Result_Set
247
- * @since m2m
248
- */
249
- private function refresh_view_for_single_association(
250
- $association_id, $relationship_source, $original_parent_id, $original_child_id, $original_intermediary_id
251
- ) {
252
- // Sanitize input
253
- $element_ids = array(
254
- Toolset_Relationship_Role::PARENT => (int) $original_parent_id,
255
- Toolset_Relationship_Role::CHILD => (int) $original_child_id
256
- );
257
-
258
- $relationship_definition = (
259
- $relationship_source instanceof Toolset_Relationship_Definition
260
- ? $relationship_source
261
- : Toolset_Relationship_Definition_Repository::get_instance()->get_definition( $relationship_source )
262
- );
263
-
264
- // Refresh the view for all posts that take part in the association.
265
- $results = new Toolset_Result_Set();
266
- foreach ( Toolset_Relationship_Role::parent_child_role_names() as $element_role ) {
267
- if ( $relationship_definition->is_post( $element_role ) ) {
268
- $result = $this->refresh_view_for_post_in_association(
269
- $element_ids[ $element_role ], $element_role, $relationship_definition->get_slug(), $association_id
270
- );
271
-
272
- $results->add( $result );
273
- }
274
- }
275
-
276
- $result = $this->refresh_view_for_post_in_association(
277
- $original_intermediary_id, Toolset_Relationship_Role::INTERMEDIARY, $relationship_definition->get_slug(), $association_id
278
- );
279
-
280
- $results->add( $result );
281
-
282
- return $results;
283
- }
284
-
285
-
286
- /**
287
- * Refresh the association translation view for one post playing a specific role in one association.
288
- *
289
- * @param int $post_id
290
- * @param string $role One of the Toolset_Relationship_Utils::ROLE_* constants.
291
- * @param string $relationship_slug
292
- * @param int $association_id
293
- *
294
- * @return Toolset_Result_Set|Toolset_Result_Updated
295
- * @since m2m
296
- */
297
- private function refresh_view_for_post_in_association( $post_id, $role, $relationship_slug, $association_id ) {
298
-
299
- if ( 0 == $post_id ) {
300
- return new Toolset_Result_Updated( true, 0 );
301
- }
302
-
303
- $post_translations = Toolset_Wpml_Utils::get_post_translations_directly( $post_id );
304
-
305
- // Handle missing original post row.
306
- if ( ! in_array( $post_id, $post_translations ) ) {
307
- $post_translations[''] = $post_id;
308
- }
309
-
310
- $insert_format = array( '%d', '%s', '%s', '%d', '%s' );
311
- $results = new Toolset_Result_Set();
312
-
313
- global $wpdb;
314
-
315
- // Insert one record per translation.
316
- foreach ( $post_translations as $language_code => $translated_post_id ) {
317
- $data = array(
318
- 'association_id' => $association_id,
319
- 'relationship' => $relationship_slug,
320
- 'language_code' => $language_code,
321
- 'post_id' => $translated_post_id,
322
- 'role' => $role
323
- );
324
-
325
- $result = $wpdb->insert( Toolset_Relationship_Table_Name::association_translations(), $data, $insert_format );
326
-
327
- if ( false === $result ) {
328
- $results->add(
329
- new Toolset_Result(
330
- false,
331
- sprintf( __( 'Unable to insert a row in the %s table.', 'wpcf' ), Toolset_Relationship_Table_Name::association_translations() )
332
- )
333
- );
334
- } else {
335
- $results->add( new Toolset_Result_Updated( true, $result ) );
336
- }
337
- }
338
-
339
- return $results;
340
- }
341
-
342
-
343
- /**
344
- * Hooked into wpml_translation_update, this method refreshes the MV when WPML performs changes
345
- * in the icl_translations table.
346
- *
347
- * Note that if too few information is provided, this might trigger a full refresh of the MV, eventually needing
348
- * user's action on very large sites.
349
- *
350
- * This heavily relies on the fact that a before_delete action is followed by an after_delete one. If WPML
351
- * fails to do that, we get a data inconsistency.
352
- *
353
- * @param array $args Following arguments will be recognized (all of them are optional):
354
- * - string $type: insert|update|before_delete|after_delete|element_type_update|reset|before_language_delete,
355
- * default is 'update'
356
- * - int $trid
357
- * - int $element_id
358
- * - string $element_type
359
- * - int $translation_id
360
- * - string $context: post|tax|...
361
- * - int $rows_affected
362
- * - string $language: Language code for the before_language_delete event.
363
- *
364
- * @since m2m
365
- */
366
- public function on_wpml_translation_update( $args ) {
367
-
368
- return; // this is totally obsolete now
369
- // Not checking is_interop_active() here, since this came from WPML.
370
-
371
- $event_type = toolset_getarr( $args, 'type', 'update' );
372
- switch ( $event_type ) {
373
-
374
- case 'before_language_delete':
375
- $this->handle_wpml_language_delete( toolset_getarr( $args, 'language' ) );
376
- break;
377
-
378
- case 'reset':
379
- case 'element_type_update':
380
- $this->handle_big_wpml_change();
381
- break;
382
-
383
- case 'after_delete':
384
- $this->after_wpml_translations_deleted();
385
- break;
386
-
387
- default:
388
- $this->handle_wpml_change_event( $event_type, $args );
389
- break;
390
- }
391
- }
392
-
393
-
394
- /**
395
- * Handle the rare but possible situation when a whole language is deleted.
396
- *
397
- * We will simply delete everything with the given language_code from the MV.
398
- *
399
- * @param string $language_code
400
- *
401
- * @since m2m
402
- */
403
- private function handle_wpml_language_delete( $language_code ) {
404
-
405
- global $wpdb;
406
-
407
- $wpdb->delete(
408
- Toolset_Relationship_Table_Name::association_translations(),
409
- array( 'language_code' => $language_code ),
410
- array( '%s' )
411
- );
412
- }
413
-
414
-
415
- private function handle_big_wpml_change() {
416
- // todo
417
- }
418
-
419
-
420
- /**
421
- * @var int[] Association IDs whose view rows have been deleted between before_delete and after_delete WPML events.
422
- * @since m2m
423
- */
424
- private $associations_without_views = array();
425
-
426
-
427
- /**
428
- * Handle a WPML event that changes icl_translations rows.
429
- *
430
- * Specifically, this works for: insert, update, before_delete.
431
- *
432
- * @param $event_type
433
- * @param $args
434
- *
435
- * @since m2m
436
- */
437
- private function handle_wpml_change_event( $event_type, $args ) {
438
-
439
- $affected_posts = $this->query_posts_affected_by_wpml_event( $args );
440
-
441
- if ( ! is_array( $affected_posts ) ) {
442
- switch ( $affected_posts ) {
443
- case self::CHANGE_TRIGGERS_FULL_REFRESH:
444
- $this->handle_big_wpml_change();
445
-
446
- return;
447
- case self::CHANGE_IRRELEVANT:
448
- // Nothing to do here.
449
- default:
450
- return;
451
- }
452
- }
453
-
454
- $affected_associations = $this->query_affected_associations( $affected_posts );
455
-
456
- if ( empty( $affected_associations ) ) {
457
- return;
458
- }
459
-
460
- $this->delete_translation_views_for_associations( $affected_associations );
461
-
462
- if ( 'before_delete' == $event_type ) {
463
- // We won't refresh anything just yet, instead we store the IDs of associations whose views we have just
464
- // erased, and wait until WPML invokes the after_delete action. Then, we'll do the refresh.
465
- $this->associations_without_views = array_merge( $this->associations_without_views, $affected_associations );
466
- } else {
467
- // Insert or update.
468
- $this->refresh_views_for_associations( $affected_associations );
469
- }
470
- }
471
-
472
-
473
- /**
474
- * Refresh the view after some WPML translations have been deleted.
475
- *
476
- * This happens during an after_delete event. In before_delete, we have deleted the view rows for possibly
477
- * affected associations and stored association IDs. Now, we will take those IDs and refresh the view for
478
- * those associations.
479
- *
480
- * This couldn't have been done sooner because a refresh before the icl_translations rows are actually deleted
481
- * would accomplish nothing.
482
- *
483
- * @since m2m
484
- */
485
- private function after_wpml_translations_deleted() {
486
- $this->refresh_views_for_associations( $this->associations_without_views );
487
- $this->associations_without_views = array();
488
- }
489
-
490
-
491
- // Return values for query_posts_affected_by_wpml_event().
492
- const CHANGE_IRRELEVANT = 'irrelevant';
493
-
494
- const CHANGE_TRIGGERS_FULL_REFRESH = 'full_refresh';
495
-
496
-
497
- /**
498
- * From arguments provided by WPML, try to understand what happened and which specific posts (and their
499
- * translations) might be affected.
500
- *
501
- * Note: This can be further optimized, for example by filtering out post types that don't participate in
502
- * any relationships (when element_type is provided/will be queried), etc.
503
- *
504
- * @param array $args
505
- *
506
- * @return string|int[] An array of post IDs that are affected by the update, CHANGE_IRRELEVANT if no posts
507
- * have been affected or CHANGE_TRIGGERS_FULL_REFRESH if the change is too big or unspecific to decide.
508
- * @since m2m
509
- */
510
- private function query_posts_affected_by_wpml_event( $args ) {
511
-
512
- if ( ! $this->could_be_wpml_post_translation_change( $args ) ) {
513
- return self::CHANGE_IRRELEVANT;
514
- }
515
-
516
- $trid = $this->get_trid_affected_by_wpml_event( $args );
517
-
518
- if ( 0 == $trid ) {
519
- return self::CHANGE_TRIGGERS_FULL_REFRESH;
520
- }
521
-
522
- return Toolset_Wpml_Utils::query_elements_by_trid( $trid );
523
- }
524
-
525
-
526
- /**
527
- * From arguments provided by WPML, get trid of everything that might be affected.
528
- *
529
- * See query_posts_affected_by_wpml_event() for details.
530
- *
531
- * @param array $args
532
- *
533
- * @return int trid or zero if it can't be determined.
534
- */
535
- private function get_trid_affected_by_wpml_event( $args ) {
536
- $trid = (int) toolset_getarr( $args, 'trid', 0 );
537
-
538
- // Less expensive query first.
539
- if ( 0 == $trid ) {
540
- $translation_id = (int) toolset_getarr( $args, 'translation_id', 0 );
541
- $trid = Toolset_Wpml_Utils::get_trid_from_translation_id( $translation_id );
542
- }
543
-
544
- if ( 0 == $trid ) {
545
- $element_id = (int) toolset_getarr( $args, 'element_id', 0 );
546
- $element_type = toolset_getarr( $args, 'element_type', 'post%' );
547
- $trid = Toolset_Wpml_Utils::get_trid_from_element_id( $element_id, $element_type );
548
- }
549
-
550
- return $trid;
551
- }
552
-
553
-
554
- /**
555
- * From arguments provided by WPML, decide if the event *could* affect post translations.
556
- *
557
- * @param array $args
558
- *
559
- * @return bool
560
- * @since m2m
561
- */
562
- private function could_be_wpml_post_translation_change( $args ) {
563
-
564
- $context = toolset_getarr( $args, 'context' );
565
- $element_type = toolset_getarr( $args, 'element_type' );
566
- $has_element_type = ( ! empty( $element_type ) );
567
-
568
- // Theoretically, we still might have the element_type even if no context was given.
569
- if ( empty( $context ) && $has_element_type ) {
570
- $context = explode( '_', $element_type );
571
- $context = $context[0];
572
- }
573
-
574
- $has_context = ( ! empty( $context ) );
575
-
576
- if ( $has_context && 'post' != $context ) {
577
- return false;
578
- } else {
579
- return true;
580
- }
581
- }
582
-
583
-
584
- /**
585
- * Query associations (through the view table) where given posts have a role.
586
- *
587
- * todo move this to the associations query
588
- *
589
- * @param int[] $post_ids
590
- *
591
- * @return int[] Association IDs
592
- * @since m2m
593
- */
594
- private function query_affected_associations( $post_ids ) {
595
- global $wpdb;
596
-
597
- $view_tn = Toolset_Relationship_Table_Name::association_translations();
598
-
599
- $query = "
600
- SELECT DISTINCT association_id
601
- FROM `{$view_tn}`
602
- WHERE post_id IN (" . Toolset_Utils::prepare_mysql_in( $post_ids, '%d' ) . ")";
603
-
604
- $association_ids = $wpdb->get_col( $query );
605
-
606
- return $association_ids;
607
- }
608
-
609
-
610
- /**
611
- * Refresh views for a set of association IDs.
612
- *
613
- * Gets all the association info in one query and then performs per-association refreshes.
614
- *
615
- * @param $association_ids
616
- *
617
- * @since m2m
618
- */
619
- private function refresh_views_for_associations( $association_ids ) {
620
-
621
- if ( empty( $association_ids ) ) {
622
- return;
623
- }
624
-
625
- global $wpdb;
626
-
627
- $associations_tn = Toolset_Relationship_Table_Name::associations();
628
- $query = "
629
- SELECT *
630
- FROM `{$associations_tn}`
631
- WHERE id IN (" . Toolset_Utils::prepare_mysql_in( $association_ids, '%d' ) . ")";
632
-
633
- $associations = $wpdb->get_results( $query );
634
-
635
- foreach ( $associations as $association ) {
636
- $this->refresh_view_for_single_association(
637
- $association->id,
638
- $association->relationship,
639
- $association->parent_id,
640
- $association->child_id,
641
- $association->intermediary_id
642
- );
643
- }
644
- }
645
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/toolset/toolset-common/inc/public_api/legacy_relationships.php ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Public-facing legacy post relationship API.
4
+ *
5
+ * Note: This file is included only when m2m is *not* active, so there's no point in checking that anymore.
6
+ */
7
+
8
+ /**
9
+ * Query related post if many-to-many relationship functionality is NOT enabled.
10
+ *
11
+ * @param int|\WP_Post $query_by_element Post to query by. All results will be posts connected to this one.
12
+ * @param string[] $relationship Array containing parent post type and child post type.
13
+ * @param string $query_by_role_name Name of the element role to query by. Accepted values: 'parent'|'child'
14
+ * @param int $limit Maximum number of returned results ("posts per page").
15
+ * @param int $offset Result offset ("page number")
16
+ * @param array $args Additional query arguments. Accepted arguments:
17
+ * - meta_key, meta_value and meta_compare: Works exactly like in WP_Query. Only limited values are supported for meta_compare ('='|'LIKE').
18
+ * - s: Text search in the posts.
19
+ * @param string $return Determines return type. 'post_id' for array of post IDs, 'post_object' for an array of \WP_Post objects.
20
+ * @param string $role_name_to_return Which posts from the relationship should be returned. Accepted values
21
+ * are 'parent'|'child', but the value must be different from $query_by_role_name.
22
+ * If $query_by_role_name is 'parent' or 'child', it is also possible to pass 'other' here.
23
+ * @param null|string $orderby Determine how the results will be ordered. Accepted values: null, 'title', 'meta_value',
24
+ * 'meta_value_num'. If the latter two are used, there also needs to be a 'meta_key' argument in $args.
25
+ * Passing null means no ordering.
26
+ * @param string $order Accepted values: 'ASC' or 'DESC'.
27
+ * @param bool $need_found_rows Signal if the query should also determine the total number of results (disregarding pagination).
28
+ * @param null|&int $found_rows If $need_found_rows is set to true, the total number of results will be set
29
+ * into the variable passed to this parameter.
30
+ *
31
+ * @return int[]|\WP_Post[]
32
+ * @throws InvalidArgumentException In case of error.
33
+ */
34
+ function toolset_get_related_posts(
35
+ $query_by_element,
36
+ $relationship,
37
+ $query_by_role_name,
38
+ $limit = 100,
39
+ $offset = 0,
40
+ $args = array(),
41
+ $return = 'post_id',
42
+ $role_name_to_return = 'other',
43
+ $orderby = null,
44
+ $order = 'ASC',
45
+ $need_found_rows = false,
46
+ &$found_rows = null
47
+ ) {
48
+ // Input validation
49
+ //
50
+ //
51
+ if( ! is_array( $relationship ) || count( $relationship ) !== 2 ) {
52
+ throw new InvalidArgumentException( 'The relationship must be an array containing parent post type and child post type.' );
53
+ }
54
+ if ( ! get_post_type_object( $relationship[0] ) || ! get_post_type_object( $relationship[1] ) ) {
55
+ throw new InvalidArgumentException( 'Invalid relationship post type, please make sure they are valid post types.' );
56
+ }
57
+ if ( ! in_array( $query_by_role_name, array( 'parent', 'child', 'intermediary' ) ) ) {
58
+ throw new InvalidArgumentException( 'The role name to query by is not valid. Allowed values are: "parent", "child"' );
59
+ }
60
+ if( ! Toolset_Utils::is_natural_numeric( $query_by_element ) && ! $query_by_element instanceof WP_Post ) {
61
+ throw new InvalidArgumentException( 'The provided argument for a related element must be either an ID or a WP_Post object.' );
62
+ }
63
+ if(
64
+ ! in_array( $role_name_to_return, array( 'parent', 'child', 'intermediary' ) )
65
+ && ( 'other' !== $role_name_to_return || 'intermediary' === $query_by_role_name )
66
+ ) {
67
+ throw new InvalidArgumentException(
68
+ 'The role name to return is not valid. Allowed values are: "parent", "child" or "other" if $query_by_role_name is parent or child.'
69
+ );
70
+ }
71
+
72
+ if( ! \Toolset_Utils::is_natural_numeric( $limit ) || ! \Toolset_Utils::is_nonnegative_numeric( $offset ) ) {
73
+ throw new InvalidArgumentException( 'Limit and offset must be non-negative integers.' );
74
+ }
75
+
76
+ if( ! in_array( $return , array( 'post_id', 'post_object' ) ) ) {
77
+ throw new InvalidArgumentException( 'The provided argument for a return type must be either "post_id" or "post_object".' );
78
+ }
79
+
80
+ if( 'meta_key' === $orderby && ! array_key_exists( 'meta_key', $args ) ) {
81
+ throw new InvalidArgumentException( 'Cannot use ordering by a meta_key if no meta_key argument is provided.' );
82
+ }
83
+
84
+ if( ! in_array( $order, array( 'ASC', 'DESC' ) ) ) {
85
+ throw new InvalidArgumentException( 'Allowed order values are only ASC and DESC.' );
86
+ }
87
+
88
+ $legacy_relationships = toolset_ensarr( get_option( 'wpcf_post_relationship', array() ) );
89
+
90
+ if(
91
+ ! array_key_exists( $relationship[0], $legacy_relationships )
92
+ || ! is_array( $legacy_relationships[ $relationship[0] ] )
93
+ || ! array_key_exists( $relationship[1], $legacy_relationships[ $relationship[0] ] )
94
+ || ! is_array( $legacy_relationships[ $relationship[0] ][ $relationship[1] ] )
95
+ ) {
96
+ return array();
97
+ }
98
+
99
+ // For now legacy relationships migration doesn't allow intermediary types and many-to-many, so this is droped from the code
100
+ /*
101
+ // Checks if it queries by intermediary post type and it is really an intermediary post type.
102
+ if ( 'intermediary' == $query_by_element ) {
103
+ // Number of ocurrences.
104
+ $ocurrences = array();
105
+ foreach ( $legacy_relationships as $_post_type => $_children ) {
106
+ if ( $query_by_element === $_post_type ) {
107
+ throw new InvalidArgumentException( 'Wrong intermediary post type, it should only be used as a child.' );
108
+ }
109
+ foreach ( array_keys( $_children) as $_child ) {
110
+ if ( ! isset( $ocurrences[ $_child ] ) ) {
111
+ $ocurrences[ $_child ] = 0;
112
+ }
113
+ $ocurrences[ $_child ]++;
114
+ }
115
+ }
116
+ if ( 2 !== $ocurrences[ $query_by_element ] ) {
117
+ throw new InvalidArgumentException( 'Wrong intermediary post type, it should be connected only to two post types.' );
118
+ }
119
+ }
120
+ */
121
+
122
+ // Order by
123
+ $order_by = '';
124
+ if ( $orderby ) {
125
+ switch ( $orderby ) {
126
+ case 'title':
127
+ $order_by = " ORDER BY posts.post_title {$order} ";
128
+ break;
129
+ case 'meta_value':
130
+ $order_by = " ORDER BY mt.meta_value {$order} ";
131
+ break;
132
+ case 'meta_value_num':
133
+ $order_by = " ORDER BY CAST(mt.meta_value AS SIGNED) {$order} ";
134
+ break;
135
+ }
136
+ }
137
+
138
+ // $is_many_to_many = isset( $legacy_relationships[ $relationship[0] ] )
139
+ // && isset( $legacy_relationships[ $relationship[1] ] )
140
+ // && ! empty ( array_intersect_key( $legacy_relationships[ $relationship[0] ], $legacy_relationships[ $relationship[1] ] ) );
141
+
142
+ global $wpdb;
143
+
144
+ $where = array( '1=1');
145
+ $joins = array();
146
+ $from = " FROM {$wpdb->posts} posts ";
147
+
148
+ $query_by_post_id = $query_by_element instanceof WP_Post
149
+ ? $query_by_element->ID
150
+ : $query_by_element;
151
+
152
+ if ( 'other' === $role_name_to_return ) {
153
+ $post_type = 'parent' === $query_by_role_name
154
+ ? $relationship[1]
155
+ : $relationship[0];
156
+ } else {
157
+ $post_type = 'parent' === $role_name_to_return
158
+ ? $relationship[0]
159
+ : $relationship[1];
160
+ }
161
+
162
+ // Joins. get_posts can't be used because some times wp_postmeta.post_id is needed and in other cases meta_value,
163
+ // or joining to wp_postmeta records is required.
164
+
165
+ // If querying by intermediary, it always return its parent.
166
+ // For now legacy relationships migration doesn't allow intermediary types and many-to-many, so this is droped from the code
167
+ /*
168
+ if ( 'intermediary' === $query_by_role_name ) {
169
+ $joins[] = $wpdb->prepare( "JOIN {$wpdb->postmeta} belongs ON
170
+ belongs.meta_key = %s AND
171
+ belongs.post_id = %d AND
172
+ belongs.meta_value = posts.ID", "_wpcf_belongs_{$post_type}_id", $query_by_post_id );
173
+ } else {
174
+ if ( $is_many_to_many ) {
175
+ $other_post_type = $relationship[0] === $post_type
176
+ ? $relationship[1]
177
+ : $relationship[0];
178
+ $joins[] = $wpdb->prepare( "JOIN wp_postmeta belongs_intermediary ON
179
+ belongs_intermediary.meta_key = %s AND
180
+ belongs_intermediary.meta_value = %d
181
+ JOIN wp_postmeta belongs_parent ON
182
+ belongs_parent.meta_key = %s AND
183
+ belongs_parent.post_id = belongs_intermediary.post_id AND
184
+ belongs_parent.meta_value = posts.ID", "_wpcf_belongs_{$other_post_type}_id", $query_by_post_id, "_wpcf_belongs_{$post_type}_id" );
185
+ } else {
186
+ */
187
+ $actual_role_name = $query_by_role_name;
188
+ if ( 'other' !== $query_by_role_name ) {
189
+ $actual_role_name = $relationship[0] === $post_type
190
+ ? 'child'
191
+ : 'parent';
192
+ }
193
+ if ( 'parent' === $actual_role_name ) {
194
+ $joins[] = $wpdb->prepare( "JOIN {$wpdb->postmeta} belongs ON
195
+ belongs.meta_key = %s AND
196
+ belongs.meta_value = %d AND
197
+ belongs.post_id = posts.ID", "_wpcf_belongs_{$relationship[0]}_id", $query_by_post_id );
198
+ } else if ( 'child' === $actual_role_name ) {
199
+ $joins[] = $wpdb->prepare( "JOIN {$wpdb->postmeta} belongs ON
200
+ belongs.meta_key = %s AND
201
+ belongs.post_id = %d AND
202
+ belongs.meta_value = posts.ID", "_wpcf_belongs_{$relationship[0]}_id", $query_by_post_id );
203
+ }
204
+ /* Eventually dropped
205
+ }
206
+ }
207
+ */
208
+
209
+ // Args (meta_key, meta_value and meta_compare) or searching
210
+ if ( ! empty( $args['meta_key'] ) && ! empty( $args['meta_value'] ) ) {
211
+ $meta_query_args = array(
212
+ array(
213
+ 'key' => $args['meta_key'],
214
+ 'value' => $args['meta_value'],
215
+ 'compare' => $args['meta_compare'] ? $args['meta_compare'] : '=',
216
+ ),
217
+ );
218
+ $meta_query = new WP_Meta_Query( $meta_query_args );
219
+ $mq_sql = $meta_query->get_sql(
220
+ 'post',
221
+ 'posts',
222
+ 'ID'
223
+ );
224
+ if ( isset( $mq_sql['join'] ) ) {
225
+ $joins[] = str_replace(
226
+ array( $wpdb->postmeta . '.', $wpdb->postmeta ),
227
+ array( 'mt.', $wpdb->postmeta . ' mt' ),
228
+ $mq_sql['join']
229
+ );
230
+ }
231
+ if ( isset( $mq_sql['where'] ) ) {
232
+ $where[] = str_replace( $wpdb->postmeta . '.', 'mt.', $mq_sql['where'] );
233
+ }
234
+ }
235
+
236
+ // Search
237
+ if ( ! empty( $args['s'] ) ) {
238
+ $like = '%' . $args['s'] . '%';
239
+ $where[] = $wpdb->prepare( " AND ( posts.post_content like %s OR posts.post_title like %s ) ", $like, $like );
240
+ }
241
+
242
+ $joins = implode( "\n", $joins );
243
+ $where = implode( "\n", $where );
244
+ $query_fields = 'posts.ID';
245
+ $found_rows = $need_found_rows ? ' SQL_CALC_FOUND_ROWS ' : '';
246
+
247
+ $sql = "SELECT {$found_rows} {$query_fields} {$from}
248
+ {$joins}
249
+ WHERE {$where}
250
+ {$order_by}
251
+ LIMIT {$offset}, {$limit}";
252
+
253
+ $posts = $wpdb->get_results( $sql );
254
+
255
+ if ( $need_found_rows ) {
256
+ $found_rows = $wpdb->num_rows;
257
+ }
258
+
259
+ $result = array();
260
+ foreach ( $posts as $post ) {
261
+ $result[] = 'post_id' === $return
262
+ ? (int) $post->ID
263
+ : get_post( $post->ID );
264
+ }
265
+
266
+ return $result;
267
+ }
268
+
269
+
270
+ /**
271
+ * Retrieve an ID of a single related post.
272
+ *
273
+ * Note: For more complex cases, use toolset_get_related_posts().
274
+ *
275
+ * @param WP_Post|int $post Post whose related post should be returned.
276
+ * @param string|string[] $relationship Slug of the relationship to query by or an array with the parent and the child post type.
277
+ * The array variant can be used only to identify relationships that have been migrated from the legacy implementation.
278
+ * @param string $role_name_to_return Which posts from the relationship should be returned. Accepted values
279
+ * are 'parent' and 'child'. The relationship needs to have only one possible result in this role,
280
+ * otherwise an exception will be thrown.
281
+ *
282
+ * @return int Post ID or zero if no related post was found.
283
+ */
284
+ function toolset_get_related_post( $post, $relationship, $role_name_to_return = 'parent' ) {
285
+ // Input validation
286
+ //
287
+ //
288
+ if( ! Toolset_Utils::is_natural_numeric( $post ) && ! $post instanceof WP_Post ) {
289
+ throw new InvalidArgumentException( 'The provided argument for a related element must be either an ID or a WP_Post object.' );
290
+ }
291
+ if( ! is_array( $relationship ) || count( $relationship ) !== 2 ) {
292
+ throw new InvalidArgumentException( 'The relationship must be an array containing parent post type and child post type.' );
293
+ }
294
+ if ( ! get_post_type_object( $relationship[0] ) || ! get_post_type_object( $relationship[1] ) ) {
295
+ throw new InvalidArgumentException( 'Invalid relationship post type, please make sure they are valid post types.' );
296
+ }
297
+ if( ! in_array( $role_name_to_return, array( 'parent', 'child' ) ) ) {
298
+ throw new InvalidArgumentException( 'The role name to return is not valid. Allowed values are: "parent", "child".' );
299
+ }
300
+ $query_by_role_name = 'parent' === $role_name_to_return
301
+ ? 'child'
302
+ : 'parent';
303
+ $result = toolset_get_related_posts(
304
+ $post,
305
+ $relationship,
306
+ $query_by_role_name,
307
+ 1,
308
+ 0,
309
+ array(),
310
+ 'post_id',
311
+ $role_name_to_return
312
+ );
313
+ return isset ( $result[0] ) ? $result[0] : 0;
314
+ }
315
+
316
+
317
+ /**
318
+ * Retrieve an ID of the parent post, using a legacy post relationship (migrated from the legacy implementation).
319
+ *
320
+ * For this to work, there needs to be a relationship between $target_type and the provided post's type.
321
+ *
322
+ * Note: For more complex cases, use toolset_get_related_post() or toolset_get_related_posts().
323
+ *
324
+ * @param WP_Post|int $post Post whose parent should be returned.
325
+ * @param string $target_type Parent post type.
326
+ *
327
+ * @return int Post ID or zero if no related post was found.
328
+ */
329
+ function toolset_get_parent_post_by_type( $post, $target_type ) {
330
+
331
+ $post = get_post( $post );
332
+
333
+ if( ! $post instanceof WP_Post ) {
334
+ return 0;
335
+ }
336
+
337
+ return toolset_get_related_post( $post, array( $target_type, $post->post_type ) );
338
+ }
vendor/toolset/toolset-common/inc/public_api/loader.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // the non-m2m part still needs to support PHP 5.2 for the time being.
4
+ //namespace OTGS\Toolset\Common\PublicAPI;
5
+
6
+ /**
7
+ * Loads the public-facing API of Toolset Common.
8
+ *
9
+ * @since 2.6.1
10
+ */
11
+ class Toolset_Public_API_Loader {
12
+
13
+
14
+ public function initialize() {
15
+
16
+ // Note: This could be used for a more generic solution.
17
+ //$files = glob( '*.php' );
18
+ //
19
+ //if( ! is_array( $files ) ) {
20
+ // // Error when enumerating files, can't do anything about it at this point.
21
+ // return;
22
+ //}
23
+ //
24
+ //foreach( $files as $file ) {
25
+ // require_once $file;
26
+ //}
27
+
28
+ if( apply_filters( 'toolset_is_m2m_enabled', false ) ) {
29
+ require_once TOOLSET_COMMON_PATH . '/inc/public_api/m2m.php';
30
+ } else {
31
+ require_once TOOLSET_COMMON_PATH . '/inc/public_api/legacy_relationships.php';
32
+ }
33
+ }
34
+
35
+ }
vendor/toolset/toolset-common/inc/public_api/m2m.php ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Public-facing m2m API.
5
+ *
6
+ * Note: This file is included only when m2m is active, so there's no point in checking that anymore.
7
+ */
8
+
9
+ /**
10
+ * Query related post if many-to-many relationship functionality is enabled.
11
+ *
12
+ * @param int|\WP_Post $query_by_element Post to query by. All results will be posts connected to this one.
13
+ * @param string|string[] $relationship Slug of the relationship to query by or an array with the parent and the child post type.
14
+ * The array variant can be used only to identify relationships that have been migrated from the legacy implementation.
15
+ * @param string $query_by_role_name Name of the element role to query by. Accepted values: 'parent'|'child'|'intermediary'
16
+ * @param int $limit Maximum number of returned results ("posts per page").
17
+ * @param int $offset Result offset ("page number")
18
+ * @param array $args Additional query arguments. Accepted arguments:
19
+ * - meta_key, meta_value and meta_compare: Works exactly like in WP_Query. Only limited values are supported for meta_compare ('='|'LIKE').
20
+ * - s: Text search in the posts.
21
+ * @param string $return Determines return type. 'post_id' for array of post IDs, 'post_object' for an array of \WP_Post objects.
22
+ * @param string $role_name_to_return Which posts from the relationship should be returned. Accepted values
23
+ * are 'parent'|'child'|'intermediary', but the value must be different from $query_by_role_name.
24
+ * If $query_by_role_name is 'parent' or 'child', it is also possible to pass 'other' here.
25
+ * @param null|string $orderby Determine how the results will be ordered. Accepted values: null, 'title', 'meta_value',
26
+ * 'meta_value_num'. If the latter two are used, there also needs to be a 'meta_key' argument in $args.
27
+ * Passing null means no ordering.
28
+ * @param string $order Accepted values: 'ASC' or 'DESC'.
29
+ * @param bool $need_found_rows Signal if the query should also determine the total number of results (disregarding pagination).
30
+ * @param null|&int $found_rows If $need_found_rows is set to true, the total number of results will be set
31
+ * into the variable passed to this parameter.
32
+ *
33
+ * @return int[]|\WP_Post[]
34
+ */
35
+ function toolset_get_related_posts(
36
+ $query_by_element,
37
+ $relationship,
38
+ $query_by_role_name,
39
+ $limit = 100,
40
+ $offset = 0,
41
+ $args = array(),
42
+ $return = 'post_id',
43
+ $role_name_to_return = 'other',
44
+ $orderby = null,
45
+ $order = 'ASC',
46
+ $need_found_rows = false,
47
+ &$found_rows = null
48
+ ) {
49
+ do_action( 'toolset_do_m2m_full_init' );
50
+
51
+ // Input validation
52
+ //
53
+ //
54
+ if( ! is_string( $relationship ) && ! ( is_array( $relationship ) && count( $relationship ) === 2 ) ) {
55
+ throw new \InvalidArgumentException( 'The relationship must be a string with the relationship slug or an array with two post types.' );
56
+ }
57
+
58
+ if( ! in_array( $query_by_role_name, \Toolset_Relationship_Role::all_role_names() ) ) {
59
+ throw new \InvalidArgumentException( 'The role name to query by is not valid. Allowed values are: "' . implode( '", "', \Toolset_Relationship_Role::all_role_names() ) . '".' );
60
+ }
61
+
62
+ if(
63
+ ! in_array( $role_name_to_return, \Toolset_Relationship_Role::all_role_names() )
64
+ && ( 'other' !== $role_name_to_return || \Toolset_Relationship_Role::INTERMEDIARY === $query_by_role_name )
65
+ ) {
66
+ throw new \InvalidArgumentException(
67
+ 'The role name to return is not valid. Allowed values are: "' .
68
+ implode( '", "', \Toolset_Relationship_Role::all_role_names() ) .
69
+ '" or "other" if $query_by_role_name is parent or child.'
70
+ );
71
+ }
72
+
73
+ if( ! \Toolset_Utils::is_natural_numeric( $query_by_element ) && ! $query_by_element instanceof \WP_Post ) {
74
+ throw new \InvalidArgumentException( 'The provided argument for a related element must be either an ID or a WP_Post object.' );
75
+ }
76
+
77
+ if( ! \Toolset_Utils::is_natural_numeric( $limit ) || ! \Toolset_Utils::is_nonnegative_numeric( $offset ) ) {
78
+ throw new \InvalidArgumentException( 'Limit and offset must be non-negative integers.' );
79
+ }
80
+
81
+ if( ! in_array( $return , array( 'post_id', 'post_object' ) ) ) {
82
+ throw new \InvalidArgumentException( 'The provided argument for a return type must be either "post_id" or "post_object".' );
83
+ }
84
+
85
+ if( 'meta_key' === $orderby && ! array_key_exists( 'meta_key', $args ) ) {
86
+ throw new \InvalidArgumentException( 'Cannot use ordering by a meta_key if no meta_key argument is provided.' );
87
+ }
88
+
89
+ if( ! in_array( strtoupper( $order ), array( 'ASC', 'DESC' ) ) ) {
90
+ throw new \InvalidArgumentException( 'Allowed order values are only ASC and DESC.' );
91
+ }
92
+
93
+ // Input post-processing
94
+ //
95
+ //
96
+ $element_id = (int) ( $query_by_element instanceof \WP_Post ? $query_by_element->ID : $query_by_element );
97
+ $limit = (int) $limit;
98
+ $offset = (int) $offset;
99
+ $query_by_role = \Toolset_Relationship_Role::role_from_name( $query_by_role_name );
100
+ $need_found_rows = (bool) $need_found_rows;
101
+ $search = toolset_getarr( $args, 's' );
102
+ $has_meta_condition = ( array_key_exists( 'meta_key', $args ) && array_key_exists( 'meta_value', $args ) );
103
+
104
+ if( 'other' === $role_name_to_return ) {
105
+ // This will happen only if the $query_by_role not intermediary.
106
+ /** @var \IToolset_Relationship_Role_Parent_Child $query_by_role */
107
+ $role_to_return = $query_by_role->other();
108
+ } else {
109
+ $role_to_return = \Toolset_Relationship_Role::role_from_name( $role_name_to_return );
110
+ }
111
+
112
+ if( is_array( $relationship ) ) {
113
+ $definition_repository = Toolset_Relationship_Definition_Repository::get_instance();
114
+ $relationship_definition = $definition_repository->get_legacy_definition( $relationship[0], $relationship[1] );
115
+ if( null === $relationship_definition ) {
116
+ //throw new \InvalidArgumentException( 'There is no relationship between the two provided post types (no migrated one from the legacy implementation).' );
117
+ return array();
118
+ }
119
+ $relationship = $relationship_definition->get_slug();
120
+ }
121
+
122
+ // Build the query
123
+ //
124
+ //
125
+ try {
126
+ $query = new \Toolset_Association_Query_V2();
127
+
128
+ $query->add( $query->relationship_slug( $relationship ) )
129
+ ->add( $query->element_id_and_domain( $element_id, \Toolset_Element_Domain::POSTS, $query_by_role ) )
130
+ ->limit( $limit )
131
+ ->offset( $offset )
132
+ ->order( $order )
133
+ ->need_found_rows( $need_found_rows );
134
+
135
+ if ( ! empty( $search ) ) {
136
+ $query->add( $query->search( $search, $role_to_return ) );
137
+ }
138
+
139
+ if ( $has_meta_condition ) {
140
+ $query->add(
141
+ $query->meta(
142
+ toolset_getarr( $args, 'meta_key' ),
143
+ toolset_getarr( $args, 'meta_value' ),
144
+ \Toolset_Element_Domain::POSTS,
145
+ $role_to_return,
146
+ toolset_getarr( $args, 'meta_compare', \Toolset_Query_Comparison_Operator::EQUALS )
147
+ )
148
+ );
149
+ }
150
+
151
+ if ( 'post_id' === $return ) {
152
+ $query->return_element_ids( $role_to_return );
153
+ } else {
154
+ $query->return_element_instances( $role_to_return );
155
+ }
156
+
157
+ switch ( $orderby ) {
158
+ case 'title':
159
+ $query->order_by_title( $role_to_return );
160
+ break;
161
+ case 'meta_value':
162
+ $query->order_by_meta( toolset_getarr( $args, 'meta_key' ), \Toolset_Element_Domain::POSTS, $role_to_return );
163
+ break;
164
+ case 'meta_value_num':
165
+ $query->order_by_meta( toolset_getarr( $args, 'meta_key' ), \Toolset_Element_Domain::POSTS, $role_to_return, true );
166
+ break;
167
+ default:
168
+ $query->dont_order();
169
+ break;
170
+ }
171
+
172
+ // Get results and post-process them
173
+ //
174
+ //
175
+ $results = $query->get_results();
176
+
177
+ if ( $need_found_rows ) {
178
+ $found_rows = $query->get_found_rows();
179
+ }
180
+
181
+ if ( 'post_id' === $return ) {
182
+ return $results;
183
+ } else {
184
+ $results = array_map(
185
+ function ( $result ) {
186
+ /** @var \IToolset_Post $result */
187
+ return $result->get_underlying_object();
188
+ }, $results
189
+ );
190
+
191
+ return $results;
192
+ }
193
+ } catch ( Exception $e ) {
194
+ // This is most probably caused by an element not existing, an exception raised from the depth of
195
+ // the association query - otherwise, there are no reasons for it to fail, all the inputs should be valid.
196
+ return array();
197
+ }
198
+ }
199
+
200
+
201
+ /**
202
+ * Retrieve an ID of a single related post.
203
+ *
204
+ * Note: For more complex cases, use toolset_get_related_posts().
205
+ *
206
+ * @param WP_Post|int $post Post whose related post should be returned.
207
+ * @param string|string[] $relationship Slug of the relationship to query by or an array with the parent and the child post type.
208
+ * The array variant can be used only to identify relationships that have been migrated from the legacy implementation.
209
+ * @param string $role_name_to_return Which posts from the relationship should be returned. Accepted values
210
+ * are 'parent' and 'child'. The relationship needs to have only one possible result in this role,
211
+ * otherwise an exception will be thrown.
212
+ *
213
+ * @return int Post ID or zero if no related post was found.
214
+ */
215
+ function toolset_get_related_post( $post, $relationship, $role_name_to_return = 'parent' ) {
216
+
217
+ do_action( 'toolset_do_m2m_full_init' );
218
+
219
+ // Input validation and pre-processing
220
+ //
221
+ //
222
+ if( ! is_string( $relationship ) && ! ( is_array( $relationship ) && count( $relationship ) === 2 ) ) {
223
+ throw new \InvalidArgumentException( 'The relationship must be a string with the relationship slug or an array with two post types.' );
224
+ }
225
+
226
+ $post = get_post( $post );
227
+
228
+ if( ! $post instanceof WP_Post ) {
229
+ return 0;
230
+ }
231
+
232
+ $definition_repository = Toolset_Relationship_Definition_Repository::get_instance();
233
+
234
+ if( is_array( $relationship ) ) {
235
+ $relationship_definition = $definition_repository->get_legacy_definition( $relationship[0], $relationship[1] );
236
+ } else {
237
+ $relationship_definition = $definition_repository->get_definition( $relationship );
238
+ }
239
+
240
+ if( null === $relationship_definition ) {
241
+ return 0;
242
+ }
243
+
244
+ if( $relationship_definition->get_cardinality()->get_limit( $role_name_to_return ) > Toolset_Relationship_Cardinality::ONE_ELEMENT ) {
245
+ return 0;
246
+ }
247
+
248
+ if( ! in_array( $role_name_to_return, \Toolset_Relationship_Role::parent_child_role_names() ) ) {
249
+ throw new \InvalidArgumentException(
250
+ 'The role name to return is not valid. Allowed values are: "' .
251
+ implode( '", "', \Toolset_Relationship_Role::parent_child_role_names() ) .
252
+ '".'
253
+ );
254
+ }
255
+
256
+ /** @var IToolset_Relationship_Role_Parent_Child $role_to_return */
257
+ $role_to_return = \Toolset_Relationship_Role::role_from_name( $role_name_to_return );
258
+
259
+ // Query the single result
260
+ //
261
+ //
262
+
263
+ try {
264
+ $query = new Toolset_Association_Query_V2();
265
+
266
+ $results = $query->add( $query->relationship( $relationship_definition ) )
267
+ ->add( $query->element_id_and_domain( $post->ID, Toolset_Element_Domain::POSTS, $role_to_return->other() ) )
268
+ ->limit( 1 )
269
+ ->return_element_ids( $role_to_return )
270
+ ->get_results();
271
+
272
+ } catch ( Exception $e ) {
273
+ // This is most probably caused by an element not existing, an exception raised from the depth of
274
+ // the association query - otherwise, there are no reasons for it to fail, all the inputs should be valid.
275
+ return 0;
276
+ }
277
+
278
+ if( empty( $results ) ) {
279
+ return 0; // No result.
280
+ }
281
+
282
+ $result = (int) array_pop( $results );
283
+
284
+ return $result;
285
+ }
286
+
287
+
288
+ /**
289
+ * Retrieve an ID of the parent post, using a legacy post relationship (migrated from the legacy implementation).
290
+ *
291
+ * For this to work, there needs to be a relationship between $target_type and the provided post's type.
292
+ *
293
+ * Note: For more complex cases, use toolset_get_related_post() or toolset_get_related_posts().
294
+ *
295
+ * @param WP_Post|int $post Post whose parent should be returned.
296
+ * @param string $target_type Parent post type.
297
+ *
298
+ * @return int Post ID or zero if no related post was found.
299
+ */
300
+ function toolset_get_parent_post_by_type( $post, $target_type ) {
301
+
302
+ $post = get_post( $post );
303
+
304
+ if( ! $post instanceof WP_Post ) {
305
+ return 0;
306
+ }
307
+
308
+ return toolset_get_related_post( $post, array( $target_type, $post->post_type ) );
309
+ }
vendor/toolset/toolset-common/inc/toolset.ajax.class.php CHANGED
@@ -36,59 +36,129 @@
36
  * @since m2m
37
  */
38
  class Toolset_Ajax {
39
-
 
40
  /** Prefix for the callback method name */
41
  const CALLBACK_PREFIX = 'callback_';
42
-
 
43
  const DELIMITER = '_';
44
 
 
 
 
 
45
  /**
46
  * @return Toolset_Ajax|false
47
  */
48
- final public static function get_instance() {
49
- static $instances = array();
50
- $called_class = get_called_class();
51
-
52
- if ( isset( $instances[ $called_class ] ) ) {
53
- return $instances[ $called_class ];
54
- } else {
55
- if ( class_exists( $called_class ) ) {
56
- $instances[ $called_class ] = new $called_class();
57
-
58
- return $instances[ $called_class ];
59
- } else {
60
- // This can unfortunately happen when the get_called_class() workaround for PHP 5.2 misbehaves.
61
- return false;
62
- }
63
  }
 
 
64
  }
65
 
66
 
67
  public static function initialize() {
68
- $instance = self::get_instance();
 
 
69
 
70
  $instance->register_callbacks();
71
  $instance->additional_ajax_init();
72
  }
73
 
74
 
75
- private function __clone() { }
76
 
 
77
 
78
- private function __construct() { }
79
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
- const CALLBACK_MIGRATE_TO_M2M = 'migrate_to_m2m';
82
-
83
 
84
  protected function get_callback_names() {
85
  return array(
86
- self::CALLBACK_MIGRATE_TO_M2M
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  );
88
  }
89
 
90
 
91
- private $callbacks_registered = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
 
94
  /**
@@ -101,34 +171,32 @@ class Toolset_Ajax {
101
  */
102
  private function register_callbacks() {
103
 
104
- if( $this->callbacks_registered ) {
105
  return;
106
  }
107
 
108
  $callback_names = $this->get_callback_names();
109
- foreach( $callback_names as $callback_name ) {
110
- $action_name = 'wp_ajax_' . $this->get_plugin_slug() . self::DELIMITER . $callback_name;
111
- add_action(
112
- $action_name,
113
- array( $this, self::CALLBACK_PREFIX . $callback_name )
114
- );
115
- }
116
 
117
  $this->callbacks_registered = true;
118
 
119
  }
120
-
121
-
122
  protected function get_plugin_slug( $capitalized = false ) {
123
  return ( $capitalized ? 'Toolset' : 'toolset' );
124
  }
125
-
126
-
127
  protected function get_handler_class_prefix() {
128
- return $this->get_plugin_slug( true ) . '_Ajax_Handler_';
129
  }
130
 
131
-
132
  public function get_action_js_name( $action ) {
133
  return $this->get_plugin_slug( false ) . self::DELIMITER . $action;
134
  }
@@ -139,12 +207,13 @@ class Toolset_Ajax {
139
  *
140
  * @param string $name Method name.
141
  * @param array $parameters Method parameters.
 
142
  * @since 2.1
143
  */
144
  public function __call( $name, $parameters ) {
145
  // Check for the callback prefix in the method name
146
  $name_parts = explode( self::DELIMITER, $name );
147
- if( 0 !== strcmp( $name_parts[0] . self::DELIMITER, self::CALLBACK_PREFIX ) ) {
148
  // Not a callback, resign.
149
  return;
150
  }
@@ -160,7 +229,7 @@ class Toolset_Ajax {
160
  try {
161
  /** @var Toolset_Ajax_Handler_Interface $handler */
162
  $handler = new $class_name( $this );
163
- } catch( Exception $e ) {
164
  // The handler class could not have been instantiated, resign.
165
  return;
166
  }
@@ -170,7 +239,6 @@ class Toolset_Ajax {
170
  }
171
 
172
 
173
-
174
  /**
175
  * Perform basic authentication check.
176
  *
@@ -178,14 +246,17 @@ class Toolset_Ajax {
178
  * is not successful.
179
  *
180
  * @param array $args Arguments (
181
- * @type string $nonce Name of the nonce that should be verified. Mandatory
182
- * @type string $nonce_parameter Name of the parameter containing nonce value.
 
183
  * Optional, defaults to "wpnonce".
184
- * @type string $parameter_source Determines where the function should look for the nonce parameter.
185
  * Allowed values are 'get' and 'post'. Optional, defaults to 'post'.
186
- * @type string $capability_needed Capability that user has to have in order to pass the check.
187
  * Optional, default is "manage_options".
188
- * @type string $type_of_death How to indicate failure:
 
 
189
  * - 'die': Call wp_json_error with array( 'type' => 'capability'|'nonce', 'message' => $error_message )
190
  * - 'return': Do not die, just return the error array as above.
191
  * Optional, default is 'die'.
@@ -201,6 +272,7 @@ class Toolset_Ajax {
201
  $nonce_name = toolset_getarr( $args, 'nonce' );
202
  $nonce_parameter = toolset_getarr( $args, 'nonce_parameter', 'wpnonce' );
203
  $capability_needed = toolset_getarr( $args, 'capability_needed', 'manage_options' );
 
204
  $parameter_source_name = toolset_getarr( $args, 'parameter_source', 'post', array( 'get', 'post' ) );
205
  $parameter_source = ( $parameter_source_name == 'get' ) ? $_GET : $_POST;
206
 
@@ -209,22 +281,22 @@ class Toolset_Ajax {
209
  $error_type = null;
210
 
211
  // Check permissions
212
- if ( ! current_user_can( $capability_needed ) ) {
213
  $error_message = __( 'You do not have permissions for that.', 'wpv-views' );
214
  $error_type = 'capability';
215
  $is_error = true;
216
  }
217
 
218
  // Check nonce
219
- if ( !$is_error && !wp_verify_nonce( toolset_getarr( $parameter_source, $nonce_parameter, '' ), $nonce_name ) ) {
220
  $error_message = __( 'Your security credentials have expired. Please reload the page to get new ones.', 'wpv-views' );
221
  $error_type = 'nonce';
222
  $is_error = true;
223
  }
224
 
225
- if( $is_error ) {
226
  $error_description = array( 'type' => $error_type, 'message' => $error_message );
227
- switch( $type_of_death ) {
228
 
229
  case 'die':
230
  wp_send_json_error( $error_description );
@@ -246,6 +318,7 @@ class Toolset_Ajax {
246
  * To be extended in the future.
247
  *
248
  * @param array $args See ajax_authenticate for details
 
249
  * @return mixed
250
  * @since 2.0
251
  */
@@ -263,10 +336,11 @@ class Toolset_Ajax {
263
  *
264
  * @param array $response Custom response data
265
  * @param bool $is_success
 
266
  * @since 2.0
267
  */
268
  public function ajax_finish( $response, $is_success = true ) {
269
- if( $is_success ) {
270
  wp_send_json_success( $response );
271
  } else {
272
  wp_send_json_error( $response );
@@ -282,6 +356,7 @@ class Toolset_Ajax {
282
  *
283
  * @since m2m
284
  */
285
- protected function additional_ajax_init() { }
286
-
 
287
  }
36
  * @since m2m
37
  */
38
  class Toolset_Ajax {
39
+
40
+
41
  /** Prefix for the callback method name */
42
  const CALLBACK_PREFIX = 'callback_';
43
+
44
+
45
  const DELIMITER = '_';
46
 
47
+
48
+ private static $instance;
49
+
50
+
51
  /**
52
  * @return Toolset_Ajax|false
53
  */
54
+ public static function get_instance() {
55
+ if ( null === self::$instance ) {
56
+ self::$instance = new self();
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
58
+
59
+ return self::$instance;
60
  }
61
 
62
 
63
  public static function initialize() {
64
+ $called_class = get_called_class();
65
+ /** @var Toolset_Ajax $instance */
66
+ $instance = call_user_func( array( $called_class, 'get_instance' ) );
67
 
68
  $instance->register_callbacks();
69
  $instance->additional_ajax_init();
70
  }
71
 
72
 
73
+ const CALLBACK_MIGRATE_TO_M2M = 'migrate_to_m2m';
74
 
75
+ const CALLBACK_SELECT2_SUGGEST_POSTS_BY_TITLE = 'select2_suggest_posts_by_title';
76
 
77
+ const CALLBACK_SELECT2_SUGGEST_TERMS = 'select2_suggest_terms';
78
 
79
+ const CALLBACK_SELECT2_SUGGEST_USERS = 'select2_suggest_users';
80
+
81
+ const CALLBACK_GET_POST_BY_ID = 'get_post_by_id';
82
+
83
+ const CALLBACK_GET_TERM_BY_ID = 'get_term_by_id';
84
+
85
+ const CALLBACK_GET_USER_BY_ID = 'get_user_by_id';
86
+
87
+ const CALLBACK_GET_VIEW_BLOCK_PREVIEW = 'get_view_block_preview';
88
+ const CALLBACK_GET_CONTENT_TEMPLATE_BLOCK_PREVIEW = 'get_content_template_block_preview';
89
+
90
+ const CALLBACK_INTERMEDIARY_POST_CLEANUP = 'intermediary_post_cleanup';
91
 
 
 
92
 
93
  protected function get_callback_names() {
94
  return array(
95
+ self::CALLBACK_MIGRATE_TO_M2M,
96
+ self::CALLBACK_INTERMEDIARY_POST_CLEANUP,
97
+ self::CALLBACK_GET_VIEW_BLOCK_PREVIEW,
98
+ self::CALLBACK_GET_CONTENT_TEMPLATE_BLOCK_PREVIEW,
99
+ );
100
+ }
101
+
102
+
103
+ protected function get_public_callback_names() {
104
+ return array(
105
+ self::CALLBACK_SELECT2_SUGGEST_POSTS_BY_TITLE,
106
+ self::CALLBACK_SELECT2_SUGGEST_TERMS,
107
+ self::CALLBACK_SELECT2_SUGGEST_USERS,
108
+ self::CALLBACK_GET_POST_BY_ID,
109
+ self::CALLBACK_GET_TERM_BY_ID,
110
+ self::CALLBACK_GET_USER_BY_ID,
111
  );
112
  }
113
 
114
 
115
+ protected $callbacks_registered = false;
116
+
117
+
118
+ /**
119
+ * Register privileged callbacks.
120
+ *
121
+ * Each callback is registered as a "{$plugin_slug}_{$callback}" action and needs to have a "callback_{$callback_name}"
122
+ * method in this class.
123
+ *
124
+ * Valid for AJAX callbacks executed by logged in users.
125
+ *
126
+ * @since m2m
127
+ *
128
+ * @param string[] $callback_names
129
+ */
130
+ private function register_priv_callbacks( $callback_names ) {
131
+ foreach ( $callback_names as $callback_name ) {
132
+ $action_name = 'wp_ajax_' . $this->get_plugin_slug() . self::DELIMITER . $callback_name;
133
+ add_action(
134
+ $action_name,
135
+ array( $this, self::CALLBACK_PREFIX . $callback_name )
136
+ );
137
+ }
138
+ }
139
+
140
+
141
+ /**
142
+ * Register unprivileged callbacks.
143
+ *
144
+ * Each callback is registered as a "{$plugin_slug}_{$callback}" action and needs to have a "callback_{$callback_name}"
145
+ * method in this class.
146
+ *
147
+ * Valid for AJAX callbacks executed by not logged in users.
148
+ *
149
+ * @since m2m
150
+ *
151
+ * @param string[] $callback_names
152
+ */
153
+ private function register_nopriv_callbacks( $callback_names ) {
154
+ foreach ( $callback_names as $callback_name ) {
155
+ $action_name = 'wp_ajax_nopriv_' . $this->get_plugin_slug() . self::DELIMITER . $callback_name;
156
+ add_action(
157
+ $action_name,
158
+ array( $this, self::CALLBACK_PREFIX . $callback_name )
159
+ );
160
+ }
161
+ }
162
 
163
 
164
  /**
171
  */
172
  private function register_callbacks() {
173
 
174
+ if ( $this->callbacks_registered ) {
175
  return;
176
  }
177
 
178
  $callback_names = $this->get_callback_names();
179
+ $this->register_priv_callbacks( $callback_names );
180
+
181
+ $public_callback_names = $this->get_public_callback_names();
182
+ $this->register_priv_callbacks( $public_callback_names );
183
+ $this->register_nopriv_callbacks( $public_callback_names );
 
 
184
 
185
  $this->callbacks_registered = true;
186
 
187
  }
188
+
189
+
190
  protected function get_plugin_slug( $capitalized = false ) {
191
  return ( $capitalized ? 'Toolset' : 'toolset' );
192
  }
193
+
194
+
195
  protected function get_handler_class_prefix() {
196
+ return $this->get_plugin_slug( true ) . '_Ajax_Handler_';
197
  }
198
 
199
+
200
  public function get_action_js_name( $action ) {
201
  return $this->get_plugin_slug( false ) . self::DELIMITER . $action;
202
  }
207
  *
208
  * @param string $name Method name.
209
  * @param array $parameters Method parameters.
210
+ *
211
  * @since 2.1
212
  */
213
  public function __call( $name, $parameters ) {
214
  // Check for the callback prefix in the method name
215
  $name_parts = explode( self::DELIMITER, $name );
216
+ if ( 0 !== strcmp( $name_parts[0] . self::DELIMITER, self::CALLBACK_PREFIX ) ) {
217
  // Not a callback, resign.
218
  return;
219
  }
229
  try {
230
  /** @var Toolset_Ajax_Handler_Interface $handler */
231
  $handler = new $class_name( $this );
232
+ } catch ( Exception $e ) {
233
  // The handler class could not have been instantiated, resign.
234
  return;
235
  }
239
  }
240
 
241
 
 
242
  /**
243
  * Perform basic authentication check.
244
  *
246
  * is not successful.
247
  *
248
  * @param array $args Arguments (
249
+ *
250
+ * @type string $nonce Name of the nonce that should be verified. Mandatory
251
+ * @type string $nonce_parameter Name of the parameter containing nonce value.
252
  * Optional, defaults to "wpnonce".
253
+ * @type string $parameter_source Determines where the function should look for the nonce parameter.
254
  * Allowed values are 'get' and 'post'. Optional, defaults to 'post'.
255
+ * @type string $capability_needed Capability that user has to have in order to pass the check.
256
  * Optional, default is "manage_options".
257
+ * @type bool $is_public Whether the action is publicly available without capability checks.
258
+ * Optional, default is FALSE.
259
+ * @type string $type_of_death How to indicate failure:
260
  * - 'die': Call wp_json_error with array( 'type' => 'capability'|'nonce', 'message' => $error_message )
261
  * - 'return': Do not die, just return the error array as above.
262
  * Optional, default is 'die'.
272
  $nonce_name = toolset_getarr( $args, 'nonce' );
273
  $nonce_parameter = toolset_getarr( $args, 'nonce_parameter', 'wpnonce' );
274
  $capability_needed = toolset_getarr( $args, 'capability_needed', 'manage_options' );
275
+ $is_public = toolset_getarr( $args, 'is_public', false );
276
  $parameter_source_name = toolset_getarr( $args, 'parameter_source', 'post', array( 'get', 'post' ) );
277
  $parameter_source = ( $parameter_source_name == 'get' ) ? $_GET : $_POST;
278
 
281
  $error_type = null;
282
 
283
  // Check permissions
284
+ if ( ! $is_public && ! current_user_can( $capability_needed ) ) {
285
  $error_message = __( 'You do not have permissions for that.', 'wpv-views' );
286
  $error_type = 'capability';
287
  $is_error = true;
288
  }
289
 
290
  // Check nonce
291
+ if ( ! $is_error && ! wp_verify_nonce( toolset_getarr( $parameter_source, $nonce_parameter, '' ), $nonce_name ) ) {
292
  $error_message = __( 'Your security credentials have expired. Please reload the page to get new ones.', 'wpv-views' );
293
  $error_type = 'nonce';
294
  $is_error = true;
295
  }
296
 
297
+ if ( $is_error ) {
298
  $error_description = array( 'type' => $error_type, 'message' => $error_message );
299
+ switch ( $type_of_death ) {
300
 
301
  case 'die':
302
  wp_send_json_error( $error_description );
318
  * To be extended in the future.
319
  *
320
  * @param array $args See ajax_authenticate for details
321
+ *
322
  * @return mixed
323
  * @since 2.0
324
  */
336
  *
337
  * @param array $response Custom response data
338
  * @param bool $is_success
339
+ *
340
  * @since 2.0
341
  */
342
  public function ajax_finish( $response, $is_success = true ) {
343
+ if ( $is_success ) {
344
  wp_send_json_success( $response );
345
  } else {
346
  wp_send_json_error( $response );
356
  *
357
  * @since m2m
358
  */
359
+ protected function additional_ajax_init() {
360
+ }
361
+
362
  }
vendor/toolset/toolset-common/inc/toolset.assets.manager.class.php CHANGED
@@ -134,7 +134,7 @@ class Toolset_Script {
134
  class Toolset_Assets_Manager {
135
 
136
 
137
- protected static $instance;
138
 
139
 
140
  protected $styles = array();
@@ -172,6 +172,8 @@ class Toolset_Assets_Manager {
172
 
173
  const SCRIPT_ICL_EDITOR = 'icl_editor-script';
174
  const SCRIPT_ICL_MEDIA_MANAGER = 'icl_media-manager-js';
 
 
175
 
176
  const SCRIPT_KNOCKOUT = 'knockout';
177
  const SCRIPT_KNOCKOUT_MAPPING = 'knockout-mapping';
@@ -193,6 +195,10 @@ class Toolset_Assets_Manager {
193
  const SCRIPT_CHOSEN = 'toolset-chosen';
194
  const SCRIPT_CHOSEN_WRAPPER = 'toolset-chosen-wrapper';
195
 
 
 
 
 
196
  /**
197
  * For compatibility with ACF Plugin that's not using the right handle for this module (wp-event-manager)
198
  * we are using ACF handle to prevent unwanted overrides of window.wp.hooks namespace (******!)
@@ -205,6 +211,8 @@ class Toolset_Assets_Manager {
205
  //
206
  //
207
 
 
 
208
  const STYLE_CODEMIRROR = 'toolset-meta-html-codemirror-css';
209
  const STYLE_CODEMIRROR_CSS_HINT = 'toolset-meta-html-codemirror-css-hint-css';
210
 
@@ -305,8 +313,17 @@ class Toolset_Assets_Manager {
305
  }
306
 
307
 
 
 
 
 
 
308
  public static function get_instance() {
309
- return self::getInstance();
 
 
 
 
310
  }
311
 
312
 
@@ -390,6 +407,13 @@ class Toolset_Assets_Manager {
390
  "5.5.0"
391
  );
392
 
 
 
 
 
 
 
 
393
  $this->register_style(
394
  self::STYLE_COLORBOX,
395
  $this->assets_url . '/res/lib/colorbox/colorbox.css',
@@ -549,6 +573,14 @@ class Toolset_Assets_Manager {
549
  true
550
  );
551
 
 
 
 
 
 
 
 
 
552
  $this->register_script(
553
  self::SCRIPT_CHOSEN,
554
  $this->assets_url . "/res/lib/chosen/chosen.jquery.js",
@@ -706,6 +738,13 @@ class Toolset_Assets_Manager {
706
  array( self::SCRIPT_ICL_EDITOR ),
707
  TOOLSET_COMMON_VERSION
708
  );
 
 
 
 
 
 
 
709
 
710
  $this->register_script(
711
  self::SCRIPT_JSCROLLPANE,
@@ -909,6 +948,15 @@ class Toolset_Assets_Manager {
909
  }
910
 
911
 
 
 
 
 
 
 
 
 
 
912
  public function register_script( $handle, $path = '', $deps = array(), $ver = false, $in_footer = false ) {
913
  if ( ! isset( $this->scripts[ $handle ] ) ) {
914
  $this->scripts[ $handle ] = new Toolset_Script( $handle, $path, $deps, $ver, $in_footer );
134
  class Toolset_Assets_Manager {
135
 
136
 
137
+ private static $instance;
138
 
139
 
140
  protected $styles = array();
172
 
173
  const SCRIPT_ICL_EDITOR = 'icl_editor-script';
174
  const SCRIPT_ICL_MEDIA_MANAGER = 'icl_media-manager-js';
175
+
176
+ const SCRIPT_TOOLSET_MEDIA_MANAGER = 'toolset-media-manager-js';
177
 
178
  const SCRIPT_KNOCKOUT = 'knockout';
179
  const SCRIPT_KNOCKOUT_MAPPING = 'knockout-mapping';
195
  const SCRIPT_CHOSEN = 'toolset-chosen';
196
  const SCRIPT_CHOSEN_WRAPPER = 'toolset-chosen-wrapper';
197
 
198
+ // parsley lib for field validation
199
+ const SCRIPT_PARSLEY = 'toolset-parsley';
200
+
201
+
202
  /**
203
  * For compatibility with ACF Plugin that's not using the right handle for this module (wp-event-manager)
204
  * we are using ACF handle to prevent unwanted overrides of window.wp.hooks namespace (******!)
211
  //
212
  //
213
 
214
+ const STYLE_PARSLEY = 'toolset-parsley-style';
215
+
216
  const STYLE_CODEMIRROR = 'toolset-meta-html-codemirror-css';
217
  const STYLE_CODEMIRROR_CSS_HINT = 'toolset-meta-html-codemirror-css-hint-css';
218
 
313
  }
314
 
315
 
316
+ /**
317
+ * Note: This *can not* be directly used in subclasses.
318
+ *
319
+ * @return Toolset_Assets_Manager
320
+ */
321
  public static function get_instance() {
322
+ if( null === self::$instance ) {
323
+ self::$instance = new self();
324
+ }
325
+
326
+ return self::$instance;
327
  }
328
 
329
 
407
  "5.5.0"
408
  );
409
 
410
+ $this->register_style(
411
+ self::STYLE_PARSLEY,
412
+ $this->assets_url . '/res/lib/parsley/parsley.css',
413
+ array(),
414
+ '2.8.0'
415
+ );
416
+
417
  $this->register_style(
418
  self::STYLE_COLORBOX,
419
  $this->assets_url . '/res/lib/colorbox/colorbox.css',
573
  true
574
  );
575
 
576
+ $this->register_script(
577
+ self::SCRIPT_PARSLEY,
578
+ $this->assets_url . '/res/lib/parsley/parsley.js',
579
+ array('jquery'),
580
+ '2.8.0',
581
+ true
582
+ );
583
+
584
  $this->register_script(
585
  self::SCRIPT_CHOSEN,
586
  $this->assets_url . "/res/lib/chosen/chosen.jquery.js",
738
  array( self::SCRIPT_ICL_EDITOR ),
739
  TOOLSET_COMMON_VERSION
740
  );
741
+
742
+ $this->register_script(
743
+ self::SCRIPT_TOOLSET_MEDIA_MANAGER,
744
+ $this->assets_url . "/res/js/toolset-media-manager.js",
745
+ array( self::SCRIPT_ICL_EDITOR, self::SCRIPT_TOOLSET_EVENT_MANAGER ),
746
+ TOOLSET_COMMON_VERSION
747
+ );
748
 
749
  $this->register_script(
750
  self::SCRIPT_JSCROLLPANE,
948
  }
949
 
950
 
951
+ public function add_script( Toolset_Script $script ) {
952
+ if( isset( $this->scripts[ $script->handle ] ) ) {
953
+ return;
954
+ }
955
+
956
+ $this->scripts[ $script->handle ] = $script;
957
+ }
958
+
959
+
960
  public function register_script( $handle, $path = '', $deps = array(), $ver = false, $in_footer = false ) {
961
  if ( ! isset( $this->scripts[ $handle ] ) ) {
962
  $this->scripts[ $handle ] = new Toolset_Script( $handle, $path, $deps, $ver, $in_footer );
vendor/toolset/toolset-common/inc/toolset.css.component.class.php CHANGED
@@ -305,7 +305,8 @@ if ( ! class_exists( 'Toolset_CssComponent' ) ) {
305
  'dd_layouts_edit',
306
  'views-editor',
307
  'ct-editor',
308
- 'view-archives-editor'
 
309
  );
310
 
311
 
305
  'dd_layouts_edit',
306
  'views-editor',
307
  'ct-editor',
308
+ 'view-archives-editor',
309
+ 'cred_association_form'
310
  );
311
 
312
 
vendor/toolset/toolset-common/inc/toolset.menu.class.php CHANGED
@@ -22,6 +22,9 @@ if ( ! class_exists( 'Toolset_Menu', false ) ) {
22
  */
23
  class Toolset_Menu {
24
 
 
 
 
25
  public $toolset_pages;
26
 
27
  public function __construct() {
@@ -32,7 +35,6 @@ if ( ! class_exists( 'Toolset_Menu', false ) ) {
32
  add_action( 'admin_init', array( &$this, 'admin_init' ), 1 );
33
  add_action( 'admin_menu', array( &$this, 'admin_menu' ) );
34
  add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueue_scripts' ) );
35
-
36
  add_filter( 'toolset_filter_register_menu_pages', array( &$this, 'register_debug_page_in_menu' ), 100 );
37
  }
38
 
@@ -96,7 +98,6 @@ if ( ! class_exists( 'Toolset_Menu', false ) ) {
96
  $this->add_submenu_page( $page, $top_level_page );
97
  }
98
  }
99
-
100
  }
101
  }
102
 
@@ -238,10 +239,10 @@ if ( ! class_exists( 'Toolset_Menu', false ) ) {
238
  public function register_debug_page_in_menu( $pages ) {
239
  if (
240
  isset( $_GET['page'] )
241
- && $_GET['page'] == 'toolset-debug-information'
242
  ) {
243
  $pages[] = array(
244
- 'slug' => 'toolset-debug-information',
245
  'menu_title' => __( 'Toolset Debug', 'wpv-views' ),
246
  'page_title' => __( 'Toolset Debug', 'wpv-views' ),
247
  'callback' => array( $this, 'debug_page' )
@@ -256,10 +257,9 @@ if ( ! class_exists( 'Toolset_Menu', false ) ) {
256
  return $pages;
257
  }
258
 
259
- public function debug_page() {
260
 
 
261
  $page = Toolset_Page_Troubleshooting::get_instance();
262
-
263
  $page->render();
264
  }
265
 
22
  */
23
  class Toolset_Menu {
24
 
25
+
26
+ const TROUBLESHOOTING_PAGE_SLUG = 'toolset-debug-information';
27
+
28
  public $toolset_pages;
29
 
30
  public function __construct() {
35
  add_action( 'admin_init', array( &$this, 'admin_init' ), 1 );
36
  add_action( 'admin_menu', array( &$this, 'admin_menu' ) );
37
  add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueue_scripts' ) );
 
38
  add_filter( 'toolset_filter_register_menu_pages', array( &$this, 'register_debug_page_in_menu' ), 100 );
39
  }
40
 
98
  $this->add_submenu_page( $page, $top_level_page );
99
  }
100
  }
 
101
  }
102
  }
103
 
239
  public function register_debug_page_in_menu( $pages ) {
240
  if (
241
  isset( $_GET['page'] )
242
+ && $_GET['page'] === self::TROUBLESHOOTING_PAGE_SLUG
243
  ) {
244
  $pages[] = array(
245
+ 'slug' => self::TROUBLESHOOTING_PAGE_SLUG,
246
  'menu_title' => __( 'Toolset Debug', 'wpv-views' ),
247
  'page_title' => __( 'Toolset Debug', 'wpv-views' ),
248
  'callback' => array( $this, 'debug_page' )
257
  return $pages;
258
  }
259
 
 
260
 
261
+ public function debug_page() {
262
  $page = Toolset_Page_Troubleshooting::get_instance();
 
263
  $page->render();
264
  }
265
 
vendor/toolset/toolset-common/inc/toolset.shortcode.generator.class.php CHANGED
@@ -43,11 +43,6 @@ abstract class Toolset_Shortcode_Generator {
43
 
44
  add_action( 'toolset_action_require_shortcodes_templates', array( $this, 'print_shortcodes_templates' ) );
45
 
46
- add_action( 'wp_ajax_toolset_select2_suggest_posts_by_title', array( $this, 'toolset_select2_suggest_posts_by_title' ) );
47
- add_action( 'wp_ajax_nopriv_toolset_select2_suggest_posts_by_title', array( $this, 'toolset_select2_suggest_posts_by_title' ) );
48
- add_action( 'wp_ajax_toolset_select2_suggest_users', array( $this, 'toolset_select2_suggest_users' ) );
49
- add_action( 'wp_ajax_nopriv_toolset_select2_suggest_users', array( $this, 'toolset_select2_suggest_users' ) );
50
-
51
  add_filter( 'toolset_filter_shortcode_script_i18n', array( $this, 'extend_script_i18n' ) );
52
  }
53
 
@@ -307,7 +302,7 @@ abstract class Toolset_Shortcode_Generator {
307
  #>
308
  <ul class="toolset-shortcode-gui-dialog-item-group js-toolset-shortcode-gui-dialog-item-group">
309
  <# _.each( data.fields, function( fieldData, fieldAttribute ) { #>
310
- <li style="width:<# print( columnsWidth ); #>%;float:left;">
311
  <#
312
  fieldData = _.defaults( fieldData, { shortcode: data.shortcode, templates: data.templates } );
313
  fieldData = _.defaults( fieldData, { defaultValue: '', required: false, hidden: false, placeholder: '' } );
@@ -323,6 +318,11 @@ abstract class Toolset_Shortcode_Generator {
323
  <# } #>
324
  </div>
325
  </script>
 
 
 
 
 
326
  <script type="text/html" id="tmpl-toolset-shortcode-attribute-text">
327
  <input id="{{{data.shortcode}}}-{{{data.attribute}}}" data-type="text" class="js-shortcode-gui-field large-text<# if ( data.required ) { #> js-toolset-shortcode-gui-required<# } #>" value="{{{data.defaultForceValue}}}" placeholder="{{{data.placeholder}}}" type="text">
328
  </script>
@@ -333,13 +333,13 @@ abstract class Toolset_Shortcode_Generator {
333
  <label>
334
  <input name="{{{data.shortcode}}}-{{{data.attribute}}}" value="{{{optionKey}}}" class="js-shortcode-gui-field" type="radio"<# if ( optionKey == data.defaultForceValue ) { #> checked="checked"<# } #>>
335
  {{{optionLabel}}}
336
- </lanel>
337
  </li>
338
  <# }); #>
339
  </ul>
340
  </script>
341
  <script type="text/html" id="tmpl-toolset-shortcode-attribute-select">
342
- <select id="{{{data.shortcode}}}-{{{data.attribute}}}" class="js-shortcode-gui-field">
343
  <# _.each( data.options, function( optionLabel, optionKey ) { #>
344
  <option value="{{{optionKey}}}"<# if ( optionKey == data.defaultForceValue ) { #> selected="selected"<# } #>>
345
  {{{optionLabel}}}
@@ -375,20 +375,19 @@ abstract class Toolset_Shortcode_Generator {
375
 
376
  <script type="text/html" id="tmpl-toolset-shortcode-content">
377
  <#
378
- data = _.defaults( data, { defaultValue: '', required: false, hidden: false, placeholder: '' } );
379
- data = _.defaults( data, { defaultForceValue: data.defaultValue } );
380
  #>
381
  <div class="toolset-shortcode-gui-attribute-wrapper js-toolset-shortcode-gui-content-wrapper" <# if ( data.hidden ) { #> style="display:none"<# } #>>
382
- <# if ( _.has( data, 'label' ) ) { #>
383
- <h3>{{{data.label}}}</h3>
384
- <# } #>
385
- <textarea id="toolset-shortcode-gui-content-{{{data.shortcode}}}" type="text" class="large-text js-toolset-shortcode-gui-content"><# {{{data.defaultValue}}} #></textarea>
386
  <# if ( _.has( data, 'description' ) ) { #>
387
  <p class="description">{{{data.description}}}</p>
388
  <# } #>
389
  </div>
390
  </script>
391
 
 
 
392
  <script type="text/html" id="tmpl-toolset-shortcode-attribute-postSelector">
393
  <ul id="{{{data.shortcode}}}-{{{data.attribute}}}">
394
  <li class="toolset-shortcode-gui-item-selector-option">
@@ -449,7 +448,7 @@ abstract class Toolset_Shortcode_Generator {
449
  <li class="toolset-shortcode-gui-item-selector-option toolset-shortcode-gui-item-selector-has-related js-toolset-shortcode-gui-item-selector-has-related">
450
  <label for="toolset-shortcode-gui-item-selector-post-id-related">
451
  <input type="radio" class="js-toolset-shortcode-gui-item-selector" id="toolset-shortcode-gui-item-selector-post-id-related" name="toolset_shortcode_gui_object_id" value="related" />
452
- <?php echo __( 'The parent of the current post in another post type, set by Types relationship', 'wpv-views' ); ?>
453
  </label>
454
  <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
455
  <ul class="toolset-advanced-setting tolset-mightlong-list" style="padding-top:15px;margin:5px 0 10px;">
@@ -461,11 +460,11 @@ abstract class Toolset_Shortcode_Generator {
461
  <?php echo sprintf( '<label for="toolset-shortcode-gui-item-selector-post-relationship-id-%s">', $slug ); ?>
462
  <?php echo sprintf(
463
  '<input type="radio" name="related_object" id="toolset-shortcode-gui-item-selector-post-relationship-id-%s" value="$%s" %s />',
464
- $slug,
465
- $slug,
466
- $first ? 'checked="checked"' : ''
467
  ); ?>
468
- <?php echo $custom_post_types_relations[ $slug ]['labels']['singular_name']; ?>
469
  </label>
470
  </li>
471
  <?php
@@ -481,30 +480,65 @@ abstract class Toolset_Shortcode_Generator {
481
  } else {
482
  // m2m relationships
483
  // Make sure m2m classes are registered in the autoloader
 
484
  $current_post_type_relationships = $this->get_m2m_current_post_type_relationships( $current_post_type );
485
 
486
- if ( ! empty( $current_post_type_relationships ) ) {
487
  ?>
488
  <li class="toolset-shortcode-gui-item-selector-option toolset-shortcode-gui-item-selector-has-related js-toolset-shortcode-gui-item-selector-has-related">
489
  <label for="toolset-shortcode-gui-item-selector-post-id-related">
490
  <input type="radio" class="js-toolset-shortcode-gui-item-selector" id="toolset-shortcode-gui-item-selector-post-id-related" name="toolset_shortcode_gui_object_id" value="related" />
491
- <?php echo __( 'The parent of the current post in another post type, set by Types relationship', 'wpv-views' ); ?>
492
  </label>
493
  <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
494
  <ul class="toolset-advanced-setting toolset-mightlong-list" style="padding-top:15px;margin:5px 0 10px;">
495
  <?php
496
  $first = true;
497
- foreach ( $current_post_type_relationships as $relationship_data ) {
498
  ?>
499
  <li>
500
  <?php echo sprintf( '<label for="toolset-shortcode-gui-item-selector-post-relationship-id-%s">', $relationship_data['id'] ); ?>
501
  <?php echo sprintf(
502
  '<input type="radio" name="related_object" id="toolset-shortcode-gui-item-selector-post-relationship-id-%s" value="%s" %s />',
503
- $relationship_data['id'],
504
- $relationship_data['value'],
505
- $first ? 'checked="checked"' : ''
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
  ); ?>
507
- <?php echo $relationship_data['name']; ?>
508
  </label>
509
  </li>
510
  <?php
@@ -525,8 +559,16 @@ abstract class Toolset_Shortcode_Generator {
525
  <input type="radio" class="js-toolset-shortcode-gui-item-selector" id="toolset-shortcode-gui-item-selector-post-id" name="toolset_shortcode_gui_object_id" value="object_id" />
526
  <?php _e( 'A specific post', 'wpv-views' ); ?>
527
  </label>
528
- <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
529
- <input type="text" id="toolset-shortcode-gui-item-selector-post-id-object_id" class="js-toolset-shortcode-gui-item-selector_object_id js-toolset-shortcode-gui-attribute-has-placeholder" name="specific_object_id" placeholder="<?php echo esc_attr( __( 'Enter a post ID, eg 15', 'wpv-views' ) ); ?>" />
 
 
 
 
 
 
 
 
530
  </div>
531
  </li>
532
  </ul>
@@ -553,8 +595,16 @@ abstract class Toolset_Shortcode_Generator {
553
  <input type="radio" class="js-toolset-shortcode-gui-item-selector" id="toolset-shortcode-gui-item-selector-user-id" name="toolset_shortcode_gui_object_id" value="object_id" />
554
  <?php _e( 'A specific user', 'wpv-views' ); ?>
555
  </label>
556
- <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
557
- <input type="text" id="toolset-shortcode-gui-item-selector-user-id-object_id" class="js-toolset-shortcode-gui-item-selector_object_id js-toolset-shortcode-gui-attribute-has-placeholder" name="specific_object_id" placeholder="<?php echo esc_attr( __( 'Enter an user ID, eg 2', 'wpv-views' ) ); ?>" />
 
 
 
 
 
 
 
 
558
  </div>
559
  </li>
560
  </ul>
@@ -570,9 +620,9 @@ abstract class Toolset_Shortcode_Generator {
570
  isset( $_GET['page'] )
571
  && in_array( $_GET['page'], array( 'views-editor', 'view-archives-editor' ) )
572
  ) {
573
- _e( 'Edit current post in the loop', 'wp-cred' );
574
  } else {
575
- _e( 'Edit current post', 'wp-cred' );
576
  }
577
  ?>
578
  </label>
@@ -580,9 +630,16 @@ abstract class Toolset_Shortcode_Generator {
580
  <li class="js-toolset-shortcode-gui-item-selector-has-related">
581
  <label>
582
  <input type="radio" name="{{{data.shortcode}}}-select-target-post" class="toolset-shortcode-gui-item-selector js-toolset-shortcode-gui-item-selector" value="object_id" />
583
- <?php _e( 'Edit another post', 'wp-cred' ); ?>
584
  <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
585
- <select id="toolset-shortcode-gui-item-selector-object_id" class="js-toolset-shortcode-gui-item-selector_object_id js-toolset-shortcode-gui-field-ajax-select2" data-action="toolset_select2_suggest_posts_by_title" data-nonce="" data-placeholder="<?php echo esc_attr( 'Search for posts by title', 'wpv-views' ); ?>">
 
 
 
 
 
 
 
586
  </select>
587
  </div>
588
  </label>
@@ -594,15 +651,22 @@ abstract class Toolset_Shortcode_Generator {
594
  <li>
595
  <label>
596
  <input type="radio" name="{{{data.shortcode}}}-select-target-user" class="toolset-shortcode-gui-item-selector js-toolset-shortcode-gui-item-selector" value="current" checked="checked" />
597
- <?php _e( 'Edit current logged in user', 'wp-cred' ); ?>
598
  </label>
599
  </li>
600
  <li class="js-toolset-shortcode-gui-item-selector-has-related">
601
  <label>
602
  <input type="radio" name="{{{data.shortcode}}}-select-target-user" class="toolset-shortcode-gui-item-selector js-toolset-shortcode-gui-item-selector" value="object_id" />
603
- <?php _e( 'Edit another user', 'wp-cred' ); ?>
604
  <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
605
- <select id="toolset-shortcode-gui-item-selector-object_id" class="js-toolset-shortcode-gui-item-selector_object_id js-toolset-shortcode-gui-field-ajax-select2" data-action="toolset_select2_suggest_users" data-nonce="" data-placeholder="<?php echo esc_attr( 'Search for users', 'wpv-views' ); ?>">
 
 
 
 
 
 
 
606
  </select>
607
  </div>
608
  </label>
@@ -685,7 +749,11 @@ abstract class Toolset_Shortcode_Generator {
685
  && is_array( $cptr_data['post_relationship']['belongs'] )
686
  ) {
687
  $this_belongs = array_keys( $cptr_data['post_relationship']['belongs'] );
688
- $current_post_type_parents = array_merge( $current_post_type_parents, $this_belongs );
 
 
 
 
689
  }
690
  }
691
  } else if (
@@ -728,6 +796,9 @@ abstract class Toolset_Shortcode_Generator {
728
  /**
729
  * Get Types one-to-many and one-to-one relationships for a given post type, or all the existing otherwise.
730
  *
 
 
 
731
  * @paran $current_post_type string|null
732
  *
733
  * @return array
@@ -735,13 +806,11 @@ abstract class Toolset_Shortcode_Generator {
735
  * @since m2m
736
  */
737
  public function get_m2m_current_post_type_relationships( $current_post_type ) {
738
- $current_post_type_relationships = array();
739
-
740
- if ( ! apply_filters( 'toolset_is_m2m_enabled', false ) ) {
741
- return $current_post_type_relationships;
742
- }
743
 
744
- do_action( 'toolset_do_m2m_full_init' );
745
  $query = new Toolset_Relationship_Query_V2();
746
 
747
  // Note that we can not use $query->do_if() because it actually runs both branches
@@ -753,7 +822,10 @@ abstract class Toolset_Shortcode_Generator {
753
  $query->do_and(
754
  $query->has_type( $current_post_type->name, new Toolset_Relationship_Role_Child() ),
755
  $query->has_cardinality( $query->cardinality()->one_to_many() ),
756
- $query->origin( Toolset_Relationship_Origin_Wizard::ORIGIN_KEYWORD )
 
 
 
757
  ),
758
  $query->has_cardinality( $query->cardinality()->one_to_one() )
759
  )
@@ -763,7 +835,10 @@ abstract class Toolset_Shortcode_Generator {
763
  $relationship_definitions = $query
764
  ->add(
765
  $query->do_and(
766
- $query->origin( Toolset_Relationship_Origin_Wizard::ORIGIN_KEYWORD ),
 
 
 
767
  $query->do_or(
768
  $query->has_cardinality( $query->cardinality()->one_to_many() ),
769
  $query->has_cardinality( $query->cardinality()->one_to_one() )
@@ -787,131 +862,30 @@ abstract class Toolset_Shortcode_Generator {
787
 
788
  $parents = $relationship_definition->get_parent_type()->get_types();
789
  $parent = $parents[0];
 
790
 
791
- $current_post_type_relationships[] = array(
792
  'name' => $relationship_definition->get_display_name(),
793
  'slug' => $relationship_definition->get_slug(),
794
  'value' => '@' . $relationship_definition->get_slug() . '.'
795
- . $relationship_definition->get_role_name(
796
- Toolset_Relationship_Role::other( $given_post_type_role )
 
 
 
797
  ),
798
  'id' => $relationship_definition->get_slug() . '-' . $parent,
799
- 'role_name' => $relationship_definition->get_role_name(
800
- Toolset_Relationship_Role::other( $given_post_type_role )
 
 
 
801
  )
802
  );
803
  }
804
 
805
  return $current_post_type_relationships;
806
  }
807
-
808
- public function toolset_select2_suggest_posts_by_title() {
809
- if ( ! isset( $_POST['s'] ) ) {
810
- $output = array(
811
- 'message' => __( 'Wrong or missing query.', 'wpv-views' ),
812
- );
813
- wp_send_json_error( $output );
814
- }
815
-
816
- global $wpdb;
817
-
818
- if ( method_exists( $wpdb, 'esc_like' ) ) {
819
- $s = '%' . $wpdb->esc_like( $_POST['s'] ) . '%';
820
- } else {
821
- $s = '%' . like_escape( esc_sql( $_POST['s'] ) ) . '%';
822
- }
823
-
824
- $toolset_post_type_exclude = new Toolset_Post_Type_Exclude_List();
825
- $toolset_post_type_exclude_list = $toolset_post_type_exclude->get();
826
- $toolset_post_type_exclude_list_string = "'" . implode( "', '", $toolset_post_type_exclude_list ) . "'";
827
-
828
- $results = $wpdb->get_results(
829
- $wpdb->prepare(
830
- "SELECT ID, post_type, post_title
831
- FROM {$wpdb->posts}
832
- WHERE post_title LIKE %s
833
- AND post_status = %s
834
- AND post_type NOT IN ( {$toolset_post_type_exclude_list_string} )
835
- LIMIT 0, 15",
836
- $s,
837
- 'publish'
838
- )
839
- );
840
-
841
- if (
842
- isset( $results )
843
- && ! empty( $results )
844
- ) {
845
- $output = array();
846
- if ( is_array( $results ) ) {
847
- foreach ( $results as $result ) {
848
- $output[] = array(
849
- 'text' => $result->post_title . ' (' . $result->post_type . ')',
850
- 'id' => $result->ID,
851
- );
852
- }
853
- wp_send_json_success( $output );
854
- }
855
- } else {
856
- $output = array(
857
- 'message' => __( 'Error while retrieving result.', 'wpv-views' ),
858
- );
859
- wp_send_json_error( $output );
860
- }
861
- }
862
-
863
- public function toolset_select2_suggest_users() {
864
- if ( ! isset( $_POST['s'] ) ) {
865
- $output = array(
866
- 'message' => __( 'Wrong or missing query.', 'wpv-views' ),
867
- );
868
- wp_send_json_error( $output );
869
- }
870
-
871
- global $wpdb;
872
-
873
-
874
- if ( method_exists( $wpdb, 'esc_like' ) ) {
875
- $s = '%' . $wpdb->esc_like( $_POST['s'] ) . '%';
876
- } else {
877
- $s = '%' . like_escape( esc_sql( $_POST['s'] ) ) . '%';
878
- }
879
-
880
- $results = $wpdb->get_results(
881
- $wpdb->prepare(
882
- "SELECT ID, display_name
883
- FROM {$wpdb->users}
884
- WHERE display_name LIKE %s
885
- OR user_login LIKE %s
886
- OR user_nicename LIKE %s
887
- LIMIT 0, 15",
888
- $s,
889
- $s,
890
- $s
891
- )
892
- );
893
-
894
- if (
895
- isset( $results )
896
- && ! empty( $results )
897
- ) {
898
- $output = array();
899
- if ( is_array( $results ) ) {
900
- foreach ( $results as $result ) {
901
- $output[] = array(
902
- 'text' => $result->display_name,
903
- 'id' => $result->ID,
904
- );
905
- }
906
- wp_send_json_success( $output );
907
- }
908
- } else {
909
- $output = array(
910
- 'message' => __( 'Error while retrieving result.', 'wpv-views' ),
911
- );
912
- wp_send_json_error( $output );
913
- }
914
- }
915
 
916
  /**
917
  * Register the Toolset shortcode transformer that will transform shortcode from the new format to the old one
43
 
44
  add_action( 'toolset_action_require_shortcodes_templates', array( $this, 'print_shortcodes_templates' ) );
45
 
 
 
 
 
 
46
  add_filter( 'toolset_filter_shortcode_script_i18n', array( $this, 'extend_script_i18n' ) );
47
  }
48
 
302
  #>
303
  <ul class="toolset-shortcode-gui-dialog-item-group js-toolset-shortcode-gui-dialog-item-group">
304
  <# _.each( data.fields, function( fieldData, fieldAttribute ) { #>
305
+ <li style="width:<# print( columnsWidth ); #>%;min-height:1px;float:left;">
306
  <#
307
  fieldData = _.defaults( fieldData, { shortcode: data.shortcode, templates: data.templates } );
308
  fieldData = _.defaults( fieldData, { defaultValue: '', required: false, hidden: false, placeholder: '' } );
318
  <# } #>
319
  </div>
320
  </script>
321
+ <script type="text/html" id="tmpl-toolset-shortcode-attribute-information">
322
+ <div id="{{{data.shortcode}}}-{{{data.attribute}}}" class="toolset-alert toolset-alert-info">
323
+ {{{data.content}}}
324
+ </div>
325
+ </script>
326
  <script type="text/html" id="tmpl-toolset-shortcode-attribute-text">
327
  <input id="{{{data.shortcode}}}-{{{data.attribute}}}" data-type="text" class="js-shortcode-gui-field large-text<# if ( data.required ) { #> js-toolset-shortcode-gui-required<# } #>" value="{{{data.defaultForceValue}}}" placeholder="{{{data.placeholder}}}" type="text">
328
  </script>
333
  <label>
334
  <input name="{{{data.shortcode}}}-{{{data.attribute}}}" value="{{{optionKey}}}" class="js-shortcode-gui-field" type="radio"<# if ( optionKey == data.defaultForceValue ) { #> checked="checked"<# } #>>
335
  {{{optionLabel}}}
336
+ </label>
337
  </li>
338
  <# }); #>
339
  </ul>
340
  </script>
341
  <script type="text/html" id="tmpl-toolset-shortcode-attribute-select">
342
+ <select id="{{{data.shortcode}}}-{{{data.attribute}}}" class="js-shortcode-gui-field<# if ( data.required ) { #> js-toolset-shortcode-gui-required<# } #>">
343
  <# _.each( data.options, function( optionLabel, optionKey ) { #>
344
  <option value="{{{optionKey}}}"<# if ( optionKey == data.defaultForceValue ) { #> selected="selected"<# } #>>
345
  {{{optionLabel}}}
375
 
376
  <script type="text/html" id="tmpl-toolset-shortcode-content">
377
  <#
378
+ data = _.defaults( data, { defaultValue: '', required: false, hidden: false, placeholder: '' } );
379
+ data = _.defaults( data, { defaultForceValue: data.defaultValue } );
380
  #>
381
  <div class="toolset-shortcode-gui-attribute-wrapper js-toolset-shortcode-gui-content-wrapper" <# if ( data.hidden ) { #> style="display:none"<# } #>>
382
+ <textarea id="toolset-shortcode-gui-content-{{{data.shortcode}}}" type="text" class="large-text js-toolset-shortcode-gui-content">{{{data.defaultValue}}}</textarea>
 
 
 
383
  <# if ( _.has( data, 'description' ) ) { #>
384
  <p class="description">{{{data.description}}}</p>
385
  <# } #>
386
  </div>
387
  </script>
388
 
389
+ <?php $toolset_ajax = Toolset_Ajax::get_instance(); ?>
390
+
391
  <script type="text/html" id="tmpl-toolset-shortcode-attribute-postSelector">
392
  <ul id="{{{data.shortcode}}}-{{{data.attribute}}}">
393
  <li class="toolset-shortcode-gui-item-selector-option">
448
  <li class="toolset-shortcode-gui-item-selector-option toolset-shortcode-gui-item-selector-has-related js-toolset-shortcode-gui-item-selector-has-related">
449
  <label for="toolset-shortcode-gui-item-selector-post-id-related">
450
  <input type="radio" class="js-toolset-shortcode-gui-item-selector" id="toolset-shortcode-gui-item-selector-post-id-related" name="toolset_shortcode_gui_object_id" value="related" />
451
+ <?php echo __( 'The parent of the current post in another post type, set by a Types relationship', 'wpv-views' ); ?>
452
  </label>
453
  <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
454
  <ul class="toolset-advanced-setting tolset-mightlong-list" style="padding-top:15px;margin:5px 0 10px;">
460
  <?php echo sprintf( '<label for="toolset-shortcode-gui-item-selector-post-relationship-id-%s">', $slug ); ?>
461
  <?php echo sprintf(
462
  '<input type="radio" name="related_object" id="toolset-shortcode-gui-item-selector-post-relationship-id-%s" value="$%s" %s />',
463
+ esc_attr( $slug ),
464
+ esc_attr( $slug ),
465
+ checked( $first, true, false )
466
  ); ?>
467
+ <?php echo esc_html( $custom_post_types_relations[ $slug ]['labels']['singular_name'] ); ?>
468
  </label>
469
  </li>
470
  <?php
480
  } else {
481
  // m2m relationships
482
  // Make sure m2m classes are registered in the autoloader
483
+ do_action( 'toolset_do_m2m_full_init' );
484
  $current_post_type_relationships = $this->get_m2m_current_post_type_relationships( $current_post_type );
485
 
486
+ if ( ! empty( $current_post_type_relationships[ Toolset_Relationship_Origin_Wizard::ORIGIN_KEYWORD ] ) ) {
487
  ?>
488
  <li class="toolset-shortcode-gui-item-selector-option toolset-shortcode-gui-item-selector-has-related js-toolset-shortcode-gui-item-selector-has-related">
489
  <label for="toolset-shortcode-gui-item-selector-post-id-related">
490
  <input type="radio" class="js-toolset-shortcode-gui-item-selector" id="toolset-shortcode-gui-item-selector-post-id-related" name="toolset_shortcode_gui_object_id" value="related" />
491
+ <?php echo __( 'A post related to the current post, set by a Types relationship', 'wpv-views' ); ?>
492
  </label>
493
  <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
494
  <ul class="toolset-advanced-setting toolset-mightlong-list" style="padding-top:15px;margin:5px 0 10px;">
495
  <?php
496
  $first = true;
497
+ foreach ( $current_post_type_relationships[ Toolset_Relationship_Origin_Wizard::ORIGIN_KEYWORD ] as $relationship_data ) {
498
  ?>
499
  <li>
500
  <?php echo sprintf( '<label for="toolset-shortcode-gui-item-selector-post-relationship-id-%s">', $relationship_data['id'] ); ?>
501
  <?php echo sprintf(
502
  '<input type="radio" name="related_object" id="toolset-shortcode-gui-item-selector-post-relationship-id-%s" value="%s" %s />',
503
+ esc_attr( $relationship_data['id'] ),
504
+ esc_attr( $relationship_data['value'] ),
505
+ checked( $first, true, false )
506
+ ); ?>
507
+ <?php echo esc_html( $relationship_data['name'] ); ?>
508
+ </label>
509
+ </li>
510
+ <?php
511
+ $first = false;
512
+ }
513
+ ?>
514
+ </ul>
515
+ </div>
516
+ </li>
517
+ <?php
518
+ }
519
+
520
+ if ( ! empty( $current_post_type_relationships[ Toolset_Relationship_Origin_Post_Reference_Field::ORIGIN_KEYWORD ] ) ) {
521
+ ?>
522
+ <li class="toolset-shortcode-gui-item-selector-option toolset-shortcode-gui-item-selector-has-related js-toolset-shortcode-gui-item-selector-has-related">
523
+ <label for="toolset-shortcode-gui-item-selector-post-id-referenced">
524
+ <input type="radio" class="js-toolset-shortcode-gui-item-selector" id="toolset-shortcode-gui-item-selector-post-id-referenced" name="toolset_shortcode_gui_object_id" value="referenced" />
525
+ <?php echo __( 'A post related to the current post, set by a Types post reference field', 'wpv-views' ); ?>
526
+ </label>
527
+ <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
528
+ <ul class="toolset-advanced-setting toolset-mightlong-list" style="padding-top:15px;margin:5px 0 10px;">
529
+ <?php
530
+ $first = true;
531
+ foreach ( $current_post_type_relationships[ Toolset_Relationship_Origin_Post_Reference_Field::ORIGIN_KEYWORD ] as $relationship_data ) {
532
+ ?>
533
+ <li>
534
+ <?php echo sprintf( '<label for="toolset-shortcode-gui-item-selector-post-relationship-id-%s">', $relationship_data['id'] ); ?>
535
+ <?php echo sprintf(
536
+ '<input type="radio" name="referenced_object" id="toolset-shortcode-gui-item-selector-post-relationship-id-%s" value="%s" %s />',
537
+ esc_attr( $relationship_data['id'] ),
538
+ esc_attr( $relationship_data['value'] ),
539
+ checked( $first, true, false )
540
  ); ?>
541
+ <?php echo esc_html( $relationship_data['name'] ); ?>
542
  </label>
543
  </li>
544
  <?php
559
  <input type="radio" class="js-toolset-shortcode-gui-item-selector" id="toolset-shortcode-gui-item-selector-post-id" name="toolset_shortcode_gui_object_id" value="object_id" />
560
  <?php _e( 'A specific post', 'wpv-views' ); ?>
561
  </label>
562
+ <div class="toolset-advanced-setting toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none;padding-top:10px;">
563
+ <select id="toolset-shortcode-gui-item-selector-post-id-object_id"
564
+ class="js-toolset-shortcode-gui-item-selector_object_id js-toolset-shortcode-gui-field-ajax-select2"
565
+ name="specific_object_id"
566
+ data-action="<?php echo esc_attr( $toolset_ajax->get_action_js_name( Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_POSTS_BY_TITLE ) ); ?>"
567
+ data-prefill="<?php echo esc_attr( $toolset_ajax->get_action_js_name( Toolset_Ajax::CALLBACK_GET_POST_BY_ID ) ); ?>"
568
+ data-nonce="<?php echo wp_create_nonce( Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_POSTS_BY_TITLE ); ?>"
569
+ data-prefill-nonce="<?php echo wp_create_nonce( Toolset_Ajax::CALLBACK_GET_POST_BY_ID ); ?>"
570
+ data-placeholder="<?php echo esc_attr( __( 'Search for a post by title', 'wpv-views' ) ); ?>">
571
+ </select>
572
  </div>
573
  </li>
574
  </ul>
595
  <input type="radio" class="js-toolset-shortcode-gui-item-selector" id="toolset-shortcode-gui-item-selector-user-id" name="toolset_shortcode_gui_object_id" value="object_id" />
596
  <?php _e( 'A specific user', 'wpv-views' ); ?>
597
  </label>
598
+ <div class="toolset-advanced-setting toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none;padding-top:10px;">
599
+ <select id="toolset-shortcode-gui-item-selector-user-id-object_id"
600
+ class="js-toolset-shortcode-gui-item-selector_object_id js-toolset-shortcode-gui-field-ajax-select2"
601
+ name="specific_object_id"
602
+ data-action="<?php echo esc_attr( $toolset_ajax->get_action_js_name( Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_USERS ) ); ?>"
603
+ data-prefill="<?php echo esc_attr( $toolset_ajax->get_action_js_name( Toolset_Ajax::CALLBACK_GET_USER_BY_ID ) ); ?>"
604
+ data-nonce="<?php echo wp_create_nonce( Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_USERS ); ?>"
605
+ data-prefill-nonce="<?php echo wp_create_nonce( Toolset_Ajax::CALLBACK_GET_USER_BY_ID ); ?>"
606
+ data-placeholder="<?php echo esc_attr( __( 'Search for a user', 'wpv-views' ) ); ?>">
607
+ </select>
608
  </div>
609
  </li>
610
  </ul>
620
  isset( $_GET['page'] )
621
  && in_array( $_GET['page'], array( 'views-editor', 'view-archives-editor' ) )
622
  ) {
623
+ _e( 'The current post in the loop', 'wp-cred' );
624
  } else {
625
+ _e( 'The current post', 'wp-cred' );
626
  }
627
  ?>
628
  </label>
630
  <li class="js-toolset-shortcode-gui-item-selector-has-related">
631
  <label>
632
  <input type="radio" name="{{{data.shortcode}}}-select-target-post" class="toolset-shortcode-gui-item-selector js-toolset-shortcode-gui-item-selector" value="object_id" />
633
+ <?php _e( 'Another post', 'wp-cred' ); ?>
634
  <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
635
+ <select id="toolset-shortcode-gui-item-selector-post-id-object_id"
636
+ class="js-toolset-shortcode-gui-item-selector_object_id js-toolset-shortcode-gui-field-ajax-select2"
637
+ name="specific_object_id"
638
+ data-action="<?php echo esc_attr( $toolset_ajax->get_action_js_name( Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_POSTS_BY_TITLE ) ); ?>"
639
+ data-prefill="<?php echo esc_attr( $toolset_ajax->get_action_js_name( Toolset_Ajax::CALLBACK_GET_POST_BY_ID ) ); ?>"
640
+ data-nonce="<?php echo wp_create_nonce( Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_POSTS_BY_TITLE ); ?>"
641
+ data-prefill-nonce="<?php echo wp_create_nonce( Toolset_Ajax::CALLBACK_GET_POST_BY_ID ); ?>"
642
+ data-placeholder="<?php echo esc_attr( __( 'Search for a post by title', 'wpv-views' ) ); ?>">
643
  </select>
644
  </div>
645
  </label>
651
  <li>
652
  <label>
653
  <input type="radio" name="{{{data.shortcode}}}-select-target-user" class="toolset-shortcode-gui-item-selector js-toolset-shortcode-gui-item-selector" value="current" checked="checked" />
654
+ <?php _e( 'The current logged in user', 'wp-cred' ); ?>
655
  </label>
656
  </li>
657
  <li class="js-toolset-shortcode-gui-item-selector-has-related">
658
  <label>
659
  <input type="radio" name="{{{data.shortcode}}}-select-target-user" class="toolset-shortcode-gui-item-selector js-toolset-shortcode-gui-item-selector" value="object_id" />
660
+ <?php _e( 'Another user', 'wp-cred' ); ?>
661
  <div class="toolset-shortcode-gui-item-selector-is-related js-toolset-shortcode-gui-item-selector-is-related" style="display:none">
662
+ <select id="toolset-shortcode-gui-item-selector-user-id-object_id"
663
+ class="js-toolset-shortcode-gui-item-selector_object_id js-toolset-shortcode-gui-field-ajax-select2"
664
+ name="specific_object_id"
665
+ data-action="<?php echo esc_attr( $toolset_ajax->get_action_js_name( Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_USERS ) ); ?>"
666
+ data-prefill="<?php echo esc_attr( $toolset_ajax->get_action_js_name( Toolset_Ajax::CALLBACK_GET_USER_BY_ID ) ); ?>"
667
+ data-nonce="<?php echo wp_create_nonce( Toolset_Ajax::CALLBACK_SELECT2_SUGGEST_USERS ); ?>"
668
+ data-prefill-nonce="<?php echo wp_create_nonce( Toolset_Ajax::CALLBACK_GET_USER_BY_ID ); ?>"
669
+ data-placeholder="<?php echo esc_attr( __( 'Search for a user', 'wpv-views' ) ); ?>">
670
  </select>
671
  </div>
672
  </label>
749
  && is_array( $cptr_data['post_relationship']['belongs'] )
750
  ) {
751
  $this_belongs = array_keys( $cptr_data['post_relationship']['belongs'] );
752
+ foreach ( $this_belongs as $this_belongs_candidate ) {
753
+ if ( isset( $custom_post_types_relations[ $this_belongs_candidate ] ) ) {
754
+ $current_post_type_parents[] = $this_belongs_candidate;
755
+ }
756
+ }
757
  }
758
  }
759
  } else if (
796
  /**
797
  * Get Types one-to-many and one-to-one relationships for a given post type, or all the existing otherwise.
798
  *
799
+ * For post reference fields relationships, make sure we alwars offer to insert the parent post data,
800
+ * as they do support relationships between the same post type, hence the relationship ends get blurred.
801
+ *
802
  * @paran $current_post_type string|null
803
  *
804
  * @return array
806
  * @since m2m
807
  */
808
  public function get_m2m_current_post_type_relationships( $current_post_type ) {
809
+ $current_post_type_relationships = array(
810
+ Toolset_Relationship_Origin_Wizard::ORIGIN_KEYWORD => array(),
811
+ Toolset_Relationship_Origin_Post_Reference_Field::ORIGIN_KEYWORD => array()
812
+ );
 
813
 
 
814
  $query = new Toolset_Relationship_Query_V2();
815
 
816
  // Note that we can not use $query->do_if() because it actually runs both branches
822
  $query->do_and(
823
  $query->has_type( $current_post_type->name, new Toolset_Relationship_Role_Child() ),
824
  $query->has_cardinality( $query->cardinality()->one_to_many() ),
825
+ $query->do_or(
826
+ $query->origin( Toolset_Relationship_Origin_Wizard::ORIGIN_KEYWORD ),
827
+ $query->origin( Toolset_Relationship_Origin_Post_Reference_Field::ORIGIN_KEYWORD )
828
+ )
829
  ),
830
  $query->has_cardinality( $query->cardinality()->one_to_one() )
831
  )
835
  $relationship_definitions = $query
836
  ->add(
837
  $query->do_and(
838
+ $query->do_or(
839
+ $query->origin( Toolset_Relationship_Origin_Wizard::ORIGIN_KEYWORD ),
840
+ $query->origin( Toolset_Relationship_Origin_Post_Reference_Field::ORIGIN_KEYWORD )
841
+ ),
842
  $query->do_or(
843
  $query->has_cardinality( $query->cardinality()->one_to_many() ),
844
  $query->has_cardinality( $query->cardinality()->one_to_one() )
862
 
863
  $parents = $relationship_definition->get_parent_type()->get_types();
864
  $parent = $parents[0];
865
+ $origin = $relationship_definition->get_origin();
866
 
867
+ $current_post_type_relationships[ $origin->get_origin_keyword() ][] = array(
868
  'name' => $relationship_definition->get_display_name(),
869
  'slug' => $relationship_definition->get_slug(),
870
  'value' => '@' . $relationship_definition->get_slug() . '.'
871
+ . ( Toolset_Relationship_Origin_Wizard::ORIGIN_KEYWORD === $origin->get_origin_keyword()
872
+ ? $relationship_definition->get_role_name(
873
+ Toolset_Relationship_Role::other( $given_post_type_role )
874
+ )
875
+ : Toolset_Relationship_Role::PARENT
876
  ),
877
  'id' => $relationship_definition->get_slug() . '-' . $parent,
878
+ 'role_name' => ( Toolset_Relationship_Origin_Wizard::ORIGIN_KEYWORD === $origin->get_origin_keyword()
879
+ ? $relationship_definition->get_role_name(
880
+ Toolset_Relationship_Role::other( $given_post_type_role )
881
+ )
882
+ : Toolset_Relationship_Role::PARENT
883
  )
884
  );
885
  }
886
 
887
  return $current_post_type_relationships;
888
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
889
 
890
  /**
891
  * Register the Toolset shortcode transformer that will transform shortcode from the new format to the old one
vendor/toolset/toolset-common/inc/toolset.wpml.compatibility.class.php CHANGED
@@ -4,15 +4,35 @@ if ( ! class_exists( 'Toolset_WPML_Compatibility', false ) ) {
4
 
5
 
6
  /**
7
- * Handle the shared interoperability tasks between WPML and any/all Toolset plugins.
8
  *
9
  * @since unknown
10
  */
11
- class Toolset_WPML_Compatibility {
12
 
 
 
 
 
 
 
 
 
 
13
  private static $instance;
14
 
15
 
 
 
 
 
 
 
 
 
 
 
 
16
  public static function get_instance() {
17
  if ( null == self::$instance ) {
18
  self::$instance = new self();
@@ -27,10 +47,9 @@ if ( ! class_exists( 'Toolset_WPML_Compatibility', false ) ) {
27
  }
28
 
29
 
30
- private function __clone() { }
31
 
32
-
33
- private function __construct() {
34
 
35
  add_action( 'init', array( $this, 'maybe_add_wpml_string_stub_shortcode' ), 100 );
36
 
@@ -44,8 +63,20 @@ if ( ! class_exists( 'Toolset_WPML_Compatibility', false ) ) {
44
  *
45
  * @since 2.3
46
  */
47
- add_filter( 'toolset_is_wpml_active_and_configured', array( $this, 'filter_is_wpml_active_and_configured' ) );
 
 
 
 
 
 
48
 
 
 
 
 
 
 
49
  }
50
 
51
 
@@ -75,7 +106,10 @@ if ( ! class_exists( 'Toolset_WPML_Compatibility', false ) ) {
75
  * @return string
76
  * @since unknown
77
  */
78
- public function stub_wpml_string_shortcode( /** @noinspection PhpUnusedParameterInspection */ $atts, $value ) {
 
 
 
79
  return do_shortcode( $value );
80
  }
81
 
@@ -94,7 +128,7 @@ if ( ! class_exists( 'Toolset_WPML_Compatibility', false ) ) {
94
 
95
  static $result = null;
96
 
97
- if( null === $result || ! $use_cache ) {
98
  global $sitepress;
99
  $is_wpml_active = (
100
  defined( 'ICL_SITEPRESS_VERSION' )
@@ -118,10 +152,14 @@ if ( ! class_exists( 'Toolset_WPML_Compatibility', false ) ) {
118
  * Instead of calling this directly, use is_wpml_configured_and_active().
119
  *
120
  * @param mixed $default_value Ignored.
 
121
  * @return bool
122
  * @since 2.3
123
  */
124
- public function filter_is_wpml_active_and_configured( /** @noinspection PhpUnusedParameterInspection */ $default_value ) {
 
 
 
125
  return $this->is_wpml_active_and_configured();
126
  }
127
 
@@ -140,7 +178,7 @@ if ( ! class_exists( 'Toolset_WPML_Compatibility', false ) ) {
140
  return false;
141
  }
142
 
143
- return ( defined( 'WPML_ST_VERSION') );
144
  }
145
 
146
  /**
@@ -171,6 +209,336 @@ if ( ! class_exists( 'Toolset_WPML_Compatibility', false ) ) {
171
  return ( defined( 'ICL_SITEPRESS_VERSION' ) ? ICL_SITEPRESS_VERSION : null );
172
  }
173
 
174
- }
175
 
176
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
 
6
  /**
7
+ * Handle the basic interactions between WPML and Toolset plugins.
8
  *
9
  * @since unknown
10
  */
11
+ class Toolset_WPML_Compatibility extends Toolset_Wpdb_User {
12
 
13
+
14
+ // Possible WPML translation modes. Use these constants instead of hardcoded strings as they might
15
+ // change without warning.
16
+ const MODE_DONT_TRANSLATE = 'dont_translate';
17
+ const MODE_TRANSLATE = 'translate';
18
+ const MODE_DISPLAY_AS_TRANSLATED = 'display_as_translated';
19
+
20
+
21
+ /** @var Toolset_WPML_Compatibility */
22
  private static $instance;
23
 
24
 
25
+ /** @var null|string Cache for the current language code. */
26
+ private $current_language;
27
+
28
+ /** @var null|string Cache for the default language code. */
29
+ private $default_language;
30
+
31
+
32
+ /** @var string[] */
33
+ private $previous_languages = array();
34
+
35
+
36
  public static function get_instance() {
37
  if ( null == self::$instance ) {
38
  self::$instance = new self();
47
  }
48
 
49
 
50
+ public function __construct( wpdb $wpdb_di = null ) {
51
 
52
+ parent::__construct( $wpdb_di );
 
53
 
54
  add_action( 'init', array( $this, 'maybe_add_wpml_string_stub_shortcode' ), 100 );
55
 
63
  *
64
  * @since 2.3
65
  */
66
+ add_filter(
67
+ 'toolset_is_wpml_active_and_configured', array(
68
+ $this,
69
+ 'filter_is_wpml_active_and_configured'
70
+ )
71
+ );
72
+
73
 
74
+ /**
75
+ * Shows a warning in WPML if the post type belongs to a relationships and it is not the proper translation mode
76
+ *
77
+ * @since m2m
78
+ */
79
+ add_filter( 'wpml_disable_translation_mode_radio', array( $this, 'wpml_disable_translation_mode_radio' ), 10, 3 );
80
  }
81
 
82
 
106
  * @return string
107
  * @since unknown
108
  */
109
+ public function stub_wpml_string_shortcode(
110
+ /** @noinspection PhpUnusedParameterInspection */
111
+ $atts, $value
112
+ ) {
113
  return do_shortcode( $value );
114
  }
115
 
128
 
129
  static $result = null;
130
 
131
+ if ( null === $result || ! $use_cache ) {
132
  global $sitepress;
133
  $is_wpml_active = (
134
  defined( 'ICL_SITEPRESS_VERSION' )
152
  * Instead of calling this directly, use is_wpml_configured_and_active().
153
  *
154
  * @param mixed $default_value Ignored.
155
+ *
156
  * @return bool
157
  * @since 2.3
158
  */
159
+ public function filter_is_wpml_active_and_configured(
160
+ /** @noinspection PhpUnusedParameterInspection */
161
+ $default_value
162
+ ) {
163
  return $this->is_wpml_active_and_configured();
164
  }
165
 
178
  return false;
179
  }
180
 
181
+ return ( defined( 'WPML_ST_VERSION' ) );
182
  }
183
 
184
  /**
209
  return ( defined( 'ICL_SITEPRESS_VERSION' ) ? ICL_SITEPRESS_VERSION : null );
210
  }
211
 
 
212
 
213
+ /**
214
+ * Check if a post type is translatable.
215
+ *
216
+ * @param string $post_type_slug
217
+ *
218
+ * @return bool
219
+ * @since m2m
220
+ */
221
+ public function is_post_type_translatable( $post_type_slug ) {
222
+ return (bool) apply_filters( 'wpml_is_translated_post_type', false, $post_type_slug );
223
+ }
224
+
225
+
226
+ /**
227
+ * Check if a post type is translatable and in the "display as translated" mode.
228
+ *
229
+ * @param string $post_type_slug
230
+ *
231
+ * @return bool
232
+ * @since 2.5.10
233
+ */
234
+ public function is_post_type_display_as_translated( $post_type_slug ) {
235
+ if ( ! $this->is_post_type_translatable( $post_type_slug ) ) {
236
+ return false;
237
+ }
238
+
239
+ return (bool) apply_filters( 'wpml_is_display_as_translated_post_type', false, $post_type_slug );
240
+ }
241
+
242
+
243
+ /**
244
+ * Get the current language.
245
+ *
246
+ * Cached.
247
+ *
248
+ * @return string
249
+ * @since m2m
250
+ */
251
+ public function get_current_language() {
252
+ if ( null === $this->current_language && $this->is_wpml_active_and_configured() ) {
253
+ $this->current_language = apply_filters( 'wpml_current_language', null );
254
+ }
255
+
256
+ return $this->current_language;
257
+ }
258
+
259
+
260
+ /**
261
+ * Get the default site language.
262
+ *
263
+ * Cached.
264
+ *
265
+ * @return string
266
+ * @since m2m
267
+ */
268
+ public function get_default_language() {
269
+ if ( null === $this->default_language && $this->is_wpml_active_and_configured() ) {
270
+ $this->default_language = apply_filters( 'wpml_default_language', null );
271
+ }
272
+
273
+ return $this->default_language;
274
+ }
275
+
276
+
277
+ /**
278
+ * @return bool True if the site is currently in the default language.
279
+ * @since 2.5.10
280
+ */
281
+ public function is_current_language_default() {
282
+ return (
283
+ ! $this->is_wpml_active_and_configured()
284
+ || $this->get_default_language() === $this->get_current_language()
285
+ );
286
+ }
287
+
288
+
289
+ public function get_post_language( $post_id ) {
290
+ $post_language_details = apply_filters( 'wpml_post_language_details', null, $post_id );
291
+ $lang = toolset_getarr( $post_language_details, 'language_code', '' );
292
+
293
+ return $lang;
294
+ }
295
+
296
+
297
+ /**
298
+ * Get an array of post translation IDs from the icl_translations table, indexed by language codes.
299
+ *
300
+ * todo consider using WPML hooks if they're available
301
+ *
302
+ * @param int $post_id
303
+ *
304
+ * @return int[]
305
+ * @since 2.5.10
306
+ */
307
+ public function get_post_translations_directly( $post_id ) {
308
+
309
+ if ( ! $this->is_wpml_active_and_configured() ) {
310
+ return array();
311
+ }
312
+
313
+ $icl_translations_table = $this->icl_translations_table_name();
314
+ $trid = $this->get_post_trid( $post_id );
315
+
316
+ if ( null === $trid ) {
317
+ return array();
318
+ }
319
+
320
+ $query = $this->wpdb->prepare(
321
+ "SELECT
322
+ element_id AS post_id,
323
+ language_code AS language_code
324
+ FROM
325
+ $icl_translations_table
326
+ WHERE
327
+ element_type LIKE %s
328
+ AND trid = %d",
329
+ 'post_%',
330
+ $trid
331
+ );
332
+
333
+ $db_results = $this->wpdb->get_results( $query );
334
+
335
+ // Return an associative array of post IDs.
336
+ $results = array();
337
+ foreach ( $db_results as $row ) {
338
+ $results[ $row->language_code ] = (int) $row->post_id;
339
+ }
340
+
341
+ return $results;
342
+
343
+ }
344
+
345
+
346
+ /**
347
+ * Retrieve the translation group ID for a post.
348
+ *
349
+ * @param int $post_id
350
+ *
351
+ * @return int "trid" value or zero.
352
+ * @since m2m
353
+ */
354
+ public function get_post_trid( $post_id ) {
355
+ $icl_translations_table = $this->icl_translations_table_name();
356
+
357
+ $query = $this->wpdb->prepare(
358
+ "SELECT trid
359
+ FROM `{$icl_translations_table}`
360
+ WHERE
361
+ element_type LIKE %s
362
+ AND element_id = %d
363
+ LIMIT 1",
364
+ 'post_%',
365
+ $post_id
366
+ );
367
+
368
+ return (int) $this->wpdb->get_var( $query );
369
+ }
370
+
371
+
372
+ /**
373
+ * @return string icl_translations table name.
374
+ */
375
+ public function icl_translations_table_name() {
376
+ return $this->wpdb->prefix . 'icl_translations';
377
+ }
378
+
379
+
380
+ /**
381
+ * Get the translation mode value for a given post type.
382
+ *
383
+ * If WPML is not active or the post type doesn't exist, self::MODE_DONT_TRANSLATE will be returned.
384
+ *
385
+ * @param string $post_type_slug
386
+ * @return string
387
+ * @since 2.5.11
388
+ */
389
+ public function get_post_type_translation_mode( $post_type_slug ) {
390
+ if(
391
+ ! $this->is_wpml_active_and_configured()
392
+ || ! $this->is_post_type_translatable( $post_type_slug )
393
+ ) {
394
+ return self::MODE_DONT_TRANSLATE;
395
+ }
396
+
397
+ if( $this->is_post_type_display_as_translated( $post_type_slug ) ) {
398
+ return self::MODE_DISPLAY_AS_TRANSLATED;
399
+ }
400
+
401
+ return self::MODE_TRANSLATE;
402
+ }
403
+
404
+
405
+ /**
406
+ * Set the translation mode of given post type.
407
+ *
408
+ * @param string $post_type_slug
409
+ * @param string $translation_mode One of the MODE_ constants defined on this class.
410
+ * @return void
411
+ * @throws InvalidArgumentException if WPML is not active or an invalid translation mode is provided.
412
+ * @since 2.5.11
413
+ */
414
+ public function set_post_type_translation_mode( $post_type_slug, $translation_mode ) {
415
+ if( ! $this->is_wpml_active_and_configured() ) {
416
+ throw new InvalidArgumentException( 'Trying to set a post translation mode while WPML is not active.' );
417
+ }
418
+
419
+ $allowed_modes = array( self::MODE_TRANSLATE, self::MODE_DONT_TRANSLATE, self::MODE_DISPLAY_AS_TRANSLATED );
420
+
421
+ if( ! in_array( $translation_mode, $allowed_modes ) ) {
422
+ throw new InvalidArgumentException( 'Trying to set an invalid translation mode for a post type' );
423
+ }
424
+
425
+ do_action( 'wpml_set_translation_mode_for_post_type', $post_type_slug, $translation_mode );
426
+ }
427
+
428
+
429
+ /**
430
+ * Set a post as a translation of another post (original).
431
+ *
432
+ * @param IToolset_Post $original_post
433
+ * @param int $translation_post_id ID of the translated post.
434
+ * @param string $lang_code Language of the translated post.
435
+ * @throws InvalidArgumentException If called when WPML inactive.
436
+ * @return void
437
+ */
438
+ public function add_post_translation( IToolset_Post $original_post, $translation_post_id, $lang_code ) {
439
+ if( ! $this->is_wpml_active_and_configured() ) {
440
+ throw new InvalidArgumentException( 'Cannot add a post translation if WPML is not active and configured.' );
441
+ }
442
+ $element_type = apply_filters( 'wpml_element_type', $original_post->get_type() );
443
+
444
+ $set_language_args = array(
445
+ 'element_id' => $translation_post_id,
446
+ 'element_type' => $element_type,
447
+ 'trid' => $original_post->get_trid(),
448
+ 'language_code' => $lang_code,
449
+ 'source_language_code' => $original_post->get_language()
450
+ );
451
+
452
+ do_action( 'wpml_set_element_language_details', $set_language_args );
453
+ }
454
+
455
+
456
+ /**
457
+ * Create a duplicate of the given post (using standard WPML mechanism to copy the content).
458
+ *
459
+ * Optionally, it is possible to _not_ mark it as an duplicate, but as a regular translation instead.
460
+ *
461
+ * @param IToolset_Post $original_post
462
+ * @param string $lang_code Language of the duplicated post.
463
+ * @param bool $mark_as_duplicate
464
+ *
465
+ * @return int ID of the duplicated post.
466
+ * @throws InvalidArgumentException If called when WPML inactive.
467
+ * @throws RuntimeException If it is not possible to perform the call to WPML.
468
+ */
469
+ public function create_post_duplicate( IToolset_Post $original_post, $lang_code, $mark_as_duplicate = true ) {
470
+ if( ! $this->is_wpml_active_and_configured() ) {
471
+ throw new InvalidArgumentException( 'Cannot add a post translation if WPML is not active and configured.' );
472
+ }
473
+
474
+ $copied_post_id = apply_filters( 'wpml_copy_post_to_language', $original_post->get_id(), $lang_code, $mark_as_duplicate );
475
+
476
+ return (int) $copied_post_id;
477
+ }
478
+
479
+ /**
480
+ * Shows a warning in WPML if the post type belongs to a relationships and it is not the proper translation mode
481
+ *
482
+ * @param array $disabled_state_for_mode Filterable array.
483
+ * @param int $mode WPML translation mode.
484
+ * @param string $content_slug Post type slug.
485
+ * @return array
486
+ * @since m2m
487
+ */
488
+ public function wpml_disable_translation_mode_radio( $disabled_state_for_mode, $mode, $content_slug ) {
489
+ do_action( 'toolset_do_m2m_full_init' );
490
+ if( ! apply_filters( 'toolset_is_m2m_enabled', false ) ) {
491
+ return $disabled_state_for_mode;
492
+ }
493
+ $relationships_query = new Toolset_Relationship_Query_V2();
494
+ $relationships_query->add( $relationships_query->has_domain( 'posts' ) )
495
+ ->add( $relationships_query->has_type( $content_slug ) )
496
+ ->do_not_add_default_conditions();
497
+ $relationships = $relationships_query->get_results();
498
+
499
+ if ( empty( $relationships ) ) {
500
+ return $disabled_state_for_mode;
501
+ }
502
+
503
+ foreach ( $relationships as $relationship ) {
504
+ $types = array_merge( $relationship->get_parent_type()->get_types(), $relationship->get_child_type()->get_types() );
505
+ if ( in_array( $content_slug, $types, true ) && defined( 'WPML_CONTENT_TYPE_TRANSLATE' ) && $mode == WPML_CONTENT_TYPE_TRANSLATE ) {
506
+ $disabled_state_for_mode['state'] = true;
507
+ // translators: Relationship name.
508
+ $disabled_state_for_mode['reason_message'] = sprintf( __( 'You cannot set this translation mode because the post type is involved in the relationship "%s".', 'wpcf' ), $relationship->get_display_name() ) . ' <a href="https://wp-types.com/documentation/translating-sites-built-with-toolset/translating-related-content/" target="_blank">' . __( 'Learn more' , 'wpcf' ) . '</a>.';
509
+ return $disabled_state_for_mode;
510
+ }
511
+ }
512
+ return $disabled_state_for_mode;
513
+ }
514
+
515
+
516
+
517
+ /**
518
+ * Switch the current language.
519
+ *
520
+ * Warning: You *MUST* revert this by calling switch_language_back() in all cases.
521
+ *
522
+ * It is possible to nest these calls, but switch_language() and switch_language_back() must always
523
+ * come in pairs.
524
+ *
525
+ * @param string $lang_code
526
+ * @since 2.5.10
527
+ */
528
+ public function switch_language( $lang_code ) {
529
+ array_push( $this->previous_languages, $this->get_current_language() );
530
+ do_action( 'wpml_switch_language', $lang_code );
531
+ }
532
+
533
+
534
+ /**
535
+ * Switch the current language back to the previous value after switch_language().
536
+ *
537
+ * @since 2.5.10
538
+ */
539
+ public function switch_language_back() {
540
+ $lang_code = array_pop( $this->previous_languages );
541
+ do_action( 'wpml_switch_language', $lang_code );
542
+ }
543
+ }
544
+ }
vendor/toolset/toolset-common/lib/whip/CHANGELOG.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/).
6
+
7
+ ## [1.1.0]
8
+ ### Added
9
+ * Allow WordPress messages to be dismissed for a period of 4 weeks.
10
+
11
+ ## [1.0.1]
12
+ ### Fixed
13
+ * Fix a missing link when the PHP message is switched to the WordPress.org hosting page.
14
+
15
+ ## [1.0.0]
16
+ ### Changed
17
+ * Updated screenshot in README
18
+
19
+ ## [1.0.0-beta.2] - 2017-03-11
20
+ ### Added
21
+ * Complete PHP version message
22
+
23
+ ### Changed
24
+ * Refactor code architecture.
25
+ * Use PHP version constant instead of function.
26
+
27
+ ### Fixed
28
+ * Fix broken version reconciliation.
29
+
30
+ ## 1.0.0-beta.1 - 2017-02-21
31
+ * Initial pre-release of whip. A package to nudge users to upgrade their software versions.
32
+
33
+ [Unreleased]: https://github.com/yoast/whip/compare/1.0.0-beta.2...HEAD
34
+ [1.0.0-beta.2]: https://github.com/yoast/whip/compare/1.0.0-beta.1...1.0.0-beta.2
vendor/toolset/toolset-common/lib/whip/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Yoast
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
vendor/toolset/toolset-common/lib/whip/README.md ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # whip
2
+ A WordPress package to nudge users to upgrade their software versions (starting with PHP)
3
+
4
+ ![Screenshot of the WordPress notice](./images/wp-message.png)
5
+
6
+ ## Requirements
7
+
8
+ The following versions of PHP are supported:
9
+
10
+ * PHP 5.2
11
+ * PHP 5.3
12
+ * PHP 5.4
13
+ * PHP 5.5
14
+ * PHP 5.6
15
+ * PHP 7.0
16
+ * PHP 7.1
17
+
18
+ WordPress is also required for certain functionality:
19
+
20
+ * The `WPMessagePresenter` requires WordPress or a function called `add_action`, to hook into WordPress.
21
+ * The `PHPVersionDetector` requires WordPress or a function called `__`, to translate strings.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ $ composer require yoast/whip
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ The easiest way to use Whip in WordPress is just by using the included function to check the versions. In this case checking if PHP 5.6 or greater is installed:
32
+ ```php
33
+ whip_wp_check_versions( array(
34
+ 'php' => '>=5.6',
35
+ ) );
36
+ ```
37
+
38
+ This will show a message to all users of your plugin on PHP5.2 to PHP 5.5. By default the message will be shown on every page of the admin and to every user. It is up to the implementing plugin to restrict this to certain users and/or pages.
39
+
40
+ ### Adding a message as a host
41
+
42
+ It is possible to add a custom message to the PHP version message by setting specific environment variables:
43
+
44
+ ```php
45
+ putenv( "WHIP_NAME_OF_HOST=Name of the host" );
46
+ putenv( "WHIP_MESSAGE_FROM_HOST_ABOUT_PHP=A message from the host" );
47
+ ```
48
+
49
+ The `WHIP_NAME_OF_HOST` environment variable could be reused in the future for showing messages about different software packages.
50
+
51
+ Both the name and the message for PHP can also be changed using WordPress filters:
52
+ ```php
53
+ function my_host__name_for_whip() {
54
+ return 'Name of the host';
55
+ }
56
+ add_filter( 'whip_name_of_host', 'my_host__name_for_whip' );
57
+
58
+ function my_host__php_message_for_whip( $message ) {
59
+ return 'A message from the host';
60
+ }
61
+ add_filter( 'whip_message_from_host_about_php', 'my_host__php_message_for_whip' );
62
+ ```
63
+
64
+ The WordPress filters can also read the value previously set by the environment variables.
65
+
66
+ As a general rule, the filter is the same as the environment variable, but lowercased.
67
+
68
+ ### Linking to the WordPress.org hosting page
69
+
70
+ We have created a hosting overview page on yoast.com which only contains hosts that we've vetted. The PHP message links to this page by default. If you really prefer to link to the WordPress.org hosting page that is possible. Just use the `whip_hosting_page_url_wordpress` filter:
71
+
72
+ ```php
73
+ add_filter( 'whip_hosting_page_url_wordpress', '__return_true' );
74
+ ```
75
+
76
+ ## Backwards compatibility policy
77
+
78
+ We follow [semantic versioning][semver] with an extra strict rule for MAJOR versions. We will do a major version bump whenever we add new methods. We have to do this because of the shared namespace in PHP. When this package will be used in multiple plugins we cannot safely add and use a method without bumping a major version. This is because the version without the new method may be autoloaded and then a fatal error occurs.
79
+
80
+ This also means that any major version bump is accompanied by a change of all class names in the package. So for version 2 of this package all classes will be postfixed with `_v2`. This prevents fatal errors when two plugins include different versions of this package.
81
+
82
+ ## Changelog
83
+
84
+
85
+ ## Security
86
+
87
+ If you discover any security related issues, please email security@yoast.com instead of using the issue tracker.
88
+
89
+ ## Credits
90
+
91
+ * [Team Yoast](https://github.com/yoast)
92
+
93
+
94
+ [semver]: http://semver.org/
vendor/toolset/toolset-common/lib/whip/src/Whip_Configuration.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Whip_Configuration
5
+ */
6
+ class Whip_Configuration {
7
+
8
+ /**
9
+ * @var array
10
+ */
11
+ private $configuration;
12
+
13
+ /**
14
+ * Whip_Configuration constructor.
15
+ *
16
+ * @param array $configuration The configuration to use.
17
+ *
18
+ * @throws Whip_InvalidType
19
+ */
20
+ public function __construct( $configuration = array() ) {
21
+ if ( ! is_array( $configuration ) ) {
22
+ throw new Whip_InvalidType( 'Configuration', gettype( $configuration), "array" );
23
+ }
24
+
25
+ $this->configuration = $configuration;
26
+ }
27
+
28
+ /**
29
+ * Retrieves the configured version of a particular requirement.
30
+ * If the requirement does not exist, this returns -1.
31
+ *
32
+ * @param Whip_Requirement $requirement The requirement to check.
33
+ *
34
+ * @return int The version of the passed requirement that was detected.
35
+ */
36
+ public function configuredVersion( Whip_Requirement $requirement ) {
37
+ if ( ! $this->hasRequirementConfigured( $requirement ) ) {
38
+ return -1;
39
+ }
40
+
41
+ return $this->configuration[ $requirement->component() ];
42
+ }
43
+
44
+ /**
45
+ * Determines whether the passed requirement is present in the configuration.
46
+ *
47
+ * @param Whip_Requirement $requirement The requirement to check.
48
+ *
49
+ * @return bool Whether or not the requirement is present in the configuration.
50
+ */
51
+ public function hasRequirementConfigured( Whip_Requirement $requirement ) {
52
+ return array_key_exists( $requirement->component(), $this->configuration );
53
+ }
54
+ }
vendor/toolset/toolset-common/lib/whip/src/Whip_Host.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Represents a host
5
+ */
6
+ class Whip_Host {
7
+ const HOST_NAME_KEY = 'WHIP_NAME_OF_HOST';
8
+ const HOSTING_PAGE_FILTER_KEY = 'whip_hosting_page_url_wordpress';
9
+
10
+ /**
11
+ * Retrieves the name of the host if set.
12
+ *
13
+ * @return string The name of the host.
14
+ */
15
+ public static function name() {
16
+ $name = (string) getenv( self::HOST_NAME_KEY );
17
+
18
+ return self::filterName( $name );
19
+ }
20
+
21
+ /**
22
+ * Filters the name if we are in a WordPress context. In a non-WordPress content this function just returns the passed name.
23
+ *
24
+ * @param string $name The current name of the host.
25
+ * @returns string The filtered name of the host.
26
+ */
27
+ private static function filterName( $name ) {
28
+ if ( function_exists( 'apply_filters' ) ) {
29
+ return (string) apply_filters( strtolower( self::HOST_NAME_KEY ), $name );
30
+ }
31
+
32
+ return $name;
33
+ }
34
+
35
+ /**
36
+ * Retrieves the message from the host if set.
37
+ *
38
+ * @param string $messageKey The key to use as the environment variable.
39
+ *
40
+ * @return string The message as set by the host.
41
+ */
42
+ public static function message( $messageKey ) {
43
+ $message = (string) getenv( $messageKey );
44
+
45
+ return self::filterMessage( $messageKey, $message );
46
+ }
47
+
48
+ /**
49
+ * Filters the message if we are in a WordPress context. In a non-WordPress content this function just returns the passed message.
50
+ *
51
+ * @param string $messageKey The key used for the environment variable.
52
+ * @param string $message The current message from the host.
53
+ *
54
+ * @return string
55
+ */
56
+ private static function filterMessage( $messageKey, $message ) {
57
+ if ( function_exists( 'apply_filters' ) ) {
58
+ return (string) apply_filters( strtolower( $messageKey ), $message );
59
+ }
60
+
61
+ return $message;
62
+ }
63
+
64
+ /**
65
+ * Returns the URL for the hosting page
66
+ *
67
+ * @returns string The URL to the hosting overview page.
68
+ */
69
+ public static function hostingPageUrl() {
70
+ $url = 'https://yoa.st/w3';
71
+
72
+ return self::filterHostingPageUrl( $url );
73
+ }
74
+
75
+ /**
76
+ * Filters the hosting page url if we are in a WordPress context. In a non-WordPress context this function just returns a link to the Yoast hosting page.
77
+ *
78
+ * @param string $url The previous URL.
79
+ * @returns string The new URL to the hosting overview page.
80
+ */
81
+ private static function filterHostingPageUrl( $url ) {
82
+ if ( function_exists( 'apply_filters' ) && apply_filters( self::HOSTING_PAGE_FILTER_KEY, false ) ) {
83
+ return 'https://wordpress.org/hosting/';
84
+ }
85
+
86
+ return $url;
87
+ }
88
+ }
vendor/toolset/toolset-common/lib/whip/src/Whip_MessageDismisser.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A class to dismiss messages.
5
+ */
6
+ class Whip_MessageDismisser {
7
+
8
+ /** @var Whip_DismissStorage */
9
+ protected $storage;
10
+
11
+ /** @var string */
12
+ protected $currentTime;
13
+
14
+ /** @var int */
15
+ protected $threshold;
16
+
17
+ /**
18
+ * Whip_MessageDismisser constructor.
19
+ *
20
+ * @param int $currentTime The current time.
21
+ * @param int $threshold The number of seconds the message will be dismissed.
22
+ * @param Whip_DismissStorage $storage Storage object to manage the dismissal state.
23
+ */
24
+ public function __construct( $currentTime, $threshold, Whip_DismissStorage $storage ) {
25
+ $this->currentTime = $currentTime;
26
+ $this->threshold = $threshold;
27
+ $this->storage = $storage;
28
+ }
29
+
30
+ /**
31
+ * Saves the version number to the storage to indicate the message as being dismissed.
32
+ */
33
+ public function dismiss() {
34
+ $this->storage->set( $this->currentTime );
35
+ }
36
+
37
+ /**
38
+ * Checks if the current time is lower than the stored time extended by the threshold.
39
+ *
40
+ * @return bool True when current time is lower than stored value + threshold.
41
+ */
42
+ public function isDismissed() {
43
+ return ( $this->currentTime <= ( $this->storage->get() + $this->threshold ) );
44
+ }
45
+ }
vendor/toolset/toolset-common/lib/whip/src/Whip_MessageFormatter.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A helper class to format messages
5
+ */
6
+ final class Whip_MessageFormatter {
7
+
8
+ /**
9
+ * Wraps a piece of text in HTML strong tags
10
+ *
11
+ * @param string $toWrap The text to wrap.
12
+ * @return string The wrapped text.
13
+ */
14
+ public static function strong( $toWrap ) {
15
+ return '<strong>' . $toWrap . '</strong>';
16
+ }
17
+
18
+ /**
19
+ * Wraps a piece of text in HTML p tags
20
+ *
21
+ * @param string $toWrap The text to wrap.
22
+ * @return string The wrapped text.
23
+ */
24
+ public static function paragraph( $toWrap ) {
25
+ return '<p>' . $toWrap . '</p>';
26
+ }
27
+
28
+ /**
29
+ * Wraps a piece of text in HTML p and strong tags
30
+ *
31
+ * @param string $toWrap The text to wrap.
32
+ * @return string The wrapped text.
33
+ */
34
+ public static function strongParagraph( $toWrap ) {
35
+ return self::paragraph( self::strong( $toWrap ) );
36
+ }
37
+ }
vendor/toolset/toolset-common/lib/whip/src/Whip_MessagesManager.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Manages messages using a global to prevent duplicate messages.
5
+ */
6
+ class Whip_MessagesManager {
7
+
8
+ /**
9
+ * Whip_MessagesManager constructor.
10
+ */
11
+ public function __construct()
12
+ {
13
+ if ( ! array_key_exists( 'whip_messages', $GLOBALS ) ) {
14
+ $GLOBALS['whip_messages'] = array();
15
+ }
16
+ }
17
+
18
+ /**
19
+ * Adds a message to the Messages Manager.
20
+ *
21
+ * @param Whip_Message $message The message to add.
22
+ */
23
+ public function addMessage( Whip_Message $message ) {
24
+ $whipVersion = require dirname( __FILE__ ) . '/configs/version.php';
25
+
26
+ $GLOBALS[ 'whip_messages' ][$whipVersion] = $message;
27
+ }
28
+
29
+ /**
30
+ * Determines whether or not there are messages available.
31
+ *
32
+ * @return bool Whether or not there are messages available.
33
+ */
34
+ public function hasMessages() {
35
+ return isset( $GLOBALS['whip_messages'] ) && count( $GLOBALS['whip_messages'] ) > 0;
36
+ }
37
+
38
+ /**
39
+ * Lists the messages that are currently available.
40
+ *
41
+ * @return array The messages that are currently set.
42
+ */
43
+ public function listMessages() {
44
+ return $GLOBALS[ 'whip_messages' ];
45
+ }
46
+
47
+ /**
48
+ * Deletes all messages.
49
+ */
50
+ public function deleteMessages() {
51
+ unset( $GLOBALS[ 'whip_messages' ] );
52
+ }
53
+
54
+ /**
55
+ * Gets the latest message.
56
+ *
57
+ * @return Whip_Message The message. Returns a NullMessage if none is found.
58
+ */
59
+ public function getLatestMessage() {
60
+ if ( ! $this->hasMessages() ) {
61
+ return new Whip_NullMessage();
62
+ }
63
+
64
+ $messages = $this->sortByVersion( $this->listMessages() );
65
+
66
+ $this->deleteMessages();
67
+
68
+ return array_pop( $messages );
69
+ }
70
+
71
+ /**
72
+ * Sorts the list of messages based on the version number.
73
+ *
74
+ * @param array $messages The list of messages to sort.
75
+ *
76
+ * @return array The sorted list of messages.
77
+ */
78
+ private function sortByVersion( array $messages ) {
79
+ uksort( $messages, 'version_compare' );
80
+
81
+ return $messages;
82
+ }
83
+ }
vendor/toolset/toolset-common/lib/whip/src/Whip_RequirementsChecker.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Main controller class to require a certain version of software.
5
+ */
6
+ class Whip_RequirementsChecker {
7
+
8
+ /**
9
+ * @var array
10
+ */
11
+ private $requirements;
12
+
13
+ /**
14
+ * @var string
15
+ */
16
+ private $textdomain;
17
+
18
+ /**
19
+ * Whip_RequirementsChecker constructor.
20
+ *
21
+ * @param array $configuration The configuration to check.
22
+ * @param string $textdomain The text domain to use for translations.
23
+ */
24
+ public function __construct( $configuration = array(), $textdomain = 'wordpress' ) {
25
+ $this->requirements = array();
26
+ $this->configuration = new Whip_Configuration( $configuration );
27
+ $this->messageMananger = new Whip_MessagesManager();
28
+ $this->textdomain = $textdomain;
29
+ }
30
+
31
+ /**
32
+ * Adds a requirement to the list of requirements if it doesn't already exist.
33
+ *
34
+ * @param Whip_Requirement $requirement The requirement to add.
35
+ */
36
+ public function addRequirement( Whip_Requirement $requirement ) {
37
+ // Only allow unique entries to ensure we're not checking specific combinations multiple times
38
+ if ( $this->requirementExistsForComponent( $requirement->component() ) ) {
39
+ return;
40
+ }
41
+
42
+ $this->requirements[] = $requirement;
43
+ }
44
+
45
+ /**
46
+ * Determines whether or not there are requirements available.
47
+ *
48
+ * @return bool Whether or not there are requirements.
49
+ */
50
+ public function hasRequirements() {
51
+ return $this->totalRequirements() > 0;
52
+ }
53
+
54
+ /**
55
+ * Gets the total amount of requirements.
56
+ *
57
+ * @return int The total amount of requirements.
58
+ */
59
+ public function totalRequirements() {
60
+ return count( $this->requirements );
61
+ }
62
+
63
+ /**
64
+ * Determines whether or not a requirement exists for a particular component.
65
+ *
66
+ * @param string $component The component to check for.
67
+ *
68
+ * @return bool Whether or not the component has a requirement defined.
69
+ */
70
+ public function requirementExistsForComponent( $component ) {
71
+ foreach ( $this->requirements as $requirement ) {
72
+ if ( $requirement->component() === $component ) {
73
+ return true;
74
+ }
75
+ }
76
+
77
+ return false;
78
+ }
79
+
80
+ /**
81
+ * Determines whether a requirement has been fulfilled.
82
+ *
83
+ * @param Whip_Requirement $requirement The requirement to check.
84
+ *
85
+ * @return bool Whether or not the requirement is fulfilled.
86
+ */
87
+ private function requirementIsFulfilled( Whip_Requirement $requirement ) {
88
+ $available_version = $this->configuration->configuredVersion( $requirement );
89
+ $required_version = $requirement->version();
90
+
91
+ if ( in_array( $requirement->operator(), array( '=', '==', '===' ), true ) ) {
92
+ return -1 !== version_compare( $available_version, $required_version );
93
+ }
94
+
95
+ return version_compare( $available_version, $required_version, $requirement->operator() );
96
+ }
97
+
98
+ /**
99
+ * Checks if all requirements are fulfilled and adds a message to the message manager if necessary.
100
+ */
101
+ public function check() {
102
+ foreach ( $this->requirements as $requirement ) {
103
+ // Match against config
104
+ $requirement_fulfilled = $this->requirementIsFulfilled( $requirement );
105
+
106
+ if ( $requirement_fulfilled ) {
107
+ continue;
108
+ }
109
+
110
+ $this->addMissingRequirementMessage( $requirement );
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Adds a message to the message manager for requirements that cannot be fulfilled.
116
+ *
117
+ * @param Whip_Requirement $requirement The requirement that cannot be fulfilled.
118
+ */
119
+ private function addMissingRequirementMessage( Whip_Requirement $requirement ) {
120
+ switch ( $requirement->component() ) {
121
+ case 'php':
122
+ $this->messageMananger->addMessage( new Whip_UpgradePhpMessage( $this->textdomain ) );
123
+ break;
124
+ default:
125
+ $this->messageMananger->addMessage( new Whip_InvalidVersionRequirementMessage( $requirement, $this->configuration->configuredVersion( $requirement ) ) );
126
+ break;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Determines whether or not there are messages available.
132
+ *
133
+ * @return bool Whether or not there are messages to display.
134
+ */
135
+ public function hasMessages() {
136
+ return $this->messageMananger->hasMessages();
137
+ }
138
+
139
+ /**
140
+ * Gets the most recent message from the message manager.
141
+ *
142
+ * @return Whip_Message The latest message.
143
+ */
144
+ public function getMostRecentMessage() {
145
+ return $this->messageMananger->getLatestMessage();
146
+ }
147
+
148
+ }
vendor/toolset/toolset-common/lib/whip/src/Whip_VersionRequirement.php ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A value object containing a version requirement for a component version.
5
+ */
6
+ class Whip_VersionRequirement implements Whip_Requirement {
7
+ /**
8
+ * @var string
9
+ */
10
+ private $component;
11
+
12
+ /**
13
+ * @var string
14
+ */
15
+ private $version;
16
+
17
+ /**
18
+ * @var string
19
+ */
20
+ private $operator;
21
+
22
+ /**
23
+ * Whip_Requirement constructor.
24
+ *
25
+ * @param string $component
26
+ * @param string $version
27
+ * @param string $operator
28
+ */
29
+ public function __construct( $component, $version, $operator = '=' ) {
30
+ $this->validateParameters( $component, $version, $operator );
31
+
32
+ $this->component = $component;
33
+ $this->version = $version;
34
+ $this->operator = $operator;
35
+ }
36
+
37
+ /**
38
+ * Gets the component name defined for the requirement.
39
+ *
40
+ * @return string The component name.
41
+ */
42
+ public function component() {
43
+ return $this->component;
44
+ }
45
+
46
+ /**
47
+ * Gets the components version defined for the requirement.
48
+ *
49
+ * @return string
50
+ */
51
+ public function version() {
52
+ return $this->version;
53
+ }
54
+
55
+ /**
56
+ * Returns the operator to use when comparing version numbers.
57
+ *
58
+ * @return string The comparison operator.
59
+ */
60
+ public function operator() {
61
+ return $this->operator;
62
+ }
63
+
64
+ /**
65
+ * Creates a new version requirement from a comparison string
66
+ *
67
+ * @throws Whip_InvalidVersionComparisonString When an invalid version comparison string is passed.
68
+ *
69
+ *@param string $component The component for this version requirement.
70
+ * @param string $comparisonString The comparison string for this version requirement.
71
+ *
72
+ *@returns Whip_VersionRequirement The parsed version requirement.
73
+ */
74
+ public static function fromCompareString( $component, $comparisonString ) {
75
+
76
+ $matcher = '(' .
77
+ '(>=?)' . // Matches >= and >.
78
+ '|' .
79
+ '(<=?)' . // Matches <= and <.
80
+ ')' .
81
+ '([^>=<\s]+)'; // Matches anything except >, <, =, and whitespace.
82
+
83
+ if ( ! preg_match( '#' . $matcher . '#', $comparisonString, $match ) ) {
84
+ throw new Whip_InvalidVersionComparisonString( $comparisonString );
85
+ }
86
+
87
+ $version = $match[4];
88
+ $operator = $match[1];
89
+
90
+ return new Whip_VersionRequirement( $component, $version, $operator );
91
+ }
92
+
93
+ /**
94
+ * Validates the parameters passed to the requirement.
95
+ *
96
+ * @param string $component The component name.
97
+ * @param string $version The component version.
98
+ * @param string $operator The operator to use when comparing version.
99
+ *
100
+ * @throws Whip_EmptyProperty
101
+ * @throws Whip_InvalidOperatorType
102
+ * @throws Whip_InvalidType
103
+ */
104
+ private function validateParameters( $component, $version, $operator ) {
105
+ if ( empty( $component ) ) {
106
+ throw new Whip_EmptyProperty( 'Component' );
107
+ }
108
+
109
+ if ( !is_string( $component ) ) {
110
+ throw new Whip_InvalidType( 'Component', 'string', $component );
111
+ }
112
+
113
+ if ( empty( $version ) ) {
114
+ throw new Whip_EmptyProperty( 'Version' );
115
+ }
116
+
117
+ if ( !is_string( $version ) ) {
118
+ throw new Whip_InvalidType( 'Version', 'string', $version );
119
+ }
120
+
121
+ if ( empty( $operator ) ) {
122
+ throw new Whip_EmptyProperty( 'Operator' );
123
+ }
124
+
125
+ if ( !is_string( $operator ) ) {
126
+ throw new Whip_InvalidType( 'Operator', 'string', $operator );
127
+ }
128
+
129
+ if ( ! in_array( $operator, array( '=', '==', '===', '<', '>', '<=', '>=' ), true ) ) {
130
+ throw new Whip_InvalidOperatorType( $operator );
131
+ }
132
+ }
133
+ }
vendor/toolset/toolset-common/lib/whip/src/Whip_WPDismissOption.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Represents the WordPress option for saving the dismissed messages.
5
+ */
6
+ class Whip_WPDismissOption implements Whip_DismissStorage {
7
+
8
+ /** @var string */
9
+ protected $optionName = 'whip_dismiss_timestamp';
10
+
11
+ /**
12
+ * Saves the value to the options.
13
+ *
14
+ * @param int $dismissedValue The value to save.
15
+ *
16
+ * @return bool True when successful.
17
+ */
18
+ public function set( $dismissedValue ) {
19
+ return update_option( $this->optionName, $dismissedValue );
20
+ }
21
+
22
+ /**
23
+ * Returns the value of the whip_dismissed option.
24
+ *
25
+ * @return int Returns the value of the option or an empty string when not set.
26
+ */
27
+ public function get() {
28
+ $dismissedOption = get_option( $this->optionName );
29
+ if ( ! $dismissedOption ) {
30
+ return 0;
31
+ }
32
+
33
+ return (int) $dismissedOption;
34
+ }
35
+
36
+ }
vendor/toolset/toolset-common/lib/whip/src/Whip_WPMessageDismissListener.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Listener for dismissing a message.
5
+ */
6
+ class Whip_WPMessageDismissListener implements Whip_Listener {
7
+
8
+ const ACTION_NAME = 'whip_dismiss';
9
+
10
+ /**
11
+ * @var Whip_MessageDismisser
12
+ */
13
+ protected $dismisser;
14
+
15
+ /**
16
+ * Sets the dismisser attribute.
17
+ *
18
+ * @param Whip_MessageDismisser $dismisser The object for dismissing a message.
19
+ */
20
+ public function __construct( Whip_MessageDismisser $dismisser ) {
21
+ $this->dismisser = $dismisser;
22
+ }
23
+
24
+ /**
25
+ * Listens to a GET request to fetch the required attributes.
26
+ *
27
+ * @return void
28
+ */
29
+ public function listen() {
30
+ $action = filter_input( INPUT_GET, 'action' );
31
+ $nonce = filter_input( INPUT_GET, 'nonce' );
32
+
33
+ if ( $action === self::ACTION_NAME && wp_verify_nonce( $nonce, self::ACTION_NAME ) ) {
34
+ $this->dismisser->dismiss();
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Creates an url for dismissing the notice.
40
+ *
41
+ * @return string The url for dismissing the message.
42
+ */
43
+ public function getDismissURL() {
44
+ return sprintf(
45
+ admin_url( 'index.php?action=%1$s&nonce=%2$s' ),
46
+ self::ACTION_NAME,
47
+ wp_create_nonce( self::ACTION_NAME )
48
+ );
49
+ }
50
+
51
+ }
vendor/toolset/toolset-common/lib/whip/src/configs/default.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ return array(
4
+ 'php' => PHP_VERSION,
5
+ );
vendor/toolset/toolset-common/lib/whip/src/configs/version.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <?php
2
+
3
+ return '1.0.1';
vendor/toolset/toolset-common/lib/whip/src/exceptions/Whip_EmptyProperty.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class EmptyProperty
5
+ */
6
+ class Whip_EmptyProperty extends Exception {
7
+ public function __construct( $property ) {
8
+ parent::__construct( sprintf( '%s cannot be empty.', (string) $property ) );
9
+ }
10
+ }
vendor/toolset/toolset-common/lib/whip/src/exceptions/Whip_InvalidOperatorType.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class InvalidOperatorType
5
+ */
6
+ class Whip_InvalidOperatorType extends Exception {
7
+
8
+ private $validOperators = array( '=', '==', '===', '<', '>', '<=', '>=' );
9
+
10
+ /**
11
+ * InvalidOperatorType constructor.
12
+ *
13
+ * @param string $value
14
+ */
15
+ public function __construct( $value ) {
16
+ parent::__construct(
17
+ sprintf( 'Invalid operator of %s used. Please use one of the following operators: %s',
18
+ $value,
19
+ implode( ', ', $this->validOperators )
20
+ ) );
21
+ }
22
+ }
vendor/toolset/toolset-common/lib/whip/src/exceptions/Whip_InvalidType.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class InvalidType
5
+ */
6
+ class Whip_InvalidType extends Exception {
7
+
8
+ /**
9
+ * InvalidType constructor.
10
+ *
11
+ * @param string $property
12
+ * @param string $value
13
+ * @param string $expectedType
14
+ */
15
+ public function __construct( $property, $value, $expectedType ) {
16
+ parent::__construct( sprintf( '%s should be of type %s. Found %s.', $property, $expectedType, gettype( $value ) ) );
17
+ }
18
+ }
vendor/toolset/toolset-common/lib/whip/src/exceptions/Whip_InvalidVersionComparisonString.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Exception for an invalid version comparison string
5
+ */
6
+ class Whip_InvalidVersionComparisonString extends Exception {
7
+
8
+ /**
9
+ * @param string $value The passed version comparison string.
10
+ */
11
+ public function __construct( $value ) {
12
+ parent::__construct(
13
+ sprintf(
14
+ 'Invalid version comparison string. Example of a valid version comparison string: >=5.3. Passed version comparison string: %s',
15
+ $value
16
+ )
17
+ );
18
+ }
19
+ }
vendor/toolset/toolset-common/lib/whip/src/facades/wordpress.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! function_exists( 'whip_wp_check_versions' ) ) {
4
+ /**
5
+ * Facade to quickly check if version requirements are met.
6
+ *
7
+ * @param array $requirements The requirements to check.
8
+ */
9
+ function whip_wp_check_versions( $requirements ) {
10
+ // Only show for admin users.
11
+ if ( ! is_array( $requirements ) ) {
12
+ return;
13
+ }
14
+
15
+ $config = include dirname( __FILE__ ) . '/../configs/default.php';
16
+ $checker = new Whip_RequirementsChecker( $config );
17
+
18
+ foreach ( $requirements as $component => $versionComparison ) {
19
+ $checker->addRequirement( Whip_VersionRequirement::fromCompareString( $component, $versionComparison ) );
20
+ }
21
+
22
+ $checker->check();
23
+
24
+ if ( ! $checker->hasMessages() ) {
25
+ return;
26
+ }
27
+
28
+ $dismissThreshold = WEEK_IN_SECONDS * 4;
29
+ $dismissMessage = __( 'Remind me again in 4 weeks.', 'wordpress' );
30
+
31
+ $dismisser = new Whip_MessageDismisser( time(), $dismissThreshold, new Whip_WPDismissOption() );
32
+
33
+ $presenter = new Whip_WPMessagePresenter( $checker->getMostRecentMessage(), $dismisser, $dismissMessage );
34
+ $presenter->register_hooks();
35
+ }
36
+ }
vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_DismissStorage.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface Whip_DismissStorage.
5
+ */
6
+ interface Whip_DismissStorage {
7
+
8
+ /**
9
+ * Saves the value.
10
+ *
11
+ * @param int $dismissedValue The value to save.
12
+ *
13
+ * @return bool True when successful.
14
+ */
15
+ public function set( $dismissedValue );
16
+
17
+ /**
18
+ * Returns the value.
19
+ *
20
+ * @return int The stored value.
21
+ */
22
+ public function get();
23
+
24
+ }
vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_Listener.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface Whip_Listener.
5
+ */
6
+ interface Whip_Listener {
7
+
8
+ /**
9
+ * Method that should implement the listen functionality.
10
+ *
11
+ * @return void
12
+ */
13
+ public function listen();
14
+
15
+ }
vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_Message.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface Whip_Message
5
+ */
6
+ interface Whip_Message {
7
+ public function body();
8
+ }
vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_MessagePresenter.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ interface Whip_MessagePresenter {
5
+
6
+ /**
7
+ * Renders the message.
8
+ */
9
+ public function renderMessage();
10
+ }
vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_Requirement.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface Whip_Requirement
5
+ */
6
+ interface Whip_Requirement {
7
+ public function component();
8
+ }
vendor/toolset/toolset-common/lib/whip/src/interfaces/Whip_VersionDetector.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * An interface that represents a version detector and message.
5
+ */
6
+ interface Whip_VersionDetector {
7
+
8
+ /**
9
+ * Detects the version of the installed software
10
+ *
11
+ * @return string
12
+ */
13
+ public function detect();
14
+
15
+ /**
16
+ * Returns the message that should be shown if a version is not deemed appropriate by the implementation.
17
+ *
18
+ * @return string
19
+ */
20
+ public function getMessage();
21
+ }
vendor/toolset/toolset-common/lib/whip/src/messages/Whip_BasicMessage.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Whip_Message
5
+ */
6
+ class Whip_BasicMessage implements Whip_Message {
7
+ /**
8
+ * @var string
9
+ */
10
+ private $body;
11
+
12
+ /**
13
+ * Whip_Message constructor.
14
+ *
15
+ * @param string $body
16
+ *
17
+ * @throws Whip_EmptyProperty
18
+ * @throws Whip_InvalidType
19
+ */
20
+ public function __construct($body) {
21
+ $this->validateParameters( $body );
22
+
23
+ $this->body = $body;
24
+ }
25
+
26
+ /**
27
+ * @return string
28
+ */
29
+ public function body() {
30
+ return $this->body;
31
+ }
32
+
33
+ private function validateParameters( $body ) {
34
+ if ( empty( $body ) ) {
35
+ throw new Whip_EmptyProperty( 'Message body' );
36
+ }
37
+
38
+ if ( ! is_string( $body ) ) {
39
+ throw new Whip_InvalidType( 'Message body', "string", $body );
40
+ }
41
+ }
42
+ }
vendor/toolset/toolset-common/lib/whip/src/messages/Whip_HostMessage.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Whip_HostMessage
5
+ */
6
+ class Whip_HostMessage implements Whip_Message {
7
+
8
+ /**
9
+ * @var string
10
+ */
11
+ private $textdomain;
12
+
13
+ /**
14
+ * @var string
15
+ */
16
+ private $messageKey;
17
+
18
+ /**
19
+ * @var string
20
+ */
21
+ private $filterKey;
22
+
23
+ /**
24
+ * Whip_Message constructor.
25
+ *
26
+ * @param string $messageKey The environment key to use to retrieve the message from.
27
+ * @param string $textdomain The text domain to use for translations.
28
+ */
29
+ public function __construct( $messageKey, $textdomain ) {
30
+ $this->textdomain = $textdomain;
31
+ $this->messageKey = $messageKey;
32
+ }
33
+
34
+ /**
35
+ * Renders the message body.
36
+ *
37
+ * @return string The message body.
38
+ */
39
+ public function body() {
40
+ $message = array();
41
+
42
+ $message[] = Whip_MessageFormatter::strong( $this->title() ) . '<br />';
43
+ $message[] = Whip_MessageFormatter::paragraph( Whip_Host::message( $this->messageKey, $this->filterKey ) );
44
+
45
+ return implode( $message, "\n" );
46
+ }
47
+
48
+ /**
49
+ * Renders the message title.
50
+ *
51
+ * @return string The message title.
52
+ */
53
+ public function title() {
54
+ return sprintf( __( 'A message from %1$s', $this->textdomain ), Whip_Host::name() );
55
+ }
56
+ }
vendor/toolset/toolset-common/lib/whip/src/messages/Whip_InvalidVersionRequirementMessage.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Whip_InvalidVersionMessage
5
+ */
6
+ class Whip_InvalidVersionRequirementMessage implements Whip_Message {
7
+
8
+ private $requirement;
9
+ /**
10
+ * @var
11
+ */
12
+ private $detected;
13
+
14
+ /**
15
+ * Whip_InvalidVersionRequirementMessage constructor.
16
+ *
17
+ * @param Whip_Requirement $requirement
18
+ * @param $detected
19
+ */
20
+ public function __construct( Whip_VersionRequirement $requirement, $detected )
21
+ {
22
+ $this->requirement = $requirement;
23
+ $this->detected = $detected;
24
+ }
25
+
26
+ /**
27
+ * @return string
28
+ */
29
+ public function body() {
30
+ return sprintf(
31
+ 'Invalid version detected for %s. Found %s but expected %s.',
32
+ $this->requirement->component(),
33
+ $this->detected,
34
+ $this->requirement->version()
35
+ );
36
+ }
37
+ }
vendor/toolset/toolset-common/lib/whip/src/messages/Whip_NullMessage.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Whip_Message
5
+ */
6
+ class Whip_NullMessage implements Whip_Message {
7
+ /**
8
+ * @return string
9
+ */
10
+ public function body() {
11
+ return '';
12
+ }
13
+ }
vendor/toolset/toolset-common/lib/whip/src/messages/Whip_UpgradePhpMessage.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Whip_UpgradePhpMessage
5
+ */
6
+ class Whip_UpgradePhpMessage implements Whip_Message {
7
+ /**
8
+ * @var string
9
+ */
10
+ private $textdomain;
11
+
12
+ /**
13
+ * Whip_UpgradePhpMessage constructor.
14
+ *
15
+ * @param string $textdomain The text domain to use for the translations.
16
+ */
17
+ public function __construct( $textdomain ) {
18
+ $this->textdomain = $textdomain;
19
+ }
20
+
21
+ /**
22
+ * Composes the body of the message to display.
23
+ *
24
+ * @return string The message to display.
25
+ */
26
+ public function body() {
27
+ $textdomain = $this->textdomain;
28
+
29
+ $message = array();
30
+
31
+ $message[] = Whip_MessageFormatter::strongParagraph( __( 'Your site could be faster and more secure with a newer PHP version.', $textdomain ) ) . '<br />';
32
+ $message[] = Whip_MessageFormatter::paragraph( __( 'Hey, we\'ve noticed that you\'re running an outdated version of PHP. PHP is the programming language that WordPress and Toolset are built on. The version that is currently used for your site is no longer supported. Newer versions of PHP are both faster and more secure. In fact, your version of PHP no longer receives security updates, which is why we\'re sending you to this notice.', $textdomain ) );
33
+ $message[] = Whip_MessageFormatter::paragraph( __( 'Hosts have the ability to update your PHP version, but sometimes they don\'t dare to do that because they\'re afraid they\'ll break your site.', $textdomain ) );
34
+ $message[] = Whip_MessageFormatter::strongParagraph( __( 'To which version should I update?', $textdomain ) ) . '<br />';
35
+ $message[] = Whip_MessageFormatter::paragraph( sprintf( __( 'You should update your PHP version to either 5.6 or to 7.0 or 7.1. On a normal WordPress site, switching to PHP 5.6 should never cause issues. We would however actually recommend you switch to PHP7. There are some plugins that are not ready for PHP7 though, so do some testing first. There is a WordPress plugin that can test whether that\'s an option for you %1$shere%2$s. PHP7 is much faster than PHP 5.6. It\'s also the only PHP version still in active development and therefore the better option for your site in the long run.', $textdomain ), '<a href="https://wordpress.org/plugins/php-compatibility-checker/" target="_blank">', '</a>' ) );
36
+
37
+ if ( Whip_Host::name() !== '' ) {
38
+ $hostMessage = new Whip_HostMessage( 'WHIP_MESSAGE_FROM_HOST_ABOUT_PHP', $textdomain );
39
+ $message[] = $hostMessage->body();
40
+ }
41
+
42
+ $hostingPageUrl = Whip_Host::hostingPageUrl();
43
+
44
+ $message[] = Whip_MessageFormatter::strongParagraph( __( 'Can\'t update? Ask your host!', $textdomain ) ) . '<br />';
45
+ $message[] = Whip_MessageFormatter::paragraph( sprintf( __( 'If you cannot upgrade your PHP version yourself, you can send an email to your host. There are some %1$sexamples here%2$s. If they don\'t want to upgrade your PHP version, we would suggest you switch hosts. Have a look at one of the recommended %3$sWordPress hosting partners%4$s recommended by Yoast.', $textdomain ), '<a href="https://yoa.st/wh" target="_blank">', '</a>', sprintf( '<a href="%1$s" target="_blank">', esc_url( $hostingPageUrl ) ), '</a>' ) );
46
+
47
+ return implode( $message, "\n" );
48
+ }
49
+
50
+ }
vendor/toolset/toolset-common/lib/whip/src/presenters/Whip_WPMessagePresenter.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A message presenter to show a WordPress notice.
5
+ */
6
+ class Whip_WPMessagePresenter implements Whip_MessagePresenter {
7
+
8
+ /** @var string The string to show to dismiss the message. */
9
+ private $dismissMessage;
10
+
11
+ /** @var Whip_Message The message to be displayed */
12
+ private $message;
13
+
14
+ /** @var Whip_MessageDismisser */
15
+ private $dismisser;
16
+
17
+ /**
18
+ * Whip_WPMessagePresenter constructor.
19
+ *
20
+ * @param Whip_Message $message The message to use in the presenter.
21
+ * @param Whip_MessageDismisser $dismisser Dismisser object.
22
+ * @param string $dismissMessage The copy to show to dismiss the message.
23
+ */
24
+ public function __construct( Whip_Message $message, Whip_MessageDismisser $dismisser, $dismissMessage ) {
25
+ $this->message = $message;
26
+ $this->dismisser = $dismisser;
27
+ $this->dismissMessage = $dismissMessage;
28
+ }
29
+
30
+ /**
31
+ * Registers hooks to WordPress. This is a separate function so you can
32
+ * control when the hooks are registered.
33
+ *
34
+ */
35
+ public function register_hooks() {
36
+ global $whip_admin_notices_added;
37
+
38
+ if ( null === $whip_admin_notices_added || ! $whip_admin_notices_added ) {
39
+ add_action( 'admin_notices', array( $this, 'renderMessage' ) );
40
+ $whip_admin_notices_added = true;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Renders the messages present in the global to notices.
46
+ */
47
+ public function renderMessage() {
48
+ $dismissListener = new Whip_WPMessageDismissListener( $this->dismisser );
49
+ $dismissListener->listen();
50
+
51
+ if ( $this->dismisser->isDismissed() ) {
52
+ return;
53
+ }
54
+
55
+ $dismissButton = sprintf(
56
+ '<a href="%2$s">%1$s</a>',
57
+ $this->dismissMessage,
58
+ $dismissListener->getDismissURL()
59
+ );
60
+
61
+ printf( '<div class="error"><p>%1$s</p><p>%2$s</p></div>', $this->kses( $this->message->body() ), $dismissButton );
62
+ }
63
+
64
+ /**
65
+ * Removes content from the message that we don't want to show.
66
+ *
67
+ * @param string $message The message to clean.
68
+ *
69
+ * @return string The cleaned message.
70
+ */
71
+ public function kses( $message ) {
72
+ return wp_kses( $message, array(
73
+ 'a' => array(
74
+ 'href' => true,
75
+ 'target' => true,
76
+ ),
77
+ 'strong' => true,
78
+ 'p' => true,
79
+ 'ul' => true,
80
+ 'li' => true,
81
+ ) );
82
+ }
83
+ }
vendor/toolset/toolset-common/loader.php CHANGED
@@ -27,7 +27,7 @@
27
  * Now that we have a unique version for all plugins
28
  * we define the version here
29
  */
30
- $toolset_common_version = 258001;
31
 
32
 
33
  /* ---------------------------------------------------------------------- *\
@@ -88,4 +88,4 @@ if ( ! function_exists( 'toolset_common_initialize' ) ) {
88
  }
89
  }
90
  }
91
- }
27
  * Now that we have a unique version for all plugins
28
  * we define the version here
29
  */
30
+ $toolset_common_version = 262000;
31
 
32
 
33
  /* ---------------------------------------------------------------------- *\
88
  }
89
  }
90
  }
91
+ }
vendor/toolset/toolset-common/recreate_classmap.sh CHANGED
@@ -42,11 +42,12 @@ echo
42
  # the main plugin structure - overwrites existing classmap
43
  echo "Generating classmap for autoloaded classes..."
44
  php "$GENERATOR" --library ./inc/autoloaded --output ./autoload_classmap.php --overwrite
45
- php "$GENERATOR" --library ./inc/controller --output ./autoload_classmap.php --append
46
  php "$GENERATOR" --library ./utility/admin --output ./autoload_classmap.php --append
47
  php "$GENERATOR" --library ./utility/condition --output ./autoload_classmap.php --append
 
48
  php "$GENERATOR" --library ./user-editors --output ./autoload_classmap.php --append
49
  php "$GENERATOR" --library ./expression-parser --output ./autoload_classmap.php --append
 
50
  sort_classmap ./autoload_classmap.php
51
  echo
52
 
42
  # the main plugin structure - overwrites existing classmap
43
  echo "Generating classmap for autoloaded classes..."
44
  php "$GENERATOR" --library ./inc/autoloaded --output ./autoload_classmap.php --overwrite
 
45
  php "$GENERATOR" --library ./utility/admin --output ./autoload_classmap.php --append
46
  php "$GENERATOR" --library ./utility/condition --output ./autoload_classmap.php --append
47
+ php "$GENERATOR" --library ./toolset-blocks --output ./autoload_classmap.php --append
48
  php "$GENERATOR" --library ./user-editors --output ./autoload_classmap.php --append
49
  php "$GENERATOR" --library ./expression-parser --output ./autoload_classmap.php --append
50
+ php "$GENERATOR" --library ./lib/whip/src --output ./autoload_classmap.php --append
51
  sort_classmap ./autoload_classmap.php
52
  echo
53
 
vendor/toolset/toolset-common/res/css/toolset-dialogs.css CHANGED
@@ -26,6 +26,12 @@
26
  }
27
  .toolset-ui-dialog .ui-dialog-title {
28
  float: none !important;
 
 
 
 
 
 
29
  }
30
  .toolset-ui-dialog .ui-widget{
31
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", "Open Sans", sans-serif;
@@ -81,7 +87,7 @@
81
  filter: alpha(opacity=70) !important;
82
  z-index: 100101;
83
  }
84
- .toolset-ui-dialog .ui-button.ui-dialog-titlebar-close {
85
  background: 0 0 !important;
86
  border: none !important;
87
  -webkit-box-shadow: none !important;
@@ -98,7 +104,7 @@
98
  height: 36px !important;
99
  text-align: center !important;
100
  }
101
- .toolset-ui-dialog .ui-button.ui-dialog-titlebar-close:hover {
102
  color: #00a0d2 !important;
103
  }
104
  .toolset-ui-dialog .ui-icon {
@@ -166,6 +172,14 @@
166
  font-size: 11px !important;
167
  letter-spacing: normal;
168
  }
 
 
 
 
 
 
 
 
169
  /**
170
  * Shortcodes dialogs styles: listing dialog.
171
  */
@@ -302,6 +316,7 @@
302
 
303
  .toolset-shortcode-gui-dialog-container + .ui-dialog-buttonpane button {
304
  float: left;
 
305
  margin-right: 10px;
306
  }
307
 
@@ -318,13 +333,73 @@
318
  .toolset-shortcode-gui-dialog-container .toolset-mightlong-list {
319
  margin: 0;
320
  }
321
- .toolset-shortcode-gui-dialog-container .toolset-mightlong-list > li {
322
  min-height: 24px;
323
  min-width: 45%;
324
  float: left;
325
  padding-right: 4%;
326
  margin: 0 0 6px;
327
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  /*********************************************
329
  Toolset Confirmation Dialog
330
 
@@ -332,14 +407,13 @@ Toolset Confirmation Dialog
332
 
333
  *********************************************/
334
  .toolset-confirmation-dialog {
 
 
335
  display: flex;
336
  }
337
  .toolset-confirmation-dialog-icon {
338
  padding: 17px 15px 20px;
339
- box-sizing: border-box;
340
- }
341
- .toolset-confirmation-dialog-content {
342
- padding: 15px;
343
  box-sizing: border-box;
344
  }
345
  @media (min-width: 768px) {
@@ -349,5 +423,9 @@ Toolset Confirmation Dialog
349
  }
350
  }
351
  .toolset-confirmation-dialog-content {
352
-
 
 
 
 
353
  }
26
  }
27
  .toolset-ui-dialog .ui-dialog-title {
28
  float: none !important;
29
+ display: block;
30
+ white-space: nowrap;
31
+ width: 100%;
32
+ overflow: hidden;
33
+ text-overflow: ellipsis;
34
+
35
  }
36
  .toolset-ui-dialog .ui-widget{
37
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", "Open Sans", sans-serif;
87
  filter: alpha(opacity=70) !important;
88
  z-index: 100101;
89
  }
90
+ .toolset-ui-dialog .ui-dialog-titlebar-close {
91
  background: 0 0 !important;
92
  border: none !important;
93
  -webkit-box-shadow: none !important;
104
  height: 36px !important;
105
  text-align: center !important;
106
  }
107
+ .toolset-ui-dialog .ui-dialog-titlebar-close:hover {
108
  color: #00a0d2 !important;
109
  }
110
  .toolset-ui-dialog .ui-icon {
172
  font-size: 11px !important;
173
  letter-spacing: normal;
174
  }
175
+ .toolset-ui-dialog .toolset-option-helper-text {
176
+ display: block;
177
+ color: #999;
178
+ font-size: 0.9em;
179
+ }
180
+ .toolset-ui-dialog .toolset-option-label-disabled {
181
+ color: #999;
182
+ }
183
  /**
184
  * Shortcodes dialogs styles: listing dialog.
185
  */
316
 
317
  .toolset-shortcode-gui-dialog-container + .ui-dialog-buttonpane button {
318
  float: left;
319
+ margin-left: 0;
320
  margin-right: 10px;
321
  }
322
 
333
  .toolset-shortcode-gui-dialog-container .toolset-mightlong-list {
334
  margin: 0;
335
  }
336
+ .toolset-shortcode-gui-dialog-container .toolset-mightlong-list > li {
337
  min-height: 24px;
338
  min-width: 45%;
339
  float: left;
340
  padding-right: 4%;
341
  margin: 0 0 6px;
342
  }
343
+ /**
344
+ * Shortcodes dialogs styles: shortcodes wizard.
345
+ */
346
+ .toolset-shortcode-gui-wizard-options-container {
347
+ display: flex;
348
+ text-align: center;
349
+ }
350
+ .toolset-shortcode-gui-wizard-option {
351
+ position: relative;
352
+ flex: 1;
353
+ margin: 0 10px 0 0;
354
+ padding: 10px;
355
+ background: #fafafa;
356
+ border: solid 1px #ccc;
357
+ border-radius: 5px;
358
+ vertical-align: top;
359
+ }
360
+ .toolset-shortcode-gui-wizard-option:last-child {
361
+ margin: 0;
362
+ }
363
+ .toolset-shortcode-gui-wizard-option-selected.toolset-shortcode-gui-wizard-option-has-settings::before,
364
+ .toolset-shortcode-gui-wizard-option-selected.toolset-shortcode-gui-wizard-option-has-settings::after{
365
+ content: '';
366
+ position: absolute;
367
+ left: 42%;
368
+ top: 100%;
369
+ width: 0;
370
+ height: 0;
371
+ border-left: 20px solid transparent;
372
+ border-right: 20px solid transparent;
373
+ border-top: 20px solid #e4e4e4;
374
+ clear: both;
375
+ }
376
+ .toolset-shortcode-gui-wizard-option-selected.toolset-shortcode-gui-wizard-option-has-settings::before {
377
+ border-color: #999 transparent transparent transparent;
378
+ border-width: 21px;
379
+ }
380
+ .toolset-shortcode-gui-wizard-option input[type="radio"].toolset-shortcode-gui-wizard-option-hidden {
381
+ display: none;
382
+ }
383
+ .toolset-shortcode-gui-wizard-option-selected {
384
+ background: #e4e4e4;
385
+ border-color: #999;
386
+ }
387
+ .toolset-shortcode-gui-wizard-option-disabled {
388
+ background: #fff;
389
+ }
390
+ .toolset-shortcode-gui-wizard-option-disabled * {
391
+ color: #999;
392
+ }
393
+ .toolset-shortcode-gui-wizard-option-icon {
394
+ display: inline-block;
395
+ width: 100%;
396
+ padding-bottom: 10px;
397
+ }
398
+ .toolset-shortcode-gui-wizard-option-extra {
399
+ padding: 0 30px;
400
+ margin-top: 30px;
401
+ border-top: solid 1px #ccc;
402
+ }
403
  /*********************************************
404
  Toolset Confirmation Dialog
405
 
407
 
408
  *********************************************/
409
  .toolset-confirmation-dialog {
410
+ display: -webkit-box;
411
+ display: -ms-flexbox;
412
  display: flex;
413
  }
414
  .toolset-confirmation-dialog-icon {
415
  padding: 17px 15px 20px;
416
+ -webkit-box-sizing: border-box;
 
 
 
417
  box-sizing: border-box;
418
  }
419
  @media (min-width: 768px) {
423
  }
424
  }
425
  .toolset-confirmation-dialog-content {
426
+ padding: 15px;
427
+ box-sizing: border-box;
428
+ }
429
+ .toolset-confirmation-dialog-content > :first-child {
430
+ margin-top: 0;
431
  }
vendor/toolset/toolset-common/res/css/toolset-notifications.css CHANGED
@@ -240,6 +240,16 @@ span.toolset-alert {
240
  /* TOOLSET POINTERS */
241
  /* ---------------- */
242
 
 
 
 
 
 
 
 
 
 
 
243
  .wp-toolset-pointer .wp-pointer-content {
244
  border: 1px solid #EF6223;
245
  background: #e9e9e9;
240
  /* TOOLSET POINTERS */
241
  /* ---------------- */
242
 
243
+ .wp-toolset-pointer-trigger {
244
+ cursor: pointer;
245
+ color: #0073aa;
246
+ vertical-align: middle;
247
+ }
248
+
249
+ .wp-toolset-pointer-content {
250
+ display: none;
251
+ }
252
+
253
  .wp-toolset-pointer .wp-pointer-content {
254
  border: 1px solid #EF6223;
255
  background: #e9e9e9;
vendor/toolset/toolset-common/res/js/toolset-bs-component-grids.js CHANGED
@@ -244,6 +244,14 @@ ToolsetCommon.BootstrapCssComponentsGrids = function( $ ) {
244
  .find( '.js-code-editor-toolbar > ul' );
245
  appendGridButtonIfMissing( toolbarList, toolbarButton );
246
  break;
 
 
 
 
 
 
 
 
247
  case 'content':
248
  // CRED main editors
249
  if (
244
  .find( '.js-code-editor-toolbar > ul' );
245
  appendGridButtonIfMissing( toolbarList, toolbarButton );
246
  break;
247
+ case 'cred_association_form_content':
248
+ // CRED association forms editor
249
+ var toolbarButton = $( button ),
250
+ toolbarList = editor
251
+ .closest( '#association_form_content' )
252
+ .find( '.js-cred-content-editor-toolbar' );
253
+ appendGridButtonIfMissing( toolbarList, toolbarButton );
254
+ break;
255
  case 'content':
256
  // CRED main editors
257
  if (
vendor/toolset/toolset-common/res/js/toolset-media-manager.js ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * API and helper functions for media buttons over custom editors and inputs.
3
+ *
4
+ * @since m2m
5
+ * @package Toolset
6
+ * @todo add support for input media buttons, with audio/video/image/file restrictions
7
+ */
8
+
9
+ var Toolset = Toolset || {};
10
+
11
+ var Toolset = Toolset || {};
12
+ if ( typeof Toolset.mediaManager === "undefined" ) {
13
+ Toolset.mediaManager = {};
14
+ }
15
+
16
+ Toolset.mediaManager.Class = function( $ ) {
17
+
18
+ var self = this;
19
+
20
+ self.wpMediaEditor = wp.media.editor;
21
+
22
+ self.editorSelector = '.js-toolset-editor-media-manager';
23
+ self.inputSelector = '.js-toolset-input-media-manager';
24
+
25
+ self.instances = {
26
+ editor: {},
27
+ input: {}
28
+ };
29
+
30
+ self.getPostId = function( $mediaButton ) {
31
+ var referredId = $mediaButton.data( 'postid' ),
32
+ postId = 0;
33
+
34
+ if ( referredId ) {
35
+ postId = parseInt( referredId ) || 0;
36
+ }
37
+
38
+ return postId;
39
+ };
40
+
41
+ self.setTarget = function( $mediaButton ) {
42
+ var targetId = $mediaButton.data( 'target' );
43
+
44
+ if ( targetId ) {
45
+ window.wpcfActiveEditor = targetId;
46
+ }
47
+ };
48
+
49
+ self.getInstanceKey = function( postId ) {
50
+ return 'toolsetMediaFor' + postId;
51
+ };
52
+
53
+ self.setEditorMediaManagerEvents = function( instanceKey ) {
54
+ // Watch changes in wp-includes/js/media-editor.js
55
+ var workflow = self.instances.editor[ instanceKey ];
56
+
57
+ self.instances.editor[ instanceKey ].on( 'insert', function() {
58
+
59
+ var state = self.instances.editor[ instanceKey ].state(),
60
+ selection = state.get( 'selection' );
61
+
62
+ if ( ! selection ) {
63
+ return;
64
+ }
65
+
66
+ $.when.apply( $, selection.map( function( attachment ) {
67
+ var display = state.display( attachment ).toJSON();
68
+ return self.wpMediaEditor.send.attachment( display, attachment.toJSON() );
69
+ }, self.wpMediaEditor ) ).done( function() {
70
+ icl_editor.insert( _.toArray( arguments ).join('\n\n') );
71
+ });
72
+ });
73
+
74
+ workflow.state( 'gallery-edit' ).on( 'update', function( selection ) {
75
+ icl_editor.insert( wp.media.gallery.shortcode( selection ).string() );
76
+ }, self.wpMediaEditor );
77
+
78
+ workflow.state( 'playlist-edit' ).on( 'update', function( selection ) {
79
+ icl_editor.insert( wp.media.playlist.shortcode( selection ).string() );
80
+ }, self.wpMediaEditor );
81
+
82
+ workflow.state( 'video-playlist-edit' ).on( 'update', function( selection ) {
83
+ icl_editor.insert( wp.media.playlist.shortcode( selection ).string() );
84
+ }, self.wpMediaEditor );
85
+
86
+ workflow.state( 'embed' ).on( 'select', function() {
87
+ var state = workflow.state(),
88
+ type = state.get( 'type' ),
89
+ embed = state.props.toJSON();
90
+
91
+ embed.url = embed.url || '';
92
+
93
+ if ( 'link' === type ) {
94
+ _.defaults( embed, {
95
+ linkText: embed.url,
96
+ linkUrl: embed.url
97
+ });
98
+
99
+ self.wpMediaEditor.send.link( embed ).done( function( resp ) {
100
+ icl_editor.insert( resp );
101
+ });
102
+
103
+ } else if ( 'image' === type ) {
104
+ _.defaults( embed, {
105
+ title: embed.url,
106
+ linkUrl: '',
107
+ align: 'none',
108
+ link: 'none'
109
+ });
110
+
111
+ if ( 'none' === embed.link ) {
112
+ embed.linkUrl = '';
113
+ } else if ( 'file' === embed.link ) {
114
+ embed.linkUrl = embed.url;
115
+ }
116
+
117
+ icl_editor.insert( wp.media.string.image( embed ) );
118
+ }
119
+ }, self.wpMediaEditor );
120
+ };
121
+
122
+ $( document ).on( 'click', self.editorSelector, function( e ) {
123
+ e.preventDefault();
124
+ var $mediaButton = $( this ),
125
+ postId = self.getPostId( $mediaButton ),
126
+ instanceKey = self.getInstanceKey( postId );
127
+
128
+ self.setTarget( $mediaButton );
129
+
130
+ if ( _.has( self.instances.editor, instanceKey ) ) {
131
+ self.instances.editor[ instanceKey ].open();
132
+ return;
133
+ }
134
+
135
+ wp.media.model.settings.post.id = postId;
136
+
137
+ self.instances.editor[ instanceKey ] = wp.media({
138
+ className: 'media-frame js-toolset-media-frame',
139
+ frame: 'post'
140
+ });
141
+
142
+ self.setEditorMediaManagerEvents( instanceKey );
143
+
144
+ self.instances.editor[ instanceKey ].open();
145
+
146
+ });
147
+
148
+ };
149
+
150
+ jQuery( document ).ready( function( $ ) {
151
+ Toolset.mediaManager.main = new Toolset.mediaManager.Class( $ );
152
+ });
vendor/toolset/toolset-common/res/js/toolset-shortcode.js CHANGED
@@ -151,7 +151,14 @@ Toolset.shortcodeManager = function( $ ) {
151
  *
152
  * @since 2.5.4
153
  */
154
- Toolset.hooks.addFilter( 'toolset-filter-get-crafted-shortcode', self.getCraftedShortcode );
 
 
 
 
 
 
 
155
 
156
  /**
157
  * Return the current crafted shortcode with the current dialog GUI attrbutes.
@@ -212,6 +219,13 @@ Toolset.shortcodeManager = function( $ ) {
212
  */
213
  Toolset.hooks.addAction( 'toolset-action-shortcode-dialog-loaded', self.initSelect2 );
214
 
 
 
 
 
 
 
 
215
  return self;
216
 
217
  };
@@ -230,6 +244,7 @@ Toolset.shortcodeManager = function( $ ) {
230
  self.templates.attributeGroupWrapper = wp.template( 'toolset-shortcode-attribute-group-wrapper' );
231
  self.templates.attributes = {
232
  content: wp.template( 'toolset-shortcode-content' ),
 
233
  text: wp.template( 'toolset-shortcode-attribute-text' ),
234
  radio: wp.template( 'toolset-shortcode-attribute-radio' ),
235
  select: wp.template( 'toolset-shortcode-attribute-select' ),
@@ -368,12 +383,12 @@ Toolset.shortcodeManager = function( $ ) {
368
  });
369
 
370
  /**
371
- * Init select2 and ajaxSelect2 attribute controls.
372
  *
373
  * @since 2.5.4
374
  */
375
- self.initSelect2 = function() {
376
- $( '.js-toolset-shortcode-gui-dialog-container .js-toolset-shortcode-gui-field-select2' ).each( function() {
377
  var selector = $( this ),
378
  selectorParent = selector.closest( '.js-toolset-shortcode-gui-dialog-container' );
379
 
@@ -392,12 +407,16 @@ Toolset.shortcodeManager = function( $ ) {
392
  .$dropdown
393
  .addClass( 'toolset_select2-dropdown-in-dialog' );
394
  });
395
-
396
- $( '.js-toolset-shortcode-gui-dialog-container .js-toolset-shortcode-gui-field-ajax-select2' ).each( function() {
397
- var selector = $( this ),
398
- selectorParent = selector.closest( '.js-toolset-shortcode-gui-dialog-container' );
399
-
400
- selector
 
 
 
 
401
  .addClass( 'js-toolset-shortcode-gui-field-select2-inited' )
402
  .css( { width: '100%' } )
403
  .toolset_select2(
@@ -406,18 +425,22 @@ Toolset.shortcodeManager = function( $ ) {
406
  dropdownAutoWidth: true,
407
  dropdownParent: selectorParent,
408
  placeholder: selector.data( 'placeholder' ),
 
409
  ajax: {
410
- url: toolset_shortcode_i18n.ajaxurl + '?action=' + selector.data( 'action' ) + '&nonce=' + selector.data( 'nonce' ),
411
  dataType: 'json',
412
  delay: 250,
413
  type: 'post',
414
  data: function( params ) {
415
  return {
416
- s: params.term,
417
- page: params.page,
 
 
418
  };
419
  },
420
- processResults: function( response, params ) {
 
421
  params.page = params.page || 1;
422
  if ( response.success ) {
423
  return {
@@ -435,9 +458,98 @@ Toolset.shortcodeManager = function( $ ) {
435
  .data( 'toolset_select2' )
436
  .$dropdown
437
  .addClass( 'toolset_select2-dropdown-in-dialog' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
  });
439
  };
440
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
441
  /**
442
  * Clean validation errors on input change.
443
  *
@@ -445,6 +557,13 @@ Toolset.shortcodeManager = function( $ ) {
445
  */
446
  $( document ).on( 'change keyup input cut paste', '.js-toolset-shortcode-gui-dialog-container input, .js-toolset-shortcode-gui-dialog-container select', function() {
447
  $( this ).removeClass( 'toolset-shortcode-gui-invalid-attr js-toolset-shortcode-gui-invalid-attr' );
 
 
 
 
 
 
 
448
  });
449
 
450
  /**
@@ -793,37 +912,44 @@ Toolset.shortcodeManager = function( $ ) {
793
  * Get the shortcode crafted with the current dialog shortcode attributes.
794
  *
795
  * @param defaultValue string Initial dummy parameter si this can be used as a filter callback.
 
796
  *
797
  * @return string
798
  *
799
  * @since m2m
800
  */
801
- self.getCraftedShortcode = function( defaultValue ) {
802
- return self.craftShortcode();
 
 
 
 
803
  }
804
 
805
  /**
806
  * Craft a shortcode given the attributes in the currently open dialog.
807
  *
 
 
808
  * @return string
809
  *
810
  * @since 2.5.4
811
  * @since m2m Add support for postSelector, userSelector, typesViewsTermSelector, typesUserSelector and typesViewsUserSelector attribute types.
812
  */
813
- self.craftShortcode = function() {
814
- var shortcodeName = $( '.js-toolset-shortcode-gui-shortcode-handle' ).val(),
815
  shortcodeAttributeString = '',
816
  shortcodeAttributeValues = {},
817
  shortcodeRawAttributeValues = {},
818
  shortcodeContent = '',
819
  shortcodeToInsert = '',
820
- shortcodeIsValid = self.validateShortcodeAttributes( $( '.js-toolset-shortcode-gui-dialog-container' ) );
821
 
822
  if ( ! shortcodeIsValid ) {
823
  return;
824
  }
825
 
826
- $( '.js-toolset-shortcode-gui-attribute-wrapper', '.js-toolset-shortcode-gui-dialog-container' ).each( function() {
827
  var attributeWrapper = $( this ),
828
  shortcodeAttributeKey = attributeWrapper.data( 'attribute' ),
829
  shortcodeAttributeValue = '',
@@ -844,6 +970,9 @@ Toolset.shortcodeManager = function( $ ) {
844
  case 'related':
845
  shortcodeAttributeValue = $( '[name="related_object"]:checked', attributeWrapper ).val();
846
  break;
 
 
 
847
  case 'object_id':
848
  shortcodeAttributeValue = $( '.js-toolset-shortcode-gui-item-selector_object_id', attributeWrapper ).val();
849
  case 'parent': // The value is correct out of the box
@@ -854,7 +983,7 @@ Toolset.shortcodeManager = function( $ ) {
854
  case 'select':
855
  case 'select2':
856
  case 'ajaxSelect2':
857
- shortcodeAttributeValue = $('option:checked', attributeWrapper ).val();
858
  break;
859
  case 'radio':
860
  case 'radiohtml':
@@ -863,6 +992,9 @@ Toolset.shortcodeManager = function( $ ) {
863
  case 'checkbox':
864
  shortcodeAttributeValue = $('input:checked', attributeWrapper ).val();
865
  break;
 
 
 
866
  default:
867
  shortcodeAttributeValue = $('input', attributeWrapper ).val();
868
  }
@@ -929,8 +1061,8 @@ Toolset.shortcodeManager = function( $ ) {
929
  shortcodeToInsert = '[' + shortcodeName + shortcodeAttributeString + ']';
930
 
931
  // Shortcodes with content: add it plus the closing shortode tag
932
- if ( $( '.js-toolset-shortcode-gui-content' ).length > 0 ) {
933
- shortcodeContent = $( '.js-toolset-shortcode-gui-content' ).val();
934
  shortcodeToInsert += shortcodeContent;
935
  shortcodeToInsert += '[/' + shortcodeName + ']';
936
  }
151
  *
152
  * @since 2.5.4
153
  */
154
+ Toolset.hooks.addFilter( 'toolset-filter-get-crafted-shortcode', self.getCraftedShortcode, 10, 2 );
155
+
156
+ /**
157
+ * Filter the generated Types shortcode to support shortcodes with different format.
158
+ *
159
+ * @since 2.5.4
160
+ */
161
+ Toolset.hooks.addFilter( 'toolset-filter-get-crafted-shortcode', self.secureShortcodeFromSanitizationIfNeeded, 11 );
162
 
163
  /**
164
  * Return the current crafted shortcode with the current dialog GUI attrbutes.
219
  */
220
  Toolset.hooks.addAction( 'toolset-action-shortcode-dialog-loaded', self.initSelect2 );
221
 
222
+ /**
223
+ * Init a wizard dialog, set the options width, and set the right value as selected.
224
+ *
225
+ * @since 2.5.4
226
+ */
227
+ Toolset.hooks.addAction( 'toolset-action-set-shortcode-wizard-gui', self.setShortcodeWizardGui );
228
+
229
  return self;
230
 
231
  };
244
  self.templates.attributeGroupWrapper = wp.template( 'toolset-shortcode-attribute-group-wrapper' );
245
  self.templates.attributes = {
246
  content: wp.template( 'toolset-shortcode-content' ),
247
+ information: wp.template( 'toolset-shortcode-attribute-information' ),
248
  text: wp.template( 'toolset-shortcode-attribute-text' ),
249
  radio: wp.template( 'toolset-shortcode-attribute-radio' ),
250
  select: wp.template( 'toolset-shortcode-attribute-select' ),
383
  });
384
 
385
  /**
386
+ * Init select2 attributes controls.
387
  *
388
  * @since 2.5.4
389
  */
390
+ self.initSelect2Attributes = function() {
391
+ $( '.js-toolset-shortcode-gui-dialog-container .js-toolset-shortcode-gui-field-select2:not(.js-toolset-shortcode-gui-field-select2-inited)' ).each( function() {
392
  var selector = $( this ),
393
  selectorParent = selector.closest( '.js-toolset-shortcode-gui-dialog-container' );
394
 
407
  .$dropdown
408
  .addClass( 'toolset_select2-dropdown-in-dialog' );
409
  });
410
+ };
411
+
412
+ /**
413
+ * Init the ajaxSelect2 attributes action.
414
+ *
415
+ * @since 2.5.4
416
+ */
417
+ self.initSelect2AjaxAction = function( selector ) {
418
+ var selectorParent = selector.closest( '.js-toolset-shortcode-gui-dialog-container' );
419
+ selector
420
  .addClass( 'js-toolset-shortcode-gui-field-select2-inited' )
421
  .css( { width: '100%' } )
422
  .toolset_select2(
425
  dropdownAutoWidth: true,
426
  dropdownParent: selectorParent,
427
  placeholder: selector.data( 'placeholder' ),
428
+ minimumInputLength: 2,
429
  ajax: {
430
+ url: toolset_shortcode_i18n.ajaxurl,
431
  dataType: 'json',
432
  delay: 250,
433
  type: 'post',
434
  data: function( params ) {
435
  return {
436
+ action: selector.data( 'action' ),
437
+ s: params.term,
438
+ page: params.page,
439
+ wpnonce: selector.data( 'nonce' )
440
  };
441
  },
442
+ processResults: function( originalResponse, params ) {
443
+ var response = WPV_Toolset.Utils.Ajax.parseResponse( originalResponse );
444
  params.page = params.page || 1;
445
  if ( response.success ) {
446
  return {
458
  .data( 'toolset_select2' )
459
  .$dropdown
460
  .addClass( 'toolset_select2-dropdown-in-dialog' );
461
+ };
462
+
463
+ /**
464
+ * Init ajaxSelect2 attributes controls.
465
+ * Get the prefill label for any existing value.
466
+ *
467
+ * @since 2.5.4
468
+ */
469
+ self.initSelect2AjaxAttributes = function() {
470
+ $( '.js-toolset-shortcode-gui-dialog-container .js-toolset-shortcode-gui-field-ajax-select2:not(.js-toolset-shortcode-gui-field-select2-inited)' ).each( function() {
471
+ var selector = $( this );
472
+
473
+ if (
474
+ selector.val()
475
+ && selector.data( 'prefill' )
476
+ ) {
477
+ var prefillData = {
478
+ action: selector.data( 'prefill' ),
479
+ wpnonce: selector.data( 'prefill-nonce' ),
480
+ s: selector.val()
481
+ };
482
+ $.ajax({
483
+ url: toolset_shortcode_i18n.ajaxurl,
484
+ data: prefillData,
485
+ type: "post",
486
+ success: function( originalResponse ) {
487
+ var response = WPV_Toolset.Utils.Ajax.parseResponse( originalResponse );
488
+ if ( response.success ) {
489
+ selector
490
+ .find( 'option:selected' )
491
+ .html( response.data.label );
492
+ } else {
493
+ selector
494
+ .find( 'option:selected' )
495
+ .remove();
496
+ }
497
+ self.initSelect2AjaxAction( selector );
498
+ },
499
+ error: function ( ajaxContext ) {
500
+ selector
501
+ .find( 'option:selected' )
502
+ .remove();
503
+ self.initSelect2AjaxAction( selector );
504
+ }
505
+ });
506
+ } else {
507
+ self.initSelect2AjaxAction( selector );
508
+ }
509
+
510
  });
511
  };
512
 
513
+ /**
514
+ * Init select2 and ajaxSelect2 attributes controls.
515
+ *
516
+ * @since 2.5.4
517
+ */
518
+ self.initSelect2 = function() {
519
+ self.initSelect2Attributes();
520
+ self.initSelect2AjaxAttributes();
521
+ };
522
+
523
+ /**
524
+ * Initialize the wizard GUI for a shortcode.
525
+ *
526
+ * @param string The value to set as selected
527
+ *
528
+ * @since m2m
529
+ */
530
+ self.setShortcodeWizardGui = function( value ) {
531
+ var $optionsContainer = $( '.js-toolset-shortcode-gui-wizard-options-container', '.js-toolset-shortcode-gui-wizard-container' ),
532
+ $options = $( '.js-toolset-shortcode-gui-wizard-option', $optionsContainer ),
533
+ optionsLength = $options.length;
534
+
535
+ $( '.toolset-shortcode-gui-wizard-option-selected', $optionsContainer ).removeClass( 'toolset-shortcode-gui-wizard-option-selected' );
536
+ $optionsContainer.find( 'input[value=' + value + ']' )
537
+ .prop( 'checked', true )
538
+ .trigger( 'change' )
539
+ .closest( '.js-toolset-shortcode-gui-wizard-option' )
540
+ .addClass( 'toolset-shortcode-gui-wizard-option-selected' );
541
+ };
542
+
543
+ $( document ).on( 'change', '.js-toolset-shortcode-gui-wizard-option input[type=radio]', function() {
544
+ var $optionsContainer = $( '.js-toolset-shortcode-gui-wizard-options-container', '.js-toolset-shortcode-gui-wizard-container' );
545
+
546
+ $( '.toolset-shortcode-gui-wizard-option-selected', $optionsContainer ).removeClass( 'toolset-shortcode-gui-wizard-option-selected' );
547
+
548
+ $( 'input[type=radio].toolset-shortcode-gui-wizard-option-hidden:checked', $optionsContainer )
549
+ .closest( '.js-toolset-shortcode-gui-wizard-option' )
550
+ .addClass( 'toolset-shortcode-gui-wizard-option-selected' );
551
+ });
552
+
553
  /**
554
  * Clean validation errors on input change.
555
  *
557
  */
558
  $( document ).on( 'change keyup input cut paste', '.js-toolset-shortcode-gui-dialog-container input, .js-toolset-shortcode-gui-dialog-container select', function() {
559
  $( this ).removeClass( 'toolset-shortcode-gui-invalid-attr js-toolset-shortcode-gui-invalid-attr' );
560
+ if ( $( this ).hasClass( 'toolset_select2-hidden-accessible' ) ) {
561
+ $( this )
562
+ .toolset_select2()
563
+ .data( 'toolset_select2' )
564
+ .$selection
565
+ .removeClass( 'toolset-shortcode-gui-invalid-attr js-toolset-shortcode-gui-invalid-attr' );
566
+ }
567
  });
568
 
569
  /**
912
  * Get the shortcode crafted with the current dialog shortcode attributes.
913
  *
914
  * @param defaultValue string Initial dummy parameter si this can be used as a filter callback.
915
+ * @param $dialog object The jQuery object that holds the dialog to craft the shortcode for.
916
  *
917
  * @return string
918
  *
919
  * @since m2m
920
  */
921
+ self.getCraftedShortcode = function( defaultValue, $dialog ) {
922
+ if ( $dialog == null ) {
923
+ // Backwards compatibility: before m2m we did not force a dialog to craft the shortcode from
924
+ $dialog = $( '.js-toolset-shortcode-gui-dialog-container' );
925
+ }
926
+ return self.craftShortcode( $dialog );
927
  }
928
 
929
  /**
930
  * Craft a shortcode given the attributes in the currently open dialog.
931
  *
932
+ * @param $dialog object The jQuery object that holds the dialog to craft the shortcode for.
933
+ *
934
  * @return string
935
  *
936
  * @since 2.5.4
937
  * @since m2m Add support for postSelector, userSelector, typesViewsTermSelector, typesUserSelector and typesViewsUserSelector attribute types.
938
  */
939
+ self.craftShortcode = function( $dialog ) {
940
+ var shortcodeName = $( '.js-toolset-shortcode-gui-shortcode-handle', $dialog ).val(),
941
  shortcodeAttributeString = '',
942
  shortcodeAttributeValues = {},
943
  shortcodeRawAttributeValues = {},
944
  shortcodeContent = '',
945
  shortcodeToInsert = '',
946
+ shortcodeIsValid = self.validateShortcodeAttributes( $dialog );
947
 
948
  if ( ! shortcodeIsValid ) {
949
  return;
950
  }
951
 
952
+ $( '.js-toolset-shortcode-gui-attribute-wrapper', $dialog ).each( function() {
953
  var attributeWrapper = $( this ),
954
  shortcodeAttributeKey = attributeWrapper.data( 'attribute' ),
955
  shortcodeAttributeValue = '',
970
  case 'related':
971
  shortcodeAttributeValue = $( '[name="related_object"]:checked', attributeWrapper ).val();
972
  break;
973
+ case 'referenced':
974
+ shortcodeAttributeValue = $( '[name="referenced_object"]:checked', attributeWrapper ).val();
975
+ break;
976
  case 'object_id':
977
  shortcodeAttributeValue = $( '.js-toolset-shortcode-gui-item-selector_object_id', attributeWrapper ).val();
978
  case 'parent': // The value is correct out of the box
983
  case 'select':
984
  case 'select2':
985
  case 'ajaxSelect2':
986
+ shortcodeAttributeValue = $('select', attributeWrapper ).val();
987
  break;
988
  case 'radio':
989
  case 'radiohtml':
992
  case 'checkbox':
993
  shortcodeAttributeValue = $('input:checked', attributeWrapper ).val();
994
  break;
995
+ case 'information':
996
+ shortcodeAttributeValue = false;
997
+ break;
998
  default:
999
  shortcodeAttributeValue = $('input', attributeWrapper ).val();
1000
  }
1061
  shortcodeToInsert = '[' + shortcodeName + shortcodeAttributeString + ']';
1062
 
1063
  // Shortcodes with content: add it plus the closing shortode tag
1064
+ if ( $( '.js-toolset-shortcode-gui-content', $dialog ).length > 0 ) {
1065
+ shortcodeContent = $( '.js-toolset-shortcode-gui-content', $dialog ).val();
1066
  shortcodeToInsert += shortcodeContent;
1067
  shortcodeToInsert += '[/' + shortcodeName + ']';
1068
  }
vendor/toolset/toolset-common/res/lib/parsley/parsley.css ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ input.parsley-success,
2
+ select.parsley-success,
3
+ textarea.parsley-success {
4
+ color: #468847;
5
+ background-color: #DFF0D8;
6
+ border: 1px solid #D6E9C6;
7
+ }
8
+
9
+ input.parsley-error,
10
+ select.parsley-error,
11
+ textarea.parsley-error {
12
+ color: #B94A48;
13
+ background-color: #F2DEDE;
14
+ border: 1px solid #EED3D7;
15
+ }
16
+
17
+ .parsley-errors-list {
18
+ margin: 2px 0 3px;
19
+ padding: 0;
20
+ list-style-type: none;
21
+ font-size: 0.9em;
22
+ line-height: 0.9em;
23
+ opacity: 0;
24
+
25
+ transition: all .3s ease-in;
26
+ -o-transition: all .3s ease-in;
27
+ -moz-transition: all .3s ease-in;
28
+ -webkit-transition: all .3s ease-in;
29
+ }
30
+
31
+ .parsley-errors-list.filled {
32
+ opacity: 1;
33
+ }
vendor/toolset/toolset-common/res/lib/parsley/parsley.js ADDED
@@ -0,0 +1,2492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Parsley.js
3
+ * Version 2.8.0 - built Wed, Sep 13th 2017, 11:04 pm
4
+ * http://parsleyjs.org
5
+ * Guillaume Potier - <guillaume@wisembly.com>
6
+ * Marc-Andre Lafortune - <petroselinum@marc-andre.ca>
7
+ * MIT Licensed
8
+ */
9
+
10
+ // The source code below is generated by babel as
11
+ // Parsley is written in ECMAScript 6
12
+ //
13
+ var _slice = Array.prototype.slice;
14
+
15
+ var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
16
+
17
+ var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
18
+
19
+ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }
20
+
21
+ (function (global, factory) {
22
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) : typeof define === 'function' && define.amd ? define(['jquery'], factory) : global.parsley = factory(global.jQuery);
23
+ })(this, function ($) {
24
+ 'use strict';
25
+
26
+ var globalID = 1;
27
+ var pastWarnings = {};
28
+
29
+ var Utils = {
30
+ // Parsley DOM-API
31
+ // returns object from dom attributes and values
32
+ attr: function attr(element, namespace, obj) {
33
+ var i;
34
+ var attribute;
35
+ var attributes;
36
+ var regex = new RegExp('^' + namespace, 'i');
37
+
38
+ if ('undefined' === typeof obj) obj = {};else {
39
+ // Clear all own properties. This won't affect prototype's values
40
+ for (i in obj) {
41
+ if (obj.hasOwnProperty(i)) delete obj[i];
42
+ }
43
+ }
44
+
45
+ if (!element) return obj;
46
+
47
+ attributes = element.attributes;
48
+ for (i = attributes.length; i--;) {
49
+ attribute = attributes[i];
50
+
51
+ if (attribute && attribute.specified && regex.test(attribute.name)) {
52
+ obj[this.camelize(attribute.name.slice(namespace.length))] = this.deserializeValue(attribute.value);
53
+ }
54
+ }
55
+
56
+ return obj;
57
+ },
58
+
59
+ checkAttr: function checkAttr(element, namespace, _checkAttr) {
60
+ return element.hasAttribute(namespace + _checkAttr);
61
+ },
62
+
63
+ setAttr: function setAttr(element, namespace, attr, value) {
64
+ element.setAttribute(this.dasherize(namespace + attr), String(value));
65
+ },
66
+
67
+ getType: function getType(element) {
68
+ return element.getAttribute('type') || 'text';
69
+ },
70
+
71
+ generateID: function generateID() {
72
+ return '' + globalID++;
73
+ },
74
+
75
+ /** Third party functions **/
76
+ deserializeValue: function deserializeValue(value) {
77
+ var num;
78
+
79
+ try {
80
+ return value ? value == "true" || (value == "false" ? false : value == "null" ? null : !isNaN(num = Number(value)) ? num : /^[\[\{]/.test(value) ? JSON.parse(value) : value) : value;
81
+ } catch (e) {
82
+ return value;
83
+ }
84
+ },
85
+
86
+ // Zepto camelize function
87
+ camelize: function camelize(str) {
88
+ return str.replace(/-+(.)?/g, function (match, chr) {
89
+ return chr ? chr.toUpperCase() : '';
90
+ });
91
+ },
92
+
93
+ // Zepto dasherize function
94
+ dasherize: function dasherize(str) {
95
+ return str.replace(/::/g, '/').replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2').replace(/([a-z\d])([A-Z])/g, '$1_$2').replace(/_/g, '-').toLowerCase();
96
+ },
97
+
98
+ warn: function warn() {
99
+ var _window$console;
100
+
101
+ if (window.console && 'function' === typeof window.console.warn) (_window$console = window.console).warn.apply(_window$console, arguments);
102
+ },
103
+
104
+ warnOnce: function warnOnce(msg) {
105
+ if (!pastWarnings[msg]) {
106
+ pastWarnings[msg] = true;
107
+ this.warn.apply(this, arguments);
108
+ }
109
+ },
110
+
111
+ _resetWarnings: function _resetWarnings() {
112
+ pastWarnings = {};
113
+ },
114
+
115
+ trimString: function trimString(string) {
116
+ return string.replace(/^\s+|\s+$/g, '');
117
+ },
118
+
119
+ parse: {
120
+ date: function date(string) {
121
+ var parsed = string.match(/^(\d{4,})-(\d\d)-(\d\d)$/);
122
+ if (!parsed) return null;
123
+
124
+ var _parsed$map = parsed.map(function (x) {
125
+ return parseInt(x, 10);
126
+ });
127
+
128
+ var _parsed$map2 = _slicedToArray(_parsed$map, 4);
129
+
130
+ var _ = _parsed$map2[0];
131
+ var year = _parsed$map2[1];
132
+ var month = _parsed$map2[2];
133
+ var day = _parsed$map2[3];
134
+
135
+ var date = new Date(year, month - 1, day);
136
+ if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) return null;
137
+ return date;
138
+ },
139
+ string: function string(_string) {
140
+ return _string;
141
+ },
142
+ integer: function integer(string) {
143
+ if (isNaN(string)) return null;
144
+ return parseInt(string, 10);
145
+ },
146
+ number: function number(string) {
147
+ if (isNaN(string)) throw null;
148
+ return parseFloat(string);
149
+ },
150
+ 'boolean': function _boolean(string) {
151
+ return !/^\s*false\s*$/i.test(string);
152
+ },
153
+ object: function object(string) {
154
+ return Utils.deserializeValue(string);
155
+ },
156
+ regexp: function regexp(_regexp) {
157
+ var flags = '';
158
+
159
+ // Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern
160
+ if (/^\/.*\/(?:[gimy]*)$/.test(_regexp)) {
161
+ // Replace the regexp literal string with the first match group: ([gimy]*)
162
+ // If no flag is present, this will be a blank string
163
+ flags = _regexp.replace(/.*\/([gimy]*)$/, '$1');
164
+ // Again, replace the regexp literal string with the first match group:
165
+ // everything excluding the opening and closing slashes and the flags
166
+ _regexp = _regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');
167
+ } else {
168
+ // Anchor regexp:
169
+ _regexp = '^' + _regexp + '$';
170
+ }
171
+ return new RegExp(_regexp, flags);
172
+ }
173
+ },
174
+
175
+ parseRequirement: function parseRequirement(requirementType, string) {
176
+ var converter = this.parse[requirementType || 'string'];
177
+ if (!converter) throw 'Unknown requirement specification: "' + requirementType + '"';
178
+ var converted = converter(string);
179
+ if (converted === null) throw 'Requirement is not a ' + requirementType + ': "' + string + '"';
180
+ return converted;
181
+ },
182
+
183
+ namespaceEvents: function namespaceEvents(events, namespace) {
184
+ events = this.trimString(events || '').split(/\s+/);
185
+ if (!events[0]) return '';
186
+ return $.map(events, function (evt) {
187
+ return evt + '.' + namespace;
188
+ }).join(' ');
189
+ },
190
+
191
+ difference: function difference(array, remove) {
192
+ // This is O(N^2), should be optimized
193
+ var result = [];
194
+ $.each(array, function (_, elem) {
195
+ if (remove.indexOf(elem) == -1) result.push(elem);
196
+ });
197
+ return result;
198
+ },
199
+
200
+ // Alter-ego to native Promise.all, but for jQuery
201
+ all: function all(promises) {
202
+ // jQuery treats $.when() and $.when(singlePromise) differently; let's avoid that and add spurious elements
203
+ return $.when.apply($, _toConsumableArray(promises).concat([42, 42]));
204
+ },
205
+
206
+ // Object.create polyfill, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill
207
+ objectCreate: Object.create || (function () {
208
+ var Object = function Object() {};
209
+ return function (prototype) {
210
+ if (arguments.length > 1) {
211
+ throw Error('Second argument not supported');
212
+ }
213
+ if (typeof prototype != 'object') {
214
+ throw TypeError('Argument must be an object');
215
+ }
216
+ Object.prototype = prototype;
217
+ var result = new Object();
218
+ Object.prototype = null;
219
+ return result;
220
+ };
221
+ })(),
222
+
223
+ _SubmitSelector: 'input[type="submit"], button:submit'
224
+ };
225
+
226
+ // All these options could be overriden and specified directly in DOM using
227
+ // `data-parsley-` default DOM-API
228
+ // eg: `inputs` can be set in DOM using `data-parsley-inputs="input, textarea"`
229
+ // eg: `data-parsley-stop-on-first-failing-constraint="false"`
230
+
231
+ var Defaults = {
232
+ // ### General
233
+
234
+ // Default data-namespace for DOM API
235
+ namespace: 'data-parsley-',
236
+
237
+ // Supported inputs by default
238
+ inputs: 'input, textarea, select',
239
+
240
+ // Excluded inputs by default
241
+ excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',
242
+
243
+ // Stop validating field on highest priority failing constraint
244
+ priorityEnabled: true,
245
+
246
+ // ### Field only
247
+
248
+ // identifier used to group together inputs (e.g. radio buttons...)
249
+ multiple: null,
250
+
251
+ // identifier (or array of identifiers) used to validate only a select group of inputs
252
+ group: null,
253
+
254
+ // ### UI
255
+ // Enable\Disable error messages
256
+ uiEnabled: true,
257
+
258
+ // Key events threshold before validation
259
+ validationThreshold: 3,
260
+
261
+ // Focused field on form validation error. 'first'|'last'|'none'
262
+ focus: 'first',
263
+
264
+ // event(s) that will trigger validation before first failure. eg: `input`...
265
+ trigger: false,
266
+
267
+ // event(s) that will trigger validation after first failure.
268
+ triggerAfterFailure: 'input',
269
+
270
+ // Class that would be added on every failing validation Parsley field
271
+ errorClass: 'parsley-error',
272
+
273
+ // Same for success validation
274
+ successClass: 'parsley-success',
275
+
276
+ // Return the `$element` that will receive these above success or error classes
277
+ // Could also be (and given directly from DOM) a valid selector like `'#div'`
278
+ classHandler: function classHandler(Field) {},
279
+
280
+ // Return the `$element` where errors will be appended
281
+ // Could also be (and given directly from DOM) a valid selector like `'#div'`
282
+ errorsContainer: function errorsContainer(Field) {},
283
+
284
+ // ul elem that would receive errors' list
285
+ errorsWrapper: '<ul class="parsley-errors-list"></ul>',
286
+
287
+ // li elem that would receive error message
288
+ errorTemplate: '<li></li>'
289
+ };
290
+
291
+ var Base = function Base() {
292
+ this.__id__ = Utils.generateID();
293
+ };
294
+
295
+ Base.prototype = {
296
+ asyncSupport: true, // Deprecated
297
+
298
+ _pipeAccordingToValidationResult: function _pipeAccordingToValidationResult() {
299
+ var _this = this;
300
+
301
+ var pipe = function pipe() {
302
+ var r = $.Deferred();
303
+ if (true !== _this.validationResult) r.reject();
304
+ return r.resolve().promise();
305
+ };
306
+ return [pipe, pipe];
307
+ },
308
+
309
+ actualizeOptions: function actualizeOptions() {
310
+ Utils.attr(this.element, this.options.namespace, this.domOptions);
311
+ if (this.parent && this.parent.actualizeOptions) this.parent.actualizeOptions();
312
+ return this;
313
+ },
314
+
315
+ _resetOptions: function _resetOptions(initOptions) {
316
+ this.domOptions = Utils.objectCreate(this.parent.options);
317
+ this.options = Utils.objectCreate(this.domOptions);
318
+ // Shallow copy of ownProperties of initOptions:
319
+ for (var i in initOptions) {
320
+ if (initOptions.hasOwnProperty(i)) this.options[i] = initOptions[i];
321
+ }
322
+ this.actualizeOptions();
323
+ },
324
+
325
+ _listeners: null,
326
+
327
+ // Register a callback for the given event name
328
+ // Callback is called with context as the first argument and the `this`
329
+ // The context is the current parsley instance, or window.Parsley if global
330
+ // A return value of `false` will interrupt the calls
331
+ on: function on(name, fn) {
332
+ this._listeners = this._listeners || {};
333
+ var queue = this._listeners[name] = this._listeners[name] || [];
334
+ queue.push(fn);
335
+
336
+ return this;
337
+ },
338
+
339
+ // Deprecated. Use `on` instead
340
+ subscribe: function subscribe(name, fn) {
341
+ $.listenTo(this, name.toLowerCase(), fn);
342
+ },
343
+
344
+ // Unregister a callback (or all if none is given) for the given event name
345
+ off: function off(name, fn) {
346
+ var queue = this._listeners && this._listeners[name];
347
+ if (queue) {
348
+ if (!fn) {
349
+ delete this._listeners[name];
350
+ } else {
351
+ for (var i = queue.length; i--;) if (queue[i] === fn) queue.splice(i, 1);
352
+ }
353
+ }
354
+ return this;
355
+ },
356
+
357
+ // Deprecated. Use `off`
358
+ unsubscribe: function unsubscribe(name, fn) {
359
+ $.unsubscribeTo(this, name.toLowerCase());
360
+ },
361
+
362
+ // Trigger an event of the given name
363
+ // A return value of `false` interrupts the callback chain
364
+ // Returns false if execution was interrupted
365
+ trigger: function trigger(name, target, extraArg) {
366
+ target = target || this;
367
+ var queue = this._listeners && this._listeners[name];
368
+ var result;
369
+ var parentResult;
370
+ if (queue) {
371
+ for (var i = queue.length; i--;) {
372
+ result = queue[i].call(target, target, extraArg);
373
+ if (result === false) return result;
374
+ }
375
+ }
376
+ if (this.parent) {
377
+ return this.parent.trigger(name, target, extraArg);
378
+ }
379
+ return true;
380
+ },
381
+
382
+ asyncIsValid: function asyncIsValid(group, force) {
383
+ Utils.warnOnce("asyncIsValid is deprecated; please use whenValid instead");
384
+ return this.whenValid({ group: group, force: force });
385
+ },
386
+
387
+ _findRelated: function _findRelated() {
388
+ return this.options.multiple ? $(this.parent.element.querySelectorAll('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]')) : this.$element;
389
+ }
390
+ };
391
+
392
+ var convertArrayRequirement = function convertArrayRequirement(string, length) {
393
+ var m = string.match(/^\s*\[(.*)\]\s*$/);
394
+ if (!m) throw 'Requirement is not an array: "' + string + '"';
395
+ var values = m[1].split(',').map(Utils.trimString);
396
+ if (values.length !== length) throw 'Requirement has ' + values.length + ' values when ' + length + ' are needed';
397
+ return values;
398
+ };
399
+
400
+ var convertExtraOptionRequirement = function convertExtraOptionRequirement(requirementSpec, string, extraOptionReader) {
401
+ var main = null;
402
+ var extra = {};
403
+ for (var key in requirementSpec) {
404
+ if (key) {
405
+ var value = extraOptionReader(key);
406
+ if ('string' === typeof value) value = Utils.parseRequirement(requirementSpec[key], value);
407
+ extra[key] = value;
408
+ } else {
409
+ main = Utils.parseRequirement(requirementSpec[key], string);
410
+ }
411
+ }
412
+ return [main, extra];
413
+ };
414
+
415
+ // A Validator needs to implement the methods `validate` and `parseRequirements`
416
+
417
+ var Validator = function Validator(spec) {
418
+ $.extend(true, this, spec);
419
+ };
420
+
421
+ Validator.prototype = {
422
+ // Returns `true` iff the given `value` is valid according the given requirements.
423
+ validate: function validate(value, requirementFirstArg) {
424
+ if (this.fn) {
425
+ // Legacy style validator
426
+
427
+ if (arguments.length > 3) // If more args then value, requirement, instance...
428
+ requirementFirstArg = [].slice.call(arguments, 1, -1); // Skip first arg (value) and last (instance), combining the rest
429
+ return this.fn(value, requirementFirstArg);
430
+ }
431
+
432
+ if (Array.isArray(value)) {
433
+ if (!this.validateMultiple) throw 'Validator `' + this.name + '` does not handle multiple values';
434
+ return this.validateMultiple.apply(this, arguments);
435
+ } else {
436
+ var instance = arguments[arguments.length - 1];
437
+ if (this.validateDate && instance._isDateInput()) {
438
+ arguments[0] = Utils.parse.date(arguments[0]);
439
+ if (arguments[0] === null) return false;
440
+ return this.validateDate.apply(this, arguments);
441
+ }
442
+ if (this.validateNumber) {
443
+ if (isNaN(value)) return false;
444
+ arguments[0] = parseFloat(arguments[0]);
445
+ return this.validateNumber.apply(this, arguments);
446
+ }
447
+ if (this.validateString) {
448
+ return this.validateString.apply(this, arguments);
449
+ }
450
+ throw 'Validator `' + this.name + '` only handles multiple values';
451
+ }
452
+ },
453
+
454
+ // Parses `requirements` into an array of arguments,
455
+ // according to `this.requirementType`
456
+ parseRequirements: function parseRequirements(requirements, extraOptionReader) {
457
+ if ('string' !== typeof requirements) {
458
+ // Assume requirement already parsed
459
+ // but make sure we return an array
460
+ return Array.isArray(requirements) ? requirements : [requirements];
461
+ }
462
+ var type = this.requirementType;
463
+ if (Array.isArray(type)) {
464
+ var values = convertArrayRequirement(requirements, type.length);
465
+ for (var i = 0; i < values.length; i++) values[i] = Utils.parseRequirement(type[i], values[i]);
466
+ return values;
467
+ } else if ($.isPlainObject(type)) {
468
+ return convertExtraOptionRequirement(type, requirements, extraOptionReader);
469
+ } else {
470
+ return [Utils.parseRequirement(type, requirements)];
471
+ }
472
+ },
473
+ // Defaults:
474
+ requirementType: 'string',
475
+
476
+ priority: 2
477
+
478
+ };
479
+
480
+ var ValidatorRegistry = function ValidatorRegistry(validators, catalog) {
481
+ this.__class__ = 'ValidatorRegistry';
482
+
483
+ // Default Parsley locale is en
484
+ this.locale = 'en';
485
+
486
+ this.init(validators || {}, catalog || {});
487
+ };
488
+
489
+ var typeTesters = {
490
+ email: /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,
491
+
492
+ // Follow https://www.w3.org/TR/html5/infrastructure.html#floating-point-numbers
493
+ number: /^-?(\d*\.)?\d+(e[-+]?\d+)?$/i,
494
+
495
+ integer: /^-?\d+$/,
496
+
497
+ digits: /^\d+$/,
498
+
499
+ alphanum: /^\w+$/i,
500
+
501
+ date: {
502
+ test: function test(value) {
503
+ return Utils.parse.date(value) !== null;
504
+ }
505
+ },
506
+
507
+ url: new RegExp("^" +
508
+ // protocol identifier
509
+ "(?:(?:https?|ftp)://)?" + // ** mod: make scheme optional
510
+ // user:pass authentication
511
+ "(?:\\S+(?::\\S*)?@)?" + "(?:" +
512
+ // IP address exclusion
513
+ // private & local networks
514
+ // "(?!(?:10|127)(?:\\.\\d{1,3}){3})" + // ** mod: allow local networks
515
+ // "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" + // ** mod: allow local networks
516
+ // "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" + // ** mod: allow local networks
517
+ // IP address dotted notation octets
518
+ // excludes loopback network 0.0.0.0
519
+ // excludes reserved space >= 224.0.0.0
520
+ // excludes network & broacast addresses
521
+ // (first & last IP address of each class)
522
+ "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" + "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" + "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" + "|" +
523
+ // host name
524
+ '(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)' +
525
+ // domain name
526
+ '(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*' +
527
+ // TLD identifier
528
+ '(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))' + ")" +
529
+ // port number
530
+ "(?::\\d{2,5})?" +
531
+ // resource path
532
+ "(?:/\\S*)?" + "$", 'i')
533
+ };
534
+ typeTesters.range = typeTesters.number;
535
+
536
+ // See http://stackoverflow.com/a/10454560/8279
537
+ var decimalPlaces = function decimalPlaces(num) {
538
+ var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
539
+ if (!match) {
540
+ return 0;
541
+ }
542
+ return Math.max(0,
543
+ // Number of digits right of decimal point.
544
+ (match[1] ? match[1].length : 0) - (
545
+ // Adjust for scientific notation.
546
+ match[2] ? +match[2] : 0));
547
+ };
548
+
549
+ // parseArguments('number', ['1', '2']) => [1, 2]
550
+ var ValidatorRegistry__parseArguments = function ValidatorRegistry__parseArguments(type, args) {
551
+ return args.map(Utils.parse[type]);
552
+ };
553
+ // operatorToValidator returns a validating function for an operator function, applied to the given type
554
+ var ValidatorRegistry__operatorToValidator = function ValidatorRegistry__operatorToValidator(type, operator) {
555
+ return function (value) {
556
+ for (var _len = arguments.length, requirementsAndInput = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
557
+ requirementsAndInput[_key - 1] = arguments[_key];
558
+ }
559
+
560
+ requirementsAndInput.pop(); // Get rid of `input` argument
561
+ return operator.apply(undefined, [value].concat(_toConsumableArray(ValidatorRegistry__parseArguments(type, requirementsAndInput))));
562
+ };
563
+ };
564
+
565
+ var ValidatorRegistry__comparisonOperator = function ValidatorRegistry__comparisonOperator(operator) {
566
+ return {
567
+ validateDate: ValidatorRegistry__operatorToValidator('date', operator),
568
+ validateNumber: ValidatorRegistry__operatorToValidator('number', operator),
569
+ requirementType: operator.length <= 2 ? 'string' : ['string', 'string'], // Support operators with a 1 or 2 requirement(s)
570
+ priority: 30
571
+ };
572
+ };
573
+
574
+ ValidatorRegistry.prototype = {
575
+ init: function init(validators, catalog) {
576
+ this.catalog = catalog;
577
+ // Copy prototype's validators:
578
+ this.validators = _extends({}, this.validators);
579
+
580
+ for (var name in validators) this.addValidator(name, validators[name].fn, validators[name].priority);
581
+
582
+ window.Parsley.trigger('parsley:validator:init');
583
+ },
584
+
585
+ // Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n
586
+ setLocale: function setLocale(locale) {
587
+ if ('undefined' === typeof this.catalog[locale]) throw new Error(locale + ' is not available in the catalog');
588
+
589
+ this.locale = locale;
590
+
591
+ return this;
592
+ },
593
+
594
+ // Add a new messages catalog for a given locale. Set locale for this catalog if set === `true`
595
+ addCatalog: function addCatalog(locale, messages, set) {
596
+ if ('object' === typeof messages) this.catalog[locale] = messages;
597
+
598
+ if (true === set) return this.setLocale(locale);
599
+
600
+ return this;
601
+ },
602
+
603
+ // Add a specific message for a given constraint in a given locale
604
+ addMessage: function addMessage(locale, name, message) {
605
+ if ('undefined' === typeof this.catalog[locale]) this.catalog[locale] = {};
606
+
607
+ this.catalog[locale][name] = message;
608
+
609
+ return this;
610
+ },
611
+
612
+ // Add messages for a given locale
613
+ addMessages: function addMessages(locale, nameMessageObject) {
614
+ for (var name in nameMessageObject) this.addMessage(locale, name, nameMessageObject[name]);
615
+
616
+ return this;
617
+ },
618
+
619
+ // Add a new validator
620
+ //
621
+ // addValidator('custom', {
622
+ // requirementType: ['integer', 'integer'],
623
+ // validateString: function(value, from, to) {},
624
+ // priority: 22,
625
+ // messages: {
626
+ // en: "Hey, that's no good",
627
+ // fr: "Aye aye, pas bon du tout",
628
+ // }
629
+ // })
630
+ //
631
+ // Old API was addValidator(name, function, priority)
632
+ //
633
+ addValidator: function addValidator(name, arg1, arg2) {
634
+ if (this.validators[name]) Utils.warn('Validator "' + name + '" is already defined.');else if (Defaults.hasOwnProperty(name)) {
635
+ Utils.warn('"' + name + '" is a restricted keyword and is not a valid validator name.');
636
+ return;
637
+ }
638
+ return this._setValidator.apply(this, arguments);
639
+ },
640
+
641
+ hasValidator: function hasValidator(name) {
642
+ return !!this.validators[name];
643
+ },
644
+
645
+ updateValidator: function updateValidator(name, arg1, arg2) {
646
+ if (!this.validators[name]) {
647
+ Utils.warn('Validator "' + name + '" is not already defined.');
648
+ return this.addValidator.apply(this, arguments);
649
+ }
650
+ return this._setValidator.apply(this, arguments);
651
+ },
652
+
653
+ removeValidator: function removeValidator(name) {
654
+ if (!this.validators[name]) Utils.warn('Validator "' + name + '" is not defined.');
655
+
656
+ delete this.validators[name];
657
+
658
+ return this;
659
+ },
660
+
661
+ _setValidator: function _setValidator(name, validator, priority) {
662
+ if ('object' !== typeof validator) {
663
+ // Old style validator, with `fn` and `priority`
664
+ validator = {
665
+ fn: validator,
666
+ priority: priority
667
+ };
668
+ }
669
+ if (!validator.validate) {
670
+ validator = new Validator(validator);
671
+ }
672
+ this.validators[name] = validator;
673
+
674
+ for (var locale in validator.messages || {}) this.addMessage(locale, name, validator.messages[locale]);
675
+
676
+ return this;
677
+ },
678
+
679
+ getErrorMessage: function getErrorMessage(constraint) {
680
+ var message;
681
+
682
+ // Type constraints are a bit different, we have to match their requirements too to find right error message
683
+ if ('type' === constraint.name) {
684
+ var typeMessages = this.catalog[this.locale][constraint.name] || {};
685
+ message = typeMessages[constraint.requirements];
686
+ } else message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);
687
+
688
+ return message || this.catalog[this.locale].defaultMessage || this.catalog.en.defaultMessage;
689
+ },
690
+
691
+ // Kind of light `sprintf()` implementation
692
+ formatMessage: function formatMessage(string, parameters) {
693
+ if ('object' === typeof parameters) {
694
+ for (var i in parameters) string = this.formatMessage(string, parameters[i]);
695
+
696
+ return string;
697
+ }
698
+
699
+ return 'string' === typeof string ? string.replace(/%s/i, parameters) : '';
700
+ },
701
+
702
+ // Here is the Parsley default validators list.
703
+ // A validator is an object with the following key values:
704
+ // - priority: an integer
705
+ // - requirement: 'string' (default), 'integer', 'number', 'regexp' or an Array of these
706
+ // - validateString, validateMultiple, validateNumber: functions returning `true`, `false` or a promise
707
+ // Alternatively, a validator can be a function that returns such an object
708
+ //
709
+ validators: {
710
+ notblank: {
711
+ validateString: function validateString(value) {
712
+ return (/\S/.test(value)
713
+ );
714
+ },
715
+ priority: 2
716
+ },
717
+ required: {
718
+ validateMultiple: function validateMultiple(values) {
719
+ return values.length > 0;
720
+ },
721
+ validateString: function validateString(value) {
722
+ return (/\S/.test(value)
723
+ );
724
+ },
725
+ priority: 512
726
+ },
727
+ type: {
728
+ validateString: function validateString(value, type) {
729
+ var _ref = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
730
+
731
+ var _ref$step = _ref.step;
732
+ var step = _ref$step === undefined ? 'any' : _ref$step;
733
+ var _ref$base = _ref.base;
734
+ var base = _ref$base === undefined ? 0 : _ref$base;
735
+
736
+ var tester = typeTesters[type];
737
+ if (!tester) {
738
+ throw new Error('validator type `' + type + '` is not supported');
739
+ }
740
+ if (!tester.test(value)) return false;
741
+ if ('number' === type) {
742
+ if (!/^any$/i.test(step || '')) {
743
+ var nb = Number(value);
744
+ var decimals = Math.max(decimalPlaces(step), decimalPlaces(base));
745
+ if (decimalPlaces(nb) > decimals) // Value can't have too many decimals
746
+ return false;
747
+ // Be careful of rounding errors by using integers.
748
+ var toInt = function toInt(f) {
749
+ return Math.round(f * Math.pow(10, decimals));
750
+ };
751
+ if ((toInt(nb) - toInt(base)) % toInt(step) != 0) return false;
752
+ }
753
+ }
754
+ return true;
755
+ },
756
+ requirementType: {
757
+ '': 'string',
758
+ step: 'string',
759
+ base: 'number'
760
+ },
761
+ priority: 256
762
+ },
763
+ pattern: {
764
+ validateString: function validateString(value, regexp) {
765
+ return regexp.test(value);
766
+ },
767
+ requirementType: 'regexp',
768
+ priority: 64
769
+ },
770
+ minlength: {
771
+ validateString: function validateString(value, requirement) {
772
+ return value.length >= requirement;
773
+ },
774
+ requirementType: 'integer',
775
+ priority: 30
776
+ },
777
+ maxlength: {
778
+ validateString: function validateString(value, requirement) {
779
+ return value.length <= requirement;
780
+ },
781
+ requirementType: 'integer',
782
+ priority: 30
783
+ },
784
+ length: {
785
+ validateString: function validateString(value, min, max) {
786
+ return value.length >= min && value.length <= max;
787
+ },
788
+ requirementType: ['integer', 'integer'],
789
+ priority: 30
790
+ },
791
+ mincheck: {
792
+ validateMultiple: function validateMultiple(values, requirement) {
793
+ return values.length >= requirement;
794
+ },
795
+ requirementType: 'integer',
796
+ priority: 30
797
+ },
798
+ maxcheck: {
799
+ validateMultiple: function validateMultiple(values, requirement) {
800
+ return values.length <= requirement;
801
+ },
802
+ requirementType: 'integer',
803
+ priority: 30
804
+ },
805
+ check: {
806
+ validateMultiple: function validateMultiple(values, min, max) {
807
+ return values.length >= min && values.length <= max;
808
+ },
809
+ requirementType: ['integer', 'integer'],
810
+ priority: 30
811
+ },
812
+ min: ValidatorRegistry__comparisonOperator(function (value, requirement) {
813
+ return value >= requirement;
814
+ }),
815
+ max: ValidatorRegistry__comparisonOperator(function (value, requirement) {
816
+ return value <= requirement;
817
+ }),
818
+ range: ValidatorRegistry__comparisonOperator(function (value, min, max) {
819
+ return value >= min && value <= max;
820
+ }),
821
+ equalto: {
822
+ validateString: function validateString(value, refOrValue) {
823
+ var $reference = $(refOrValue);
824
+ if ($reference.length) return value === $reference.val();else return value === refOrValue;
825
+ },
826
+ priority: 256
827
+ }
828
+ }
829
+ };
830
+
831
+ var UI = {};
832
+
833
+ var diffResults = function diffResults(newResult, oldResult, deep) {
834
+ var added = [];
835
+ var kept = [];
836
+
837
+ for (var i = 0; i < newResult.length; i++) {
838
+ var found = false;
839
+
840
+ for (var j = 0; j < oldResult.length; j++) if (newResult[i].assert.name === oldResult[j].assert.name) {
841
+ found = true;
842
+ break;
843
+ }
844
+
845
+ if (found) kept.push(newResult[i]);else added.push(newResult[i]);
846
+ }
847
+
848
+ return {
849
+ kept: kept,
850
+ added: added,
851
+ removed: !deep ? diffResults(oldResult, newResult, true).added : []
852
+ };
853
+ };
854
+
855
+ UI.Form = {
856
+
857
+ _actualizeTriggers: function _actualizeTriggers() {
858
+ var _this2 = this;
859
+
860
+ this.$element.on('submit.Parsley', function (evt) {
861
+ _this2.onSubmitValidate(evt);
862
+ });
863
+ this.$element.on('click.Parsley', Utils._SubmitSelector, function (evt) {
864
+ _this2.onSubmitButton(evt);
865
+ });
866
+
867
+ // UI could be disabled
868
+ if (false === this.options.uiEnabled) return;
869
+
870
+ this.element.setAttribute('novalidate', '');
871
+ },
872
+
873
+ focus: function focus() {
874
+ this._focusedField = null;
875
+
876
+ if (true === this.validationResult || 'none' === this.options.focus) return null;
877
+
878
+ for (var i = 0; i < this.fields.length; i++) {
879
+ var field = this.fields[i];
880
+ if (true !== field.validationResult && field.validationResult.length > 0 && 'undefined' === typeof field.options.noFocus) {
881
+ this._focusedField = field.$element;
882
+ if ('first' === this.options.focus) break;
883
+ }
884
+ }
885
+
886
+ if (null === this._focusedField) return null;
887
+
888
+ return this._focusedField.focus();
889
+ },
890
+
891
+ _destroyUI: function _destroyUI() {
892
+ // Reset all event listeners
893
+ this.$element.off('.Parsley');
894
+ }
895
+
896
+ };
897
+
898
+ UI.Field = {
899
+
900
+ _reflowUI: function _reflowUI() {
901
+ this._buildUI();
902
+
903
+ // If this field doesn't have an active UI don't bother doing something
904
+ if (!this._ui) return;
905
+
906
+ // Diff between two validation results
907
+ var diff = diffResults(this.validationResult, this._ui.lastValidationResult);
908
+
909
+ // Then store current validation result for next reflow
910
+ this._ui.lastValidationResult = this.validationResult;
911
+
912
+ // Handle valid / invalid / none field class
913
+ this._manageStatusClass();
914
+
915
+ // Add, remove, updated errors messages
916
+ this._manageErrorsMessages(diff);
917
+
918
+ // Triggers impl
919
+ this._actualizeTriggers();
920
+
921
+ // If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user
922
+ if ((diff.kept.length || diff.added.length) && !this._failedOnce) {
923
+ this._failedOnce = true;
924
+ this._actualizeTriggers();
925
+ }
926
+ },
927
+
928
+ // Returns an array of field's error message(s)
929
+ getErrorsMessages: function getErrorsMessages() {
930
+ // No error message, field is valid
931
+ if (true === this.validationResult) return [];
932
+
933
+ var messages = [];
934
+
935
+ for (var i = 0; i < this.validationResult.length; i++) messages.push(this.validationResult[i].errorMessage || this._getErrorMessage(this.validationResult[i].assert));
936
+
937
+ return messages;
938
+ },
939
+
940
+ // It's a goal of Parsley that this method is no longer required [#1073]
941
+ addError: function addError(name) {
942
+ var _ref2 = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
943
+
944
+ var message = _ref2.message;
945
+ var assert = _ref2.assert;
946
+ var _ref2$updateClass = _ref2.updateClass;
947
+ var updateClass = _ref2$updateClass === undefined ? true : _ref2$updateClass;
948
+
949
+ this._buildUI();
950
+ this._addError(name, { message: message, assert: assert });
951
+
952
+ if (updateClass) this._errorClass();
953
+ },
954
+
955
+ // It's a goal of Parsley that this method is no longer required [#1073]
956
+ updateError: function updateError(name) {
957
+ var _ref3 = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
958
+
959
+ var message = _ref3.message;
960
+ var assert = _ref3.assert;
961
+ var _ref3$updateClass = _ref3.updateClass;
962
+ var updateClass = _ref3$updateClass === undefined ? true : _ref3$updateClass;
963
+
964
+ this._buildUI();
965
+ this._updateError(name, { message: message, assert: assert });
966
+
967
+ if (updateClass) this._errorClass();
968
+ },
969
+
970
+ // It's a goal of Parsley that this method is no longer required [#1073]
971
+ removeError: function removeError(name) {
972
+ var _ref4 = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
973
+
974
+ var _ref4$updateClass = _ref4.updateClass;
975
+ var updateClass = _ref4$updateClass === undefined ? true : _ref4$updateClass;
976
+
977
+ this._buildUI();
978
+ this._removeError(name);
979
+
980
+ // edge case possible here: remove a standard Parsley error that is still failing in this.validationResult
981
+ // but highly improbable cuz' manually removing a well Parsley handled error makes no sense.
982
+ if (updateClass) this._manageStatusClass();
983
+ },
984
+
985
+ _manageStatusClass: function _manageStatusClass() {
986
+ if (this.hasConstraints() && this.needsValidation() && true === this.validationResult) this._successClass();else if (this.validationResult.length > 0) this._errorClass();else this._resetClass();
987
+ },
988
+
989
+ _manageErrorsMessages: function _manageErrorsMessages(diff) {
990
+ if ('undefined' !== typeof this.options.errorsMessagesDisabled) return;
991
+
992
+ // Case where we have errorMessage option that configure an unique field error message, regardless failing validators
993
+ if ('undefined' !== typeof this.options.errorMessage) {
994
+ if (diff.added.length || diff.kept.length) {
995
+ this._insertErrorWrapper();
996
+
997
+ if (0 === this._ui.$errorsWrapper.find('.parsley-custom-error-message').length) this._ui.$errorsWrapper.append($(this.options.errorTemplate).addClass('parsley-custom-error-message'));
998
+
999
+ return this._ui.$errorsWrapper.addClass('filled').find('.parsley-custom-error-message').html(this.options.errorMessage);
1000
+ }
1001
+
1002
+ return this._ui.$errorsWrapper.removeClass('filled').find('.parsley-custom-error-message').remove();
1003
+ }
1004
+
1005
+ // Show, hide, update failing constraints messages
1006
+ for (var i = 0; i < diff.removed.length; i++) this._removeError(diff.removed[i].assert.name);
1007
+
1008
+ for (i = 0; i < diff.added.length; i++) this._addError(diff.added[i].assert.name, { message: diff.added[i].errorMessage, assert: diff.added[i].assert });
1009
+
1010
+ for (i = 0; i < diff.kept.length; i++) this._updateError(diff.kept[i].assert.name, { message: diff.kept[i].errorMessage, assert: diff.kept[i].assert });
1011
+ },
1012
+
1013
+ _addError: function _addError(name, _ref5) {
1014
+ var message = _ref5.message;
1015
+ var assert = _ref5.assert;
1016
+
1017
+ this._insertErrorWrapper();
1018
+ this._ui.$errorsWrapper.addClass('filled').append($(this.options.errorTemplate).addClass('parsley-' + name).html(message || this._getErrorMessage(assert)));
1019
+ },
1020
+
1021
+ _updateError: function _updateError(name, _ref6) {
1022
+ var message = _ref6.message;
1023
+ var assert = _ref6.assert;
1024
+
1025
+ this._ui.$errorsWrapper.addClass('filled').find('.parsley-' + name).html(message || this._getErrorMessage(assert));
1026
+ },
1027
+
1028
+ _removeError: function _removeError(name) {
1029
+ this._ui.$errorsWrapper.removeClass('filled').find('.parsley-' + name).remove();
1030
+ },
1031
+
1032
+ _getErrorMessage: function _getErrorMessage(constraint) {
1033
+ var customConstraintErrorMessage = constraint.name + 'Message';
1034
+
1035
+ if ('undefined' !== typeof this.options[customConstraintErrorMessage]) return window.Parsley.formatMessage(this.options[customConstraintErrorMessage], constraint.requirements);
1036
+
1037
+ return window.Parsley.getErrorMessage(constraint);
1038
+ },
1039
+
1040
+ _buildUI: function _buildUI() {
1041
+ // UI could be already built or disabled
1042
+ if (this._ui || false === this.options.uiEnabled) return;
1043
+
1044
+ var _ui = {};
1045
+
1046
+ // Give field its Parsley id in DOM
1047
+ this.element.setAttribute(this.options.namespace + 'id', this.__id__);
1048
+
1049
+ /** Generate important UI elements and store them in this **/
1050
+ // $errorClassHandler is the $element that woul have parsley-error and parsley-success classes
1051
+ _ui.$errorClassHandler = this._manageClassHandler();
1052
+
1053
+ // $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer
1054
+ _ui.errorsWrapperId = 'parsley-id-' + (this.options.multiple ? 'multiple-' + this.options.multiple : this.__id__);
1055
+ _ui.$errorsWrapper = $(this.options.errorsWrapper).attr('id', _ui.errorsWrapperId);
1056
+
1057
+ // ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly
1058
+ _ui.lastValidationResult = [];
1059
+ _ui.validationInformationVisible = false;
1060
+
1061
+ // Store it in this for later
1062
+ this._ui = _ui;
1063
+ },
1064
+
1065
+ // Determine which element will have `parsley-error` and `parsley-success` classes
1066
+ _manageClassHandler: function _manageClassHandler() {
1067
+ // Class handled could also be determined by function given in Parsley options
1068
+ if ('string' === typeof this.options.classHandler && $(this.options.classHandler).length) return $(this.options.classHandler);
1069
+
1070
+ // Class handled could also be determined by function given in Parsley options
1071
+ var $handlerFunction = this.options.classHandler;
1072
+
1073
+ // It might also be the function name of a global function
1074
+ if ('string' === typeof this.options.classHandler && 'function' === typeof window[this.options.classHandler]) $handlerFunction = window[this.options.classHandler];
1075
+
1076
+ if ('function' === typeof $handlerFunction) {
1077
+ var $handler = $handlerFunction.call(this, this);
1078
+
1079
+ // If this function returned a valid existing DOM element, go for it
1080
+ if ('undefined' !== typeof $handler && $handler.length) return $handler;
1081
+ } else if ('object' === typeof $handlerFunction && $handlerFunction instanceof jQuery && $handlerFunction.length) {
1082
+ return $handlerFunction;
1083
+ } else if ($handlerFunction) {
1084
+ Utils.warn('The class handler `' + $handlerFunction + '` does not exist in DOM nor as a global JS function');
1085
+ }
1086
+
1087
+ return this._inputHolder();
1088
+ },
1089
+
1090
+ _inputHolder: function _inputHolder() {
1091
+ // if simple element (input, texatrea, select...) it will perfectly host the classes and precede the error container
1092
+ if (!this.options.multiple || this.element.nodeName === 'SELECT') return this.$element;
1093
+
1094
+ // But if multiple element (radio, checkbox), that would be their parent
1095
+ return this.$element.parent();
1096
+ },
1097
+
1098
+ _insertErrorWrapper: function _insertErrorWrapper() {
1099
+ var $errorsContainer = this.options.errorsContainer;
1100
+
1101
+ // Nothing to do if already inserted
1102
+ if (0 !== this._ui.$errorsWrapper.parent().length) return this._ui.$errorsWrapper.parent();
1103
+
1104
+ if ('string' === typeof $errorsContainer) {
1105
+ if ($($errorsContainer).length) return $($errorsContainer).append(this._ui.$errorsWrapper);else if ('function' === typeof window[$errorsContainer]) $errorsContainer = window[$errorsContainer];else Utils.warn('The errors container `' + $errorsContainer + '` does not exist in DOM nor as a global JS function');
1106
+ }
1107
+
1108
+ if ('function' === typeof $errorsContainer) $errorsContainer = $errorsContainer.call(this, this);
1109
+
1110
+ if ('object' === typeof $errorsContainer && $errorsContainer.length) return $errorsContainer.append(this._ui.$errorsWrapper);
1111
+
1112
+ return this._inputHolder().after(this._ui.$errorsWrapper);
1113
+ },
1114
+
1115
+ _actualizeTriggers: function _actualizeTriggers() {
1116
+ var _this3 = this;
1117
+
1118
+ var $toBind = this._findRelated();
1119
+ var trigger;
1120
+
1121
+ // Remove Parsley events already bound on this field
1122
+ $toBind.off('.Parsley');
1123
+ if (this._failedOnce) $toBind.on(Utils.namespaceEvents(this.options.triggerAfterFailure, 'Parsley'), function () {
1124
+ _this3._validateIfNeeded();
1125
+ });else if (trigger = Utils.namespaceEvents(this.options.trigger, 'Parsley')) {
1126
+ $toBind.on(trigger, function (event) {
1127
+ _this3._validateIfNeeded(event);
1128
+ });
1129
+ }
1130
+ },
1131
+
1132
+ _validateIfNeeded: function _validateIfNeeded(event) {
1133
+ var _this4 = this;
1134
+
1135
+ // For keyup, keypress, keydown, input... events that could be a little bit obstrusive
1136
+ // do not validate if val length < min threshold on first validation. Once field have been validated once and info
1137
+ // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.
1138
+ if (event && /key|input/.test(event.type)) if (!(this._ui && this._ui.validationInformationVisible) && this.getValue().length <= this.options.validationThreshold) return;
1139
+
1140
+ if (this.options.debounce) {
1141
+ window.clearTimeout(this._debounced);
1142
+ this._debounced = window.setTimeout(function () {
1143
+ return _this4.validate();
1144
+ }, this.options.debounce);
1145
+ } else this.validate();
1146
+ },
1147
+
1148
+ _resetUI: function _resetUI() {
1149
+ // Reset all event listeners
1150
+ this._failedOnce = false;
1151
+ this._actualizeTriggers();
1152
+
1153
+ // Nothing to do if UI never initialized for this field
1154
+ if ('undefined' === typeof this._ui) return;
1155
+
1156
+ // Reset all errors' li
1157
+ this._ui.$errorsWrapper.removeClass('filled').children().remove();
1158
+
1159
+ // Reset validation class
1160
+ this._resetClass();
1161
+
1162
+ // Reset validation flags and last validation result
1163
+ this._ui.lastValidationResult = [];
1164
+ this._ui.validationInformationVisible = false;
1165
+ },
1166
+
1167
+ _destroyUI: function _destroyUI() {
1168
+ this._resetUI();
1169
+
1170
+ if ('undefined' !== typeof this._ui) this._ui.$errorsWrapper.remove();
1171
+
1172
+ delete this._ui;
1173
+ },
1174
+
1175
+ _successClass: function _successClass() {
1176
+ this._ui.validationInformationVisible = true;
1177
+ this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass);
1178
+ },
1179
+ _errorClass: function _errorClass() {
1180
+ this._ui.validationInformationVisible = true;
1181
+ this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass);
1182
+ },
1183
+ _resetClass: function _resetClass() {
1184
+ this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass);
1185
+ }
1186
+ };
1187
+
1188
+ var Form = function Form(element, domOptions, options) {
1189
+ this.__class__ = 'Form';
1190
+
1191
+ this.element = element;
1192
+ this.$element = $(element);
1193
+ this.domOptions = domOptions;
1194
+ this.options = options;
1195
+ this.parent = window.Parsley;
1196
+
1197
+ this.fields = [];
1198
+ this.validationResult = null;
1199
+ };
1200
+
1201
+ var Form__statusMapping = { pending: null, resolved: true, rejected: false };
1202
+
1203
+ Form.prototype = {
1204
+ onSubmitValidate: function onSubmitValidate(event) {
1205
+ var _this5 = this;
1206
+
1207
+ // This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior
1208
+ if (true === event.parsley) return;
1209
+
1210
+ // If we didn't come here through a submit button, use the first one in the form
1211
+ var submitSource = this._submitSource || this.$element.find(Utils._SubmitSelector)[0];
1212
+ this._submitSource = null;
1213
+ this.$element.find('.parsley-synthetic-submit-button').prop('disabled', true);
1214
+ if (submitSource && null !== submitSource.getAttribute('formnovalidate')) return;
1215
+
1216
+ window.Parsley._remoteCache = {};
1217
+
1218
+ var promise = this.whenValidate({ event: event });
1219
+
1220
+ if ('resolved' === promise.state() && false !== this._trigger('submit')) {
1221
+ // All good, let event go through. We make this distinction because browsers
1222
+ // differ in their handling of `submit` being called from inside a submit event [#1047]
1223
+ } else {
1224
+ // Rejected or pending: cancel this submit
1225
+ event.stopImmediatePropagation();
1226
+ event.preventDefault();
1227
+ if ('pending' === promise.state()) promise.done(function () {
1228
+ _this5._submit(submitSource);
1229
+ });
1230
+ }
1231
+ },
1232
+
1233
+ onSubmitButton: function onSubmitButton(event) {
1234
+ this._submitSource = event.currentTarget;
1235
+ },
1236
+ // internal
1237
+ // _submit submits the form, this time without going through the validations.
1238
+ // Care must be taken to "fake" the actual submit button being clicked.
1239
+ _submit: function _submit(submitSource) {
1240
+ if (false === this._trigger('submit')) return;
1241
+ // Add submit button's data
1242
+ if (submitSource) {
1243
+ var $synthetic = this.$element.find('.parsley-synthetic-submit-button').prop('disabled', false);
1244
+ if (0 === $synthetic.length) $synthetic = $('<input class="parsley-synthetic-submit-button" type="hidden">').appendTo(this.$element);
1245
+ $synthetic.attr({
1246
+ name: submitSource.getAttribute('name'),
1247
+ value: submitSource.getAttribute('value')
1248
+ });
1249
+ }
1250
+
1251
+ this.$element.trigger(_extends($.Event('submit'), { parsley: true }));
1252
+ },
1253
+
1254
+ // Performs validation on fields while triggering events.
1255
+ // @returns `true` if all validations succeeds, `false`
1256
+ // if a failure is immediately detected, or `null`
1257
+ // if dependant on a promise.
1258
+ // Consider using `whenValidate` instead.
1259
+ validate: function validate(options) {
1260
+ if (arguments.length >= 1 && !$.isPlainObject(options)) {
1261
+ Utils.warnOnce('Calling validate on a parsley form without passing arguments as an object is deprecated.');
1262
+
1263
+ var _arguments = _slice.call(arguments);
1264
+
1265
+ var group = _arguments[0];
1266
+ var force = _arguments[1];
1267
+ var event = _arguments[2];
1268
+
1269
+ options = { group: group, force: force, event: event };
1270
+ }
1271
+ return Form__statusMapping[this.whenValidate(options).state()];
1272
+ },
1273
+
1274
+ whenValidate: function whenValidate() {
1275
+ var _Utils$all$done$fail$always,
1276
+ _this6 = this;
1277
+
1278
+ var _ref7 = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
1279
+
1280
+ var group = _ref7.group;
1281
+ var force = _ref7.force;
1282
+ var event = _ref7.event;
1283
+
1284
+ this.submitEvent = event;
1285
+ if (event) {
1286
+ this.submitEvent = _extends({}, event, { preventDefault: function preventDefault() {
1287
+ Utils.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`");
1288
+ _this6.validationResult = false;
1289
+ } });
1290
+ }
1291
+ this.validationResult = true;
1292
+
1293
+ // fire validate event to eventually modify things before every validation
1294
+ this._trigger('validate');
1295
+
1296
+ // Refresh form DOM options and form's fields that could have changed
1297
+ this._refreshFields();
1298
+
1299
+ var promises = this._withoutReactualizingFormOptions(function () {
1300
+ return $.map(_this6.fields, function (field) {
1301
+ return field.whenValidate({ force: force, group: group });
1302
+ });
1303
+ });
1304
+
1305
+ return (_Utils$all$done$fail$always = Utils.all(promises).done(function () {
1306
+ _this6._trigger('success');
1307
+ }).fail(function () {
1308
+ _this6.validationResult = false;
1309
+ _this6.focus();
1310
+ _this6._trigger('error');
1311
+ }).always(function () {
1312
+ _this6._trigger('validated');
1313
+ })).pipe.apply(_Utils$all$done$fail$always, _toConsumableArray(this._pipeAccordingToValidationResult()));
1314
+ },
1315
+
1316
+ // Iterate over refreshed fields, and stop on first failure.
1317
+ // Returns `true` if all fields are valid, `false` if a failure is detected
1318
+ // or `null` if the result depends on an unresolved promise.
1319
+ // Prefer using `whenValid` instead.
1320
+ isValid: function isValid(options) {
1321
+ if (arguments.length >= 1 && !$.isPlainObject(options)) {
1322
+ Utils.warnOnce('Calling isValid on a parsley form without passing arguments as an object is deprecated.');
1323
+
1324
+ var _arguments2 = _slice.call(arguments);
1325
+
1326
+ var group = _arguments2[0];
1327
+ var force = _arguments2[1];
1328
+
1329
+ options = { group: group, force: force };
1330
+ }
1331
+ return Form__statusMapping[this.whenValid(options).state()];
1332
+ },
1333
+
1334
+ // Iterate over refreshed fields and validate them.
1335
+ // Returns a promise.
1336
+ // A validation that immediately fails will interrupt the validations.
1337
+ whenValid: function whenValid() {
1338
+ var _this7 = this;
1339
+
1340
+ var _ref8 = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
1341
+
1342
+ var group = _ref8.group;
1343
+ var force = _ref8.force;
1344
+
1345
+ this._refreshFields();
1346
+
1347
+ var promises = this._withoutReactualizingFormOptions(function () {
1348
+ return $.map(_this7.fields, function (field) {
1349
+ return field.whenValid({ group: group, force: force });
1350
+ });
1351
+ });
1352
+ return Utils.all(promises);
1353
+ },
1354
+
1355
+ refresh: function refresh() {
1356
+ this._refreshFields();
1357
+ return this;
1358
+ },
1359
+
1360
+ // Reset UI
1361
+ reset: function reset() {
1362
+ // Form case: emit a reset event for each field
1363
+ for (var i = 0; i < this.fields.length; i++) this.fields[i].reset();
1364
+
1365
+ this._trigger('reset');
1366
+ },
1367
+
1368
+ // Destroy Parsley instance (+ UI)
1369
+ destroy: function destroy() {
1370
+ // Field case: emit destroy event to clean UI and then destroy stored instance
1371
+ this._destroyUI();
1372
+
1373
+ // Form case: destroy all its fields and then destroy stored instance
1374
+ for (var i = 0; i < this.fields.length; i++) this.fields[i].destroy();
1375
+
1376
+ this.$element.removeData('Parsley');
1377
+ this._trigger('destroy');
1378
+ },
1379
+
1380
+ _refreshFields: function _refreshFields() {
1381
+ return this.actualizeOptions()._bindFields();
1382
+ },
1383
+
1384
+ _bindFields: function _bindFields() {
1385
+ var _this8 = this;
1386
+
1387
+ var oldFields = this.fields;
1388
+
1389
+ this.fields = [];
1390
+ this.fieldsMappedById = {};
1391
+
1392
+ this._withoutReactualizingFormOptions(function () {
1393
+ _this8.$element.find(_this8.options.inputs).not(_this8.options.excluded).each(function (_, element) {
1394
+ var fieldInstance = new window.Parsley.Factory(element, {}, _this8);
1395
+
1396
+ // Only add valid and not excluded `Field` and `FieldMultiple` children
1397
+ if (('Field' === fieldInstance.__class__ || 'FieldMultiple' === fieldInstance.__class__) && true !== fieldInstance.options.excluded) {
1398
+ var uniqueId = fieldInstance.__class__ + '-' + fieldInstance.__id__;
1399
+ if ('undefined' === typeof _this8.fieldsMappedById[uniqueId]) {
1400
+ _this8.fieldsMappedById[uniqueId] = fieldInstance;
1401
+ _this8.fields.push(fieldInstance);
1402
+ }
1403
+ }
1404
+ });
1405
+
1406
+ $.each(Utils.difference(oldFields, _this8.fields), function (_, field) {
1407
+ field.reset();
1408
+ });
1409
+ });
1410
+ return this;
1411
+ },
1412
+
1413
+ // Internal only.
1414
+ // Looping on a form's fields to do validation or similar
1415
+ // will trigger reactualizing options on all of them, which
1416
+ // in turn will reactualize the form's options.
1417
+ // To avoid calling actualizeOptions so many times on the form
1418
+ // for nothing, _withoutReactualizingFormOptions temporarily disables
1419
+ // the method actualizeOptions on this form while `fn` is called.
1420
+ _withoutReactualizingFormOptions: function _withoutReactualizingFormOptions(fn) {
1421
+ var oldActualizeOptions = this.actualizeOptions;
1422
+ this.actualizeOptions = function () {
1423
+ return this;
1424
+ };
1425
+ var result = fn();
1426
+ this.actualizeOptions = oldActualizeOptions;
1427
+ return result;
1428
+ },
1429
+
1430
+ // Internal only.
1431
+ // Shortcut to trigger an event
1432
+ // Returns true iff event is not interrupted and default not prevented.
1433
+ _trigger: function _trigger(eventName) {
1434
+ return this.trigger('form:' + eventName);
1435
+ }
1436
+
1437
+ };
1438
+
1439
+ var Constraint = function Constraint(parsleyField, name, requirements, priority, isDomConstraint) {
1440
+ var validatorSpec = window.Parsley._validatorRegistry.validators[name];
1441
+ var validator = new Validator(validatorSpec);
1442
+ priority = priority || parsleyField.options[name + 'Priority'] || validator.priority;
1443
+ isDomConstraint = true === isDomConstraint;
1444
+
1445
+ _extends(this, {
1446
+ validator: validator,
1447
+ name: name,
1448
+ requirements: requirements,
1449
+ priority: priority,
1450
+ isDomConstraint: isDomConstraint
1451
+ });
1452
+ this._parseRequirements(parsleyField.options);
1453
+ };
1454
+
1455
+ var capitalize = function capitalize(str) {
1456
+ var cap = str[0].toUpperCase();
1457
+ return cap + str.slice(1);
1458
+ };
1459
+
1460
+ Constraint.prototype = {
1461
+ validate: function validate(value, instance) {
1462
+ var _validator;
1463
+
1464
+ return (_validator = this.validator).validate.apply(_validator, [value].concat(_toConsumableArray(this.requirementList), [instance]));
1465
+ },
1466
+
1467
+ _parseRequirements: function _parseRequirements(options) {
1468
+ var _this9 = this;
1469
+
1470
+ this.requirementList = this.validator.parseRequirements(this.requirements, function (key) {
1471
+ return options[_this9.name + capitalize(key)];
1472
+ });
1473
+ }
1474
+ };
1475
+
1476
+ var Field = function Field(field, domOptions, options, parsleyFormInstance) {
1477
+ this.__class__ = 'Field';
1478
+
1479
+ this.element = field;
1480
+ this.$element = $(field);
1481
+
1482
+ // Set parent if we have one
1483
+ if ('undefined' !== typeof parsleyFormInstance) {
1484
+ this.parent = parsleyFormInstance;
1485
+ }
1486
+
1487
+ this.options = options;
1488
+ this.domOptions = domOptions;
1489
+
1490
+ // Initialize some properties
1491
+ this.constraints = [];
1492
+ this.constraintsByName = {};
1493
+ this.validationResult = true;
1494
+
1495
+ // Bind constraints
1496
+ this._bindConstraints();
1497
+ };
1498
+
1499
+ var parsley_field__statusMapping = { pending: null, resolved: true, rejected: false };
1500
+
1501
+ Field.prototype = {
1502
+ // # Public API
1503
+ // Validate field and trigger some events for mainly `UI`
1504
+ // @returns `true`, an array of the validators that failed, or
1505
+ // `null` if validation is not finished. Prefer using whenValidate
1506
+ validate: function validate(options) {
1507
+ if (arguments.length >= 1 && !$.isPlainObject(options)) {
1508
+ Utils.warnOnce('Calling validate on a parsley field without passing arguments as an object is deprecated.');
1509
+ options = { options: options };
1510
+ }
1511
+ var promise = this.whenValidate(options);
1512
+ if (!promise) // If excluded with `group` option
1513
+ return true;
1514
+ switch (promise.state()) {
1515
+ case 'pending':
1516
+ return null;
1517
+ case 'resolved':
1518
+ return true;
1519
+ case 'rejected':
1520
+ return this.validationResult;
1521
+ }
1522
+ },
1523
+
1524
+ // Validate field and trigger some events for mainly `UI`
1525
+ // @returns a promise that succeeds only when all validations do
1526
+ // or `undefined` if field is not in the given `group`.
1527
+ whenValidate: function whenValidate() {
1528
+ var _whenValid$always$done$fail$always,
1529
+ _this10 = this;
1530
+
1531
+ var _ref9 = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
1532
+
1533
+ var force = _ref9.force;
1534
+ var group = _ref9.group;
1535
+
1536
+ // do not validate a field if not the same as given validation group
1537
+ this.refresh();
1538
+ if (group && !this._isInGroup(group)) return;
1539
+
1540
+ this.value = this.getValue();
1541
+
1542
+ // Field Validate event. `this.value` could be altered for custom needs
1543
+ this._trigger('validate');
1544
+
1545
+ return (_whenValid$always$done$fail$always = this.whenValid({ force: force, value: this.value, _refreshed: true }).always(function () {
1546
+ _this10._reflowUI();
1547
+ }).done(function () {
1548
+ _this10._trigger('success');
1549
+ }).fail(function () {
1550
+ _this10._trigger('error');
1551
+ }).always(function () {
1552
+ _this10._trigger('validated');
1553
+ })).pipe.apply(_whenValid$always$done$fail$always, _toConsumableArray(this._pipeAccordingToValidationResult()));
1554
+ },
1555
+
1556
+ hasConstraints: function hasConstraints() {
1557
+ return 0 !== this.constraints.length;
1558
+ },
1559
+
1560
+ // An empty optional field does not need validation
1561
+ needsValidation: function needsValidation(value) {
1562
+ if ('undefined' === typeof value) value = this.getValue();
1563
+
1564
+ // If a field is empty and not required, it is valid
1565
+ // Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators
1566
+ if (!value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty) return false;
1567
+
1568
+ return true;
1569
+ },
1570
+
1571
+ _isInGroup: function _isInGroup(group) {
1572
+ if (Array.isArray(this.options.group)) return -1 !== $.inArray(group, this.options.group);
1573
+ return this.options.group === group;
1574
+ },
1575
+
1576
+ // Just validate field. Do not trigger any event.
1577
+ // Returns `true` iff all constraints pass, `false` if there are failures,
1578
+ // or `null` if the result can not be determined yet (depends on a promise)
1579
+ // See also `whenValid`.
1580
+ isValid: function isValid(options) {
1581
+ if (arguments.length >= 1 && !$.isPlainObject(options)) {
1582
+ Utils.warnOnce('Calling isValid on a parsley field without passing arguments as an object is deprecated.');
1583
+
1584
+ var _arguments3 = _slice.call(arguments);
1585
+
1586
+ var force = _arguments3[0];
1587
+ var value = _arguments3[1];
1588
+
1589
+ options = { force: force, value: value };
1590
+ }
1591
+ var promise = this.whenValid(options);
1592
+ if (!promise) // Excluded via `group`
1593
+ return true;
1594
+ return parsley_field__statusMapping[promise.state()];
1595
+ },
1596
+
1597
+ // Just validate field. Do not trigger any event.
1598
+ // @returns a promise that succeeds only when all validations do
1599
+ // or `undefined` if the field is not in the given `group`.
1600
+ // The argument `force` will force validation of empty fields.
1601
+ // If a `value` is given, it will be validated instead of the value of the input.
1602
+ whenValid: function whenValid() {
1603
+ var _this11 = this;
1604
+
1605
+ var _ref10 = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
1606
+
1607
+ var _ref10$force = _ref10.force;
1608
+ var force = _ref10$force === undefined ? false : _ref10$force;
1609
+ var value = _ref10.value;
1610
+ var group = _ref10.group;
1611
+ var _refreshed = _ref10._refreshed;
1612
+
1613
+ // Recompute options and rebind constraints to have latest changes
1614
+ if (!_refreshed) this.refresh();
1615
+ // do not validate a field if not the same as given validation group
1616
+ if (group && !this._isInGroup(group)) return;
1617
+
1618
+ this.validationResult = true;
1619
+
1620
+ // A field without constraint is valid
1621
+ if (!this.hasConstraints()) return $.when();
1622
+
1623
+ // Value could be passed as argument, needed to add more power to 'field:validate'
1624
+ if ('undefined' === typeof value || null === value) value = this.getValue();
1625
+
1626
+ if (!this.needsValidation(value) && true !== force) return $.when();
1627
+
1628
+ var groupedConstraints = this._getGroupedConstraints();
1629
+ var promises = [];
1630
+ $.each(groupedConstraints, function (_, constraints) {
1631
+ // Process one group of constraints at a time, we validate the constraints
1632
+ // and combine the promises together.
1633
+ var promise = Utils.all($.map(constraints, function (constraint) {
1634
+ return _this11._validateConstraint(value, constraint);
1635
+ }));
1636
+ promises.push(promise);
1637
+ if (promise.state() === 'rejected') return false; // Interrupt processing if a group has already failed
1638
+ });
1639
+ return Utils.all(promises);
1640
+ },
1641
+
1642
+ // @returns a promise
1643
+ _validateConstraint: function _validateConstraint(value, constraint) {
1644
+ var _this12 = this;
1645
+
1646
+ var result = constraint.validate(value, this);
1647
+ // Map false to a failed promise
1648
+ if (false === result) result = $.Deferred().reject();
1649
+ // Make sure we return a promise and that we record failures
1650
+ return Utils.all([result]).fail(function (errorMessage) {
1651
+ if (!(_this12.validationResult instanceof Array)) _this12.validationResult = [];
1652
+ _this12.validationResult.push({
1653
+ assert: constraint,
1654
+ errorMessage: 'string' === typeof errorMessage && errorMessage
1655
+ });
1656
+ });
1657
+ },
1658
+
1659
+ // @returns Parsley field computed value that could be overrided or configured in DOM
1660
+ getValue: function getValue() {
1661
+ var value;
1662
+
1663
+ // Value could be overriden in DOM or with explicit options
1664
+ if ('function' === typeof this.options.value) value = this.options.value(this);else if ('undefined' !== typeof this.options.value) value = this.options.value;else value = this.$element.val();
1665
+
1666
+ // Handle wrong DOM or configurations
1667
+ if ('undefined' === typeof value || null === value) return '';
1668
+
1669
+ return this._handleWhitespace(value);
1670
+ },
1671
+
1672
+ // Reset UI
1673
+ reset: function reset() {
1674
+ this._resetUI();
1675
+ return this._trigger('reset');
1676
+ },
1677
+
1678
+ // Destroy Parsley instance (+ UI)
1679
+ destroy: function destroy() {
1680
+ // Field case: emit destroy event to clean UI and then destroy stored instance
1681
+ this._destroyUI();
1682
+ this.$element.removeData('Parsley');
1683
+ this.$element.removeData('FieldMultiple');
1684
+ this._trigger('destroy');
1685
+ },
1686
+
1687
+ // Actualize options and rebind constraints
1688
+ refresh: function refresh() {
1689
+ this._refreshConstraints();
1690
+ return this;
1691
+ },
1692
+
1693
+ _refreshConstraints: function _refreshConstraints() {
1694
+ return this.actualizeOptions()._bindConstraints();
1695
+ },
1696
+
1697
+ refreshConstraints: function refreshConstraints() {
1698
+ Utils.warnOnce("Parsley's refreshConstraints is deprecated. Please use refresh");
1699
+ return this.refresh();
1700
+ },
1701
+
1702
+ /**
1703
+ * Add a new constraint to a field
1704
+ *
1705
+ * @param {String} name
1706
+ * @param {Mixed} requirements optional
1707
+ * @param {Number} priority optional
1708
+ * @param {Boolean} isDomConstraint optional
1709
+ */
1710
+ addConstraint: function addConstraint(name, requirements, priority, isDomConstraint) {
1711
+
1712
+ if (window.Parsley._validatorRegistry.validators[name]) {
1713
+ var constraint = new Constraint(this, name, requirements, priority, isDomConstraint);
1714
+
1715
+ // if constraint already exist, delete it and push new version
1716
+ if ('undefined' !== this.constraintsByName[constraint.name]) this.removeConstraint(constraint.name);
1717
+
1718
+ this.constraints.push(constraint);
1719
+ this.constraintsByName[constraint.name] = constraint;
1720
+ }
1721
+
1722
+ return this;
1723
+ },
1724
+
1725
+ // Remove a constraint
1726
+ removeConstraint: function removeConstraint(name) {
1727
+ for (var i = 0; i < this.constraints.length; i++) if (name === this.constraints[i].name) {
1728
+ this.constraints.splice(i, 1);
1729
+ break;
1730
+ }
1731
+ delete this.constraintsByName[name];
1732
+ return this;
1733
+ },
1734
+
1735
+ // Update a constraint (Remove + re-add)
1736
+ updateConstraint: function updateConstraint(name, parameters, priority) {
1737
+ return this.removeConstraint(name).addConstraint(name, parameters, priority);
1738
+ },
1739
+
1740
+ // # Internals
1741
+
1742
+ // Internal only.
1743
+ // Bind constraints from config + options + DOM
1744
+ _bindConstraints: function _bindConstraints() {
1745
+ var constraints = [];
1746
+ var constraintsByName = {};
1747
+
1748
+ // clean all existing DOM constraints to only keep javascript user constraints
1749
+ for (var i = 0; i < this.constraints.length; i++) if (false === this.constraints[i].isDomConstraint) {
1750
+ constraints.push(this.constraints[i]);
1751
+ constraintsByName[this.constraints[i].name] = this.constraints[i];
1752
+ }
1753
+
1754
+ this.constraints = constraints;
1755
+ this.constraintsByName = constraintsByName;
1756
+
1757
+ // then re-add Parsley DOM-API constraints
1758
+ for (var name in this.options) this.addConstraint(name, this.options[name], undefined, true);
1759
+
1760
+ // finally, bind special HTML5 constraints
1761
+ return this._bindHtml5Constraints();
1762
+ },
1763
+
1764
+ // Internal only.
1765
+ // Bind specific HTML5 constraints to be HTML5 compliant
1766
+ _bindHtml5Constraints: function _bindHtml5Constraints() {
1767
+ // html5 required
1768
+ if (null !== this.element.getAttribute('required')) this.addConstraint('required', true, undefined, true);
1769
+
1770
+ // html5 pattern
1771
+ if (null !== this.element.getAttribute('pattern')) this.addConstraint('pattern', this.element.getAttribute('pattern'), undefined, true);
1772
+
1773
+ // range
1774
+ var min = this.element.getAttribute('min');
1775
+ var max = this.element.getAttribute('max');
1776
+ if (null !== min && null !== max) this.addConstraint('range', [min, max], undefined, true);
1777
+
1778
+ // HTML5 min
1779
+ else if (null !== min) this.addConstraint('min', min, undefined, true);
1780
+
1781
+ // HTML5 max
1782
+ else if (null !== max) this.addConstraint('max', max, undefined, true);
1783
+
1784
+ // length
1785
+ if (null !== this.element.getAttribute('minlength') && null !== this.element.getAttribute('maxlength')) this.addConstraint('length', [this.element.getAttribute('minlength'), this.element.getAttribute('maxlength')], undefined, true);
1786
+
1787
+ // HTML5 minlength
1788
+ else if (null !== this.element.getAttribute('minlength')) this.addConstraint('minlength', this.element.getAttribute('minlength'), undefined, true);
1789
+
1790
+ // HTML5 maxlength
1791
+ else if (null !== this.element.getAttribute('maxlength')) this.addConstraint('maxlength', this.element.getAttribute('maxlength'), undefined, true);
1792
+
1793
+ // html5 types
1794
+ var type = Utils.getType(this.element);
1795
+
1796
+ // Small special case here for HTML5 number: integer validator if step attribute is undefined or an integer value, number otherwise
1797
+ if ('number' === type) {
1798
+ return this.addConstraint('type', ['number', {
1799
+ step: this.element.getAttribute('step') || '1',
1800
+ base: min || this.element.getAttribute('value')
1801
+ }], undefined, true);
1802
+ // Regular other HTML5 supported types
1803
+ } else if (/^(email|url|range|date)$/i.test(type)) {
1804
+ return this.addConstraint('type', type, undefined, true);
1805
+ }
1806
+ return this;
1807
+ },
1808
+
1809
+ // Internal only.
1810
+ // Field is required if have required constraint without `false` value
1811
+ _isRequired: function _isRequired() {
1812
+ if ('undefined' === typeof this.constraintsByName.required) return false;
1813
+
1814
+ return false !== this.constraintsByName.required.requirements;
1815
+ },
1816
+
1817
+ // Internal only.
1818
+ // Shortcut to trigger an event
1819
+ _trigger: function _trigger(eventName) {
1820
+ return this.trigger('field:' + eventName);
1821
+ },
1822
+
1823
+ // Internal only
1824
+ // Handles whitespace in a value
1825
+ // Use `data-parsley-whitespace="squish"` to auto squish input value
1826
+ // Use `data-parsley-whitespace="trim"` to auto trim input value
1827
+ _handleWhitespace: function _handleWhitespace(value) {
1828
+ if (true === this.options.trimValue) Utils.warnOnce('data-parsley-trim-value="true" is deprecated, please use data-parsley-whitespace="trim"');
1829
+
1830
+ if ('squish' === this.options.whitespace) value = value.replace(/\s{2,}/g, ' ');
1831
+
1832
+ if ('trim' === this.options.whitespace || 'squish' === this.options.whitespace || true === this.options.trimValue) value = Utils.trimString(value);
1833
+
1834
+ return value;
1835
+ },
1836
+
1837
+ _isDateInput: function _isDateInput() {
1838
+ var c = this.constraintsByName.type;
1839
+ return c && c.requirements === 'date';
1840
+ },
1841
+
1842
+ // Internal only.
1843
+ // Returns the constraints, grouped by descending priority.
1844
+ // The result is thus an array of arrays of constraints.
1845
+ _getGroupedConstraints: function _getGroupedConstraints() {
1846
+ if (false === this.options.priorityEnabled) return [this.constraints];
1847
+
1848
+ var groupedConstraints = [];
1849
+ var index = {};
1850
+
1851
+ // Create array unique of priorities
1852
+ for (var i = 0; i < this.constraints.length; i++) {
1853
+ var p = this.constraints[i].priority;
1854
+ if (!index[p]) groupedConstraints.push(index[p] = []);
1855
+ index[p].push(this.constraints[i]);
1856
+ }
1857
+ // Sort them by priority DESC
1858
+ groupedConstraints.sort(function (a, b) {
1859
+ return b[0].priority - a[0].priority;
1860
+ });
1861
+
1862
+ return groupedConstraints;
1863
+ }
1864
+
1865
+ };
1866
+
1867
+ var parsley_field = Field;
1868
+
1869
+ var Multiple = function Multiple() {
1870
+ this.__class__ = 'FieldMultiple';
1871
+ };
1872
+
1873
+ Multiple.prototype = {
1874
+ // Add new `$element` sibling for multiple field
1875
+ addElement: function addElement($element) {
1876
+ this.$elements.push($element);
1877
+
1878
+ return this;
1879
+ },
1880
+
1881
+ // See `Field._refreshConstraints()`
1882
+ _refreshConstraints: function _refreshConstraints() {
1883
+ var fieldConstraints;
1884
+
1885
+ this.constraints = [];
1886
+
1887
+ // Select multiple special treatment
1888
+ if (this.element.nodeName === 'SELECT') {
1889
+ this.actualizeOptions()._bindConstraints();
1890
+
1891
+ return this;
1892
+ }
1893
+
1894
+ // Gather all constraints for each input in the multiple group
1895
+ for (var i = 0; i < this.$elements.length; i++) {
1896
+
1897
+ // Check if element have not been dynamically removed since last binding
1898
+ if (!$('html').has(this.$elements[i]).length) {
1899
+ this.$elements.splice(i, 1);
1900
+ continue;
1901
+ }
1902
+
1903
+ fieldConstraints = this.$elements[i].data('FieldMultiple')._refreshConstraints().constraints;
1904
+
1905
+ for (var j = 0; j < fieldConstraints.length; j++) this.addConstraint(fieldConstraints[j].name, fieldConstraints[j].requirements, fieldConstraints[j].priority, fieldConstraints[j].isDomConstraint);
1906
+ }
1907
+
1908
+ return this;
1909
+ },
1910
+
1911
+ // See `Field.getValue()`
1912
+ getValue: function getValue() {
1913
+ // Value could be overriden in DOM
1914
+ if ('function' === typeof this.options.value) return this.options.value(this);else if ('undefined' !== typeof this.options.value) return this.options.value;
1915
+
1916
+ // Radio input case
1917
+ if (this.element.nodeName === 'INPUT') {
1918
+ var type = Utils.getType(this.element);
1919
+ if (type === 'radio') return this._findRelated().filter(':checked').val() || '';
1920
+
1921
+ // checkbox input case
1922
+ if (type === 'checkbox') {
1923
+ var values = [];
1924
+
1925
+ this._findRelated().filter(':checked').each(function () {
1926
+ values.push($(this).val());
1927
+ });
1928
+
1929
+ return values;
1930
+ }
1931
+ }
1932
+
1933
+ // Select multiple case
1934
+ if (this.element.nodeName === 'SELECT' && null === this.$element.val()) return [];
1935
+
1936
+ // Default case that should never happen
1937
+ return this.$element.val();
1938
+ },
1939
+
1940
+ _init: function _init() {
1941
+ this.$elements = [this.$element];
1942
+
1943
+ return this;
1944
+ }
1945
+ };
1946
+
1947
+ var Factory = function Factory(element, options, parsleyFormInstance) {
1948
+ this.element = element;
1949
+ this.$element = $(element);
1950
+
1951
+ // If the element has already been bound, returns its saved Parsley instance
1952
+ var savedparsleyFormInstance = this.$element.data('Parsley');
1953
+ if (savedparsleyFormInstance) {
1954
+
1955
+ // If the saved instance has been bound without a Form parent and there is one given in this call, add it
1956
+ if ('undefined' !== typeof parsleyFormInstance && savedparsleyFormInstance.parent === window.Parsley) {
1957
+ savedparsleyFormInstance.parent = parsleyFormInstance;
1958
+ savedparsleyFormInstance._resetOptions(savedparsleyFormInstance.options);
1959
+ }
1960
+
1961
+ if ('object' === typeof options) {
1962
+ _extends(savedparsleyFormInstance.options, options);
1963
+ }
1964
+
1965
+ return savedparsleyFormInstance;
1966
+ }
1967
+
1968
+ // Parsley must be instantiated with a DOM element or jQuery $element
1969
+ if (!this.$element.length) throw new Error('You must bind Parsley on an existing element.');
1970
+
1971
+ if ('undefined' !== typeof parsleyFormInstance && 'Form' !== parsleyFormInstance.__class__) throw new Error('Parent instance must be a Form instance');
1972
+
1973
+ this.parent = parsleyFormInstance || window.Parsley;
1974
+ return this.init(options);
1975
+ };
1976
+
1977
+ Factory.prototype = {
1978
+ init: function init(options) {
1979
+ this.__class__ = 'Parsley';
1980
+ this.__version__ = '2.8.0';
1981
+ this.__id__ = Utils.generateID();
1982
+
1983
+ // Pre-compute options
1984
+ this._resetOptions(options);
1985
+
1986
+ // A Form instance is obviously a `<form>` element but also every node that is not an input and has the `data-parsley-validate` attribute
1987
+ if (this.element.nodeName === 'FORM' || Utils.checkAttr(this.element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)) return this.bind('parsleyForm');
1988
+
1989
+ // Every other element is bound as a `Field` or `FieldMultiple`
1990
+ return this.isMultiple() ? this.handleMultiple() : this.bind('parsleyField');
1991
+ },
1992
+
1993
+ isMultiple: function isMultiple() {
1994
+ var type = Utils.getType(this.element);
1995
+ return type === 'radio' || type === 'checkbox' || this.element.nodeName === 'SELECT' && null !== this.element.getAttribute('multiple');
1996
+ },
1997
+
1998
+ // Multiples fields are a real nightmare :(
1999
+ // Maybe some refactoring would be appreciated here...
2000
+ handleMultiple: function handleMultiple() {
2001
+ var _this13 = this;
2002
+
2003
+ var name;
2004
+ var multiple;
2005
+ var parsleyMultipleInstance;
2006
+
2007
+ // Handle multiple name
2008
+ this.options.multiple = this.options.multiple || (name = this.element.getAttribute('name')) || this.element.getAttribute('id');
2009
+
2010
+ // Special select multiple input
2011
+ if (this.element.nodeName === 'SELECT' && null !== this.element.getAttribute('multiple')) {
2012
+ this.options.multiple = this.options.multiple || this.__id__;
2013
+ return this.bind('parsleyFieldMultiple');
2014
+
2015
+ // Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it
2016
+ } else if (!this.options.multiple) {
2017
+ Utils.warn('To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.', this.$element);
2018
+ return this;
2019
+ }
2020
+
2021
+ // Remove special chars
2022
+ this.options.multiple = this.options.multiple.replace(/(:|\.|\[|\]|\{|\}|\$)/g, '');
2023
+
2024
+ // Add proper `data-parsley-multiple` to siblings if we have a valid multiple name
2025
+ if (name) {
2026
+ $('input[name="' + name + '"]').each(function (i, input) {
2027
+ var type = Utils.getType(input);
2028
+ if (type === 'radio' || type === 'checkbox') input.setAttribute(_this13.options.namespace + 'multiple', _this13.options.multiple);
2029
+ });
2030
+ }
2031
+
2032
+ // Check here if we don't already have a related multiple instance saved
2033
+ var $previouslyRelated = this._findRelated();
2034
+ for (var i = 0; i < $previouslyRelated.length; i++) {
2035
+ parsleyMultipleInstance = $($previouslyRelated.get(i)).data('Parsley');
2036
+ if ('undefined' !== typeof parsleyMultipleInstance) {
2037
+
2038
+ if (!this.$element.data('FieldMultiple')) {
2039
+ parsleyMultipleInstance.addElement(this.$element);
2040
+ }
2041
+
2042
+ break;
2043
+ }
2044
+ }
2045
+
2046
+ // Create a secret Field instance for every multiple field. It will be stored in `data('FieldMultiple')`
2047
+ // And will be useful later to access classic `Field` stuff while being in a `FieldMultiple` instance
2048
+ this.bind('parsleyField', true);
2049
+
2050
+ return parsleyMultipleInstance || this.bind('parsleyFieldMultiple');
2051
+ },
2052
+
2053
+ // Return proper `Form`, `Field` or `FieldMultiple`
2054
+ bind: function bind(type, doNotStore) {
2055
+ var parsleyInstance;
2056
+
2057
+ switch (type) {
2058
+ case 'parsleyForm':
2059
+ parsleyInstance = $.extend(new Form(this.element, this.domOptions, this.options), new Base(), window.ParsleyExtend)._bindFields();
2060
+ break;
2061
+ case 'parsleyField':
2062
+ parsleyInstance = $.extend(new parsley_field(this.element, this.domOptions, this.options, this.parent), new Base(), window.ParsleyExtend);
2063
+ break;
2064
+ case 'parsleyFieldMultiple':
2065
+ parsleyInstance = $.extend(new parsley_field(this.element, this.domOptions, this.options, this.parent), new Multiple(), new Base(), window.ParsleyExtend)._init();
2066
+ break;
2067
+ default:
2068
+ throw new Error(type + 'is not a supported Parsley type');
2069
+ }
2070
+
2071
+ if (this.options.multiple) Utils.setAttr(this.element, this.options.namespace, 'multiple', this.options.multiple);
2072
+
2073
+ if ('undefined' !== typeof doNotStore) {
2074
+ this.$element.data('FieldMultiple', parsleyInstance);
2075
+
2076
+ return parsleyInstance;
2077
+ }
2078
+
2079
+ // Store the freshly bound instance in a DOM element for later access using jQuery `data()`
2080
+ this.$element.data('Parsley', parsleyInstance);
2081
+
2082
+ // Tell the world we have a new Form or Field instance!
2083
+ parsleyInstance._actualizeTriggers();
2084
+ parsleyInstance._trigger('init');
2085
+
2086
+ return parsleyInstance;
2087
+ }
2088
+ };
2089
+
2090
+ var vernums = $.fn.jquery.split('.');
2091
+ if (parseInt(vernums[0]) <= 1 && parseInt(vernums[1]) < 8) {
2092
+ throw "The loaded version of jQuery is too old. Please upgrade to 1.8.x or better.";
2093
+ }
2094
+ if (!vernums.forEach) {
2095
+ Utils.warn('Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim');
2096
+ }
2097
+ // Inherit `on`, `off` & `trigger` to Parsley:
2098
+ var Parsley = _extends(new Base(), {
2099
+ element: document,
2100
+ $element: $(document),
2101
+ actualizeOptions: null,
2102
+ _resetOptions: null,
2103
+ Factory: Factory,
2104
+ version: '2.8.0'
2105
+ });
2106
+
2107
+ // Supplement Field and Form with Base
2108
+ // This way, the constructors will have access to those methods
2109
+ _extends(parsley_field.prototype, UI.Field, Base.prototype);
2110
+ _extends(Form.prototype, UI.Form, Base.prototype);
2111
+ // Inherit actualizeOptions and _resetOptions:
2112
+ _extends(Factory.prototype, Base.prototype);
2113
+
2114
+ // ### jQuery API
2115
+ // `$('.elem').parsley(options)` or `$('.elem').psly(options)`
2116
+ $.fn.parsley = $.fn.psly = function (options) {
2117
+ if (this.length > 1) {
2118
+ var instances = [];
2119
+
2120
+ this.each(function () {
2121
+ instances.push($(this).parsley(options));
2122
+ });
2123
+
2124
+ return instances;
2125
+ }
2126
+
2127
+ // Return undefined if applied to non existing DOM element
2128
+ if (this.length == 0) {
2129
+ return;
2130
+ }
2131
+
2132
+ return new Factory(this[0], options);
2133
+ };
2134
+
2135
+ // ### Field and Form extension
2136
+ // Ensure the extension is now defined if it wasn't previously
2137
+ if ('undefined' === typeof window.ParsleyExtend) window.ParsleyExtend = {};
2138
+
2139
+ // ### Parsley config
2140
+ // Inherit from ParsleyDefault, and copy over any existing values
2141
+ Parsley.options = _extends(Utils.objectCreate(Defaults), window.ParsleyConfig);
2142
+ window.ParsleyConfig = Parsley.options; // Old way of accessing global options
2143
+
2144
+ // ### Globals
2145
+ window.Parsley = window.psly = Parsley;
2146
+ Parsley.Utils = Utils;
2147
+ window.ParsleyUtils = {};
2148
+ $.each(Utils, function (key, value) {
2149
+ if ('function' === typeof value) {
2150
+ window.ParsleyUtils[key] = function () {
2151
+ Utils.warnOnce('Accessing `window.ParsleyUtils` is deprecated. Use `window.Parsley.Utils` instead.');
2152
+ return Utils[key].apply(Utils, arguments);
2153
+ };
2154
+ }
2155
+ });
2156
+
2157
+ // ### Define methods that forward to the registry, and deprecate all access except through window.Parsley
2158
+ var registry = window.Parsley._validatorRegistry = new ValidatorRegistry(window.ParsleyConfig.validators, window.ParsleyConfig.i18n);
2159
+ window.ParsleyValidator = {};
2160
+ $.each('setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator hasValidator'.split(' '), function (i, method) {
2161
+ window.Parsley[method] = function () {
2162
+ return registry[method].apply(registry, arguments);
2163
+ };
2164
+ window.ParsleyValidator[method] = function () {
2165
+ var _window$Parsley;
2166
+
2167
+ Utils.warnOnce('Accessing the method \'' + method + '\' through Validator is deprecated. Simply call \'window.Parsley.' + method + '(...)\'');
2168
+ return (_window$Parsley = window.Parsley)[method].apply(_window$Parsley, arguments);
2169
+ };
2170
+ });
2171
+
2172
+ // ### UI
2173
+ // Deprecated global object
2174
+ window.Parsley.UI = UI;
2175
+ window.ParsleyUI = {
2176
+ removeError: function removeError(instance, name, doNotUpdateClass) {
2177
+ var updateClass = true !== doNotUpdateClass;
2178
+ Utils.warnOnce('Accessing UI is deprecated. Call \'removeError\' on the instance directly. Please comment in issue 1073 as to your need to call this method.');
2179
+ return instance.removeError(name, { updateClass: updateClass });
2180
+ },
2181
+ getErrorsMessages: function getErrorsMessages(instance) {
2182
+ Utils.warnOnce('Accessing UI is deprecated. Call \'getErrorsMessages\' on the instance directly.');
2183
+ return instance.getErrorsMessages();
2184
+ }
2185
+ };
2186
+ $.each('addError updateError'.split(' '), function (i, method) {
2187
+ window.ParsleyUI[method] = function (instance, name, message, assert, doNotUpdateClass) {
2188
+ var updateClass = true !== doNotUpdateClass;
2189
+ Utils.warnOnce('Accessing UI is deprecated. Call \'' + method + '\' on the instance directly. Please comment in issue 1073 as to your need to call this method.');
2190
+ return instance[method](name, { message: message, assert: assert, updateClass: updateClass });
2191
+ };
2192
+ });
2193
+
2194
+ // ### PARSLEY auto-binding
2195
+ // Prevent it by setting `ParsleyConfig.autoBind` to `false`
2196
+ if (false !== window.ParsleyConfig.autoBind) {
2197
+ $(function () {
2198
+ // Works only on `data-parsley-validate`.
2199
+ if ($('[data-parsley-validate]').length) $('[data-parsley-validate]').parsley();
2200
+ });
2201
+ }
2202
+
2203
+ var o = $({});
2204
+ var deprecated = function deprecated() {
2205
+ Utils.warnOnce("Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley");
2206
+ };
2207
+
2208
+ // Returns an event handler that calls `fn` with the arguments it expects
2209
+ function adapt(fn, context) {
2210
+ // Store to allow unbinding
2211
+ if (!fn.parsleyAdaptedCallback) {
2212
+ fn.parsleyAdaptedCallback = function () {
2213
+ var args = Array.prototype.slice.call(arguments, 0);
2214
+ args.unshift(this);
2215
+ fn.apply(context || o, args);
2216
+ };
2217
+ }
2218
+ return fn.parsleyAdaptedCallback;
2219
+ }
2220
+
2221
+ var eventPrefix = 'parsley:';
2222
+ // Converts 'parsley:form:validate' into 'form:validate'
2223
+ function eventName(name) {
2224
+ if (name.lastIndexOf(eventPrefix, 0) === 0) return name.substr(eventPrefix.length);
2225
+ return name;
2226
+ }
2227
+
2228
+ // $.listen is deprecated. Use Parsley.on instead.
2229
+ $.listen = function (name, callback) {
2230
+ var context;
2231
+ deprecated();
2232
+ if ('object' === typeof arguments[1] && 'function' === typeof arguments[2]) {
2233
+ context = arguments[1];
2234
+ callback = arguments[2];
2235
+ }
2236
+
2237
+ if ('function' !== typeof callback) throw new Error('Wrong parameters');
2238
+
2239
+ window.Parsley.on(eventName(name), adapt(callback, context));
2240
+ };
2241
+
2242
+ $.listenTo = function (instance, name, fn) {
2243
+ deprecated();
2244
+ if (!(instance instanceof parsley_field) && !(instance instanceof Form)) throw new Error('Must give Parsley instance');
2245
+
2246
+ if ('string' !== typeof name || 'function' !== typeof fn) throw new Error('Wrong parameters');
2247
+
2248
+ instance.on(eventName(name), adapt(fn));
2249
+ };
2250
+
2251
+ $.unsubscribe = function (name, fn) {
2252
+ deprecated();
2253
+ if ('string' !== typeof name || 'function' !== typeof fn) throw new Error('Wrong arguments');
2254
+ window.Parsley.off(eventName(name), fn.parsleyAdaptedCallback);
2255
+ };
2256
+
2257
+ $.unsubscribeTo = function (instance, name) {
2258
+ deprecated();
2259
+ if (!(instance instanceof parsley_field) && !(instance instanceof Form)) throw new Error('Must give Parsley instance');
2260
+ instance.off(eventName(name));
2261
+ };
2262
+
2263
+ $.unsubscribeAll = function (name) {
2264
+ deprecated();
2265
+ window.Parsley.off(eventName(name));
2266
+ $('form,input,textarea,select').each(function () {
2267
+ var instance = $(this).data('Parsley');
2268
+ if (instance) {
2269
+ instance.off(eventName(name));
2270
+ }
2271
+ });
2272
+ };
2273
+
2274
+ // $.emit is deprecated. Use jQuery events instead.
2275
+ $.emit = function (name, instance) {
2276
+ var _instance;
2277
+
2278
+ deprecated();
2279
+ var instanceGiven = instance instanceof parsley_field || instance instanceof Form;
2280
+ var args = Array.prototype.slice.call(arguments, instanceGiven ? 2 : 1);
2281
+ args.unshift(eventName(name));
2282
+ if (!instanceGiven) {
2283
+ instance = window.Parsley;
2284
+ }
2285
+ (_instance = instance).trigger.apply(_instance, _toConsumableArray(args));
2286
+ };
2287
+
2288
+ var pubsub = {};
2289
+
2290
+ $.extend(true, Parsley, {
2291
+ asyncValidators: {
2292
+ 'default': {
2293
+ fn: function fn(xhr) {
2294
+ // By default, only status 2xx are deemed successful.
2295
+ // Note: we use status instead of state() because responses with status 200
2296
+ // but invalid messages (e.g. an empty body for content type set to JSON) will
2297
+ // result in state() === 'rejected'.
2298
+ return xhr.status >= 200 && xhr.status < 300;
2299
+ },
2300
+ url: false
2301
+ },
2302
+ reverse: {
2303
+ fn: function fn(xhr) {
2304
+ // If reverse option is set, a failing ajax request is considered successful
2305
+ return xhr.status < 200 || xhr.status >= 300;
2306
+ },
2307
+ url: false
2308
+ }
2309
+ },
2310
+
2311
+ addAsyncValidator: function addAsyncValidator(name, fn, url, options) {
2312
+ Parsley.asyncValidators[name] = {
2313
+ fn: fn,
2314
+ url: url || false,
2315
+ options: options || {}
2316
+ };
2317
+
2318
+ return this;
2319
+ }
2320
+
2321
+ });
2322
+
2323
+ Parsley.addValidator('remote', {
2324
+ requirementType: {
2325
+ '': 'string',
2326
+ 'validator': 'string',
2327
+ 'reverse': 'boolean',
2328
+ 'options': 'object'
2329
+ },
2330
+
2331
+ validateString: function validateString(value, url, options, instance) {
2332
+ var data = {};
2333
+ var ajaxOptions;
2334
+ var csr;
2335
+ var validator = options.validator || (true === options.reverse ? 'reverse' : 'default');
2336
+
2337
+ if ('undefined' === typeof Parsley.asyncValidators[validator]) throw new Error('Calling an undefined async validator: `' + validator + '`');
2338
+
2339
+ url = Parsley.asyncValidators[validator].url || url;
2340
+
2341
+ // Fill current value
2342
+ if (url.indexOf('{value}') > -1) {
2343
+ url = url.replace('{value}', encodeURIComponent(value));
2344
+ } else {
2345
+ data[instance.element.getAttribute('name') || instance.element.getAttribute('id')] = value;
2346
+ }
2347
+
2348
+ // Merge options passed in from the function with the ones in the attribute
2349
+ var remoteOptions = $.extend(true, options.options || {}, Parsley.asyncValidators[validator].options);
2350
+
2351
+ // All `$.ajax(options)` could be overridden or extended directly from DOM in `data-parsley-remote-options`
2352
+ ajaxOptions = $.extend(true, {}, {
2353
+ url: url,
2354
+ data: data,
2355
+ type: 'GET'
2356
+ }, remoteOptions);
2357
+
2358
+ // Generate store key based on ajax options
2359
+ instance.trigger('field:ajaxoptions', instance, ajaxOptions);
2360
+
2361
+ csr = $.param(ajaxOptions);
2362
+
2363
+ // Initialise querry cache
2364
+ if ('undefined' === typeof Parsley._remoteCache) Parsley._remoteCache = {};
2365
+
2366
+ // Try to retrieve stored xhr
2367
+ var xhr = Parsley._remoteCache[csr] = Parsley._remoteCache[csr] || $.ajax(ajaxOptions);
2368
+
2369
+ var handleXhr = function handleXhr() {
2370
+ var result = Parsley.asyncValidators[validator].fn.call(instance, xhr, url, options);
2371
+ if (!result) // Map falsy results to rejected promise
2372
+ result = $.Deferred().reject();
2373
+ return $.when(result);
2374
+ };
2375
+
2376
+ return xhr.then(handleXhr, handleXhr);
2377
+ },
2378
+
2379
+ priority: -1
2380
+ });
2381
+
2382
+ Parsley.on('form:submit', function () {
2383
+ Parsley._remoteCache = {};
2384
+ });
2385
+
2386
+ Base.prototype.addAsyncValidator = function () {
2387
+ Utils.warnOnce('Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`');
2388
+ return Parsley.addAsyncValidator.apply(Parsley, arguments);
2389
+ };
2390
+
2391
+ // This is included with the Parsley library itself,
2392
+ // thus there is no use in adding it to your project.
2393
+ Parsley.addMessages('en', {
2394
+ defaultMessage: "This value seems to be invalid.",
2395
+ type: {
2396
+ email: "This value should be a valid email.",
2397
+ url: "This value should be a valid url.",
2398
+ number: "This value should be a valid number.",
2399
+ integer: "This value should be a valid integer.",
2400
+ digits: "This value should be digits.",
2401
+ alphanum: "This value should be alphanumeric."
2402
+ },
2403
+ notblank: "This value should not be blank.",
2404
+ required: "This value is required.",
2405
+ pattern: "This value seems to be invalid.",
2406
+ min: "This value should be greater than or equal to %s.",
2407
+ max: "This value should be lower than or equal to %s.",
2408
+ range: "This value should be between %s and %s.",
2409
+ minlength: "This value is too short. It should have %s characters or more.",
2410
+ maxlength: "This value is too long. It should have %s characters or fewer.",
2411
+ length: "This value length is invalid. It should be between %s and %s characters long.",
2412
+ mincheck: "You must select at least %s choices.",
2413
+ maxcheck: "You must select %s choices or fewer.",
2414
+ check: "You must select between %s and %s choices.",
2415
+ equalto: "This value should be the same."
2416
+ });
2417
+
2418
+ Parsley.setLocale('en');
2419
+
2420
+ /**
2421
+ * inputevent - Alleviate browser bugs for input events
2422
+ * https://github.com/marcandre/inputevent
2423
+ * @version v0.0.3 - (built Thu, Apr 14th 2016, 5:58 pm)
2424
+ * @author Marc-Andre Lafortune <github@marc-andre.ca>
2425
+ * @license MIT
2426
+ */
2427
+
2428
+ function InputEvent() {
2429
+ var _this14 = this;
2430
+
2431
+ var globals = window || global;
2432
+
2433
+ // Slightly odd way construct our object. This way methods are force bound.
2434
+ // Used to test for duplicate library.
2435
+ _extends(this, {
2436
+
2437
+ // For browsers that do not support isTrusted, assumes event is native.
2438
+ isNative