Xdebug has detected a possible infinite loops, and aborted your script with a stack depth of 256 frames

Cupara
Member | 90
+
0
-

I'm not really understanding what the issue is. If I look at the Presenters-templates-@layout.latte--6858b406f6.php in the temp/cache/latte/ directory then at line 133 this is there $this->renderBlock('title', get_defined_vars(), function ($s, $type) but I am not understanding how it can get an infinite loop from title.

In my presenter I figured it might be, the query looks fine.

HomePresenter.php

    public function renderDefault(): void
    {
        $this->template->news = $this->facade
            ->getPublicArticles()
            ->limit(5);
    }

That is the only thing being called on my index page that could even remotely have anything to do with an infinite loop not something to do with title.

If anyone can advise me on this I would greatly appreciate it. If you need more information or specific outputs, please let me know.

Infanticide0
Member | 59
+
0
-

@Cupara
Try clean cache (remove temp/cache folder).
If that doesn't help, show your template file (templates/Home/default.latte)

Cupara
Member | 90
+
0
-

@Infanticide0 that didn't do any good so here is my default.latte template.

{block content}
	<h1>Serenity Development</h1>

	<div><a n:href="Edit:create" n:if="$user->isLoggedIn()">Create Article</a></div>

	<div>Motto: Empowering Creators, Enriching Communities</div>

	<div>Summary: We are a pioneering hub where visionary content creators and tech innovators unite to collaborate and build the future of online entertainment as well as digital engagement.
		Ditch the dusty dev studios, ditch the clunky tools. Serenity Development isn't just building tech, we're recharging the content creator universe. Think high-octane collaborations with fellow visionaries, where killer tools fuel epic online communities.
		Tired of wonky giveaways? We built a platform so smooth, it'll make your viewers squeal with excitement. Need a bot that dances between Discord and Guilded like a party panda? Got you covered. We even crafted a Twitch and SharePlay chat bot so smart, it practically reads minds (and announces winners on point, obviously).
		But it's not just about gadgets. We're obsessed with user experience so seamless, it'll feel like magic. Think chat moderation that melts away negativity, leaving pure community gold. Think a future where engagement isn't a chore, it's a thriving, vibrant explosion.
		Stop creating in the shadows. Join the revolution. Reimagine content. Unleash Serenity.</div>

	{foreach $news as $new}
	<div class="post">
		<div class="author">{$new->author}</div>

		<div class="date">Posted: {$new->created_at|date:'F j, Y'}</div>

		<h2><a href="{link News:show $new->id}">{$new->title}</a></h2>

		<div>{$new->content|truncate:256}</div>
	</div>
	{/foreach}
{/block}
Marek Bartoš
Nette Blogger | 1173
+
+1
-

Your code looks fine.

Does it happen without xdebug enabled?
If you have Tracy enabled, it should be able to show you if there is an actual problem.

Also I noticed in your previous post that you setup Latte\Engine manually. Is it still a case? You shouldn't need that with full Nette setup.
Make sure that you set up Latte temp directory as an absolute path. Generally, any path in PHP should be absolute, if you don't have some abstraction that works with relative paths. You will avoid a lot of potential issues. $latte->setTempDirectory(__DIR__ . '/temp');

Last edited by Marek Bartoš (2023-12-24 15:22)

Cupara
Member | 90
+
0
-

@MarekBartoš Yes this happens with Xdebug disabled. I'm not sure how to check if I have Tracy enabled or not.

No I did not setup Latte\Engine manually this time around, I used the web-project.

I have the Latte temp directory as an absolute path. Here is my Bootstrap.php file:

<?php

declare(strict_types=1);

namespace App;

use Nette\Bootstrap\Configurator;


class Bootstrap
{
	public static function boot(): Configurator
	{
		$configurator = new Configurator;
		$appDir = dirname(__DIR__);

		//$configurator->setDebugMode('cupara790482@72.206.26.238'); // enable for your remote IP
		$configurator->enableTracy($appDir . '/log');

		$configurator->setTempDirectory($appDir . '/temp');

		$configurator->createRobotLoader()
			->addDirectory(__DIR__)
			->register();

		$configurator->addConfig($appDir . '/config/common.neon');
		$configurator->addConfig($appDir . '/config/services.neon');
		$configurator->addConfig($appDir . '/config/local.neon');

		return $configurator;
	}
}

