Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render "normal" metaboxes created by Advanced Custom Fields #2251

Closed
wants to merge 5 commits into from

Conversation

nylen
Copy link
Member

@nylen nylen commented Aug 6, 2017

This PR is an initial exploration of rendering PHP metaboxes in the Gutenberg editor. See #952.

A fairly basic metabox configuration added by the Advanced Custom Fields plugin looks like this in the wp-admin editor:

This PR renders the HTML for this field group in the Gutenberg editor. It does not attempt to handle saving, JavaScript attached to the field boxes, or any number of other things that can and will go wrong when attempting to implement this feature.

Here's what it looks like currently:

Technical details

As noted in the PHP comments, Advanced Custom Fields adds its metaboxes by registering a hook against admin_enqueue_scripts. This hook verifies that the current page load is either post.php or post-new.php, and if so, adds an admin_head action which calls add_meta_box. WP core does its do_meta_boxes calls shortly after that action, in edit-form-advanced.php.

This PR works by modifying the $pagenow variable during the appropriate portion of the Gutenberg page load so that Advanced Custom Fields will register its metaboxes and inject its scripts.

This is not even close to an acceptable approach. It is already having a lot of unintended side effects. For example, it doesn't seem to be breaking the Gutenberg editor when using Advanced Custom Fields, but here are the console errors that result from this "unorthodox" loading process:

Also, the way this PR renders the metabox HTML is unacceptable because any malformed markup will probably completely break the React app, and any scripts that expect to manipulate the traditional editor page structure will fail and probably break things along the way.

From the extensive modification of the WP load process needed to get this initial example working, and from the resulting issues, it's clear that we will need to create an API endpoint to render and return metabox HTML. This API endpoint would then be called in a separate request after the Gutenberg editor has loaded, where it can do whatever horrible things it wants to the WP load process.

To avoid concerns about rendering unfiltered HTML inside a React app, we had previously discussed rendering metaboxes in a separate element not managed by React. We can try this next; however, based on the number and type of errors I am already seeing, and the likely difficulties in managing the load-save lifecycle of the metabox content, I'm skeptical that it will work well.

Lots of unshippable hacks here.  See TODO comments.
@nylen nylen added the [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). label Aug 6, 2017
@WordPress WordPress deleted a comment from codecov bot Aug 6, 2017
@nylen nylen added [Status] In Progress Tracking issues with work in progress [Status] Horrible Hack and removed [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). labels Aug 6, 2017
@WordPress WordPress deleted a comment from codecov bot Aug 6, 2017
@nylen nylen mentioned this pull request Aug 6, 2017
@aduth
Copy link
Member

aduth commented Aug 7, 2017

any malformed markup will probably completely break the React app

Can you elaborate on what breaks if we're just rendering by dangerouslySetInnerHTML ?

any scripts that expect to manipulate the traditional editor page structure will fail and probably break things along the way.

Two thoughts:

From the extensive modification of the WP load process needed to get this initial example working, and from the resulting issues, it's clear that we will need to create an API endpoint to render and return metabox HTML. This API endpoint would then be called in a separate request after the Gutenberg editor has loaded, where it can do whatever horrible things it wants to the WP load process.

Seems also this might tie into: What needs to happen to meta boxes after a save occurs? Currently plugins will expect a full page reload any time the post is saved. Might be able to recreate this with said metabox endpoint. I believe this was mentioned by @westonruter previously.

To avoid concerns about rendering unfiltered HTML inside a React app

Another thing we'll probably want is to prevent rerenders on the Metaboxes component except in the very few managed cases we expect them. See also shouldComponentUpdate = () => false, <TinyMCE />.

@nylen
Copy link
Member Author

nylen commented Aug 9, 2017

Can you elaborate on what breaks if we're just rendering by dangerouslySetInnerHTML?

I haven't seen anything break yet specifically due to that reason, but it seems likely that something will / maybe not the best approach.

What needs to happen to meta boxes after a save occurs? Currently plugins will expect a full page reload any time the post is saved. Might be able to recreate this with said metabox endpoint.

Yep, I think this would be best addressed with an endpoint that simulates a POST, save_post action, etc.

Another thing we'll probably want is to prevent rerenders on the Metaboxes component

👍

@lucasstark
Copy link
Contributor

How about rather than rendering it inline you render some form of data preview and then when editing the block it would open a modal with the meta box inside of it.

@codecov
Copy link

codecov bot commented Aug 15, 2017

Codecov Report

Merging #2251 into master will decrease coverage by 2.36%.
The diff coverage is 8.69%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2251      +/-   ##
==========================================
- Coverage   26.51%   24.15%   -2.37%     
==========================================
  Files         158      144      -14     
  Lines        4853     4484     -369     
  Branches      816      763      -53     
