widgets.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. <?php
  2. namespace Elementor;
  3. use Elementor\Core\Ajax_Manager;
  4. use Elementor\Core\Utils\Exceptions;
  5. if ( ! defined( 'ABSPATH' ) ) {
  6. exit; // Exit if accessed directly.
  7. }
  8. /**
  9. * Elementor widgets manager.
  10. *
  11. * Elementor widgets manager handler class is responsible for registering and
  12. * initializing all the supported Elementor widgets.
  13. *
  14. * @since 1.0.0
  15. */
  16. class Widgets_Manager {
  17. /**
  18. * Widget types.
  19. *
  20. * Holds the list of all the widget types.
  21. *
  22. * @since 1.0.0
  23. * @access private
  24. *
  25. * @var Widget_Base[]
  26. */
  27. private $_widget_types = null;
  28. /**
  29. * Init widgets.
  30. *
  31. * Initialize Elementor widgets manager. Include all the the widgets files
  32. * and register each Elementor and WordPress widget.
  33. *
  34. * @since 2.0.0
  35. * @access private
  36. */
  37. private function init_widgets() {
  38. $build_widgets_filename = [
  39. 'common',
  40. 'heading',
  41. 'image',
  42. 'text-editor',
  43. 'video',
  44. 'button',
  45. 'divider',
  46. 'spacer',
  47. 'image-box',
  48. 'google-maps',
  49. 'icon',
  50. 'icon-box',
  51. 'image-gallery',
  52. 'image-carousel',
  53. 'icon-list',
  54. 'counter',
  55. 'progress',
  56. 'testimonial',
  57. 'tabs',
  58. 'accordion',
  59. 'toggle',
  60. 'social-icons',
  61. 'alert',
  62. 'audio',
  63. 'shortcode',
  64. 'html',
  65. 'menu-anchor',
  66. 'sidebar',
  67. ];
  68. $this->_widget_types = [];
  69. foreach ( $build_widgets_filename as $widget_filename ) {
  70. include( ELEMENTOR_PATH . 'includes/widgets/' . $widget_filename . '.php' );
  71. $class_name = str_replace( '-', '_', $widget_filename );
  72. $class_name = __NAMESPACE__ . '\Widget_' . $class_name;
  73. $this->register_widget_type( new $class_name() );
  74. }
  75. $this->register_wp_widgets();
  76. /**
  77. * After widgets registered.
  78. *
  79. * Fires after Elementor widgets are registered.
  80. *
  81. * @since 1.0.0
  82. *
  83. * @param Widgets_Manager $this The widgets manager.
  84. */
  85. do_action( 'elementor/widgets/widgets_registered', $this );
  86. }
  87. /**
  88. * Register WordPress widgets.
  89. *
  90. * Add native WordPress widget to the list of registered widget types.
  91. *
  92. * Exclude the widgets that are in Elementor widgets black list. Theme and
  93. * plugin authors can filter the black list.
  94. *
  95. * @since 2.0.0
  96. * @access private
  97. */
  98. private function register_wp_widgets() {
  99. global $wp_widget_factory;
  100. // Skip Pojo widgets.
  101. $pojo_allowed_widgets = [
  102. 'Pojo_Widget_Recent_Posts',
  103. 'Pojo_Widget_Posts_Group',
  104. 'Pojo_Widget_Gallery',
  105. 'Pojo_Widget_Recent_Galleries',
  106. 'Pojo_Slideshow_Widget',
  107. 'Pojo_Forms_Widget',
  108. 'Pojo_Widget_News_Ticker',
  109. 'Pojo_Widget_WC_Products',
  110. 'Pojo_Widget_WC_Products_Category',
  111. 'Pojo_Widget_WC_Product_Categories',
  112. ];
  113. // Allow themes/plugins to filter out their widgets.
  114. $black_list = [];
  115. /**
  116. * Elementor widgets black list.
  117. *
  118. * Filters the widgets black list that won't be displayed in the panel.
  119. *
  120. * @since 1.0.0
  121. *
  122. * @param array $black_list A black list of widgets. Default is an empty array.
  123. */
  124. $black_list = apply_filters( 'elementor/widgets/black_list', $black_list );
  125. foreach ( $wp_widget_factory->widgets as $widget_class => $widget_obj ) {
  126. if ( in_array( $widget_class, $black_list ) ) {
  127. continue;
  128. }
  129. if ( $widget_obj instanceof \Pojo_Widget_Base && ! in_array( $widget_class, $pojo_allowed_widgets ) ) {
  130. continue;
  131. }
  132. $elementor_widget_class = __NAMESPACE__ . '\Widget_WordPress';
  133. $this->register_widget_type(
  134. new $elementor_widget_class( [], [
  135. 'widget_name' => $widget_class,
  136. ] )
  137. );
  138. }
  139. }
  140. /**
  141. * Require files.
  142. *
  143. * Require Elementor widget base class.
  144. *
  145. * @since 2.0.0
  146. * @access private
  147. */
  148. private function require_files() {
  149. require ELEMENTOR_PATH . 'includes/base/widget-base.php';
  150. }
  151. /**
  152. * Register widget type.
  153. *
  154. * Add a new widget type to the list of registered widget types.
  155. *
  156. * @since 1.0.0
  157. * @access public
  158. *
  159. * @param Widget_Base $widget Elementor widget.
  160. *
  161. * @return true True if the widget was registered.
  162. */
  163. public function register_widget_type( Widget_Base $widget ) {
  164. if ( is_null( $this->_widget_types ) ) {
  165. $this->init_widgets();
  166. }
  167. $this->_widget_types[ $widget->get_name() ] = $widget;
  168. return true;
  169. }
  170. /**
  171. * Unregister widget type.
  172. *
  173. * Removes widget type from the list of registered widget types.
  174. *
  175. * @since 1.0.0
  176. * @access public
  177. *
  178. * @param string $name Widget name.
  179. *
  180. * @return true True if the widget was unregistered, False otherwise.
  181. */
  182. public function unregister_widget_type( $name ) {
  183. if ( ! isset( $this->_widget_types[ $name ] ) ) {
  184. return false;
  185. }
  186. unset( $this->_widget_types[ $name ] );
  187. return true;
  188. }
  189. /**
  190. * Get widget types.
  191. *
  192. * Retrieve the registered widget types list.
  193. *
  194. * @since 1.0.0
  195. * @access public
  196. *
  197. * @param string $widget_name Optional. Widget name. Default is null.
  198. *
  199. * @return Widget_Base|Widget_Base[]|null Registered widget types.
  200. */
  201. public function get_widget_types( $widget_name = null ) {
  202. if ( is_null( $this->_widget_types ) ) {
  203. $this->init_widgets();
  204. }
  205. if ( null !== $widget_name ) {
  206. return isset( $this->_widget_types[ $widget_name ] ) ? $this->_widget_types[ $widget_name ] : null;
  207. }
  208. return $this->_widget_types;
  209. }
  210. /**
  211. * Get widget types config.
  212. *
  213. * Retrieve all the registered widgets with config for each widgets.
  214. *
  215. * @since 1.0.0
  216. * @access public
  217. *
  218. * @return array Registered widget types with each widget config.
  219. */
  220. public function get_widget_types_config() {
  221. $config = [];
  222. foreach ( $this->get_widget_types() as $widget_key => $widget ) {
  223. $config[ $widget_key ] = $widget->get_config();
  224. }
  225. return $config;
  226. }
  227. /**
  228. * Ajax render widget.
  229. *
  230. * Ajax handler for Elementor render_widget.
  231. *
  232. * Fired by `wp_ajax_elementor_render_widget` action.
  233. *
  234. * @since 1.0.0
  235. * @access public
  236. *
  237. * @throws \Exception If current user don't have permissions to edit the post.
  238. *
  239. * @param array $request Ajax request.
  240. *
  241. * @return array {
  242. * Rendered widget.
  243. *
  244. * @type string $render The rendered HTML.
  245. * }
  246. */
  247. public function ajax_render_widget( $request ) {
  248. $document = Plugin::$instance->documents->get( $request['editor_post_id'] );
  249. if ( ! $document->is_editable_by_current_user() ) {
  250. throw new \Exception( 'Access denied.', Exceptions::FORBIDDEN );
  251. }
  252. // Override the global $post for the render.
  253. query_posts(
  254. [
  255. 'p' => $request['editor_post_id'],
  256. 'post_type' => 'any',
  257. ]
  258. );
  259. $editor = Plugin::$instance->editor;
  260. $is_edit_mode = $editor->is_edit_mode();
  261. $editor->set_edit_mode( true );
  262. Plugin::$instance->documents->switch_to_document( $document );
  263. $render_html = $document->render_element( $request['data'] );
  264. $editor->set_edit_mode( $is_edit_mode );
  265. return [
  266. 'render' => $render_html,
  267. ];
  268. }
  269. /**
  270. * Ajax get WordPress widget form.
  271. *
  272. * Ajax handler for Elementor editor get_wp_widget_form.
  273. *
  274. * Fired by `wp_ajax_elementor_editor_get_wp_widget_form` action.
  275. *
  276. * @since 1.0.0
  277. * @access public
  278. *
  279. * @param array $request Ajax request.
  280. *
  281. * @return bool|string Rendered widget form.
  282. */
  283. public function ajax_get_wp_widget_form( $request ) {
  284. if ( empty( $request['widget_type'] ) ) {
  285. return false;
  286. }
  287. if ( empty( $request['data'] ) ) {
  288. $request['data'] = [];
  289. }
  290. $element_data = [
  291. 'id' => $request['id'],
  292. 'elType' => 'widget',
  293. 'widgetType' => $request['widget_type'],
  294. 'settings' => $request['data'],
  295. ];
  296. /**
  297. * @var $widget_obj Widget_WordPress
  298. */
  299. $widget_obj = Plugin::$instance->elements_manager->create_element_instance( $element_data );
  300. if ( ! $widget_obj ) {
  301. return false;
  302. }
  303. return $widget_obj->get_form();
  304. }
  305. /**
  306. * Render widgets content.
  307. *
  308. * Used to generate the widget templates on the editor using Underscore JS
  309. * template, for all the registered widget types.
  310. *
  311. * @since 1.0.0
  312. * @access public
  313. */
  314. public function render_widgets_content() {
  315. foreach ( $this->get_widget_types() as $widget ) {
  316. $widget->print_template();
  317. }
  318. }
  319. /**
  320. * Get widgets frontend settings keys.
  321. *
  322. * Retrieve frontend controls settings keys for all the registered widget
  323. * types.
  324. *
  325. * @since 1.3.0
  326. * @access public
  327. *
  328. * @return array Registered widget types with settings keys for each widget.
  329. */
  330. public function get_widgets_frontend_settings_keys() {
  331. $keys = [];
  332. foreach ( $this->get_widget_types() as $widget_type_name => $widget_type ) {
  333. $widget_type_keys = $widget_type->get_frontend_settings_keys();
  334. if ( $widget_type_keys ) {
  335. $keys[ $widget_type_name ] = $widget_type_keys;
  336. }
  337. }
  338. return $keys;
  339. }
  340. /**
  341. * Enqueue widgets scripts.
  342. *
  343. * Enqueue all the scripts defined as a dependency for each widget.
  344. *
  345. * @since 1.3.0
  346. * @access public
  347. */
  348. public function enqueue_widgets_scripts() {
  349. foreach ( $this->get_widget_types() as $widget ) {
  350. $widget->enqueue_scripts();
  351. }
  352. }
  353. /**
  354. * Retrieve inline editing configuration.
  355. *
  356. * Returns general inline editing configurations like toolbar types etc.
  357. *
  358. * @access public
  359. * @since 1.8.0
  360. *
  361. * @return array {
  362. * Inline editing configuration.
  363. *
  364. * @type array $toolbar {
  365. * Toolbar types and the actions each toolbar includes.
  366. * Note: Wysiwyg controls uses the advanced toolbar, textarea controls
  367. * uses the basic toolbar and text controls has no toolbar.
  368. *
  369. * @type array $basic Basic actions included in the edit tool.
  370. * @type array $advanced Advanced actions included in the edit tool.
  371. * }
  372. * }
  373. */
  374. public function get_inline_editing_config() {
  375. $basic_tools = [
  376. 'bold',
  377. 'underline',
  378. 'italic',
  379. ];
  380. $advanced_tools = array_merge( $basic_tools, [
  381. 'createlink',
  382. 'unlink',
  383. 'h1' => [
  384. 'h1',
  385. 'h2',
  386. 'h3',
  387. 'h4',
  388. 'h5',
  389. 'h6',
  390. 'p',
  391. 'blockquote',
  392. 'pre',
  393. ],
  394. 'list' => [
  395. 'insertOrderedList',
  396. 'insertUnorderedList',
  397. ],
  398. ] );
  399. return [
  400. 'toolbar' => [
  401. 'basic' => $basic_tools,
  402. 'advanced' => $advanced_tools,
  403. ],
  404. ];
  405. }
  406. /**
  407. * Widgets manager constructor.
  408. *
  409. * Initializing Elementor widgets manager.
  410. *
  411. * @since 1.0.0
  412. * @access public
  413. */
  414. public function __construct() {
  415. $this->require_files();
  416. add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
  417. }
  418. /**
  419. * Register ajax actions.
  420. *
  421. * Add new actions to handle data after an ajax requests returned.
  422. *
  423. * @since 2.0.0
  424. * @access public
  425. *
  426. * @param Ajax_Manager $ajax_manager
  427. */
  428. public function register_ajax_actions( $ajax_manager ) {
  429. $ajax_manager->register_ajax_action( 'render_widget', [ $this, 'ajax_render_widget' ] );
  430. $ajax_manager->register_ajax_action( 'editor_get_wp_widget_form', [ $this, 'ajax_get_wp_widget_form' ] );
  431. }
  432. }