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

How to use dynamic data with registerFormatType #18490

Open
mahnunchik opened this issue Nov 13, 2019 · 16 comments
Open

How to use dynamic data with registerFormatType #18490

mahnunchik opened this issue Nov 13, 2019 · 16 comments
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Extensibility The ability to extend blocks or the editing experience [Package] Format library /packages/format-library [Type] Enhancement A suggestion for improvement.

Comments

@mahnunchik
Copy link

mahnunchik commented Nov 13, 2019

Part of #41236.

How to use dynamic data with format registered by registerFormatType?

const type = 'test/test';
registerFormatType(type, {
  title: 'Slug link',
  tagName: 'a',
  className: 'slug',
  edit ({ isActive, value, onChange }) {
    const onToggle = () => {
      onChange(toggleFormat(value, {
        type,
        // Question?
        attributes: {
          'data-slug': POST SLUG
        }
      }));
    };

    return <RichTextToolbarButton
      icon={ 'editor-code' }
      title={ 'Post slug' }
      onClick={ onToggle }
      isActive={ isActive }
    />;
  }
});
@mahnunchik
Copy link
Author

Or maybe there is way to render server side such format.

@mahnunchik
Copy link
Author

@danieliser Thanks!

It is like static format insertion, I mean using data which may be changed while editing like post slug or post name.

@ellatrix
Copy link
Member

You can use normal useSelect hooks within the edit function. See https://developer.wordpress.org/block-editor/packages/packages-data/#useSelect. Does that make sense?

@ellatrix ellatrix added [Type] Question Questions about the design or development of the editor. [Type] Help Request Help with setup, implementation, or "How do I?" questions. and removed [Type] Question Questions about the design or development of the editor. labels Nov 20, 2019
@mahnunchik
Copy link
Author

Hi @ellatrix

const type = 'test/test';
registerFormatType(type, {
  title: 'Slug link',
  tagName: 'a',
  className: 'slug',
  edit ({ isActive, value, onChange }) {

    const permalink = useSelect(( select ) => {
      return select('core/editor').getPermalink();
    });

    const onToggle = () => {
      onChange(toggleFormat(value, {
        type,
        attributes: {
          'href': '#',
          // I'd like to change it on post permalink change
          'data-permalink': permalink,
        },
      }));
    };

    return <RichTextToolbarButton
      icon={ 'editor-code' }
      title={ 'Post slug' }
      onClick={ onToggle }
      isActive={ isActive }
    />;
  }
});

I'd like to have attribute data-permalink to be changed on post permalink change. Current implementation stores permalink valid on editing time. After change post permalink the data-permalink attribute remains unchanged.

@mahnunchik
Copy link
Author

It is an example with permalink, I mean using in Format any data which may be changed during editing.

@danieliser
Copy link
Contributor

@mahnunchik - So I see it 2 ways.

  1. You need to find an action that is fired with permalink is updated and link your toggleFormat call into that action to update the value. Problem I see is the link is nearly impossible to maintain. The format API affects currently selected text, so when permalink is updated you would need to manually check all Rich Text entries and find all matching formatted text to update.

  2. Alternatively and more reliably, can your format be a placeholder that is replaced via PHP filtering of the_content at render time? That way if the permalink changes, even while the editor is not open (say from the All Posts screen -> quick edit mode), your rendering works.

@mahnunchik
Copy link
Author

Hi @danieliser

Yep, server side approach solves the problem. I'm using shortcodes for now. But would like to have gutenberg only solution.

I think @ellatrix as a core developer and author of many things in format library can tell us if this is possible or not.

More general question: Is is possible to hook changes in select('core/editor') to already applied formatted entries in all Rich Text blocks.

@danieliser
Copy link
Contributor

@mahnunchik Well sure it’s possible, but a Gutenberg only solution could very well still use server side approach. Many blocks already do this such as showing latest 5 posts in a list.

So the question isn’t can you do it, it’s should you do it, or more importantly should you spend the time when the most reliable method is much simpler.

