elements_manager->getCategories(); } /** * Get properties. * * Retrieve the document properties. * * @since 2.0.0 * @static * * @return array Document properties */ public static function getProperties() { return [ 'has_elements' => true, 'is_editable' => true, 'edit_capability' => '', 'show_in_finder' => true, // 'show_on_admin_bar' => true, 'support_kit' => false, ]; } /** * @since 2.1.0 * @static */ public static function getEditorPanelConfig() { return [ 'title' => static::getTitle(), // JS Container title. 'widgets_settings' => [], 'elements_categories' => static::getEditorPanelCategories(), 'default_route' => 'panel/elements/categories', 'has_elements' => static::getProperty('has_elements'), 'support_kit' => static::getProperty('support_kit'), 'messages' => [ /* translators: %s: the document title. */ 'publish_notification' => sprintf(__('Hurray! Your %s is live.'), static::getTitle()), ], ]; } /** * Get element title. * * Retrieve the element title. * * @since 2.0.0 * @static * * @return string Element title */ public static function getTitle() { return __('Document'); } /** * Get property. * * Retrieve the document property. * * @since 2.0.0 * @static * * @param string $key The property key * * @return mixed The property value */ public static function getProperty($key) { $id = static::getClassFullName(); if (!isset(self::$properties[$id])) { self::$properties[$id] = static::getProperties(); } return self::getItems(self::$properties[$id], $key); } /** * @since 2.0.0 * @static */ public static function getClassFullName() { return get_called_class(); } /** * @since 2.0.0 */ public function getUniqueName() { return $this->getName() . '-' . $this->post->ID; } /** * @since 2.3.0 */ public function getPostTypeTitle() { $post_type_object = get_post_type_object($this->post->post_type); return $post_type_object->labels->singular_name; } /** * @since 2.0.0 */ public function getMainId() { if (!$this->main_id) { $post_id = $this->post->ID; $parent_post_id = wp_is_post_revision($post_id); if ($parent_post_id) { $post_id = $parent_post_id; } $this->main_id = $post_id; } return $this->main_id; } /** * @since 2.0.0 * * @param $data * * @return string * * @throws \Exception if the widget was not found */ public function renderElement($data) { // Start buffering ob_start(); /* @var WidgetBase $widget */ $widget = Plugin::$instance->elements_manager->createElementInstance($data); if (!$widget) { throw new \Exception('Widget not found.'); } $widget->renderContent(); $render_html = ob_get_clean(); return $render_html; } /** * @since 2.0.0 */ public function getMainPost() { return get_post($this->getMainId()); } public function getContainerAttributes() { $id = $this->getMainId(); $attributes = [ 'data-elementor-type' => $this->getName(), 'data-elementor-id' => $id, 'class' => 'elementor elementor-' . $id, ]; $version_meta = $this->getMainMeta('_elementor_version'); if (version_compare($version_meta, '2.5.0', '<')) { $attributes['class'] .= ' elementor-bc-flex-widget'; } if (Plugin::$instance->preview->isPreview()) { $attributes['data-elementor-title'] = static::getTitle(); } else { $attributes['data-elementor-settings'] = json_encode($this->getFrontendSettings()); } return $attributes; } /** * @since 2.0.0 */ public function getWpPreviewUrl() { // $main_post_id = $this->getMainId(); $document = $this; // Ajax request from editor. if (!empty(${'_POST'}['initial_document_id'])) { $document = Plugin::$instance->documents->get(${'_POST'}['initial_document_id']); } $url = get_preview_post_link( $document->getMainId(), [ // 'preview_id' => $main_post_id, // 'preview_nonce' => wp_create_nonce('post_preview_' . $main_post_id), 'preview' => 'true', ] ); /* * Document "PrestaShop preview" URL. * * Filters the PrestaShop preview URL. * * @since 2.0.0 * * @param string $url PrestaShop preview URL * @param Document $this The document instance */ $url = apply_filters('elementor/document/urls/wp_preview', $url, $this); return $url; } /** * @since 2.0.0 */ public function getExitToDashboardUrl() { $url = get_edit_post_link($this->getMainId(), 'raw'); /* * Document "exit to dashboard" URL. * * Filters the "Exit To Dashboard" URL. * * @since 2.0.0 * * @param string $url The exit URL * @param Document $this The document instance */ $url = apply_filters('elementor/document/urls/exit_to_dashboard', $url, $this); return $url; } /** * Get auto-saved post revision. * * Retrieve the auto-saved post revision that is newer than current post. * * @since 2.0.0 * * @return bool|Document */ public function getNewerAutosave() { $autosave = $this->getAutosave(); // Detect if there exists an autosave newer than the post. if ($autosave && strtotime($autosave->getPost()->post_modified) > strtotime($this->post->post_modified)) { return $autosave; } return false; } /** * @since 2.0.0 */ public function isAutosave() { return wp_is_post_autosave($this->post->ID); } /** * @since 2.0.0 * * @param int $user_id * @param bool $create * * @return bool|Document */ public function getAutosave($user_id = 0, $create = false) { if (!$user_id) { $user_id = get_current_user_id(); } $autosave_id = $this->getAutosaveId($user_id); if ($autosave_id) { $document = Plugin::$instance->documents->get($autosave_id); } elseif ($create) { $autosave_id = wp_create_post_autosave([ 'post_ID' => $this->post->uid->toDefault(), 'post_type' => $this->post->post_type, 'post_title' => $this->post->post_title, 'post_excerpt' => $this->post->post_excerpt, // Hack to cause $autosave_is_different=true in `wp_create_post_autosave`. 'post_content' => '', 'post_modified' => date('Y-m-d H:i:s'), 'template_type' => $this->post->template_type, ]); Plugin::$instance->db->copyElementorMeta($this->post->ID, $autosave_id); $document = Plugin::$instance->documents->get($autosave_id); $document->saveTemplateType(); } else { $document = false; } return $document; } // public function filterAdminRowActions($actions) /** * @since 2.0.0 */ public function isEditableByCurrentUser() { // $edit_capability = static::getProperty( 'edit_capability' ); // if ( $edit_capability && ! current_user_can( $edit_capability ) ) { // return false; // } return self::getProperty('is_editable') && User::isCurrentUserCanEdit($this->getMainId()); } /** * @since 2.9.0 */ protected function getInitialConfig() { // Get document data *after* the scripts hook - so plugins can run compatibility before get data, but *before* enqueue the editor script - so elements can enqueue their own scripts that depended in editor script. $locked_user = Plugin::$instance->editor->getLockedUser($this->getMainId()); if ($locked_user) { $locked_user = $locked_user->display_name; } $post_type_object = get_post_type_object($this->getMainPost()->post_type); $settings = SettingsManager::getSettingsManagersConfig(); $config = [ // 'id' => $this->getMainId(), 'id' => UId::parse($this->getMainId())->toDefault(), 'type' => $this->getName(), 'version' => $this->getMainMeta('_elementor_version'), 'settings' => $settings['page'], 'remoteLibrary' => $this->getRemoteLibraryConfig(), 'last_edited' => $this->getLastEdited(), 'panel' => static::getEditorPanelConfig(), 'container' => 'body', 'post_type_title' => $this->getPostTypeTitle(), 'user' => [ 'can_publish' => current_user_can($post_type_object->cap->publish_posts), // Deprecated config since 2.9.0. 'locked' => $locked_user, ], 'urls' => [ 'exit_to_dashboard' => $this->getExitToDashboardUrl(), 'preview' => $this->getPreviewUrl(), 'wp_preview' => $this->getWpPreviewUrl(), 'permalink' => $this->getPermalink(), 'have_a_look' => $this->getHaveALookUrl(), ], ]; if (static::getProperty('has_elements')) { $config['elements'] = $this->getElementsRawData(null, true); $config['widgets'] = Plugin::$instance->widgets_manager->getWidgetTypesConfig(); } $additional_config = apply_filters('elementor/document/config', [], $this->getMainId()); if (!empty($additional_config)) { $config = array_replace_recursive($config, $additional_config); } return $config; } /** * @since 2.0.0 */ protected function _registerControls() { $this->registerDocumentControls(); /* * Register document controls. * * Fires after Elementor registers the document controls. * * @since 2.0.0 * * @param Document $this The document instance */ do_action('elementor/documents/register_controls', $this); } /** * @since 2.0.0 * * @param $data * * @return bool */ public function save($data) { if (!$this->isEditableByCurrentUser()) { return false; } /* * Before document save. * * Fires when document save starts on Elementor. * * @since 2.5.12 * * @param \Elementor\Core\Base\Document $this The current document * @param $data */ do_action('elementor/document/before_save', $this, $data); // if (!current_user_can('unfiltered_html')) { // $data = wp_kses_post_deep($data); // } if (!empty($data['settings'])) { if (isset($data['settings']['post_status']) && DB::STATUS_AUTOSAVE === $data['settings']['post_status']) { if (!defined('DOING_AUTOSAVE')) { define('DOING_AUTOSAVE', true); } } $this->saveSettings($data['settings']); // Refresh post after save settings. $this->post = get_post($this->post->ID); } // Don't check is_empty, because an empty array should be saved. if (isset($data['elements']) && is_array($data['elements'])) { $this->saveElements($data['elements']); } $this->saveTemplateType(); $this->saveVersion(); // Create revision wp_save_post_revision($this->post); // Remove Post CSS $post_css = PostCSS::create($this->post->ID); $post_css->delete(); /* * After document save. * * Fires when document save is complete. * * @since 2.5.12 * * @param \Elementor\Core\Base\Document $this The current document * @param $data */ do_action('elementor/document/after_save', $this, $data); return true; } /** * Is built with Elementor. * * Check whether the post was built with Elementor. * * @since 2.0.0 * * @return bool Whether the post was built with Elementor */ public function isBuiltWithElementor() { $id_type = (int) substr($this->post->ID, -6, 2); if (in_array($id_type, [UId::REVISION, UId::TEMPLATE, UId::CONTENT, UId::THEME])) { return true; } return (bool) get_post_meta($this->post->ID, '_elementor_edit_mode', true); } // public function getEditUrl() /** * @since 2.0.0 */ public function getPreviewUrl() { /* * Use a static var - to avoid change the `ver` parameter on every call. */ static $url; if (empty($url)) { // add_filter('pre_option_permalink_structure', '__return_empty_string'); $url = add_query_arg([ // 'elementor-preview' => $this->getMainId(), 'ctx' => \Shop::getContext(), 'ver' => time(), ], $this->getPermalink()); // remove_filter('pre_option_permalink_structure', '__return_empty_string'); /* * Document preview URL. * * Filters the document preview URL. * * @since 2.0.0 * * @param string $url The preview URL * @param Document $this The document instance */ $url = apply_filters('elementor/document/urls/preview', $url, $this); } return $url; } /** * @since 2.0.0 * * @param string $key * * @return array */ public function getJsonMeta($key) { $meta = get_post_meta($this->post->ID, $key, true); if (is_string($meta) && !empty($meta)) { $meta = json_decode($meta, true); } if (empty($meta)) { $meta = []; } return $meta; } /** * @since 2.0.0 * * @param null $data * @param bool $with_html_content * * @return array */ public function getElementsRawData($data = null, $with_html_content = false) { if (!static::getProperty('has_elements')) { return []; } if (is_null($data)) { $data = $this->getElementsData(); } // Change the current documents, so widgets can use `documents->get_current` and other post data Plugin::$instance->documents->switchToDocument($this); $editor_data = []; foreach ($data as $element_data) { $element = Plugin::$instance->elements_manager->createElementInstance($element_data); if (!$element) { continue; } $editor_data[] = $element->getRawData($with_html_content); } Plugin::$instance->documents->restoreDocument(); return $editor_data; } /** * @since 2.0.0 * * @param string $status * * @return array */ public function getElementsData($status = DB::STATUS_PUBLISH) { $elements = $this->getJsonMeta('_elementor_data'); if (DB::STATUS_DRAFT === $status) { $autosave = $this->getNewerAutosave(); if (is_object($autosave)) { $autosave_elements = Plugin::$instance->documents ->get($autosave->getPost()->ID) ->getJsonMeta('_elementor_data'); } } if (Plugin::$instance->editor->isEditMode()) { if (empty($elements) && empty($autosave_elements)) { // Convert to Elementor. $elements = $this->convertToElementor(); if ($this->isAutosave()) { Plugin::$instance->db->copyElementorMeta($this->post->post_parent, $this->post->ID); } } } if (!empty($autosave_elements)) { $elements = $autosave_elements; } return $elements; } /** * @since 2.3.0 */ public function convertToElementor() { $this->save([]); if (empty($this->post->post_content)) { return []; } $widget_type = Plugin::$instance->widgets_manager->getWidgetTypes('text-editor'); $settings = [ 'editor' => $this->post->post_content, ]; // TODO: Better coding to start template for editor return [ [ 'id' => Utils::generateRandomString(), 'elType' => 'section', 'elements' => [ [ 'id' => Utils::generateRandomString(), 'elType' => 'column', 'elements' => [ [ 'id' => Utils::generateRandomString(), 'elType' => $widget_type::getType(), 'widgetType' => $widget_type->getName(), 'settings' => $settings, ], ], ], ], ], ]; } /** * @since 2.1.3 */ public function printElementsWithWrapper($elements_data = null) { if (!$elements_data) { $elements_data = $this->getElementsData(); } ?>