AdvancedCustomFields / acf

Advanced Custom Fields
http://advancedcustomfields.com/
824 stars 167 forks source link

Gutenberg compatibility for "Hide on screen" settings #112

Open elliotcondon opened 5 years ago

elliotcondon commented 5 years ago

Description

Each field group contains a setting called "Hide on screen". This setting allows a user to select from a list of known "elements" on the page such as Permalink, Excerpt, Revisions, Format, etc.

Developers enjoy this setting as they can use it to hide core metaboxes from within the field group.

For example, you can create a field group called "Home" with some custom fields, and then hide all the WP default metaboxes (except the publish box). This makes the edit screen look highly customized with little effort.

To do this, we use CSS to hide these "elements".

Issues

Questions

noisysocks commented 5 years ago

Copying some answers over from https://github.com/WordPress/gutenberg/issues/12692#issuecomment-452165743.

  • How can we hide / show the following "elements"?
    • Permalink
    • Content Editor (not sure if this is possible now)
    • Excerpt
    • Discussion
    • Comments
    • Revisions
    • Slug
    • Author
    • Format
    • Page Attributes
    • Featured Image
    • Categories
    • Tags
    • Send Trackbacks

Some panels can be removed by dispatching removeEditorPanel().

wp.data.dispatch( 'core/edit-post' ).removeEditorPanel( 'post-link' ); // Permalink
wp.data.dispatch( 'core/edit-post' ).removeEditorPanel( 'post-excerpt' ); // Excerpt
wp.data.dispatch( 'core/edit-post' ).removeEditorPanel( 'discussion-panel' ); // Discussion
wp.data.dispatch( 'core/edit-post' ).removeEditorPanel( 'page-attributes' ); // Page Attributes
wp.data.dispatch( 'core/edit-post' ).removeEditorPanel( 'featured-image' ); // Featured Image
wp.data.dispatch( 'core/edit-post' ).removeEditorPanel( 'post-status' ); // Status & Visibility

📌 We'll need to expand this API so that the rest of your use cases are covered: Comments, Revisions, Slug, Author, Format, Categories, Tags, Send Trackbacks. We also will need to improve the documentation here.

Not sure what you mean by disabling Content Editor. Is that a panel?

  • Can we still achieve this via CSS, or can we use the JS API?

Using CSS will do the job here but it's not an official API that we support. That is, we might change a CSS selector in the future without any warning.

  • These "hide on screen" settings update via the "Dynamic metaboxes" feature, so we need the ability to hide an "element" and then show it later if need be.

📌 For this we will likely will need to change the removeEditorPanel() API so that panels can be 'un-removed' later.

jnicol commented 5 years ago

@elliotcondon, a workaround for hiding the editor is to disable all Gutenberg blocks for the post type. Then, all the Gutenberg UI for adding blocks will be removed from the editing screen.

Something like this:

add_filter('allowed_block_types', 'my_allowed_block_types', 10, 2);
function my_allowed_block_types($allowed_blocks, $post) {
  if( $post->post_type === 'myCPT' ) {
     return array();
    }
}

In my tests this removes everything but the title and custom fields from the editing interface, which is how "hide editor" worked with the Classic editor, with one caveat: if the post already had blocks, they will still be displayed. But for new posts it seems to do the trick.

As I mentioned this is a workaround, but for people looking to make the new editor play nice with ACF it might be a viable approach.

jg314 commented 5 years ago

If you want to hide the main block editor based on which ACF fields are loaded on the page, here's an example using the ACF JavaScript API and some CSS.

Pre-WordPress 5.4:

function hide_gutenberg_editor() {
    ?>
    <script type="text/javascript">
        ( function($){

            acf.addAction( 'load', function(){

                var field = acf.getField( 'field_5b5f6a5e50308' ); // the ACF field key

                if( field.$el.length > 0 ){

                    $( '.editor-block-list__layout' ).css( 'display', 'none' );
                    $( '.edit-post-layout__content .edit-post-visual-editor' ).css( 'flex', 'none' );
                    $( '.edit-post-header-toolbar' ).css( 'visibility', 'hidden' );
                }
            });

        })( jQuery );
    </script>
    <?php
}

add_action( 'acf/input/admin_footer', 'hide_gutenberg_editor' );

WordPress 5.4:

function hide_gutenberg_editor() {
    ?>
    <script type="text/javascript">
        ( function($){

            acf.addAction( 'load', function(){

                var field = acf.getField( 'field_5b5f6a5e50308' ); // the ACF field key

                if( field.$el.length > 0 ){

                    $( '.block-editor-block-list__layout' ).css( 'display', 'none' );
                    $( '.block-editor-writing-flow__click-redirect' ).css( 'display', 'none' );
                    $( '.edit-post-visual-editor' ).css({ 'flex-basis': '0', 'flex': 'none' });
                    $( '.edit-post-header-toolbar' ).css( 'visibility', 'hidden' );
                }
            });

        })( jQuery );
    </script>
    <?php
}

