Deekshith's avatar

Replace shortcode with html of specific data

Hi, i have created some shorcodes like below,

[Figures 10]
[Figures 11]

Here 10 and 11 are figure id's and every figure id has some html data.

Now i want to replace [Figures 10] and [Figures 11] with the respective HTML data. Example:

<p>Some text goes here, lorem ipsum lorem ipsum</p>
[Figures 10]

lets say [Figures 10] has html like below,

<img src="" class="img-responsive">
<p>figure text<p>

So now the final content after render will be like below,

<p>Some text goes here, lorem ipsum lorem ipsum</p>
<img src="" class="img-responsive">
<p>figure text<p>

i am using below code to find all figure id's present in the content,

preg_match_all('/\[Figure\s(.*?)\]/', $contentget, $matches);
$figureids = $matches[1];

in above code i will get all figure id's but i am not getting how to replace shortcode from this data.

now i want to replace shortcodes with shortcode content which i will fetch from db. Thank you.

0 likes
6 replies
rodrigo.pedra's avatar

I had a similar task last week. This is how I solved it (simplified):

<?php

use App\Models\Figure;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;

Route::get('/', function () {
    $contentget = <<<HTML
<p>Some text goes here, lorem ipsum lorem ipsum</p>
[Figures 10]
HTML;

    $results = preg_match_all('/\[Figures (\d+)]/', $contentget, $matches);

    if ($results === false || $results === 0) {
        return $contentget;
    }

    [$placeholders, $figureids] = $matches;

    $figures = Figure::query()
        ->whereKey($figureids)
        ->get();

    if ($figures->isEmpty()) {
        return $contentget;
    }

    foreach ($placeholders as $index => $placeholder) {
        $figure = $figures->find($figureids[$index] ?? 0);

        if ($figure) {
            $content = Str::of('<img src="##URL##" alt="##ALT##" class="img-responsive"><p>##TEXT##<p>')
                ->replace('##URL##', $figure->url)
                ->replace('##ALT##', $figure->text)
                ->replace('##TEXT##', $figure->text);

            $contentget = str_replace($placeholder, $content, $contentget);
        }
    }

    return $contentget;
});

Hope this helps!

Deekshith's avatar

@rodrigo.pedra Thank you so much for the reply. i have some doubts.

What is $placeholders here and also,

if i store html data directly in db for each figure id then i can directly fetch right ? instead of this?

$content = Str::of('<img src="##URL##" alt="##ALT##" class="img-responsive"><p>##TEXT##<p>')
                ->replace('##URL##', $figure->url)
                ->replace('##ALT##', $figure->text)
                ->replace('##TEXT##', $figure->text);

Thank you

rodrigo.pedra's avatar
Level 56

You're welcome.

What is $placeholders

When you use preg_match_all, the $matches variable is populated with:

  • all matches from the full pattern on index 0
  • all matches from the first capture group on index 1
  • all matches from the second capture group on index 2
  • and so on

In our regular expression we only have one capture group (\d+) so the $matches variable will be populated with:

  • all matches from the full pattern on index 0
  • all matches from the (\d+) capture group on index 1

Assume we have this HTML input:

<p>Some text goes here, lorem ipsum lorem ipsum</p>
[Figures 3]
[Figures 10]

So when running this line:

$results = preg_match_all('/\[Figures (\d+)]/', $contentget, $matches);

The $matches variable will have this content:

[
  0 => [
    0 => "[Figures 3]"
    1 => "[Figures 10]"
  ]
  1 => [
    0 => "3"
    1 => "10"
  ]
]

So we can use the results on the index 0 to replace the short codes more easily.

This line just de-structure the $matches array elements into two variables:

[$placeholders, $figureids] = $matches;

So:

  • $placeholders will be assigned to the array in $matches index 0 (the full short codes), and
  • $figureids will be assigned to the array in $matches index 1 (the figure ids)

This notation of auto assigning is somewhat recent in PHP, but you could do this "multi-assignment" from an array before (I think even in PHP 4, not sure now) using the list() operator:

list($placeholders, $figureids) = $matches;

If i store html data directly in db for each figure id then i can directly fetch right ? instead of this?

Yes.

Deekshith's avatar

@rodrigo.pedra Hi, I have one doubt suppose if i want to add another shortcode like below how to alter this to check data dynamically

$figresults = preg_match_all('/\[Figures (\d+)]/', $contentget, $matches);
    $refresults = preg_match_all('/\[Reference (\d+)]/', $contentget, $refmatches);

        if ($figresults === false || $figresults === 0) {

          if ($refresults === false || $refresults === 0) {
              return $contentget;
          }

            return $contentget;
        }

        [$placeholders, $figureids] = $matches;
        [$refplaceholders, $refids] = $refmatches;

        $figures = ArticleFigure::query()
       ->whereKey($figureids)
       ->get();

        if ($figures->isEmpty()) {
            return $contentget;
        }

        foreach ($placeholders as $index => $placeholder) {
            $figure = $figures->find($figureids[$index] ?? 0);

            if ($figure) {
                $imageUrl = url('/article-figure/'.$figure->figureuuid);

                $content = Str::of('<img src="##URL##" alt="##ALT##" class="img-responsive"><p>##TEXT##<p>')
               ->replace('##URL##', $imageUrl)
               ->replace('##ALT##', $figure->title)
               ->replace('##TEXT##', $figure->content);

                $contentget = str_replace($placeholder, $content, $contentget);
            }
        }

Here if figures not found then it will return empty set. in references section figures shortcodes will be empty but it should display references shortcode data. i cant pass type parameter too in function becuase all are dynamic here so. any suggestion?

Please or to participate in this conversation.