Current Path : /home/church/www/wp-content/plugins/siteorigin-panels/inc/ |
Current File : /home/church/www/wp-content/plugins/siteorigin-panels/inc/admin-layouts.php |
<?php /** * Class SiteOrigin_Panels_Admin * * Handles all the admin and database interactions. */ class SiteOrigin_Panels_Admin_Layouts { const LAYOUT_URL = 'https://layouts.siteorigin.com/'; const VALID_MIME_TYPES = array( 'application/json', 'text/plain', 'text/html', ); public function __construct() { // Filter all the available external layout directories. add_filter( 'siteorigin_panels_external_layout_directories', array( $this, 'filter_directories' ), 8 ); // Filter all the available local layout folders. add_filter( 'siteorigin_panels_prebuilt_layouts', array( $this, 'get_local_layouts' ), 8 ); add_action( 'wp_ajax_so_panels_layouts_query', array( $this, 'action_get_prebuilt_layouts' ) ); add_action( 'wp_ajax_so_panels_get_layout', array( $this, 'action_get_prebuilt_layout' ) ); add_action( 'wp_ajax_so_panels_import_layout', array( $this, 'action_import_layout' ) ); add_action( 'wp_ajax_so_panels_export_layout', array( $this, 'action_export_layout' ) ); add_action( 'wp_ajax_so_panels_directory_enable', array( $this, 'action_directory_enable' ) ); } /** * @return SiteOrigin_Panels_Admin_Layouts */ public static function single() { static $single; return empty( $single ) ? $single = new self() : $single; } /** * Add the main SiteOrigin layout directory */ public function filter_directories( $directories ) { if ( apply_filters( 'siteorigin_panels_layouts_directory_enabled', true ) ) { $directories['siteorigin'] = array( // The title of the layouts directory in the sidebar. 'title' => __( 'Layouts Directory', 'siteorigin-panels' ), // The URL of the directory. 'url' => self::LAYOUT_URL, // Any additional arguments to pass to the layouts server 'args' => array(), ); } return $directories; } /** * Get all the layout directories. * * @return array */ public function get_directories() { $directories = apply_filters( 'siteorigin_panels_external_layout_directories', array() ); if ( empty( $directories ) || ! is_array( $directories ) ) { $directories = array(); } return $directories; } /** * Check if the file has a valid MIME type. * * This method checks if the given file has a valid MIME type. It first verifies * if the `mime_content_type` function exists. If it doesn't, it returns true * as it can't check the MIME type due to server settings. * If the function exists, it retrieves the MIME type of the file and checks * if it is in the list of valid MIME types. * * @param string $file The file path to check. * * @return bool True if the file has a valid MIME type, false otherwise. */ private static function check_file_mime( $file ) { if ( ! function_exists( 'mime_content_type' ) ) { // Can't check mime type due to server settings. return true; } $mime_type = mime_content_type( $file ); return in_array( $mime_type, self::VALID_MIME_TYPES ); } /** * Determines if file has a JSON extension. * * @param string $file File path. * @return bool True if JSON, false otherwise. */ private static function check_file_ext( $file ) { $ext = pathinfo( $file, PATHINFO_EXTENSION ); return ! empty( $ext ) && $ext === 'json'; } /** * Looks through local folders in the active theme and any others filtered in by theme and plugins, to find JSON * prebuilt layouts. */ public function get_local_layouts() { // By default we'll look for layouts in a directory in the active theme $layout_folders = array( get_template_directory() . '/siteorigin-page-builder-layouts' ); // And the child theme if there is one. if ( is_child_theme() ) { $layout_folders[] = get_stylesheet_directory() . '/siteorigin-page-builder-layouts'; } // This allows themes and plugins to customize where we look for layouts. $layout_folders = apply_filters( 'siteorigin_panels_local_layouts_directories', $layout_folders ); $layouts = array(); foreach ( $layout_folders as $folder ) { $folder = realpath( $folder ); if ( file_exists( $folder ) && is_dir( $folder ) ) { $files = list_files( $folder, 1 ); if ( empty( $files ) ) { continue; } foreach ( $files as $file ) { // Check the file. if ( ! self::check_file_mime( $file ) || ! self::check_file_ext( $file ) ) { continue; } // get file contents $file_contents = file_get_contents( $file ); // skip if file_get_contents fails if ( $file_contents === false ) { continue; } $panels_data = $this->decode_panels_data( $file_contents ); if ( empty( $panels_data ) ) { continue; } // get file name by stripping out folder path and .json extension $file_name = str_replace( array( $folder . '/', '.json' ), '', $file ); // get name: check for id or name else use filename $panels_data['id'] = sanitize_title_with_dashes( $this->get_layout_id( $panels_data, $file_name ) ); if ( empty( $panels_data['name'] ) ) { $panels_data['name'] = $file_name; } $panels_data['name'] = sanitize_text_field( $panels_data['name'] ); // get screenshot: check for screenshot prop else try use image file with same filename. $panels_data['screenshot'] = $this->get_layout_file_screenshot( $panels_data, $folder, $file_name ); // set item on layouts array $layouts[ $panels_data['id'] ] = $panels_data; } } } return $layouts; } private function get_layout_id( $layout_data, $fallback ) { if ( ! empty( $layout_data['id'] ) ) { return $layout_data['id']; } elseif ( ! empty( $layout_data['name'] ) ) { return $layout_data['name']; } else { return $fallback; } } private static function get_files( $folder_path, $file_name ) { $paths = array(); $types = array( 'jpg', 'jpeg', 'gif', 'png', ); foreach ( $types as $ext ) { $paths = array_merge( glob( $folder_path . "/$file_name.$ext" ), $paths ); } return $paths; } private function get_layout_file_screenshot( $panels_data, $folder_path, $file_name ) { if ( ! empty( $panels_data['screenshot'] ) ) { return $panels_data['screenshot']; } else { $paths = self::get_files( $folder_path, $file_name ); // Highlander Condition. There can be only one. $screenshot_path = empty( $paths ) ? '' : wp_normalize_path( $paths[0] ); $wp_content_dir = wp_normalize_path( WP_CONTENT_DIR ); $screenshot_url = ''; if ( file_exists( $screenshot_path ) && strrpos( $screenshot_path, $wp_content_dir ) === 0 ) { $screenshot_url = str_replace( $wp_content_dir, content_url(), $screenshot_path ); } return $screenshot_url; } } /** * Gets all the prebuilt layouts. */ public function action_get_prebuilt_layouts() { if ( empty( $_REQUEST['_panelsnonce'] ) || ! wp_verify_nonce( $_REQUEST['_panelsnonce'], 'panels_action' ) ) { wp_die( __( 'Invalid request.', 'siteorigin-panels' ), 403 ); } // Get any layouts that the current user could edit. header( 'content-type: application/json' ); $type = ! empty( $_REQUEST['type'] ) ? $_REQUEST['type'] : 'directory-siteorigin'; $search = ! empty( $_REQUEST['search'] ) ? trim( strtolower( $_REQUEST['search'] ) ) : ''; $page_num = ! empty( $_REQUEST['page'] ) ? (int) $_REQUEST['page'] : 1; $return = array( 'title' => '', 'items' => array(), ); if ( $type == 'prebuilt' ) { $return['title'] = __( 'Theme Defined Layouts', 'siteorigin-panels' ); // This is for theme bundled prebuilt directories $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() ); foreach ( $layouts as $id => $vals ) { if ( ! empty( $search ) && strpos( strtolower( $vals['name'] ), $search ) === false ) { continue; } $return['items'][] = array( 'title' => esc_html( $vals['name'] ), 'id' => esc_html( $id ), 'type' => 'prebuilt', 'description' => isset( $vals['description'] ) ? esc_html( $vals['description'] ) : '', 'screenshot' => ! empty( $vals['screenshot'] ) ? esc_url( $vals['screenshot'] ) : '', ); } $return['max_num_pages'] = 1; } elseif ( substr( $type, 0, 10 ) == 'directory-' ) { $return['title'] = __( 'Layouts Directory', 'siteorigin-panels' ); // This is a query of the prebuilt layout directory $query = array(); if ( ! empty( $search ) ) { $query['search'] = $search; } $query['page'] = $page_num; $directory_id = str_replace( 'directory-', '', $type ); $directories = $this->get_directories(); $directory = ! empty( $directories[ $directory_id ] ) ? $directories[ $directory_id ] : false; if ( empty( $directory ) ) { return false; } $cache = get_transient( 'siteorigin_panels_layouts_directory_' . $directory_id .'_page_' . $page_num ); if ( empty( $search ) && ! empty( $cache ) ) { $return = $cache; } else { $url = add_query_arg( $query, $directory[ 'url' ] . 'wp-admin/admin-ajax.php?action=query_layouts' ); if ( ! empty( $directory['args'] ) && is_array( $directory['args'] ) ) { $url = add_query_arg( $directory['args'], $url ); } $url = apply_filters( 'siteorigin_panels_layouts_directory_url', $url ); $response = wp_remote_get( esc_url_raw( $url ) ); if ( ! is_wp_error( $response ) && is_array( $response ) && $response['response']['code'] == 200 ) { $results = json_decode( $response['body'], true ); if ( ! empty( $results ) && ! empty( $results['items'] ) ) { foreach ( $results['items'] as $item ) { $item['id'] = esc_html( $item['slug'] ); $item['type'] = esc_html( $type ); if ( empty( $item['screenshot'] ) && ! empty( $item['preview'] ) ) { $preview_url = add_query_arg( 'screenshot', 'true', $item[ 'preview' ] ); $item['screenshot'] = esc_url( 'https://s.wordpress.com/mshots/v1/' . urlencode( $preview_url ) . '?w=700' ); } $return['items'][] = $item; } } $return['max_num_pages'] = $results['max_num_pages']; set_transient( 'siteorigin_panels_layouts_directory_' . $directory_id .'_page_' . $page_num, $return, 86400 ); } } } elseif ( strpos( $type, 'clone_' ) !== false ) { $post_type = str_replace( 'clone_', '', $type ); $post_types_editable_by_user = SiteOrigin_Panels_Admin_Layouts::single()->post_types(); // Can the user edit posts from this post type? if ( empty( $post_type ) || empty( $post_types_editable_by_user ) || ! in_array( $post_type, $post_types_editable_by_user ) ) { return; } $post_type = get_post_type_object( $post_type ); if ( empty( $post_type ) ) { return; } $return['title'] = sprintf( __( 'Clone %s', 'siteorigin-panels' ), esc_html( $post_type->labels->singular_name ) ); global $wpdb; $user_can_read_private = ( $post_type->name == 'post' && current_user_can( 'read_private_posts' ) || ( $post_type->name == 'page' && current_user_can( 'read_private_pages' ) ) ); $include_private = $user_can_read_private ? "OR posts.post_status = 'private' " : ''; // Select only the posts with the given post type that also have panels_data $results = $wpdb->get_results( " SELECT SQL_CALC_FOUND_ROWS DISTINCT ID, post_title, meta.meta_value FROM {$wpdb->posts} AS posts JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id WHERE posts.post_type = '" . esc_sql( $post_type->name ) . "' AND meta.meta_key = 'panels_data' " . ( ! empty( $search ) ? 'AND posts.post_title LIKE "%' . esc_sql( $search ) . '%"' : '' ) . " AND ( posts.post_status = 'publish' OR posts.post_status = 'draft' " . $include_private . ') ORDER BY post_date DESC LIMIT 16 OFFSET ' . (int) ( $page_num - 1 ) * 16 ); $total_posts = $wpdb->get_var( 'SELECT FOUND_ROWS();' ); foreach ( $results as $result ) { $thumbnail = get_the_post_thumbnail_url( (int) $result->ID, array( 400, 300 ) ); $return['items'][] = array( 'id' => (int) $result->ID, 'title' => esc_html( $result->post_title ), 'type' => esc_html( $type ), 'screenshot' => ! empty( $thumbnail ) ? esc_url( $thumbnail ) : '', ); } $return['max_num_pages'] = ceil( $total_posts / 16 ); } else { // An invalid type. Display an error message. } // Add the search part to the title if ( ! empty( $search ) ) { $return['title'] .= __( ' - Results For:', 'siteorigin-panels' ) . ' <em>' . esc_html( $search ) . '</em>'; } echo wp_json_encode( apply_filters( 'siteorigin_panels_layouts_result', $return, $type ) ); wp_die(); } private function delete_file( $file ) { if ( ! empty( $file ) && file_exists( $file ) ) { @unlink( $file ); } } public function decode_panels_data( $data, $file = null ) { $panels_data = json_decode( $data, true ); if ( json_last_error() !== JSON_ERROR_NONE ) { $this->delete_file( $file ); wp_die(); } // Newer exports may require further decoding. if ( ! is_array( $panels_data ) ) { $panels_data = $this->decode_panels_data( $panels_data ); } $panels_data = wp_unslash( $panels_data ); $this->delete_file( $file ); return $panels_data; } /** * Ajax handler to get an individual prebuilt layout */ public function action_get_prebuilt_layout() { if ( empty( $_REQUEST['type'] ) ) { wp_die(); } if ( ! isset( $_REQUEST['lid'] ) ) { wp_die(); } if ( empty( $_REQUEST['_panelsnonce'] ) || ! wp_verify_nonce( $_REQUEST['_panelsnonce'], 'panels_action' ) ) { wp_die(); } header( 'content-type: application/json' ); $panels_data = array(); $raw_panels_data = false; if ( $_REQUEST['type'] == 'prebuilt' ) { $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() ); if ( ! is_numeric( $_REQUEST['lid'] ) && empty( $layouts[ $_REQUEST['lid'] ] ) ) { wp_send_json_error( array( 'error' => true, 'message' => __( 'Missing layout ID or no such layout exists', 'siteorigin-panels' ), ) ); } $layout = $layouts[ $_REQUEST['lid'] ]; // Fix the format of this layout if ( ! empty( $layout[ 'filename' ] ) ) { $filename = $layout[ 'filename' ]; // Only accept filenames that end with .json if ( substr( $filename, -5, 5 ) === '.json' && file_exists( $filename ) ) { $panels_data = json_decode( file_get_contents( $filename ), true ); $layout[ 'widgets' ] = ! empty( $panels_data[ 'widgets' ] ) ? $panels_data[ 'widgets' ] : array(); $layout[ 'grids' ] = ! empty( $panels_data[ 'grids' ] ) ? $panels_data[ 'grids' ] : array(); $layout[ 'grid_cells' ] = ! empty( $panels_data[ 'grid_cells' ] ) ? $panels_data[ 'grid_cells' ] : array(); } } // A theme or plugin could use this to change the data in the layout $panels_data = apply_filters( 'siteorigin_panels_prebuilt_layout', $layout, $_REQUEST['lid'] ); // Remove all the layout specific attributes if ( isset( $panels_data['name'] ) ) { unset( $panels_data['name'] ); } if ( isset( $panels_data['screenshot'] ) ) { unset( $panels_data['screenshot'] ); } if ( isset( $panels_data['filename'] ) ) { unset( $panels_data['filename'] ); } $raw_panels_data = true; } elseif ( substr( $_REQUEST['type'], 0, 10 ) == 'directory-' ) { $directory_id = str_replace( 'directory-', '', $_REQUEST['type'] ); $directories = $this->get_directories(); $directory = ! empty( $directories[ $directory_id ] ) ? $directories[ $directory_id ] : false; if ( ! empty( $directory ) ) { $url = $directory[ 'url' ] . 'layout/' . urlencode( $_REQUEST[ 'lid' ] ) . '/?action=download'; if ( ! empty( $directory[ 'args' ] ) && is_array( $directory[ 'args' ] ) ) { $url = add_query_arg( $directory[ 'args' ], $url ); } $response = wp_remote_get( $url ); if ( $response['response']['code'] == 200 ) { // For now, we'll just pretend to load this $panels_data = json_decode( $response['body'], true ); } else { wp_send_json_error( array( 'error' => true, 'message' => __( 'There was a problem fetching the layout. Please try again later.', 'siteorigin-panels' ), ) ); } } $raw_panels_data = true; } elseif ( current_user_can( 'edit_post', $_REQUEST['lid'] ) ) { $panels_data = get_post_meta( $_REQUEST['lid'], 'panels_data', true ); // Clear id and timestamp for SO widgets to prevent 'newer content version' notification in widget forms. foreach ( $panels_data['widgets'] as &$widget ) { unset( $widget['_sow_form_id'] ); unset( $widget['_sow_form_timestamp'] ); } } if ( $raw_panels_data ) { // This panels_data is flagged as raw, so it needs to be processed. $panels_data = apply_filters( 'siteorigin_panels_data', $panels_data, false ); $panels_data['widgets'] = SiteOrigin_Panels_Admin::single()->process_raw_widgets( $panels_data['widgets'], array(), true, true ); } wp_send_json_success( $panels_data ); } /** * Ajax handler to import a layout */ public function action_import_layout() { if ( empty( $_REQUEST['_panelsnonce'] ) || ! wp_verify_nonce( $_REQUEST['_panelsnonce'], 'panels_action' ) ) { wp_die(); } // Ensure there wasn't an error during upload. if ( empty( $_FILES['panels_import_data']['tmp_name'] ) || ! file_exists( $_FILES['panels_import_data']['tmp_name'] ) ) { wp_die(); } $json = file_get_contents( $_FILES['panels_import_data']['tmp_name'] ); $panels_data = $this->decode_panels_data( $json, $_FILES['panels_import_data']['tmp_name'] ); header( 'content-type:application/json' ); $panels_data = apply_filters( 'siteorigin_panels_data', $panels_data, false ); $panels_data['widgets'] = SiteOrigin_Panels_Admin::single()->process_raw_widgets( $panels_data['widgets'], array(), true, true ); echo wp_json_encode( $panels_data ); wp_die(); } /** * Export a given layout as a JSON file. */ public function action_export_layout() { if ( empty( $_REQUEST['_panelsnonce'] ) || ! wp_verify_nonce( $_REQUEST['_panelsnonce'], 'panels_action' ) ) { wp_die(); } $export_data = wp_unslash( $_POST['panels_export_data'] ); $decoded_export_data = $this->decode_panels_data( $export_data ); if ( ! empty( $decoded_export_data['name'] ) ) { $decoded_export_data['id'] = sanitize_title_with_dashes( $decoded_export_data['name'] ); $filename = sanitize_file_name( $decoded_export_data['id'] ); } else { $filename = 'layout-' . date( 'dmY' ); } header( 'content-type: application/json' ); header( "Content-Disposition: attachment; filename=$filename.json" ); echo wp_json_encode( $export_data ); wp_die(); } /** * Enable the directory. */ public function action_directory_enable() { if ( empty( $_REQUEST['_panelsnonce'] ) || ! wp_verify_nonce( $_REQUEST['_panelsnonce'], 'panels_action' ) ) { wp_die(); } $user = get_current_user_id(); update_user_meta( $user, 'so_panels_directory_enabled', true ); wp_die(); } /** * Load a layout from a json file * * @param bool $screenshot * * @return array The data for the layout */ public function load_layout( $id, $name, $json_file, $screenshot = false ) { $json = file_get_contents( $json_file ); $layout_data = $this->decode_panels_data( $json ); $layout_data = apply_filters( 'siteorigin_panels_load_layout_' . $id, $layout_data ); $layout_data = array_merge( array( 'name' => sanitize_text_field( $name ), 'screenshot' => esc_url( $screenshot ), ), $layout_data ); return $layout_data; } /** * Get the post types that the current user can edit. * * This function retrieves the post types specified in the * SiteOrigin Panels settings. It then filters out post types that the * current user does not have permission to edit. * * @return array The post types that the current user can edit. */ public function post_types() { $post_types = siteorigin_panels_setting( 'post-types' ); if ( empty( $post_types ) ) { return array(); } foreach ( $post_types as $id => $post_type ) { $post_type_object = get_post_type_object( $post_type ); if ( empty( $post_type_object ) || ! current_user_can( $post_type_object->cap->edit_posts ) ) { unset( $post_types[ $id ] ); } } return $post_types; } }