Tagging URL --> Summary Page

I’ve looked a bit closer, here’s a page method:

You can pass a field as parameter. If you don’t, the raw content is used.

page::$methods['getTaggedLinklist'] = function($page, $field = null) {
  if(!is_null($field) && in_array($field, $page->content()->fields())) {
    $raw = $page->{$field}();
  } else {
    $raw = $page->content()->raw();
  }
  // find all tags
  preg_match_all('!(?=[^\]])\([a-z0-9_-]+:.*?\)!', $raw, $matches);
  $list = [];
  if(count($matches[0]) > 0) {
    // loop through the matches
    foreach($matches[0] as $match) {
      // remove the brackets
      $tag  = trim(rtrim(ltrim($match, '('), ')'));
      // get the name of the tag
      $name = trim(substr($tag, 0, strpos($tag, ':')));
      // check if it is a link tag
      if($name === 'link') {
        // create a new Kirbytag instance
        $tag = new Kirbytag(null, $name, $tag);
        // make sure the tag attr is present
        if(!is_null($tag->attr('tag'))) {
          // get all attributes we need from the tag and add to list array
           $list[] = [
             'link' => $tag->attr('link'),
             'tag' => $tag->attr('tag'),
             'text' => $tag->attr('text')
           ];
        }
      }
    }
  }
  return $list;

};

dump($page->getTaggedLinklist());

Note: this method requires a modified link kirbytag with a tag attribute. However, similar code can be quite useful for other use cases as well. You could also make this a pages method (with some modifications) or use the code inside.

wow… thx a lot!
i also took a look into the regex and found this for the first instance https://regex101.com/r/uhjrYR/1/ (after hours of playing with regex)
this regex also excludes code snippets that are inside backticks.

wouldn’t it be easier and/or more compatible to store all attributes into the list-array, regardless of content and/or name?

again: thx a lot!

That’s not difficult, $tag->attr() gives you an array of all attributes:

page::$methods['getTaggedLinklist'] = function($page, $field = null) {
  if(!is_null($field) && in_array($field, $page->content()->fields())) {
    $raw = $page->{$field}();
  } else {
    $raw = $page->content()->raw();
  }
  // find all tags
  preg_match_all('!(?=[^\]])\([a-z0-9_-]+:.*?\)!', $raw, $matches);
  $list = [];
  if(count($matches[0]) > 0) {
    // loop through the matches
    foreach($matches[0] as $match) {
      // remove the brackets
      $tag  = trim(rtrim(ltrim($match, '('), ')'));
      // get the name of the tag
      $name = trim(substr($tag, 0, strpos($tag, ':')));
      // check if it is a link tag
      if($name == 'link') {
        // create a new Kirbytag instance
        $tag = new Kirbytag(null, $name, $tag);
        // get all the attributes and add them to our list
        $attributes = $tag->attr();
        $list[] = $attributess;
      }
    }
  }
  return $list;

};

dump($page->getTaggedLinklist());

We could, of course, make this more versatile by passing the tags we want to catch as a parameter array instead of hard-coding the link tag… but this is just an example.

I don’t think that time is wasted… This regex stuff is useful all the time.

Ok… after several days of playing around, i was able to get an array sorted by tags, with subarrays sorted by date.
everything is filtered: no doublicate links, no links of code-blocks nor inline-code-lines.

currently i am thinking about the real usecase. i would like to have an output, that does not depend on the kirby-template. so i think it would be logical to produce markdown output.

i think it could be done via another custom tag. any better ideas?