add_action( 'acf/input/admin_footer', 'hide_gutenberg_editor' );
kikeonline commented 5 years ago

I´m using this approach:

add_action( 'admin_init', 'hide_editor' );
function hide_editor() {
  $post_id = $_GET['post'] ? $_GET['post'] : $_POST['post_ID'] ;
  if( !isset( $post_id ) ) return;
  $home = get_the_title($post_id);
  //$contact = get_the_title($post_id);
  if($home == 'Home' || $contact == 'Contact'){ 
    remove_post_type_support('page', 'editor');
  }
}
ghost commented 4 years ago

Any pointers as to when this feature will be compatible with Gutenberg @elliotcondon?

elliotcondon commented 4 years ago

Hi @dnnsjsk

I haven't had any luck with this just yet, sorry.

martonlente commented 4 years ago

Hello,

The issue in subject is still present, however there may already be a workaround. Though it may not be a perfect solution, but in newer WP versions (maybe from 5.2 ), in Gutenberg's options you can disable both ducument panels (e.g. Permalink, Featured image etc.), and in 'Block manager' also blocks. Disabling all blocks disables the content editor itself. The settings globally apply to all posts within the same post type, so you don't have to 'repeat yourself'.

Activating 'Classic Editor' also works of course.

Kind regards, Márton Lente

Koli14 commented 4 years ago

I use the following code to disable Gutenberg on all Page:

add_action('init', 'remove_guttenberg_from_pages', 10);
function remove_guttenberg_from_pages()
{
    remove_post_type_support('page', 'editor');
}

or on specific pages based on @kikeonline answer:

add_action('admin_init', function () {
    if (array_key_exists('post', $_GET) || array_key_exists('post_ID', $_GET)) {
        $post_id = $_GET['post'] ? $_GET['post'] : $_POST['post_ID'] ;
        if (!isset($post_id)) {
            return;
        }
        $title = get_the_title($post_id);
        //$contact = get_the_title($post_id);
        if ($title == 'Home' || $title == 'About Us') {
            remove_post_type_support('page', 'editor');
        }
    }
}, 10);
isuke01 commented 4 years ago

Is there any way to get ACF settings Hide on screen in JS, like build in solution? Or just some custom code that add those values into footer?

simplenotezy commented 4 years ago

Would love a solution to this as well, the editor is very annoying and blocking the whole page.

fregante commented 4 years ago

If you're not gonna use Gutemberg, just disable it, for example with the Disable Gutemberg plugin.

nick6352683 commented 3 years ago

The ACF Extended plugin has a working solution... editor

EmilMoe commented 2 years ago

The ACF Extended plugin has a working solution... !

unfortunately this isn't working anymore

JetLewis commented 2 years ago

"allowed_block_types" being depreciated, use "allowed_block_types_all" instead: add_filter('allowed_block_types_all', 'my_allowed_block_types', 10, 2); function my_allowed_block_types($allowed_blocks, $editor_context) { if( $editor_context->post->post_type === 'post_type_name' ) { return array(); } else{ return $allowed_blocks; } }

EarthlingDavey commented 1 year ago

An example of how to hide panels based on post type.

add_action('init', 'ual_modify_block_panels');

function ual_modify_block_panels()
{
    // Enqueue our script
    wp_enqueue_script(
        'ual-blocks-modify-panels',
        esc_url(plugins_url('/build/modifyPanels.js', __FILE__)),
        array('wp-blocks', 'wp-edit-post', 'wp-data'),
        '1.0.0',
        true // Enqueue the script in the footer.
    );
}
import { dispatch, select, subscribe } from '@wordpress/data';

const getPostType = (): string => select('core/editor').getCurrentPostType();

// set the initial postFormat
let postFormat = getPostType();

// @see https://stackoverflow.com/questions/52301472/using-wp-data-subscribe-properly

subscribe(() => {
    // get the current postFormat
    const newPostType = getPostType();

    // only do something if postFormat has changed.
    if (postFormat !== newPostType) {
        // Do whatever you want after postFormat has changed
        maybeModifyPanels(newPostType);
    }

    // update the postFormat variable.
    postFormat = newPostType;
});

const maybeModifyPanels = (postType: string) => {
    if (postType !== 'faq') return;

    dispatch('core/edit-post').removeEditorPanel('taxonomy-panel-category'); // category
    //  // dispatch('core/edit-post').removeEditorPanel(
    //  //  'taxonomy-panel-TAXONOMY-NAME'
    //  // ); // custom taxonomy
    dispatch('core/edit-post').removeEditorPanel('taxonomy-panel-post_tag'); // tags
    dispatch('core/edit-post').removeEditorPanel('featured-image'); // featured image
    dispatch('core/edit-post').removeEditorPanel('post-link'); // permalink
    dispatch('core/edit-post').removeEditorPanel('page-attributes'); // page attributes
    dispatch('core/edit-post').removeEditorPanel('post-excerpt'); // Excerpt
    dispatch('core/edit-post').removeEditorPanel('discussion-panel'); // Discussion
    dispatch('core/edit-post').removeEditorPanel('template'); // Template
};
vreemt commented 1 year ago

postFormat

thanks for the example. I would like to note that post format is (still) a term used by WP for eg aside, video, gallery etc. (and apparently still supported in some custom themes). It can be confusing if used as a variable name for post type.

in my testing, it took a while for all the things to load, so a panel wasn't hidden until at least a few seconds (probably more like 10-15) when loading the page. it also seems silly to remove the panel after it's been loaded, so I'm hoping there'll be some better (php or Gutenberg) support soon...

also, when using window.wp.data.select( 'core/edit-post' ).getPreferences().panels; I got a deprecation warning:

deprecated.min.js?ver=6c963cb9494ba26b77eb:2 select( 'core/edit-post' ).getPreferences is deprecated since version 6.0. Please use select( 'core/preferences' ).get instead.

but as per usual, the docs are less-than-helpful in telling me what I actually need to get a list of panels

https://developer.wordpress.org/block-editor/reference-guides/data/data-core-preferences/ https://developer.wordpress.org/block-editor/reference-guides/packages/packages-preferences/

window.wp.data.select( 'core/preferences' ).get('panels');
undefined

window.wp.data.select( 'core/preferences' )
{getCachedResolvers: ƒ, getIsResolving: ƒ, getResolutionError: ƒ, getResolutionState: ƒ, hasFinishedResolution: ƒ, …}

thanks for all the hard work! 👍

zielinskila commented 1 year ago

Thank you guys. Based on @Koli14 answer, I've created solution that relies on group settings (so you don't need to hardcode post title anymore), using acf_get_field_groups(), which returns the list of groups, with $post_id as a parameter:

add_action('admin_init', function () {
    if (array_key_exists('post', $_GET) || array_key_exists('post_ID', $_GET)) {
        $post_id = $_GET['post'] ? $_GET['post'] : $_POST['post_ID'] ;
        if (!isset($post_id)) {
            return;
        }
        $groups = acf_get_field_groups(array('post_id' => $post_id));
        $disable_editor = false;
        foreach ($groups as $group) {
            if (is_array($group['hide_on_screen'])) {
                $hide_on_screen = $group['hide_on_screen'];
                if (in_array('the_content', $hide_on_screen)) {
                    $disable_editor = true;
                }
            }
        }
        if ($disable_editor) {
            $post_type = get_post_type($post_id);
            remove_post_type_support($post_type, 'editor');
        }
    }
}, 10);

I decided to iterate through all groups attached to post and if any has $group['hide_on_screen']['the_content'] then hide the editor, but you can expand it to include the $group['menu_order'] to comply with ACF core rules about priority of settings when it comes to multiple groups per posts.

This post helped too: https://support.advancedcustomfields.com/forums/topic/get-all-field-groups-related-to-post/#post-34539

bad-jesus commented 2 months ago

@elliotcondon, a workaround for hiding the editor is to disable all Gutenberg blocks for the post type. Then, all the Gutenberg UI for adding blocks will be removed from the editing screen.

Something like this:

add_filter('allowed_block_types', 'my_allowed_block_types', 10, 2);
function my_allowed_block_types($allowed_blocks, $post) {
  if( $post->post_type === 'myCPT' ) {
     return array();
    }
}

In my tests this removes everything but the title and custom fields from the editing interface, which is how "hide editor" worked with the Classic editor, with one caveat: if the post already had blocks, they will still be displayed. But for new posts it seems to do the trick.

As I mentioned this is a workaround, but for people looking to make the new editor play nice with ACF it might be a viable approach.

I just spent HOURS trying to do this. This deserves a HIGH FIVE! THIS! How is this not made it into the latest ACF pro version yet? This just made it to the top of my code library.

matiyin commented 2 months ago

solved this in functions.php (per template) until ACF found a solution:

add_action('init', 'remove_gutenberg_editor');
function remove_gutenberg_editor()
{
  if (is_admin() && isset($_GET['post']) && isset($_GET['action'])) {
    $post_id = $_GET['post'];
    $template_file = get_post_meta($post_id, '_wp_page_template', true);
    if ($template_file == 'page_gallery.php' || $template_file == 'page_shop.php') {
      remove_post_type_support('page', 'editor');
    }
  }
}