Shortcode to Gutenberg-block: additional text on front-end and conditional display

Shortcode output

I’m working to translate a custom shortcode to a Gutenberg-block but am stuck on two issues. This post first treats the current situation, the next heading shows the problems I’m running into in greater detail.

Current situation

I’m using the shortcode (syntax and code below) to display resume-items on my website. It includes fields for a title, organisation, location, duration, number of hours per week and/or GPA and outputs as follows. There are links to some of the attributes.

Syntax of the shortcode (removed part of the description for brevity) is as follows:

[cv-item naam='Aerospace Engineering (MSc)' organisatie='Delft University of Technology' locatie='Delft, The Netherlands' duur='09/2014 - current' status='open' cijfer='7.7/10' cijfer_datum='11/2018'] Double-track specialisation (180 EC, three years) in the [...] on the other. [/cv-item]

Shortcode definition is as follows:

function cv_item( $atts, $content = null ) {
$atts_completed = shortcode_atts( array(
    'naam'         => null,
    'organisatie'  => null,
    'locatie'      => null,
    'duur'         => null,
    'uren'         => null,
    'status'       => 'closed',
    'cijfer'       => null,
    'cijfer_datum' => null,
), $atts );

$naam         = $atts_completed['naam'];
$organisatie  = $atts_completed['organisatie'];
$locatie      = $atts_completed['locatie'];
$duur         = $atts_completed['duur'];
$uren         = $atts_completed['uren'];
$status       = $atts_completed['status'];
$cijfer       = $atts_completed['cijfer'];
$cijfer_datum = $atts_completed['cijfer_datum'];

static $id = 1;
$id ++;

$output = '<div class="cv-item" id="cv-item-' . $id . '">';

/* Uit-/inklap-knop */
if ( $status == 'open' ) {
    $toggle_class = 'fa-arrow-up';
} else {
    $toggle_class = 'fa-arrow-down';
}

if ( $content != null ) {
    $output .= '<i class="fa ' . $toggle_class . ' cv-item-toggle" id="cv-item-' . $id . '"></i>';
}

/* Eerste regel, met naam, bedrijf en locatie */
$output .= '<span class="cv-item-title">';
$output .= '<strong>' . $naam . '</strong>';

if ( $organisatie != null ) {
    $output .= ', <span class="organisation">' . $organisatie . '</span>';

    if ( $locatie != null ) {
        $output .= ' (' . $locatie . ')';
    }
}
$output .= '</span>';

/* Tweede regel, met duur en aantal uren per week */
if ( $duur != null || $uren != null || $cijfer != null ) {
    $output .= '<span class="cv-item-details">';

    if ( $duur != null ) {
        $output .= $duur;
    }

    if ( $uren != null | $cijfer != null ) {
        if ( $duur != null ) {
            $output .= ' | ';
        }

        if ( $uren != null ) {
            $output .= $uren . __( ' uur per week', 'peerlings' );
        }

        if ( $cijfer != null ) {
            $output .= $cijfer;

            if ( $cijfer_datum != null ) {
                $output .= ' (' . __( 'per', 'peerlings', 'Cijfer XX per YY' ) . ' ' . $cijfer_datum . ')';
            }
        }

    }

    $output .= '</span>';
}

/* Omschrijving */
if ( $content != null ) {
    $output .= '<div class="cv-item-description ' . $status . '">' . $content . '</div>';
}

/* Closing */
$output .= '</div>';

return $output; }

As you can see, there are a bunch of conditionals in the function that processes the shortcode. Also, some separators (like the comma between item title and organisation) are added, as are a bunch of wrapper-spans used for styling purposes (such as span.cv-item-title and span.details). I have trouble replicating this in Gutenberg.

New situation, problems and solution attempts

I’ve been working on adjusting this custom profile block to suit my needs. So far, that has worked reasonably well (full block.js-code here), but I’m stuck on two problems:

  • Replicating the conditionals
  • Adding the separators and span-wrappers

Conditionals

In the original code, values from the block settings (in the right sidebar) are displayed conditionally, per the code below (extract from return-statement from the edit– and save-functions):

el('div', {className: 'organic-profile-social'},
    attributes.nameURL && el('a', {
        className: 'social-link',
        href: attributes.nameURL,
        target: '_blank'
    },
    el('i', {className: 'fa fa-facebook'})
    ),
    attributes.organisationURL && el('a', {
        className: 'social-link',
        href: attributes.organisationURL,
        target: '_blank'
    },
    el('i', {className: 'fa fa-twitter'})
    )
)

The same logic, however, doesn’t apply to regular fields, as shown below (extract from return-statement from the save-function):

el('span', {},
    attributes.grade && el('span', {
        className: 'grade',
        value: attributes.grade
    }),
    attributes.gradeDate && el('span', {
        className: 'grade-date',
        value: attributes.gradeDate
    }
    )
)

This outputs the grade and grade-date spans regardless of their content. Also, the span that is supposed to wrap the these two, turns up as an empty span preceding them:

<span></span><span class="grade"></span><span class="grade-date"></span>

Of course, I can just move all conditional fields to the settings-panel in the sidebar, but that (to me) defeats the entire WYSIWYG-on-the-back-end-approach that Gutenberg is (insofar I understand correctly) all about.

Question: Is it even possible to achieve what I have in mind, and how can I do so?

Separators, wrappers and intermediate text

I thought I had this to work, by adding the separators using helper-functions that set a particular separator, or set it to null if the surrounding values are empty, like so:

if (typeof props.attributes.grade !== 'undefined' && typeof props.attributes.gradeDate !== 'undefined') {
    var separatorGradeGradeDatePre = ' (' + i18n.__('per')
    var separatorGradeGradeDateSuf = ')'
} else {
    var separatorGradeGradeDatePre = null
    var separatorGradeGradeDateSuf = null
}

I then added these two the return-statement of the save-function. That worked well one way, but not the way back. Put differently: if the edit-function goes to read the post_content-HTML, it comes across text that isn’t specified in the edit-function and throws an error.

Idea’s I’ve thought of so far – as well as my reasons for not implementing (yet):

  • Including the separators in the edit-function, too, and then hiding these using editor-specific CSS. Haven’t implemented, because I think it’s ugly (to say the least) to include content that I’m then (in all instances) going to hide using CSS.
  • Not including the separators in the save-function, but adding them using CSS content-properties. Even more ugly than the previous option, especially as it will require a nasty PHP-CSS-mashup to include the conditional statements.

Question: Are there any other ways to achieve this, or should I just go for one of my ideas posted above?

Read more here:: Shortcode to Gutenberg-block: additional text on front-end and conditional display

Leave a Reply

Your email address will not be published. Required fields are marked *