Ok, here is the code, if anyone is interested in. maybe it is a help for someone.
Since, the markdown-extra tables are not very comfortable to align and multiple head-lines are not supported, i will change my original idea and write my own html table and/or tab based template. also i’m not sure which data i will output. so, here is a sample output you will have to modifiy for yourself. at this stage, i think, every change will just help myself and not anyone else… so here are my findings/is my code.

  • The Plugin analyses the raw content files for Markdown Links which are extended by a tag: attribut.
  • Original: (link: http://wikipedia.de text: wikipedia Website)
  • New: (link: http://wikipedia.de tag: wiki text: wikipedia Website)
  • when you use the new snippet tag in any of your pages, you will get a table of link collection.

site/snippets/linksnippet.php

<div>
<?php
$items = page('home')->children()->visible();

foreach($items as $item) {
    page::$methods['getTaggedLinklist'] = function($page, $field = null) {
          if(!is_null($field) && in_array($field, $page->content()->fields())) {
          $raw = $page->{$field}();
            } else {
                $raw = $page->content()->raw();
                }
        // find all tags
        preg_match_all('!`[^``]*`(*SKIP)(*F)|\(([^)]+\))!', $raw, $matches);
        $list = [];
        if(count($matches[0]) > 0) {
          // loop through the matches
          foreach($matches[0] as $match) {
            // remove the brackets
            $tag  = trim(rtrim(ltrim($match, '('), ')'));
              // get the name of the tag
              $name = trim(substr($tag, 0, strpos($tag, ':')));
                // check if it is a link tag
                if($name == 'link') {
                  // create a new Kirbytag instance
                  $tag = new Kirbytag(null, $name, $tag);
                  // check if tag is included
                  if(!is_null($tag->attr('tag'))) {
                    // get all the attributes and add them to our list
                    $list[] = $tag->attr();
                  }
                }
          }
        }
        return $list;
      };

      foreach($item->getTaggedLinklist() as $element) {
          // define content of each link-array
      if(empty($element['text'])) {
            $textelement = parse_url($element['link'], PHP_URL_HOST);
              } else {
                $textelement = $element['text'];
                }
          $output = array(
                  'tag' => $element['tag'],
                  'link' => $element['link'],
                  'text' => $textelement,
                  'pagetitle' => $item->title()->value(),
                  'pagelink' => $item->url(),
                  'date' => $item->date()
                  );
          $key = $element['tag'];
          $full[$key][] = $output; // add link-array to tag-group
          // filter duplicate links while
              $temparr = array_unique(array_column($full[$key], 'link'));
              $finalarray[$key] = array_intersect_key($full[$key], $temparr);
          // sort each element in a tag-group by date
              usort($finalarray[$key], function($a, $b) {
                        return $a['date'] - $b['date'];
                        }
                    );
      }
    }

    // sort tag-groups by alphabet
    uksort($finalarray, 'strcasecmp');

    // generate markdown table of array

    $tgmt = "\n"; // tag group markdown table
    foreach($finalarray as $taggroupname => $taggroup) {
    $tgmt .= '### ' . $taggroupname . "\n";
    $tgmt .= '|link|text|date|' . "\n"; // table header
    $tgmt .= '|--|--:|--:|' . "\n";
        foreach($taggroup as $tgi) { // taggroupitem
            // convert unix timestamp
            $timeconv = date('Y.m.d - H:i', $tgi['date']);

            // generate table row
            $linkstring = url::short($tgi['link'], 33);

            $link = '(link: ' .  $tgi['link'] . ' text: ' . $linkstring . ')';
            $tgmt .= '|' . $link . '|' . $tgi['text'] . '|(link: ' .  $tgi['pagelink'] . ' text: ' . $timeconv . ')|' . "\n";
        }
    }
    echo kirbytext($tgmt);
?>
</div>

site/tag/link.php

<?php

// link tag
kirbytext::$tags['link'] = array(
  'attr' => array(
    'text',
    'class',
    'role',
    'title',
    'rel',
    'lang',
    'target',
    'popup',
    'tag'
  ),
  'html' => function($tag) {

    $link = url($tag->attr('link'), $tag->attr('lang'));
    $text = $tag->attr('text');

    if(empty($text)) {
      $text = $link;
    }

    if(str::isURL($text)) {
      $text = url::short($text);
    }

    return html::a($link, $text, array(
      'rel'    => $tag->attr('rel'),
      'class'  => $tag->attr('class'),
      'role'   => $tag->attr('role'),
      'title'  => $tag->attr('title'),
      'target' => $tag->target(),
    ));

  }
);

site/tag/snippet.php

<?php
kirbytext::$tags['snippet'] = array(
  'attr' => array(
  ),
  'html' => function($tag) {
        $file =  $tag->attr('snippet');
        return snippet($file, array(), true);
  }
);

some notes:

  • links inside codeblocks or inline-code are ignored
  • duplicate links are ignored
  • invisible pages are ignored
  • output is sorted by tag and by date
  • when text attribute is empty, the hostname of the link is used as text
  • tags are case-sensitive
  • take a look at linksnippet.php to get an idea of outputcode
  • i’m not a coder. those few lines of code cost me a lot of time. most of you will laugh on the ugly code, the ugly structure and time i wasted. i know, the most of you would write something like this is an hour or less. for me it took several full days of finding code snippets and trying to understand them.
  • thx a lot to @texnixe for your help.
  • also a lot help was the idea of this thread: Embedding Snippets

Include in site
snippet-tag

possible output (with align-problem)

Forgive me if i have missed something but isn’t that alignment issue a CSS style problem? Looks to me like the tables are deciding for themselves what the column widths should be?

Markdown tables are pretty fussy… i have used this tool before to help me out.

Setting the table layout to fixed in the css should line up those columns.

table {
 table-layout: fixed;
}

I had a similar problem on a site I built, that had a bunch of separate price tables with text in-between like you have. That was the fix.

Problem is cell-content.
The Markdown allows only the alignment inside the cells.

Aligning cells is indeed a template/css styling option. and for this, it is impossible to use markdown tables AND column alignment at the same time WITHOUT changing template-code.

my original idea was to create table via markdown to have a nice integration for nearly every template without any further code changes.

so, until kirby has any feature to align collums integrated, it is a template based problem

Two things:

  • the page method shouldn’t live within the snippet, but in a separate plugin file
  • why markdown at all in this context? Doesn’t make sense to me. Also, with standard HTML, you can apply classes as needed.

Edit: only saw your last post after posting my own

why markdown at all in this context? Doesn’t make sense to me.

the only reason was to code a “plugin”, that is compatible in design for every template.
for sure it is possible to generate output in html, however i want. but then, it is not “universal-compatible” =)

The only thing you could do with your current markup is add a class to the headings and then style the tables after the headings with that class. Hacky, though.

## Heading ##    {.there-s-a-table-following-this-heading}

Well, i think it is not needed to stay on markdown-output. i think i will create html directly for my used template (lingonberry).

Im not sure i follow you. It’s in a snippet / tag combination so you don’t get to see the markdown in your snippet, because it is behind the scenes. It would have been totally fine to use HTML or even Bricks, I think.

Exactly, it’s not a text file.

I think/thought, using kirbytext() to generate html output is pre-designed by css of template? so the output is different on every template?

well… you see, i’m not a coder =)

