How to Parse Gutenberg Table into JSON

If you have a simple ACF Repeater Field, try replacing it with a plain Table. Other than being easier to edit, the performance is much better.

Gutenberg (also knows as Block Editor) is the official drag-n-drop builder in WordPress version 5.0+.

Case Study

Few months ago, I had a request from a music school to make a Price Calculator. We choose a course and duration, then it will show the price.

Their brochure has a pricing table like below.

MonthsGuitarAcoustic GuitarElectric GuitarBass

The increase and discount is not linear, so we can’t use formula to calculate.

The client said they will edit it often. Plus, there are many categories like Piano and Violin. So we need to make it as friendly to edit as possible.

After going through many options, we decided to use a plain-old table because they can copy-paste it from Excel.

Step 1 – Create a Page with the Data Table

Page containing the data table

I use hashtag format for the page title to let the client know that they shouldn’t edit that. I also put it as a child page of Price Calculator just to make it tidier.

If you use an SEO plugin, set this page to noindex.

Step 2 – Create Pseudocode

Let’s plan the logic and flow:

Call a function - pass in: Page name, Course name, Duration

Get the page with that Page name.

Get the page's content

Use regex to find the Column using Course name (eg: "Acoustic Guitar" at column 3)

Use regex to find the Row using Duration

Return the number that is in the found Column and Row

Step 3 – Coding

get_price( '#guitar', 'Electric Guitar', 2 );
function get_price( $page_name, $course, $duration ) {
  $page = get_page_by_title( $page_name );
  $content = $page->post_content;

  // find columns
  preg_match_all('/<th>(.*)<\/th>/Ui', $content, $columns );
  $column_index = array_search( $course, $columns[1] );

  // find row
  preg_match( "/<tr><td>($duration.+)<\/td><\/tr>/Ui", $content, $row_html );
  $row = preg_split( '/<\/td><td>/', $row_html[1] );
  // get price
  return $row[ $column_index ];

LINE 9 – It matches all header texts. Then we use array_search to get the index.

LINE 13 – It looks for first column that contain the specified duration. Then it returns the HTML code of that row like this:


LINE 14 – We split the HTML above to get all row texts.

LINE 17 – Now we can get the price by matching the row and column.


Where else can you apply this? If you have a simple ACF Repeater, you can replace it with this technique.

Other than being easier to edit, I believe the performance is better too since we only do 1 query and no heavy task.

Leave a comment below if you have any question or want to share your story of using this tip! 🙂

Default image
Henner Setyono
A web developer who mainly build custom theme for WordPress since 2013. Young enough to never had to deal with using Table as layout.
Leave a Reply