Also my proposal would be to use the Format API to wrap your text with a tag (not shortcode) along with some string which is easily parsed and replaced later.

So your format api might add a span with unique data attribute around the selected text. It could even be JSON. During server side processing you replace that data attribute with the proper dynamically rendered content.

The other way is both unreliable and likely to conflict over time if your constantly searching and replacing content across the entire editor that could be formatted by other plugins etc.

Just my 2 cents.

@mahnunchik
Copy link
Author

@danieliser

Many blocks already do this such as showing latest 5 posts in a list.

It is server side rendering of block itself not a format part. render_callback of register_block_type method.

Also my proposal would be to use the Format API to wrap your text with a tag (not shortcode) along with some string which is easily parsed and replaced later.

Yep, I'm implementing this approach for now. Unique class name helps to find and replace.

But it would be pretty cool to have some of:

  1. Gutenberg only dynamic format.
  2. Some kind of server side register_format_type with render_callback for formatted part of existing blocks with Rich Text field.

@talldan talldan added [Package] Format library /packages/format-library [Type] Enhancement A suggestion for improvement. and removed [Type] Help Request Help with setup, implementation, or "How do I?" questions. labels Apr 23, 2020
@talldan
Copy link
Contributor

talldan commented Apr 23, 2020

I don't think it's possible to change an already applied format, only those that are yet to be applied, so lets change this to an enhancement request.

It is probably a bit beyond the scope of most formatting use cases though and might be better handled through a plugin that filters post content.

@mahnunchik
Copy link
Author

Hi @talldan @danieliser @ellatrix

Yep, I've already wrote about it: Some kind of server side register_format_type with render_callback for formatted part of existing blocks with Rich Text field. #18490 (comment)

Use cases I'm working on:

  1. Inline currency converter. For example it costs 100 THB should be converted to it costs 100 THB (3 USD). We can apply format it costs <span class="currency" data-amount="100" data-currency="THB">100 THB</span> and handle it server side by the_content filter and regexp by currency class. It should be handled by PHP to have static pages even for AMP support.
  2. Custom link attribution. As I described above How to use dynamic data with registerFormatType #18490 (comment)

Yep, it is handled by the_content filter and regexp on whole content but it will be more robust to have handler server side only for formatted part.

@ellatrix
Copy link
Member

I would love a solution for this, but it's low priority for me to work on right now to be honest. Would love to see explorations!

@danieliser
Copy link
Contributor

@mahnunchik - From my experience, the currency converter concept doesn't make sense in this context. Specifically because of caching any real solution would need to be JavaScript based, so the most that needs to happen is a format tags text with something that JS detects and replaces on the fly. A simple css class or data-attribute handles that without dynamic replacement.

That said this sounds like it should be one offed honestly. There is no way that running regex across the content of every page will be viable / scalable if this replacement technique were picked up by dozens of plugins on the same site.

Instead it would probably be better to do a simple strpos check that some key part of the phrase exists first before running it for matches needlessly. But that likely means doing this on a per plugin/theme basis, as opposed to as some built in mechanism.

The best solution is gonna come in the form of JS based rendering at runtime, its the only way to beat the caching setups on most WP hosts these days.

@mahnunchik
Copy link
Author

Hi @danieliser

Currency converter is just a sample. For my case it should be static (not JS based) because:

  1. rate change once a week (IATA rate).
  2. pages should support AMP.

I hope I was able to show the main idea: post processing of format entry.

@fabiankaegy
Copy link
Member

I'm also currently solving this use case by storing some data in data-attributes and then using a filter on the_content to replace it with the actual dynamic data.

However, I just found that there is no way to filter the content of block templates. So this method breaks for any rich text format that gets used in any template...

@ndiego ndiego added the [Feature] Extensibility The ability to extend blocks or the editing experience label Jul 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Extensibility The ability to extend blocks or the editing experience [Package] Format library /packages/format-library [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

No branches or pull requests

7 participants