html = $html; $this->viewMarkup = $viewMarkup; $this->plugin = $plugin; } protected function cloneItemMeta(int $originPostId, int $targetPostId): void { $originAcfViewGroup = new View($originPostId); $originAcfViewGroup->setSource($targetPostId); $originAcfViewGroup->save(true); } protected function updateMarkup(int $postId): void { $view = new View($postId); // pageId 0, so without CSS $viewMarkup = $this->viewMarkup->getMarkup($view, 0); $view->markup = $viewMarkup; $view->save(); } protected function addProBannerMetabox(): void { add_meta_box( 'acf-views_pro', 'PRO', function ($post, $meta) { echo $this->html->proBanner(Plugin::PRO_MAIL_TO, $this->plugin->getAssetsUrl('pro.png')); }, [ self::NAME, ], 'side' ); } public function setHooks(): void { add_action('init', [$this, 'addCPT']); add_action('add_meta_boxes', [$this, 'addMetaboxes']); add_action( 'manage_' . self::NAME . '_posts_custom_column', [ $this, 'printColumn', ], 10, 2 ); // priority is important here, should be after the acf code, so bigger than 10 // also identifiers update should be the first add_action('acf/save_post', [$this, 'updateIdentifiersOnPostSave',], 19); add_action('acf/save_post', [$this, 'updateMarkupOnPostSave',], 20); add_action('admin_enqueue_scripts', [$this, 'addCodemirrorToCPTEditScreens']); add_action('admin_init', [$this, 'cloneItemAction']); add_action('admin_notices', [$this, 'showItemClonedMessage']); add_filter('manage_' . self::NAME . '_posts_columns', [$this, 'getColumns',]); add_filter('manage_edit-' . self::NAME . '_sortable_columns', [$this, 'getSortableColumns',]); add_action('pre_get_posts', [$this, 'addSortableColumnsToRequest',]); add_filter('enter_title_here', [$this, 'getTitlePlaceholder',]); add_filter('post_row_actions', [$this, 'getRowActions',], 10, 2); } public function addCPT(): void { $labels = [ 'name' => 'ACF Views', 'singular_name' => 'ACF View', 'menu_name' => 'ACF Views', 'parent_item_colon' => 'Parent ACF View', 'all_items' => 'ACF Views', 'view_item' => 'Browse ACF View', 'add_new_item' => 'Add New ACF View', 'add_new' => 'Add New', 'edit_item' => 'Edit ACF View', 'update_item' => 'Update ACF View', 'search_items' => 'Search ACF View', 'not_found' => 'Not Found', 'not_found_in_trash' => 'Not Found In Trash', ]; $args = [ 'label' => 'acf views', 'description' => 'acf views', 'labels' => $labels, 'public' => true, 'publicly_queryable' => false, 'show_ui' => true, 'show_in_rest' => false, 'has_archive' => false, 'show_in_menu' => true, 'show_in_nav_menus' => false, 'delete_with_user' => false, 'exclude_from_search' => true, 'capability_type' => 'post', 'hierarchical' => false, 'can_export' => false, 'rewrite' => false, 'query_var' => false, 'menu_icon' => 'dashicons-format-gallery', 'supports' => ['title',], 'show_in_graphql' => false, ]; register_post_type(self::NAME, $args); } public function getColumns(array $columns): array { unset($columns['date']); return array_merge($columns, [ self::COLUMN_DESCRIPTION => 'Description', self::COLUMN_SHORTCODE => 'Shortcode', self::COLUMN_AUTHOR => 'Author', self::COLUMN_LAST_MODIFIED => 'Last modified', self::COLUMN_CREATED => 'Created', ]); } public function getSortableColumns(array $columns): array { return array_merge($columns, [ self::COLUMN_AUTHOR => self::COLUMN_AUTHOR, self::COLUMN_LAST_MODIFIED => self::COLUMN_LAST_MODIFIED, self::COLUMN_CREATED => self::COLUMN_CREATED, ]); } function addSortableColumnsToRequest(WP_Query $query): void { if (! is_admin()) { return; } $orderBy = $query->get('orderby'); switch ($orderBy) { case self::COLUMN_AUTHOR: $query->set('orderby', 'post_author'); break; case self::COLUMN_LAST_MODIFIED: $query->set('orderby', 'post_modified'); break; case self::COLUMN_CREATED: $query->set('orderby', 'post_date'); break; } } public function printColumn(string $column, int $postId): void { switch ($column) { case self::COLUMN_DESCRIPTION: $view = new View($postId); echo esc_html($view->description); break; case self::COLUMN_SHORTCODE: echo $this->html->postboxShortcodes($postId, true); break; case self::COLUMN_AUTHOR: echo esc_html(get_user_by('id', get_post($postId)->post_author)->display_name ?? ''); break; case self::COLUMN_LAST_MODIFIED: echo esc_html(explode(' ', get_post($postId)->post_modified)[0]); break; case self::COLUMN_CREATED: echo esc_html(explode(' ', get_post($postId)->post_date)[0]); break; } } public function addMetaboxes(): void { add_meta_box( 'acf-views_shortcode', 'Shortcode', function ($post, $meta) { if (! $post || 'publish' !== $post->post_status) { echo 'Press the publish button to see the shortcode.'; return; } echo $this->html->postboxShortcodes($post->ID, false); }, [ self::NAME, ], 'side' ); add_meta_box( 'acf-views_review', 'Rate & Review', function ($post, $meta) { echo $this->html->postboxReview(); }, [ self::NAME, ], 'side' ); add_meta_box( 'acf-views_support', 'Having issues?', function ($post, $meta) { echo $this->html->postboxSupport(); }, [ self::NAME, ], 'side' ); $this->addProBannerMetabox(); } /** * @param int|string $postId Could be string e.g. for 'site-settings' * * @return void */ public function updateMarkupOnPostSave($postId): void { // for 'site-settings' and such if (! is_numeric($postId)) { return; } $post = get_post($postId); if (self::NAME !== $post->post_type || wp_is_post_revision($postId) || 'publish' !== $post->post_status) { return; } $this->updateMarkup($post->ID); } /** * @param int|string $postId Could be string e.g. for 'site-settings' * * @return void */ public function updateIdentifiersOnPostSave($postId): void { $post = get_post($postId); if (self::NAME !== $post->post_type || wp_is_post_revision($postId) || 'publish' !== $post->post_status) { return; } $view = new View($postId); foreach ($view->items as $item) { $item->field->id = ($item->field->id && ! preg_match('/^[a-zA-Z0-9_\-]+$/', $item->field->id)) ? '' : $item->field->id; if (! $item->field->id) { $item->field->id = $item->field->getAcfFieldId(); } } $view->save(); } public function addCodemirrorToCPTEditScreens() { $currentScreen = get_current_screen(); if (in_array($currentScreen->id, [self::NAME,], true) || in_array($currentScreen->post_type, [self::NAME], true)) { $cmSettings = [ 'codeEditor' => wp_enqueue_code_editor(['type' => 'text/css']), ]; wp_localize_script('jquery', 'cm_settings', $cmSettings); wp_enqueue_script('wp-theme-plugin-editor'); wp_enqueue_style('wp-codemirror'); } } public function cloneItemAction(): void { if (! isset($_GET[self::ACTION_CLONE])) { return; } $viewId = (int)$_GET[self::ACTION_CLONE]; $viewPost = get_post($viewId); if (! $viewPost || self::NAME !== $viewPost->post_type) { return; } check_admin_referer('bulk-posts'); $args = [ 'post_type' => $viewPost->post_type, 'post_status' => 'draft', 'post_name' => $viewPost->post_name, 'post_title' => $viewPost->post_title . ' Clone', 'post_author' => $viewPost->post_author, ]; $newPostId = wp_insert_post($args); // something went wrong if (is_wp_error($newPostId)) { return; } $this->cloneItemMeta($viewPost->ID, $newPostId); $targetUrl = get_admin_url(null, '/edit.php?post_type=' . self::NAME); $targetUrl .= '&' . self::ACTION_CLONED . '=1'; wp_redirect($targetUrl); exit; } public function showItemClonedMessage(): void { if (! isset($_GET[self::ACTION_CLONED])) { return; } echo '
' . '

ACF view success cloned.

' . '
'; } public function getTitlePlaceholder(string $title): string { if (! function_exists('get_current_screen')) { return $title; } $screen = get_current_screen()->post_type ?? ''; if (self::NAME !== $screen) { return $title; } return 'Name your view'; } public function getRowActions(array $actions, WP_Post $view): array { if (self::NAME !== $view->post_type) { return $actions; } $trash = str_replace('>Trash<', '>Delete<', $actions['trash']); // quick edit unset($actions['inline hide-if-no-js']); unset($actions['trash']); $cloneLink = get_admin_url(null, '/edit.php?post_type=' . self::NAME); $cloneLink .= '&' . self::ACTION_CLONE . '=' . $view->ID . '&_wpnonce=' . wp_create_nonce('bulk-posts'); $actions['clone'] = "Clone"; $actions['trash'] = $trash; return $actions; } }