Cupara
Member | 90
+
0
-

Here is a full-page screenshot of my error report.

Error Image

Cupara
Member | 90
+
0
-

I have narrowed down the issue to be with this part of the @layout.latte template:

<title>{block title}Serenity Development{ifset title} | {include title|stripHtml}{/ifset}{/block}</title>

If I change that to just <title>Serenity Development</title> then the error is gone.

Cupara
Member | 90
+
0
-

Ok I have it all working except the {block title}Serenity Development{ifset title} | {include title|stripHtml}{/ifset}{/block} isn't working. I'm not sure if that is correct but I'm looking through the documentation for any reference to {block title}.

Infanticide0
Member | 59
+
0
-

You are including block title in block title.

Try this in layout

<title>{ifset title}{include title|stripHtml} | {/ifset}default title</title>

You define new {block title}news page{/block} or <h1 n:block=title>news page</h1>

Last edited by Infanticide0 (2023-12-25 01:56)

Cupara
Member | 90
+
0
-

@Infanticide0 thanks. All fixed and looking good. Now I'm having to go through and style everything with Bootstrap-specific classes.

Cupara
Member | 90
+
0
-

@Infanticide0 is there anything wrong with this snippet? <link rel="stylesheet" href="{$basePath}/css/style.css"> as it's looking for my css files in the wrong place instead of where they are which is under the /www/ directory in it's own folder /css/.

Infanticide0
Member | 59
+
0
-

@Cupara
How does look generated url?

That href should look for domain.com/css/style.css → www/css/style.css
Folder www is at the same level as your app, temp, log folders.

Make sure you have debug mode enabled, if it is disabled (you are in production mode), layouts are cached you won't see changes until you clean cache manually.

You can see Tracy debug bar when debug mode is enabled.

Last edited by Infanticide0 (2023-12-25 02:06)

Cupara
Member | 90
+
0
-

@Infanticide0 ok in that case it does look for it at domain.com/css/style.css but when I click to load it in my browser it's just a white page.

Cupara
Member | 90
+
0
-

How do I enable the Tracy debug bar then?

Infanticide0
Member | 59
+
0
-

Is your css file in /www/css/style.css and is name of that file style.css and not styles.css?

White page? 404 errors are in Nette style by default, not a blank page, is your style empty?

Cupara
Member | 90
+
0
-

@Infanticide0 I got it to load after you mentioned clearing the cache. So that part is fixed.

Now to enable Tracy. How do I do that exactly?

Infanticide0
Member | 59
+
0
-

https://doc.nette.org/…on/bootstrap#…

You can force debug mode with $configurator->setDebugMode(true); in app/bootstrap.php file
It is not safe (for production) and you should use it only for this testing.

When you are on localhost, Nette should enable it automatically.

Last edited by Infanticide0 (2023-12-25 02:20)

Cupara
Member | 90
+
0
-

Yeah, I'm using localhost for building right now, when I move it to my server then I'll turn it back off.

Nette didn't enable it automatically because I use domains through my virtualhost files via WAMP to run it like sdmain.local or test.local so I can enable SSL and test out things that deal with SSL.

I got the bar showing now though, thanks for all your help @Infanticide0

Cupara
Member | 90
+
0
-

@Infanticide0 next issue is if my page is active it's not including the active class.

Here is the line:

<li class="nav-item"><i class="fa-solid fa-house"></i><a n:href="Home:" class="nav-link {if $presenter->isLinkCurrent('Homepage')}active{/if}"{if $presenter->isLinkCurrent('Homepage')} aria-current="page"{/if}>Home</a></li>

Do you see anything wrong with my if condition?

Last edited by Cupara (2023-12-25 02:48)

Cupara
Member | 90
+
0
-

Another question, I am using a form for my sign in page. In my template I have {control signInForm}, the question is this, is there anyway I can style that form with Bootstrap classes?

Infanticide0
Member | 59
+
0
-

@Cupara

you are creating href link to “Home:” (HomePresenter) and checking current link of Homepage (HomepagePresenter)

does isLinkCurrent(‘Home:’) work?

Infanticide0
Member | 59
+
0
-

https://doc.nette.org/…ms/rendering#…

To style Forms you can create your own Form renderer or just use package with Bootstrap v4/5 renderer already defined.