==========================================
- Hits         1287     1083     -204     
+ Misses       3013     2870     -143     
+ Partials      553      531      -22
Impacted Files Coverage Δ
editor/metaboxes/normal.js 0% <0%> (ø)
editor/layout/index.js 0% <0%> (ø) ⬆️
editor/metaboxes/index.js 0% <0%> (ø)
editor/index.js 0% <0%> (ø) ⬆️
editor/state.js 92.1% <66.66%> (+3.82%) ⬆️
blocks/api/paste/strip-attributes.js 0% <0%> (-100%) ⬇️
blocks/inspector-controls/range-control/index.js 0% <0%> (-100%) ⬇️
blocks/inspector-controls/base-control/index.js 0% <0%> (-100%) ⬇️
components/popover/index.js 65.21% <0%> (-30.1%) ⬇️
editor/effects.js 26.76% <0%> (-13.24%) ⬇️
... and 87 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8274602...03a7414. Read the comment docs.

@nylen
Copy link
Member Author

nylen commented Aug 15, 2017

In the last couple of commits I've added the beginning of a metaboxes API endpoint.

Unfortunately this is impossible to do from within a plugin. Here is the debug log from a sample request to the endpoint:

load acf wp-content/plugins/advanced-custom-fields/acf.php
acf.php include_before_theme false
load gutenberg wp-content/plugins/gutenberg/lib/api/class-gutenberg-metaboxes-controller.php
plugins_loaded
init
rest_api_init
load wp-admin/includes/template.php

It shows that:

  • Advanced Custom Fields is loaded before Gutenberg
  • ACF checks is_admin(), sees that it is false, and skips loading the logic that would register its metaboxes
  • Gutenberg initializes, and there is already no way to call back into the core ACF logic to reinitialize it. Even if this were possible, it would also have to be done specifically for each plugin, which is not a good idea.
  • plugins_loaded, init, rest_api_init, and the API endpoint callback happen later still.

Potential next steps:

  • Try getting this API endpoint to work using a core hack instead. This would indicate that it is possible to write such an endpoint in WP core.
  • Follow a URL scheme based on post.php like @westonruter suggested in Supporting Metaboxes #952 (comment) and stick closer to the current WP load order. This will probably require a core patch as well: it's unlikely that enough hooks are present to allow us to successfully suppress all output except what we want.

@StaggerLeee
Copy link

I cannot believe you went into this adventure without knowing how to make it work.
In the beginning I thought you had some ideas and prototypes.

One decision from the top, and now you have to fix this mess.
As I personally see it, you are making completely new CMS. Wordpress will never be as it was before. So be careful.

@lkraav
Copy link

lkraav commented Aug 16, 2017

I cannot believe you went into this adventure without knowing how to make it work. In the beginning I thought you had some ideas and prototypes.

Nobody knows "how to make it work" yet, getting to "knowing more" is the whole point of this experimentation process. Let's let the people that over time have the highest probability of figuring the (massively complex) details out (such as @nylen) do their work in peace.

@StaggerLeee
Copy link

I love when you core persons experiment, and seek new ways. I mean it, no joke here.
"Slight" problem is, Gutenberg is already announced as part of the WP core code.

@aduth
Copy link
Member

aduth commented Aug 16, 2017

@StaggerLeee A pull request is not an appropriate venue for venting your frustrations with the direction or status of the project, and should be reserved for constructive feedback to the proposed implementation. Ideas, requirements, or discussion is better suited for related issues (#952) or weekly editor chats in Core WordPress Slack.

To use this hit the
`wp-admin/post.php?post=ID&action=edit&metabox=some-location`. This will
currently render the metaboxes for the base set of meta boxes. Adds and
iframe as well to pull these in from endpoint.
@nylen
Copy link
Member Author

nylen commented Aug 16, 2017

^ The latest commit by @BE-Webdesign is a much cleaner and more workable approach to fetching metabox data than either of the two I've tried. We discussed a little bit yesterday and it is basically working for some of the Yoast metaboxes. I would recommend reworking metabox support around it instead.

@BE-Webdesign
Copy link
Contributor

I will not have time for the foreseeable future to continue work on this but the last commit essentially adds an "endpoint" of sorts to wp-admin/post.php. When a ?metabox=location query param is provided it will die early on one of the hooks for post.php. This will render some of the metaboxes. Then on the rendering of the gutenberg admin page there is an iframe that is being generated with its source set to the "post.php endpoint". This was a quick bit of work, and I think this approach moving forward could potentially be a reasonable solution, but I have my doubts as well, as this is a beast of a technical issue in some ways.

@nylen
Copy link
Member Author

nylen commented Sep 29, 2017

Superseded by #2804.

@nylen nylen closed this Sep 29, 2017
@nylen nylen deleted the support/metaboxes branch September 29, 2017 21:45
Tug pushed a commit that referenced this pull request May 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Status] In Progress Tracking issues with work in progress
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants