Add table of contents generation and header ID processing to Articles class

- Implemented `generateTableOfContents` method to create a structured table of contents from article content.
- Added `processHeaders` method to ensure headers have unique IDs for linking.
- Updated `generateHeadersIds` to apply ID generation to headers in article content.
- Modified `article_full` method to include table of contents in rendered articles.
- Enhanced `submenu_details` and `subpages` methods in Menu class to support language ID.
- Updated caching mechanisms to include language ID for subpages and menu details.
- Refactored various methods in Articles view class for improved readability and consistency.
- Added new sftp configuration file for deployment settings.
This commit is contained in:
2026-03-05 22:38:16 +01:00
parent bfe866fec7
commit 86c704fd31
30 changed files with 851 additions and 696 deletions

12
.vscode/sftp.json vendored Normal file
View File

@@ -0,0 +1,12 @@
{
"name": "inwestprofil.fr",
"host": "inwestprofil.pl",
"protocol": "ftp",
"port": 21,
"username": "ftp@inwestprofil.fr",
"password": "4wCFuWYSQlckbqGBT",
"remotePath": "/public_html",
"uploadOnSave": false,
"useTempFile": false,
"openSsh": false
}

View File

@@ -2,7 +2,6 @@
<script type="text/javascript" src="/libraries/ckeditor/adapters/jquery.js"></script> <script type="text/javascript" src="/libraries/ckeditor/adapters/jquery.js"></script>
<script type="text/javascript" src="/libraries/jquery/sortable/sortable.js"></script> <script type="text/javascript" src="/libraries/jquery/sortable/sortable.js"></script>
<? <?
;
global $db, $settings; global $db, $settings;
ob_start(); ob_start();
@@ -120,12 +119,19 @@ ob_start();
</div> </div>
</div> </div>
<div> <div>
<? if ( is_array( $this -> authors ) ): foreach ( $this -> authors as $author ): $authors[ $author['id'] ] = $author['author']; endforeach; endif;?> <?
$authors[0] = '--- wybierz autora ---';
if ( is_array( $this -> authors ) ):
foreach ( $this -> authors as $author ):
$authors[ $author['id'] ] = $author['author'];
endforeach;
endif;
?>
<?= \Html::select( [ <?= \Html::select( [
'label' => 'Autor', 'label' => 'Autor',
'name' => "id_author", 'name' => "id_author",
'id' => 'id_author', 'id' => 'id_author',
'values' => array_merge( [ '0' => '--- wybierz autora ---' ], $authors ), 'values' => $authors,
'value' => $this -> article['id_author'] 'value' => $this -> article['id_author']
] );?> ] );?>
<?= \Html::input_switch( <?= \Html::input_switch(
@@ -149,6 +155,11 @@ ob_start();
'checked' => $this -> article['show_title'] == 1 ? true : false 'checked' => $this -> article['show_title'] == 1 ? true : false
) )
);?> );?>
<?= \Html::input_switch( [
'label' => 'Pokaż spis treści',
'name' => 'show_table_of_contents',
'checked' => $this -> article['show_table_of_contents'] == 1 ? true : false
] );?>
<?= \Html::input_switch( <?= \Html::input_switch(
array( array(
'label' => 'Pokaż datę dodania', 'label' => 'Pokaż datę dodania',

View File

@@ -351,6 +351,14 @@ ob_start();
'value' => $this -> settings['link_version'] ? 1 : 0 'value' => $this -> settings['link_version'] ? 1 : 0
] );?> ] );?>
</div> </div>
<div class="form-group">
<?= \Html::select( [
'label' => "Wersja adresów url",
'name' => "url_version",
'values' => [ 0 => 'bez / na końcu adresu url', 1 => 'z / na końcu adresu url' ],
'value' => $this -> settings['url_version'] ? 1 : 0
] );?>
</div>
<div class="form-group"> <div class="form-group">
<?= \Html::select( [ <?= \Html::select( [
'label' => "Newsletter", 'label' => "Newsletter",

View File

@@ -207,7 +207,7 @@
<? endif;?> <? endif;?>
</li> </li>
<li> <li>
<? if ( \admin\factory\Users::check_privileges( 'seo_additional', $user[ 'id' ] ) ):?> <? if ( \admin\factory\Users::check_privileges( 'seo_administration', $user[ 'id' ] ) ):?>
<a href="/admin/seo_additional/main_view/"> <a href="/admin/seo_additional/main_view/">
<img src="/admin/css/icons/settings-20-filled.svg">Dodatkowe ustawienia SEO <img src="/admin/css/icons/settings-20-filled.svg">Dodatkowe ustawienia SEO
</a> </a>

View File

@@ -74,23 +74,27 @@ if ( \S::get( 'a' ) == 'widget-phone-now' )
if ( \S::get( 'a' ) == 'contact_form' ) if ( \S::get( 'a' ) == 'contact_form' )
{ {
$response = [ 'status' => 'error' ]; $response = [ 'status' => 'error' ];
$email = trim( (string) \S::get( 'email' ) );
$phone = trim( (string) \S::get( 'phone' ) );
$subject = trim( (string) \S::get( 'subject' ) );
$text = trim( (string) \S::get( 'text' ) );
if ( \S::get( 'email' ) ) if ( $email || $phone )
{ {
if ( \S::send_email( if ( \S::send_email(
$settings['contact_email'], $settings['contact_email'],
\S::get( 'subject' ), $subject,
'<p>Nr telefonu: ' . \S::get( 'phone' ) . '</p>' '<p>Nr telefonu: ' . $phone . '</p>'
. '<p>Email: ' . \S::get( 'email' ) . '</p>' . '<p>Email: ' . $email . '</p>'
. '<p>' . \S::get( 'text' ) . '</p>', . '<p>' . $text . '</p>',
\S::get( 'email' ) $email
) ) ) )
{ {
$mdb -> insert( 'pp_contact_emails', [ $mdb -> insert( 'pp_contact_emails', [
'email' => \S::get( 'email' ), 'email' => $email,
'phone' => \S::get('phone' ), 'phone' => $phone,
'title' => \S::get( 'subject' ), 'title' => $subject,
'mail' => \S::get( 'text' ), 'mail' => $text,
'add_date' => date("Y-m-d, H:i") 'add_date' => date("Y-m-d, H:i")
]); ]);

View File

@@ -98,7 +98,7 @@ class Articles
$values['params'] = $params; $values['params'] = $params;
if ( $id = \admin\factory\Articles::article_save( if ( $id = \admin\factory\Articles::article_save(
$values['id'], $values['title'], $values['main_image'], $values['entry'], $values['text'], $values['table_of_contents'], $values['status'], $values['show_title'], $values['show_date_add'], $values['date_add'], $values['id'], $values['title'], $values['main_image'], $values['entry'], $values['text'], $values['table_of_contents'], $values['status'], $values['show_title'], $values['show_table_of_contents'], $values['show_date_add'], $values['date_add'],
$values['show_date_modify'], $values['seo_link'], $values['meta_title'], $values['meta_description'], $values['meta_keywords'], $values['layout_id'], $values['show_date_modify'], $values['seo_link'], $values['meta_title'], $values['meta_description'], $values['meta_keywords'], $values['layout_id'],
$values['pages'], $values['noindex'], $values['repeat_entry'], $values['copy_from'], $values['social_icons'], $values['event_date'], $values['hidden-tags'], $values['block_direct_access'], $values['pages'], $values['noindex'], $values['repeat_entry'], $values['copy_from'], $values['social_icons'], $values['event_date'], $values['hidden-tags'], $values['block_direct_access'],
$values['priority'], $values['password'], $values['pixieset'], $values['id_author'], $params $values['priority'], $values['password'], $values['pixieset'], $values['id_author'], $params

View File

@@ -54,6 +54,7 @@ class Settings
\admin\factory\Settings::settings_update( 'lazy_loading', $values['lazy_loading'] == 'on' ? 1 : 0 ); \admin\factory\Settings::settings_update( 'lazy_loading', $values['lazy_loading'] == 'on' ? 1 : 0 );
\admin\factory\Settings::settings_update( 'generate_webp', $values['generate_webp'] == 'on' ? 1 : 0 ); \admin\factory\Settings::settings_update( 'generate_webp', $values['generate_webp'] == 'on' ? 1 : 0 );
\admin\factory\Settings::settings_update( 'contact_form_captcha', $values['contact_form_captcha'] == 'on' ? 1 : 0 ); \admin\factory\Settings::settings_update( 'contact_form_captcha', $values['contact_form_captcha'] == 'on' ? 1 : 0 );
\admin\factory\Settings::settings_update( 'url_version', $values['url_version'] );
\S::alert( 'Ustawienia zostały zapisane.' ); \S::alert( 'Ustawienia zostały zapisane.' );

View File

@@ -238,7 +238,7 @@ class Articles
} }
public static function article_save( public static function article_save(
$article_id, $title, $main_image, $entry, $text, $table_of_contents, $status, $show_title, $show_date_add, $date_add, $show_date_modify, $seo_link, $meta_title, $meta_description, $article_id, $title, $main_image, $entry, $text, $table_of_contents, $status, $show_title, $show_table_of_contents, $show_date_add, $date_add, $show_date_modify, $seo_link, $meta_title, $meta_description,
$meta_keywords, $layout_id, $pages, $noindex, $repeat_entry, $copy_from, $social_icons, $event_date, $tags, $block_direct_access, $priority, $meta_keywords, $layout_id, $pages, $noindex, $repeat_entry, $copy_from, $social_icons, $event_date, $tags, $block_direct_access, $priority,
$password, $pixieset, $id_author, $params ) $password, $pixieset, $id_author, $params )
{ {
@@ -251,6 +251,7 @@ class Articles
{ {
$mdb -> insert( 'pp_articles', [ $mdb -> insert( 'pp_articles', [
'show_title' => $show_title == 'on' ? 1 : 0, 'show_title' => $show_title == 'on' ? 1 : 0,
'show_table_of_contents' => $show_table_of_contents == 'on' ? 1 : 0,
'show_date_add' => $show_date_add == 'on' ? 1 : 0, 'show_date_add' => $show_date_add == 'on' ? 1 : 0,
'show_date_modify' => $show_date_modify == 'on' ? 1 : 0, 'show_date_modify' => $show_date_modify == 'on' ? 1 : 0,
'date_add' => $date_add ? $date_add : date( 'Y-m-d H:i:s' ), 'date_add' => $date_add ? $date_add : date( 'Y-m-d H:i:s' ),
@@ -435,6 +436,7 @@ class Articles
{ {
$mdb -> update( 'pp_articles', [ $mdb -> update( 'pp_articles', [
'show_title' => $show_title == 'on' ? 1 : 0, 'show_title' => $show_title == 'on' ? 1 : 0,
'show_table_of_contents' => $show_table_of_contents == 'on' ? 1 : 0,
'show_date_add' => $show_date_add == 'on' ? 1 : 0, 'show_date_add' => $show_date_add == 'on' ? 1 : 0,
'show_date_modify' => $show_date_modify == 'on' ? 1 : 0, 'show_date_modify' => $show_date_modify == 'on' ? 1 : 0,
'date_modify' => date( 'Y-m-d H:i:s' ), 'date_modify' => date( 'Y-m-d H:i:s' ),

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,87 @@
namespace front\factory; namespace front\factory;
class Articles class Articles
{ {
public static function pixieset_save_favorite_images( $hash ) { static public function generateTableOfContents($content) {
$result = '';
$currentLevel = [];
preg_match_all('/<(h[1-6])([^>]*)>(.*?)<\/\1>/', $content, $matches, PREG_SET_ORDER);
$firstLevel = true;
foreach ($matches as $match) {
$level = intval(substr($match[1], 1));
while ($level < count($currentLevel)) {
$result .= '</li></ol>';
array_pop($currentLevel);
}
if ($level > count($currentLevel)) {
while ($level > count($currentLevel)) {
if (count($currentLevel) > 0 || $firstLevel) {
$result .= '<ol>';
$firstLevel = false;
}
array_push($currentLevel, 0);
}
$result .= '<li>';
} else {
$result .= '</li><li>';
}
$currentLevel[count($currentLevel) - 1]++;
preg_match('/\sid="([^"]*)"/', $match[2], $idMatches);
$id = isset($idMatches[1]) ? $idMatches[1] : '';
$result .= sprintf(
'<a href="#%s">%s</a>',
urlencode(strtolower($id)),
$match[3]
);
}
while (!empty($currentLevel)) {
$result .= '</li></ol>';
array_pop($currentLevel);
}
if (substr($result, 0, 8) === '<ol><ol>') {
return substr($result, 4, -5);
} else {
return $result;
}
}
// funkcja wywoływana dla każdego dopasowania do wyrażenia regularnego
static public function processHeaders( $matches )
{
$level = $matches[1];
$attrs = $matches[2];
$content = $matches[3];
$id_attr = 'id=';
$id_attr_pos = strpos($attrs, $id_attr);
if ($id_attr_pos === false) { // jeśli nie ma atrybutu id
$id = \S::seo( $content );
$attrs .= sprintf(' id="%s"', $id);
}
$html = sprintf( '<h%d%s>%s</h%d>', $level, $attrs, $content, $level );
return $html;
}
static public function generateHeadersIds( $text )
{
$pattern = '/<h([1-6])(.*?)>(.*?)<\/h\1>/si';
$text = preg_replace_callback( $pattern, array(__CLASS__, 'processHeaders'), $text );
return $text;
}
public static function pixieset_save_favorite_images( $hash )
{
global $mdb, $settings; global $mdb, $settings;
\S::delete_dir( 'temp/' ); \S::delete_dir( 'temp/' );
@@ -149,6 +229,12 @@ class Articles
public static function get_image( $article, $skip_entry = false ) public static function get_image( $article, $skip_entry = false )
{ {
if ( $article['language']['main_image'] )
{
if ( file_exists( substr( $article['language']['main_image'], 1, strlen( $article['language']['main_image'] ) ) ) )
return $article['language']['main_image'];
}
if ( !$skip_entry ) if ( !$skip_entry )
{ {
$dom = new \DOMDocument(); $dom = new \DOMDocument();

View File

@@ -3,51 +3,51 @@ namespace front\factory;
class Menu class Menu
{ {
public static function submenu_details( $page_id ) public static function submenu_details( $page_id, $lang_id )
{ {
return self::subpages( $page_id ); return self::subpages( $page_id, $lang_id );
} }
public static function subpages( $page_id ) static public function subpages( $page_id, $lang_id )
{ {
global $mdb; global $mdb;
if ( !$pages = \Cache::fetch( "subpages:$page_id" ) ) if ( !$pages = \Cache::fetch( "subpages:$page_id:$lang_id" ) )
{ {
$results = $mdb -> select( 'pp_pages', [ 'id' ], [ 'AND' => [ 'status' => 1, 'parent_id' => $page_id ], 'ORDER' => [ 'o' => 'ASC' ] ] ); $results = $mdb -> select( 'pp_pages', [ 'id' ], [ 'AND' => [ 'status' => 1, 'parent_id' => $page_id ], 'ORDER' => [ 'o' => 'ASC' ] ] );
if ( is_array( $results ) ) foreach ( $results as $row ) if ( is_array( $results ) ) foreach ( $results as $row )
{ {
$page = \front\factory\Pages::page_details( $row['id'] ); $page = \front\factory\Pages::page_details( $row['id'] );
$page['pages'] = self::subpages( $row['id'] ); $page['pages'] = self::subpages( $row['id'], $lang_id );
$pages[] = $page; $pages[] = $page;
} }
\Cache::store( "subpages:$page_id", $pages ); \Cache::store( "subpages:$page_id", $pages );
} }
return $pages; return $pages;
} }
public static function menu_details( $menu_id ) public static function menu_details( $menu_id )
{ {
global $mdb, $lang_id; global $mdb, $lang_id;
if ( !$menu = \Cache::fetch( "menu_details:$menu_id:$lang_id" ) ) if ( !$menu = \Cache::fetch( "menu_details:$menu_id:$lang_id" ) )
{ {
$menu = $mdb -> get( 'pp_menus', '*', [ 'id' => (int)$menu_id ] ); $menu = $mdb -> get( 'pp_menus', '*', [ 'id' => (int)$menu_id ] );
$menu['pages'] = self::menu_pages( $menu_id ); $menu['pages'] = self::menu_pages( $menu_id );
\Cache::store( "menu_details:$menu_id:$lang_id", $menu ); \Cache::store( "menu_details:$menu_id:$lang_id", $menu );
} }
return $menu; return $menu;
} }
public static function menu_pages( $menu_id, $parent_id = null ) public static function menu_pages( $menu_id, $parent_id = null )
{ {
global $mdb, $lang_id; global $mdb, $lang_id;
if ( !$pages = \Cache::fetch( "menu_pages:$menu_id:$parent_id:$lang_id" ) ) if ( !$pages = \Cache::fetch( "menu_pages:$menu_id:$parent_id:$lang_id" ) )
{ {
$results = $mdb -> select( 'pp_pages', [ 'id' ], [ 'AND' => [ 'status' => 1, 'menu_id' => (int)$menu_id, 'parent_id' => $parent_id ], 'ORDER' => [ 'o' => 'ASC' ] ] ); $results = $mdb -> select( 'pp_pages', [ 'id' ], [ 'AND' => [ 'status' => 1, 'menu_id' => (int)$menu_id, 'parent_id' => $parent_id ], 'ORDER' => [ 'o' => 'ASC' ] ] );
if ( is_array( $results ) ) foreach ( $results as $row ) if ( is_array( $results ) ) foreach ( $results as $row )
{ {
@@ -56,7 +56,7 @@ class Menu
$pages[] = $page; $pages[] = $page;
} }
\Cache::store( "menu_pages:$menu_id:$parent_id:$lang_id", $pages ); \Cache::store( "menu_pages:$menu_id:$parent_id:$lang_id", $pages );
} }
return $pages; return $pages;

View File

@@ -10,7 +10,7 @@ class Articles
$tpl -> $key = $val; $tpl -> $key = $val;
return $tpl -> render( 'articles/password-view' ); return $tpl -> render( 'articles/password-view' );
} }
public static function map( $settings, $map_counter ) public static function map( $settings, $map_counter )
{ {
$tpl = new \Tpl; $tpl = new \Tpl;
@@ -18,19 +18,19 @@ class Articles
$tpl -> map_counter = $map_counter; $tpl -> map_counter = $map_counter;
return $tpl -> render( 'articles/map' ); return $tpl -> render( 'articles/map' );
} }
public static function tags_cloud() public static function tags_cloud()
{ {
global $settings; global $settings;
if ( !$settings['tags'] ) if ( !$settings['tags'] )
return false; return false;
$tpl = new \Tpl; $tpl = new \Tpl;
$tpl -> tags = \front\factory\Articles::tags(); $tpl -> tags = \front\factory\Articles::tags();
return $tpl -> render( 'articles/tags-cloud' ); return $tpl -> render( 'articles/tags-cloud' );
} }
public static function news( $page_id, $articles ) public static function news( $page_id, $articles )
{ {
$tpl = new \Tpl; $tpl = new \Tpl;
@@ -38,14 +38,14 @@ class Articles
$tpl -> articles = $articles; $tpl -> articles = $articles;
return $tpl -> render( 'articles/news' ); return $tpl -> render( 'articles/news' );
} }
public static function articles_list( $articles ) public static function articles_list( $articles )
{ {
$tpl = new \Tpl; $tpl = new \Tpl;
$tpl -> articles = $articles; $tpl -> articles = $articles;
return $tpl -> render( 'articles/articles-list' ); return $tpl -> render( 'articles/articles-list' );
} }
public static function article( $values ) public static function article( $values )
{ {
$tpl = new \Tpl; $tpl = new \Tpl;
@@ -53,26 +53,26 @@ class Articles
$tpl -> $key = $val; $tpl -> $key = $val;
return $tpl -> render( 'articles/article' ); return $tpl -> render( 'articles/article' );
} }
public static function article_full( $article_id, $lang_id ) public static function article_full( $article_id, $lang_id )
{ {
$tpl = new \Tpl; $tpl = new \Tpl;
$tpl -> article = \front\factory\Articles::article_details( $article_id, $lang_id ); $tpl -> article = \front\factory\Articles::article_details( $article_id, $lang_id );
return $tpl -> render( 'articles/article-full' ); return $tpl -> render( 'articles/article-full' );
} }
public static function miniature_articles_list( $page, $lang_id, $bs = 1 ) public static function miniature_articles_list( $page, $lang_id, $bs = 1 )
{ {
$results = \front\factory\Articles::page_articles( $page, $lang_id, $bs ); $results = \front\factory\Articles::page_articles( $page, $lang_id, $bs );
if ( is_array( $results['articles'] ) ) foreach ( $results['articles'] as $article ) if ( is_array( $results['articles'] ) ) foreach ( $results['articles'] as $article )
$articles[] = \front\factory\Articles::article_details( $article, $lang_id ); $articles[] = \front\factory\Articles::article_details( $article, $lang_id );
$tpl = new \Tpl; $tpl = new \Tpl;
$tpl -> page_id = $page['id']; $tpl -> page_id = $page['id'];
$tpl -> articles = $articles; $tpl -> articles = $articles;
$out .= $tpl -> render( 'articles/articles-miniatures' ); $out .= $tpl -> render( 'articles/articles-miniatures' );
if ( $results['ls'] > 1 ) if ( $results['ls'] > 1 )
{ {
$tpl = new \Tpl; $tpl = new \Tpl;
@@ -81,24 +81,24 @@ class Articles
$tpl -> page = $page; $tpl -> page = $page;
$out .= $tpl -> render( 'site/pager' ); $out .= $tpl -> render( 'site/pager' );
} }
return $out; return $out;
} }
public static function entry_articles_list( $page, $lang_id, $bs = 1 ) public static function entry_articles_list( $page, $lang_id, $bs = 1 )
{ {
global $page; global $page;
$results = \front\factory\Articles::page_articles( $page, $lang_id, $bs ); $results = \front\factory\Articles::page_articles( $page, $lang_id, $bs );
if ( is_array( $results['articles'] ) ) foreach ( $results['articles'] as $article ) if ( is_array( $results['articles'] ) ) foreach ( $results['articles'] as $article )
$articles[] = \front\factory\Articles::article_details( $article, $lang_id ); $articles[] = \front\factory\Articles::article_details( $article, $lang_id );
$tpl = new \Tpl; $tpl = new \Tpl;
$tpl -> page_id = $page['id']; $tpl -> page_id = $page['id'];
$tpl -> articles = $articles; $tpl -> articles = $articles;
$out .= $tpl -> render( 'articles/articles-entries' ); $out .= $tpl -> render( 'articles/articles-entries' );
if ( $results['ls'] > 1 ) if ( $results['ls'] > 1 )
{ {
$tpl = new \Tpl; $tpl = new \Tpl;
@@ -107,28 +107,29 @@ class Articles
$tpl -> page = $page; $tpl -> page = $page;
$out .= $tpl -> render( 'site/pager' ); $out .= $tpl -> render( 'site/pager' );
} }
return $out; return $out;
} }
public static function full_articles_list( $page, $lang_id, $bs = 1 ) public static function full_articles_list( $page, $lang_id, $bs = 1 )
{ {
$results = \front\factory\Articles::page_articles( $page, $lang_id, $bs ); $results = \front\factory\Articles::page_articles( $page, $lang_id, $bs );
if ( is_array( $results['articles'] ) ) foreach ( $results['articles'] as $article ) if ( is_array( $results['articles'] ) ) foreach ( $results['articles'] as $article )
{ {
$article_details = \front\factory\Articles::article_details( $article, $lang_id ); $article_details = \front\factory\Articles::article_details( $article, $lang_id );
if ( $article_details['password'] and !\S::get_session( 'article-' . $article . '-' . $article_details['password'] ) ) if ( $article_details['password'] and !\S::get_session( 'article-' . $article . '-' . $article_details['password'] ) )
$out .= \front\view\Articles::password_view( [ 'article' => $article ] ); $out .= \front\view\Articles::password_view( [ 'article' => $article ] );
else else
{ {
$tpl = new \Tpl; $out .= \Tpl::view( 'articles/article-full', [
$tpl -> article = $article_details; 'article' => $article_details,
$out .= $tpl -> render( 'articles/article-full' ); 'table_of_contents' => \front\factory\Articles::generateTableOfContents( $article_details['language']['text'] )
] );
} }
} }
if ( $results['ls'] > 1 ) if ( $results['ls'] > 1 )
{ {
$tpl = new \Tpl; $tpl = new \Tpl;
@@ -137,7 +138,7 @@ class Articles
$tpl -> page = $page; $tpl -> page = $page;
$out .= $tpl -> render( 'site/pager' ); $out .= $tpl -> render( 'site/pager' );
} }
return $out; return $out;
} }
} }

View File

@@ -109,7 +109,7 @@ class Site
{ {
$submenu_tmp = explode( ':', $submenu_tmp ); $submenu_tmp = explode( ':', $submenu_tmp );
$html = str_replace( '[SUBMENU:' . $submenu_tmp[1] . ']', \front\view\Menu::submenu( $html = str_replace( '[SUBMENU:' . $submenu_tmp[1] . ']', \front\view\Menu::submenu(
\front\factory\Menu::submenu_details( $submenu_tmp[1] ), $page['id'], $submenu_tmp[1] \front\factory\Menu::submenu_details( $submenu_tmp[1], $lang_id ), $page['id'], $submenu_tmp[1]
), $html ); ), $html );
} }