https://componette.org/…s-bootstrap/
https://contributte.org/…otstrap.html#…

Cupara
Member | 90
+
0
-

Infanticide0 wrote:

@Cupara

you are creating href link to “Home:” (HomePresenter) and checking current link of Homepage (HomepagePresenter)

does isLinkCurrent(‘Home:’) work?

Ok, I understand that. Yes the isLinkCurrent(‘Home:’) is working after I changed it from ‘Homepage’ to ‘Home:’.

Cupara
Member | 90
+
0
-

Infanticide0 wrote:

https://doc.nette.org/…ms/rendering#…

To style Forms you can create your own Form renderer or just use package with Bootstrap v4/5 renderer already defined.

https://componette.org/…s-bootstrap/
https://contributte.org/…otstrap.html#…

I'm using the package with Bootstrap 4/5 already defined but it's not styling the sign-in form.

Infanticide0
Member | 59
+
0
-

To keep your layouts nice and clean, try using n: attributes

your <li> can look like this:

<li class="nav-item">
	<i class="fa-solid fa-house"></i>
	<a n:href="Home:" n:class="nav-link, isLinkCurrent('Home:') ? active" n:attr="aria-current => isLinkCurrent('Home:') ? page">Home</a>
</li>
Infanticide0
Member | 59
+
0
-

Cupara wrote:

Infanticide0 wrote:

https://doc.nette.org/…ms/rendering#…

To style Forms you can create your own Form renderer or just use package with Bootstrap v4/5 renderer already defined.

https://componette.org/…s-bootstrap/
https://contributte.org/…otstrap.html#…

I'm using the package with Bootstrap 4/5 already defined but it's not styling the sign-in form.

you have to create instance of BootstrapForm class instead of Nette\Application\UI\Form

Cupara
Member | 90
+
0
-

I'll try following the guide on contributte.org to see if I can get it so my forms are styled properly.

Cupara
Member | 90
+
0
-

Infanticide0 wrote:

Cupara wrote:

Infanticide0 wrote:

https://doc.nette.org/…ms/rendering#…

To style Forms you can create your own Form renderer or just use package with Bootstrap v4/5 renderer already defined.

https://componette.org/…s-bootstrap/
https://contributte.org/…otstrap.html#…

I'm using the package with Bootstrap 4/5 already defined but it's not styling the sign-in form.

you have to create instance of BootstrapForm class instead of Nette\Application\UI\Form

Gotcha, I'll give that a try here shortly and report back if I need assistance.

Cupara
Member | 90
+
0
-

Infanticide0 wrote:

To keep your layouts nice and clean, try using n: attributes

your <li> can look like this:

<li class="nav-item">
	<i class="fa-solid fa-house"></i>
	<a n:href="Home:" n:class="nav-link, isLinkCurrent('Home:') ? active" n:attr="aria-current => isLinkCurrent('Home:') ? page">Home</a>
</li>

Thanks, I updated my code to make it look better.

Cupara
Member | 90
+
0
-

@Infanticide0 So I have another question, I have my news articles stored in one table in my database and my comments in a different table in the database, is there any way to count the comments for each article without doing a secondary call to the database to just grab the comment count?

Here is the snippet from my default.latte template:

{foreach $news as $new}
		<div class="card">
			<div class="card-header">Author: {$new->author}</div>

			<h2 class="card-title"><a href="{link Post:show $new->id}">{$new->title}</a></h2>

			<div class="card-text">{$new->content|truncate:200}</div>
			<div style="text-align: right;">
				<a href="{link Post:show $new->id}">Read More...</a>
			</div>

			<div class="card-footer">
				<p style="align: left;" class="date">
					Posted: {$new->created_at|date:'F j, Y'}
				</p>
				<p style="align: right;">
					<a href="{link Post:show $new->id}#comments">Comments: {$new->comments->count()}</a>
				</p>
			</div>
		</div>
		<div>&nbsp;</div>
	{/foreach}

Here is my HomePresenter.php file:

<?php

declare(strict_types=1);

namespace App\Presenters;

use App\Model\PostFacade;
use Nette;
use Nette\Application\UI\Form;


final class HomePresenter extends Nette\Application\UI\Presenter
{
    public function __construct(
        private PostFacade $facade,
    ) {
    }

    public function renderDefault(): void
    {
        $this->template->news = $this->facade
            ->getPublicArticles()
            ->limit(5);
    }
}

And here is my PostFacade.php file:

<?php
namespace App\Model;

use Nette;

final class PostFacade
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	public function getPublicArticles()
	{
		return $this->database
			->table('news')
			->where('created_at < ', new \DateTime)
			->order('created_at DESC');
	}
}

Last edited by Cupara (2023-12-25 05:47)

Infanticide0
Member | 59
+
0
-

@Cupara

It's not possible (in easy way) in plain SQL query so Nette Database can't do it either. You can cache comment count and set expire time or invalidate by tag when any user creates new comment, or admin deletes/edits existing one.

https://doc.nette.org/en/caching#…

Last edited by Infanticide0 (2023-12-25 16:46)

Cupara
Member | 90
+
0
-

@Infanticide0 so there is no way to do left, inner, or right joins?

Infanticide0
Member | 59
+
0
-

@Cupara

If you need more complex queries, use $explorer->query(“sql query with variable placeholders ?”, $value1, $value2 …)
Explorer optimize sql queries to keep your app fast even when you are selecting complex relations (I am talking about N+1 queries)

https://doc.nette.org/…atabase/core#…

Cupara
Member | 90
+
0
-

Gotcha, can I use explorer in this snippet?

	public function getPublicArticles()
	{
		return $this->database
			->table('news')
			->where('created_at < ', new \DateTime)
			->order('created_at DESC');
	}
Cupara
Member | 90
+
0
-

@Infanticide0 Also, I have this snippet:

{$new->created_at|date:'F j, Y'}

That only shows the date, how do I get it to show the time as well in a specific format?

Last edited by Cupara (2023-12-26 09:21)

Cupara
Member | 90
+
0
-

One last thing, how do you form an n:tag-if that needs to parameters to work? Such as one parameter I have is if they supplied their email and the second parameter is if they check the box to show their email.

<p>
	<b><a href="mailto:{$comment->email}" n:tag-if="$comment->email">
		{$comment->name}
	</a></b> said:
</p>

That is the snippet where I need to use two if conditions. So it would have to be provided email AND want to show their email.

Last edited by Cupara (2023-12-26 09:31)

nightfish
Member | 472
+
0
-

@Cupara

ad date/time format: date filter (|date) takes as its argument a PHP date formatting string. See documentation for various date and time parts you can use.

ad n:tag-if: the expression inside n:tag-if is a standard PHP expression, so you can use && (logical AND) to merge multiple conditions. Could be something like n:tag-if="$comment->email && $new->author->emailVisible" (you'll need to change the second part of the condition to match what you have in database).

nightfish
Member | 472
+
0
-

@Cupara
ad “comment count”: There are several options how to implement counting comments for articles.

If you want to use Database Explorer (which allows you to easily traverse from one table to another), following options come to mind:

  1. You can add comment_count to your news table and populate it with after insert/after delete trigger on comments table. After a comment is added/removed, the comment_count in your news table will get updated. (https://www.mysqltutorial.org/mysql-triggers/)
  2. You can do something similar, but the calculation and updating of the comment_count will be done from PHP. After you save a new comment to the database, you will execute a query to return a count of all comments for the current article and save it to comment_count.
  3. You can create a VIEW on your news table that will contain both columns of news table and an additional column comment_count, that will be calculated on the fly whenever you SELECT from the view. This could get slow with a large number of news and comments, but also should be easiest to implement. (https://www.mysqltutorial.org/…utorial.aspx)

You can also implement the third solution using PHP – collect IDs of news items and execute another query (using Database Core) to retrieve a number of comments for each ID (in a single query, result would be an array of ID ⇒ COUNT), then pass the result to the template and use it when rendering news items.

David Grudl
Nette Core | 8139
+
0
-

It should be possible to call $comments->count() there, right?

Cupara
Member | 90
+
0
-

nightfish wrote:

@Cupara

ad date/time format: date filter (|date) takes as its argument a PHP date formatting string. See documentation for various date and time parts you can use.

ad n:tag-if: the expression inside n:tag-if is a standard PHP expression, so you can use && (logical AND) to merge multiple conditions. Could be something like n:tag-if="$comment->email && $new->author->emailVisible" (you'll need to change the second part of the condition to match what you have in database).

Thanks

Cupara
Member | 90
+
0
-

nightfish wrote:

@Cupara
ad “comment count”: There are several options how to implement counting comments for articles.

If you want to use Database Explorer (which allows you to easily traverse from one table to another), following options come to mind:

  1. You can add comment_count to your news table and populate it with after insert/after delete trigger on comments table. After a comment is added/removed, the comment_count in your news table will get updated. (https://www.mysqltutorial.org/mysql-triggers/)
  2. You can do something similar, but the calculation and updating of the comment_count will be done from PHP. After you save a new comment to the database, you will execute a query to return a count of all comments for the current article and save it to comment_count.
  3. You can create a VIEW on your news table that will contain both columns of news table and an additional column comment_count, that will be calculated on the fly whenever you SELECT from the view. This could get slow with a large number of news and comments, but also should be easiest to implement. (https://www.mysqltutorial.org/…utorial.aspx)

You can also implement the third solution using PHP – collect IDs of news items and execute another query (using Database Core) to retrieve a number of comments for each ID (in a single query, result would be an array of ID ⇒ COUNT), then pass the result to the template and use it when rendering news items.

I went with option 2. I just need to implement the deleting process for just me being able to delete comments until I implement a user system.

Cupara
Member | 90
+
0
-

nightfish wrote:

@Cupara

ad date/time format: date filter (|date) takes as its argument a PHP date formatting string. See documentation for various date and time parts you can use.

ad n:tag-if: the expression inside n:tag-if is a standard PHP expression, so you can use && (logical AND) to merge multiple conditions. Could be something like n:tag-if="$comment->email && $new->author->emailVisible" (you'll need to change the second part of the condition to match what you have in database).

In regards to the date filter I added time to it like so datatime then added HH:mm after F j, Y but it just errors out so I'm not sure how it would look in the code for Nette as datetime is the only PHP way I know to do it.

Cupara
Member | 90
+
0
-

@Infanticide0 I did that and it still didn't work. I'll try again. What is the letter to get AM or PM to display?

Can you show me an example using https://doc.nette.org/…ls/paginator ?

I'm trying to figure it out but I'm struggling. Since I'm using PostFacade.php above, I can't figure out how to implement it from the doc I linked.

Cupara
Member | 90
+
0
-

Infanticide0 wrote:

@Cupara

https://fiddle.nette.org/latte/#…

Ok so it worked this time but I don't like that it uses 24 hour format. I prefer it using 12 hour format and use AM/PM.

Cupara
Member | 90
+
0
-

@Infanticide0 instead of an example here is my code that I have so far.

PostFacade.php

<?php
namespace App\Model;

use Nette;

final class PostFacade
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	public function getPublicArticles(int $page, $itemsPerPage)
	{
		return $this->database
			->table('news')
			->where('created_at < ', new \DateTime)
			->order('created_at DESC')
			->limit($itemsPerPage, $page);
	}

	public function getArticlesCount(): int
	{
		return $this->database->fetchField('SELECT COUNT(*) FROM news WHERE created_at < ?', new \DateTime);
	}
}

HomePresenter.php

<?php

declare(strict_types=1);

namespace App\Presenters;

use App\Model\PostFacade;
use Nette;
use Nette\Application\UI\Form;
use Nette\Utils\Paginator;


final class HomePresenter extends Nette\Application\UI\Presenter
{
    public function __construct(
        private PostFacade $facade,
    ) {
    }

    public function renderDefault(): void
    {
        $page = 1; // Initialize the variable '$page' with a default value
        $itemsPerPage = 10;

        $getArticlesCount = $this->facade
            ->getArticlesCount();

        $paginator = new Paginator;
        $paginator->setItemCount($getArticlesCount);
        $paginator->setItemsPerPage($itemsPerPage);
        $paginator->setPage($page);

        $this->template->news = $this->facade
            ->getPublicArticles($page, $itemsPerPage);
        $this->template->paginator = $paginator;
    }
}

paginator code in default.latte

	<div class="d-flex mb-5 pagination">
		{if !$paginator->isFirst()}
			<a n:href="default, 1">First</a>
			&nbsp;|&nbsp;
			<a n:href="default, $paginator->page-1">Previous</a>
			&nbsp;|&nbsp;
		{/if}

		Page {$paginator->getPage()} of {$paginator->getPageCount()}

		{if !$paginator->isLast()}
			&nbsp;|&nbsp;
			<a n:href="default, $paginator->getPage() + 1">Next</a>
			&nbsp;|&nbsp;
			<a n:href="default, $paginator->getPageCount()">Last</a>
		{/if}
	</div>
Cupara
Member | 90
+
0
-

I figured out the time structure. That part is solved.

Infanticide0
Member | 59
+
0
-

@Cupara
you need to read current page number instead of setting it always to the first page

public function renderDefault(int $page = 1): void
    {
        $itemsPerPage = 10;

        $getArticlesCount = $this->facade->getArticlesCount();

        $paginator = new Paginator;
        $paginator->setItemCount($getArticlesCount);
        $paginator->setItemsPerPage($itemsPerPage);
        $paginator->setPage($page); // use page number from URL parameter or first page by default (you get these variables in renderDefault(parameters) automatically)

        $this->template->news = $this->facade
            ->getPublicArticles($page, $itemsPerPage);
        $this->template->paginator = $paginator;
    }

public function renderDefault(int $page = 1, int $perPage = 10): void
    {
        $getArticlesCount = $this->facade->getArticlesCount();

        $paginator = new Paginator;
        $paginator->setItemCount($getArticlesCount);
        $paginator->setItemsPerPage($perPage);
        $paginator->setPage($page); // use page number from URL parameter or first page by default (you get these variables in renderDefault(parameters) automatically)

        $this->template->news = $this->facade
            ->getPublicArticles($page, $itemsPerPage);
        $this->template->paginator = $paginator;
    }
<a n:href="default, 1">First</a> // navigate to action=default with first parameter=1
<a n:href="default, $paginator->getPage() + 1">Next</a> // navigate to action=default with first parameter=(current page - 1)
<a n:href="default, page: 1, perPage: 5">set 5 items per page</a> // calls renderDefault(1, 5) and keep new values in get parameters in url

Last edited by Infanticide0 (2023-12-27 16:49)

Cupara
Member | 90
+
0
-

Infanticide0 wrote:

@Cupara
you need to read current page number instead of setting it always to the first page

public function renderDefault(int $page = 1): void
    {
        $itemsPerPage = 10;

        $getArticlesCount = $this->facade->getArticlesCount();

        $paginator = new Paginator;
        $paginator->setItemCount($getArticlesCount);
        $paginator->setItemsPerPage($itemsPerPage);
        $paginator->setPage($page); // use page number from URL parameter or first page by default (you get these variables in renderDefault(parameters) automatically)

        $this->template->news = $this->facade
            ->getPublicArticles($page, $itemsPerPage);
        $this->template->paginator = $paginator;
    }

public function renderDefault(int $page = 1, int $perPage = 10): void
    {
        $getArticlesCount = $this->facade->getArticlesCount();

        $paginator = new Paginator;
        $paginator->setItemCount($getArticlesCount);
        $paginator->setItemsPerPage($perPage);
        $paginator->setPage($page); // use page number from URL parameter or first page by default (you get these variables in renderDefault(parameters) automatically)

        $this->template->news = $this->facade
            ->getPublicArticles($page, $itemsPerPage);
        $this->template->paginator = $paginator;
    }
<a n:href="default, 1">First</a> // navigate to action=default with first parameter=1
<a n:href="default, $paginator->getPage() + 1">Next</a> // navigate to action=default with first parameter=(current page - 1)
<a n:href="default, page: 1, perPage: 5">set 5 items per page</a> // calls renderDefault(1, 5) and keep new values in get parameters in url

Thanks for all the help. That is all covered now I can move on to finishing everything up and upload the site.

Is there way to implement a WYSIWYG editor in my forms so it saves new lines without using <br /> in the article? If you can point me to an article for implementing that would suffice.

Infanticide0
Member | 59
+
0
-

@Cupara

WYSIWYG editor is more javascript problem, you can use any editor (CKEditor, TinyMCE…) and load editor in your Form input.
Input value will be HTML code, by default Latte escapes all tags when you try to print it. To render HTML code you have to use noescape filter (it is security risk, read docs)

https://latte.nette.org/en/tags#…

Or you can use Texy or Markdown syntax renderers.