queryBuilder = $queryBuilder; $this->cardMarkup = $cardMarkup; } protected function updateQueryPreview(AcfCardData $acfCardData): void { $acfCardData->queryPreview = print_r($this->queryBuilder->getQueryArgs($acfCardData, 1), true); } protected function updateMarkup(AcfCardData $acfCardData): void { $acfCardData->markup = $this->cardMarkup->getMarkup($acfCardData, false, true); } protected function addLayoutCSS(AcfCardData $acfCardData): void { $layoutCSS = $this->cardMarkup->getLayoutCSS($acfCardData); if (!$layoutCSS) { return; } $acfCardData->cssCode = false === strpos($acfCardData->cssCode, '/*BEGIN LAYOUT_RULES*/') ? ($acfCardData->cssCode . "\n" . $layoutCSS . "\n") : preg_replace( '|\/\*BEGIN LAYOUT_RULES\*\/(.*\s)+\/\*END LAYOUT_RULES\*\/|', $layoutCSS, $acfCardData->cssCode ); } public function addCPT(): void { $labels = [ 'name' => __('ACF Cards', 'acf-views'), 'singular_name' => __('ACF Card', 'acf-views'), 'menu_name' => __('ACF Cards', 'acf-views'), 'parent_item_colon' => __('Parent ACF Card', 'acf-views'), 'all_items' => __('ACF Cards', 'acf-views'), 'view_item' => __('Browse ACF Card', 'acf-views'), 'add_new_item' => __('Add New ACF Card', 'acf-views'), 'add_new' => __('Add New', 'acf-views'), 'edit_item' => __('Edit ACF Card', 'acf-views'), 'update_item' => __('Update ACF Card', 'acf-views'), 'search_items' => __('Search ACF Card', 'acf-views'), 'not_found' => __('Not Found', 'acf-views'), 'not_found_in_trash' => __('Not Found In Trash', 'acf-views'), ]; $args = [ 'label' => __('ACF Cards', 'acf-views'), 'description' => __( 'Create ACF Card item to choose a set of posts (or CPT items) and paste the shortcode in a target place to display the posts with their ACF fields.', 'acf-views' ) . '
' . __('(which fields are printed depending on a selected ACF View in the Card settings)', 'acf-views'), 'labels' => $labels, 'public' => true, // e.g. Yoast doesn't reflect in Sitemap then 'publicly_queryable' => false, 'show_ui' => true, 'show_in_rest' => false, 'has_archive' => false, 'show_in_menu' => false, '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 setHooks(): void { parent::setHooks(); add_action('init', [$this, 'addCPT']); add_action('admin_menu', [$this, 'addPage']); add_action( 'manage_' . self::NAME . '_posts_custom_column', [ $this, 'printColumn', ], 10, 2 ); add_action('pre_get_posts', [$this, 'addSortableColumnsToRequest',]); // priority is important here, should be 1) after the acf code (20) // 2) after the CPT save hook, which replaces fields with json (30) add_action('acf/save_post', [$this, 'performSaveActions'], 30); add_filter('manage_' . self::NAME . '_posts_columns', [$this, 'getColumns',]); add_filter('manage_edit-' . self::NAME . '_sortable_columns', [$this, 'getSortableColumns',]); add_filter('enter_title_here', [$this, 'getTitlePlaceholder',]); } public function replacePostUpdatedMessage(array $messages): array { global $post; $restoredMessage = false; $scheduledMessage = __('ACF Card scheduled for:', 'acf-views'); $scheduledMessage .= sprintf( ' %1$s', date_i18n('M j, Y @ G:i', strtotime($post->post_date)) ); if (isset($_GET['revision'])) { $restoredMessage = __('ACF Card restored to revision from', 'acf-views'); $restoredMessage .= ' ' . wp_post_revision_title((int)$_GET['revision'], false); } $messages[self::NAME] = [ 0 => '', // Unused. Messages start at index 1. 1 => __('ACF Card updated.', 'acf-views'), 2 => __('Custom field updated.', 'acf-views'), 3 => __('Custom field deleted.', 'acf-views'), 4 => __('ACF Card updated.', 'acf-views'), 5 => $restoredMessage, 6 => __('ACF Card published.', 'acf-views'), 7 => __('ACF Card saved.', 'acf-views'), 8 => __('ACF Card submitted.', 'acf-views'), 9 => $scheduledMessage, 10 => __('ACF Card draft updated.', 'acf-views'), ]; return $messages; } /** * @param int|string $postId * * @return void */ public function performSaveActions($postId): void { if (!$this->isMyPost($postId)) { return; } $acfCardData = $this->cache->getAcfCardData($postId); $this->updateQueryPreview($acfCardData); $this->updateMarkup($acfCardData); $this->addLayoutCSS($acfCardData); $acfCardData->saveToPostContent(); } public function addPage(): void { $url = sprintf('edit.php?post_type=%s', AcfViews::NAME); global $submenu; if (!$submenu[$url]) { $submenu[$url] = []; } // 'ACF Views' has 5, so 6 is right after $submenu[$url][6] = [ __('ACF Cards', 'acf-views'), 'manage_options', sprintf( 'edit.php?post_type=%s', self::NAME ) ]; ksort($submenu[$url]); } public function getTitlePlaceholder(string $title): string { $screen = get_current_screen()->post_type ?? ''; if (self::NAME !== $screen) { return $title; } return __('Name your card', 'acf-views'); } public function getColumns(array $columns): array { unset($columns['date']); return array_merge($columns, [ self::COLUMN_DESCRIPTION => __('Description', 'acf-views'), self::COLUMN_SHORTCODE => __('Shortcode', 'acf-views'), self::COLUMN_AUTHOR => __('Author', 'acf-views'), self::COLUMN_LAST_MODIFIED => __('Last modified', 'acf-views'), self::COLUMN_CREATED => __('Created', 'acf-views'), ]); } 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, ]); } public 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 = $this->cache->getAcfCardData($postId); echo esc_html($view->description); break; case self::COLUMN_SHORTCODE: echo $this->html->postboxShortcodes( $postId, true, Plugin::SHORTCODE_CARDS, get_the_title($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 { parent::addMetaboxes(); add_meta_box( 'acf-views_shortcode_cpt', __('Shortcode', 'acf-views'), function ($post, $meta) { if (!$post || 'publish' !== $post->post_status) { echo __('Your Card shortcode is available after publishing.', 'acf-views'); return; } echo $this->html->postboxShortcodes( $post->ID, false, Plugin::SHORTCODE_CARDS, get_the_title($post), true ); }, [ self::NAME, ], 'side', // right after the publish button 'core' ); } }