first commit
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\SiteNavigation\Data;
|
||||
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Data\V2\Base\Controller as Base_Controller;
|
||||
use Elementor\Modules\SiteNavigation\Data\Endpoints\Add_New_Post;
|
||||
use Elementor\Modules\SiteNavigation\Data\Endpoints\Duplicate_Post;
|
||||
use Elementor\Modules\SiteNavigation\Data\Endpoints\Homepage;
|
||||
use Elementor\Modules\SiteNavigation\Data\Endpoints\Recent_Posts;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Controller extends Base_Controller {
|
||||
|
||||
public function get_name() {
|
||||
return 'site-navigation';
|
||||
}
|
||||
|
||||
public function get_items_permissions_check( $request ) {
|
||||
return current_user_can( 'edit_posts' );
|
||||
}
|
||||
|
||||
public function create_items_permissions_check( $request ): bool {
|
||||
// Permissions check is located in the endpoint
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_item_permissions_check( $request ) {
|
||||
return $this->get_items_permissions_check( $request );
|
||||
}
|
||||
|
||||
public function create_item_permissions_check( $request ): bool {
|
||||
return $this->create_items_permissions_check( $request );
|
||||
}
|
||||
|
||||
public function register_endpoints() {
|
||||
$this->register_endpoint( new Recent_Posts( $this ) );
|
||||
$this->register_endpoint( new Add_New_Post( $this ) );
|
||||
|
||||
if ( Plugin::$instance->experiments->is_feature_active( 'pages_panel' ) ) {
|
||||
$this->register_endpoint( new Duplicate_Post( $this ) );
|
||||
$this->register_endpoint( new Homepage( $this ) );
|
||||
}
|
||||
}
|
||||
|
||||
protected function register_index_endpoint() {
|
||||
// Bypass, currently does not required.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\SiteNavigation\Data\Endpoints;
|
||||
|
||||
use Elementor\Data\V2\Base\Endpoint;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\User;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Add_New_Post extends Endpoint {
|
||||
|
||||
protected function register() {
|
||||
$args = [
|
||||
'post_type' => [
|
||||
'description' => 'Post type to create',
|
||||
'type' => 'string',
|
||||
'required' => false,
|
||||
'default' => 'post',
|
||||
'sanitize_callback' => function ( $value ) {
|
||||
return sanitize_text_field( $value );
|
||||
},
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
],
|
||||
];
|
||||
|
||||
$this->register_items_route( \WP_REST_Server::CREATABLE, $args );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'add-new-post';
|
||||
}
|
||||
|
||||
public function get_format() {
|
||||
return 'site-navigation/add-new-post';
|
||||
}
|
||||
|
||||
public function create_items( $request ) {
|
||||
$post_type = $request->get_param( 'post_type' );
|
||||
|
||||
if ( ! $this->validate_post_type( $post_type ) ) {
|
||||
return new \WP_Error( 400, sprintf( 'Post type %s does not exist.', $post_type ), [ 'status' => 400 ] );
|
||||
}
|
||||
|
||||
if ( ! User::is_current_user_can_edit_post_type( $post_type ) ) {
|
||||
return new \WP_Error( 401, sprintf( 'User dont have capability to create page of type - %s.', $post_type ), [ 'status' => 401 ] );
|
||||
}
|
||||
|
||||
// Temporary solution for the fact that documents creation not using the actual registered post types.
|
||||
$post_type = $this->map_post_type( $post_type );
|
||||
|
||||
$document = Plugin::$instance->documents->create( $post_type );
|
||||
|
||||
if ( is_wp_error( $document ) ) {
|
||||
return new \WP_Error( 500, sprintf( 'Error while creating %s.', $post_type ) );
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $document->get_main_id(),
|
||||
'edit_url' => $document->get_edit_url(),
|
||||
];
|
||||
}
|
||||
|
||||
private function validate_post_type( $post_type ): bool {
|
||||
$post_types = get_post_types();
|
||||
|
||||
return in_array( $post_type, $post_types );
|
||||
}
|
||||
|
||||
/**
|
||||
* Map post type to Elementor document type.
|
||||
*
|
||||
* @param $post_type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function map_post_type( $post_type ): string {
|
||||
$post_type_map = [
|
||||
'page' => 'wp-page',
|
||||
'post' => 'wp-post',
|
||||
];
|
||||
|
||||
return $post_type_map[ $post_type ] ?? $post_type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\SiteNavigation\Data\Endpoints;
|
||||
|
||||
use Elementor\Data\V2\Base\Endpoint;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\User;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Duplicate_Post extends Endpoint {
|
||||
|
||||
protected function register() {
|
||||
$args = [
|
||||
'post_id' => [
|
||||
'description' => 'Post id to duplicate',
|
||||
'type' => 'integer',
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
],
|
||||
'title' => [
|
||||
'description' => 'Post title',
|
||||
'type' => 'string',
|
||||
'required' => false,
|
||||
'sanitize_callback' => function ( $value ) {
|
||||
return sanitize_text_field( $value );
|
||||
},
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
],
|
||||
];
|
||||
|
||||
$this->register_items_route( \WP_REST_Server::CREATABLE, $args );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'duplicate-post';
|
||||
}
|
||||
|
||||
public function get_format() {
|
||||
return 'site-navigation/duplicate-post';
|
||||
}
|
||||
|
||||
public function create_items( $request ) {
|
||||
$post_id = $request->get_param( 'post_id' );
|
||||
$post_title = $request->get_param( 'title' );
|
||||
|
||||
$post = get_post( $post_id );
|
||||
|
||||
if ( ! User::is_current_user_can_edit_post_type( $post->post_type ) ) {
|
||||
return new \WP_Error( 401, sprintf( 'User dont have capability to create page of type - %s.', $post->post_type ), [ 'status' => 401 ] );
|
||||
}
|
||||
|
||||
if ( ! $post ) {
|
||||
return new \WP_Error( 500, 'Post not found' );
|
||||
}
|
||||
|
||||
$new_post_id = $this->duplicate_post( $post, $post_title );
|
||||
|
||||
if ( is_wp_error( $new_post_id ) ) {
|
||||
return new \WP_Error( 500, 'Error while duplicating post.' );
|
||||
}
|
||||
|
||||
//Duplicate all post meta
|
||||
$this->duplicate_post_meta( $post_id, $new_post_id );
|
||||
|
||||
//Duplicate all taxonomies
|
||||
$this->duplicate_post_taxonomies( $post_id, $new_post_id );
|
||||
|
||||
return [
|
||||
'post_id' => $new_post_id,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate post
|
||||
*
|
||||
* @param $post
|
||||
*
|
||||
* @return int|\WP_Error
|
||||
*/
|
||||
private function duplicate_post( $post, $post_title ) {
|
||||
$post_status = 'draft';
|
||||
$current_user = wp_get_current_user();
|
||||
$new_post_author = $current_user->ID;
|
||||
|
||||
$args = [
|
||||
'comment_status' => $post->comment_status,
|
||||
'ping_status' => $post->ping_status,
|
||||
'post_author' => $new_post_author,
|
||||
'post_content' => $post->post_content,
|
||||
'post_excerpt' => $post->post_excerpt,
|
||||
'post_parent' => $post->post_parent,
|
||||
'post_password' => $post->post_password,
|
||||
'post_status' => $post_status,
|
||||
'post_title' => $post_title,
|
||||
'post_type' => $post->post_type,
|
||||
'to_ping' => $post->to_ping,
|
||||
'menu_order' => $post->menu_order,
|
||||
];
|
||||
|
||||
return wp_insert_post( $args );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Duplicate the associated post meta to the new post ID.
|
||||
*
|
||||
* @param int $post_id
|
||||
* @param int $new_post_id
|
||||
*/
|
||||
private function duplicate_post_meta( int $post_id, int $new_post_id ) {
|
||||
$post_meta = get_post_meta( $post_id );
|
||||
|
||||
if ( empty( $post_meta ) || ! is_array( $post_meta ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $post_meta as $key => $values ) {
|
||||
if ( '_wp_old_slug' === $key ) { // Ignore this meta key
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $values as $value ) {
|
||||
$value = maybe_unserialize( $value );
|
||||
add_post_meta( $new_post_id, $key, wp_slash( $value ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* duplicate_post_taxonomies
|
||||
*
|
||||
* @param int $post_id
|
||||
* @param int $new_post_id
|
||||
*/
|
||||
private function duplicate_post_taxonomies( $post_id, $new_post_id ) {
|
||||
$taxonomies = array_map( 'sanitize_text_field', get_object_taxonomies( get_post_type( $post_id ) ) );
|
||||
|
||||
if ( empty( $taxonomies ) || ! is_array( $taxonomies ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
$post_terms = wp_get_object_terms( $post_id, $taxonomy, [ 'fields' => 'slugs' ] );
|
||||
|
||||
if ( ! is_wp_error( $post_terms ) ) {
|
||||
wp_set_object_terms( $new_post_id, $post_terms, $taxonomy, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\SiteNavigation\Data\Endpoints;
|
||||
|
||||
use Elementor\Data\V2\Base\Endpoint;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Homepage extends Endpoint {
|
||||
|
||||
public function get_permission_callback( $request ) {
|
||||
return current_user_can( 'edit_posts' );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'homepage';
|
||||
}
|
||||
|
||||
public function get_format() {
|
||||
return 'site-navigation/homepage';
|
||||
}
|
||||
|
||||
public function get_items( $request ) {
|
||||
$homepage_id = get_option( 'page_on_front' );
|
||||
$show_on_front = get_option( 'show_on_front' );
|
||||
|
||||
return 'page' === $show_on_front ? intval( $homepage_id ) : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\SiteNavigation\Data\Endpoints;
|
||||
|
||||
use Elementor\Core\Base\Document;
|
||||
use Elementor\Core\Kits\Documents\Kit;
|
||||
use Elementor\Data\V2\Base\Endpoint;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\TemplateLibrary\Source_Local;
|
||||
use Elementor\Utils;
|
||||
use WP_REST_Server;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Recent_Posts extends Endpoint {
|
||||
|
||||
public function register_items_route( $methods = WP_REST_Server::READABLE, $args = [] ) {
|
||||
$args = [
|
||||
'posts_per_page' => [
|
||||
'description' => 'Number of posts to return',
|
||||
'type' => 'integer',
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
],
|
||||
'post_type' => [
|
||||
'description' => 'Post types to retrieve',
|
||||
'type' => 'array',
|
||||
'required' => false,
|
||||
'default' => [ 'page', 'post', Source_Local::CPT ],
|
||||
'sanitize_callback' => 'rest_sanitize_array',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
],
|
||||
'post__not_in' => [
|
||||
'description' => 'Post id`s to exclude',
|
||||
'type' => 'array',
|
||||
'required' => [],
|
||||
'sanitize_callback' => 'wp_parse_id_list',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
],
|
||||
];
|
||||
|
||||
parent::register_items_route( $methods, $args );
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'recent-posts';
|
||||
}
|
||||
|
||||
public function get_format() {
|
||||
return 'site-navigation/recent-posts';
|
||||
}
|
||||
|
||||
public function get_items( $request ) {
|
||||
$args = [
|
||||
'posts_per_page' => $request->get_param( 'posts_per_page' ),
|
||||
'post_type' => $request->get_param( 'post_type' ),
|
||||
'fields' => 'ids',
|
||||
'meta_query' => [
|
||||
[
|
||||
'key' => Document::TYPE_META_KEY,
|
||||
'value' => Kit::get_type(), // Exclude kits.
|
||||
'compare' => '!=',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$exclude = $request->get_param( 'post__not_in' );
|
||||
|
||||
if ( ! empty( $exclude ) ) {
|
||||
$args['post__not_in'] = $exclude;
|
||||
}
|
||||
|
||||
$recently_edited_query = Utils::get_recently_edited_posts_query( $args );
|
||||
|
||||
$recent = [];
|
||||
|
||||
foreach ( $recently_edited_query->posts as $id ) {
|
||||
$document = Plugin::$instance->documents->get( $id );
|
||||
|
||||
$recent[] = [
|
||||
'id' => $id,
|
||||
'title' => get_the_title( $id ),
|
||||
'edit_url' => $document->get_edit_url(),
|
||||
'date_modified' => get_post_timestamp( $id, 'modified' ),
|
||||
'type' => [
|
||||
'post_type' => get_post_type( $id ),
|
||||
'doc_type' => $document->get_name(),
|
||||
'label' => $document->get_title(),
|
||||
],
|
||||
'user_can' => [
|
||||
'edit' => current_user_can( 'edit_post', $id ),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return $recent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\SiteNavigation;
|
||||
|
||||
use Elementor\Core\Base\Module as Module_Base;
|
||||
use Elementor\Core\Experiments\Manager as Experiments_Manager;
|
||||
use Elementor\Modules\SiteNavigation\Data\Controller;
|
||||
use Elementor\Modules\SiteNavigation\Rest_Fields\Page_User_Can;
|
||||
use Elementor\Plugin;
|
||||
use Elementor\Utils;
|
||||
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class Module extends Module_Base {
|
||||
const PAGES_PANEL_EXPERIMENT_NAME = 'pages_panel';
|
||||
|
||||
/**
|
||||
* Initialize the Site navigation module.
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct() {
|
||||
Plugin::$instance->data_manager_v2->register_controller( new Controller() );
|
||||
|
||||
$is_tests = Utils::is_elementor_tests();
|
||||
$is_v2_experiment_on = Plugin::$instance->experiments->is_feature_active( 'editor_v2' );
|
||||
if ( ! $is_v2_experiment_on && ! $is_tests ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->register_pages_panel_experiment();
|
||||
|
||||
if ( Plugin::$instance->experiments->is_feature_active( self::PAGES_PANEL_EXPERIMENT_NAME ) ) {
|
||||
add_filter( 'elementor/editor/v2/scripts/env', function( $env ) {
|
||||
$env['@elementor/editor-site-navigation'] = [
|
||||
'is_pages_panel_active' => true,
|
||||
];
|
||||
|
||||
return $env;
|
||||
} );
|
||||
$this->register_rest_fields();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the module name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'site-navigation';
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Experiment
|
||||
*
|
||||
* @since 3.16.0
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function register_pages_panel_experiment() {
|
||||
Plugin::$instance->experiments->add_feature( [
|
||||
'name' => self::PAGES_PANEL_EXPERIMENT_NAME,
|
||||
'title' => esc_html__( 'Pages Panel', 'elementor' ),
|
||||
'release_status' => Experiments_Manager::RELEASE_STATUS_ALPHA,
|
||||
'default' => Experiments_Manager::STATE_INACTIVE,
|
||||
'hidden' => true,
|
||||
'dependencies' => [
|
||||
'editor_v2',
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
private function register_rest_fields() {
|
||||
add_action( 'rest_api_init', function() {
|
||||
( new Page_User_Can() )->register_rest_field();
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\SiteNavigation\Rest_Fields;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Page_User_Can {
|
||||
public function register_rest_field() {
|
||||
if ( ! isset( $_GET['_fields'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = sanitize_text_field( wp_unslash( $_GET['_fields'] ) );
|
||||
$array_fields = explode( ',', $fields );
|
||||
|
||||
if ( ! in_array( 'user_can', $array_fields ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
register_rest_field(
|
||||
'page',
|
||||
'user_can',
|
||||
[
|
||||
'get_callback' => [ $this, 'get_callback' ],
|
||||
'schema' => [
|
||||
'description' => __( 'Whether the current user can edit or delete this post', 'elementor' ),
|
||||
'type' => 'array',
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function get_callback( $post ) {
|
||||
$can_edit = current_user_can( 'edit_post', $post['id'] );
|
||||
$can_delete = current_user_can( 'delete_post', $post['id'] );
|
||||
|
||||
return [
|
||||
'edit' => $can_edit,
|
||||
'delete' => $can_delete,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user