You can totally throw HTML in a Kirby Textarea in the panel and it will handle it :slight_smile: But don’t though, it confuses clients :slight_smile:

I must admit I don’t understand that sentence. First of all, a template generates HTML. The Markup and classes together with your CSS file then determine what your page actually looks like in the browser.

Kirbytext parses Markdown and Kirbytag into HTML. But the question is what else you want to do with that Markdown hidden away in a PHP template? Of course, you could write your Markdown to file and then do whatever you want with those files. But I don’t see what you gain from generating Markdown and then parsing it to HTML in that snippet apart from making your life more difficult than necessary.

i thought, that the generated html of kirbytext() has any style related content, like classes or something like that.

well… maybe this all is just a missunderstanding by me. i’m realy not a coder =)

i’ll give it a try to generate html table instead of markdown which then will be converted via kirbytext().

Well, if the text in a text file contains any classes - added via kirbytags (e.g. (link: some.pdf class: someclass) or MarkdownExtra, or even via HTML itself - than the generated output will contain classes, yes.

ok… i did it in html - and i like the output =)
both columns are now responsive.

// generate html-table of array
foreach($finalarray as $taggroupname => $taggroup) {
echo '<h3>' . $taggroupname . '</h3>';
echo '
<table style="table-layout: fixed;">
 <thead>
   <tr>
     <th>Link</th>
     <th style="text-align: right;">Text</th>
   </tr>
 </thead>
 <tbody>';

foreach($taggroup as $tgi) { // taggroupitem
$linkstring = url::short($tgi['link']);
echo '
 <tr>
   <td style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"><a href="' . $tgi['link'] . '">' . $linkstring . '</a></td>';
echo '
   <td style="text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"><a href="' .  $tgi['pagelink'] . '">' . $tgi['text'] . '</a></td>';
echo '
 </tr>';
}
echo '
 </tbody>
</table>
<br>
';
}