Guide to Getting Template Path and Name in Cotonti

This guide discusses in detail three practical ways to get the path and name of a template file. The developer and the layout designer need to know which template file is being used.

Rating based on reviews:
Total stars received: 0
Total reviews: 0
Average rating: 0
Filed under: User Blog

Guide to Getting Template Path and Name in Cotonti

Table of Contents


Introduction

Cotonti is a flexible content management system in which templates play a key role in shaping the appearance of the site. Developers and layout designers often need to determine which template file is used to display a particular page or part of it. Knowing the path to the template helps to quickly make edits, debug layout, include additional resources, and create development tools.

This guide covers three practical ways to obtain the path and name of a template file:

  1. The cot_tpl_url() function — forms an absolute URL to the template file by its name, passed manually.
  2. The cot_debug_tpl_url() function — automatically determines the current template by analyzing the PHP call stack.
  3. Assigning the path via $t->assign() — passing the path from the extension PHP code to the template through the XTemplate mechanism.

Each method has its own features, advantages, and limitations. The guide will help you choose the right option for your specific task, as well as explain how to properly place user-defined functions in system/functions.custom.php so that they are available system‑wide.

Important: In the examples, we will show the path to the template as text, not as a clickable link. The .tpl file is not meant to be opened directly in a browser: it contains HTML markup with XTemplate tags that must be processed by the engine. Therefore, linking to such a file is useless and misleading. The path should be displayed for information purposes, e.g., during debugging or documentation.


Chapter 1. Cotonti Template Architecture

Before proceeding to the methods of obtaining the path, it is necessary to understand the basic principles of working with templates in Cotonti.

1.1. The cot_tplfile() Function

The central function for determining the path to a template file is cot_tplfile(). It is declared in the file system/functions.php and has the following signature:

function cot_tplfile($base, $type = 'module', $admin = null)

Parameters:

  • $base – a string or array specifying the template name. If the string contains a dot, it is split into parts. For example, 'forums.editpost' becomes the array ['forums', 'editpost'].
  • $type – the type of extension: 'plug' (plugin), 'module' (module), or 'core' (core). Default is 'module'.
  • $admin – a flag indicating whether to look for the template in the admin theme. If null (default), Cotonti automatically determines whether the template is administrative (by checking for the presence of admin in the name).

What the function does:

  1. Normalises the passed template name into an array of parts.
  2. Determines the extension code (the first element of the array) and the remaining parts.
  3. Depending on the extension type and the $admin flag, builds a list of directories to search:
    • The user's current theme (may be overridden).
    • The admin theme (for admin templates).
    • The module/plugin folder (fallback).
  4. Iterates over the list of directories and looks for a file whose name is formed from the parts of $base joined with dots, with the extension .tpl. For example, for ['forums', 'editpost'], it will look for forums.editpost.tpl.
  5. Returns the relative path to the found file (e.g., themes/mytheme/modules/forums/editpost.tpl) or null if the file is not found.

Call examples:

$tpl = cot_tplfile('index');                     // -> themes/.../index.tpl
$tpl = cot_tplfile('page.add');                  // -> themes/.../page.add.tpl
$tpl = cot_tplfile(['users', 'edit', '5'], 'module');
$tpl = cot_tplfile('myplugin.admin', 'plug', true);

Note that the function returns a path relative to the site root, without a leading slash and without a base URL. To use it in HTML (e.g., in an href or src attribute), you need to convert it to an absolute URL.

1.2. The XTemplate Class and Its Role

After determining the path to the template file, an instance of the XTemplate class is created, which is responsible for parsing and rendering the template:

$t = new XTemplate($tpl_file);

The XTemplate class (a Cotonti extension) stores the path to the template file internally. This is used in the second method (cot_debug_tpl_url) to obtain the current template. In different versions, the property that stores the path may have different names: filename, file, tpl_name, etc. Therefore, in the cot_debug_tpl_url() function, we iterate over possible names using the Reflection API.

1.3. Site Base URL $sys['abs_url']

The global variable $sys['abs_url'] contains the base URL of the site, e.g., https://example.com/. It usually ends with a slash. To correctly form an absolute URL, you need to combine the base URL and the relative path, avoiding duplicate slashes. In our functions, we use rtrim($absUrl, '/') and ltrim($filePath, '/').


Chapter 2. Method 1: The cot_tpl_url() Function – Getting Template URL by Name

2.1. Purpose and Principle of Operation

The cot_tpl_url() function is a convenient wrapper around cot_tplfile(). It takes the same arguments as cot_tplfile(), but instead of a relative path it returns the full absolute URL to the template file. This is useful when the developer knows exactly which template they need and wants to obtain its address for display in text, saving in configuration, or using as a resource path.

The function:

  1. Calls cot_tplfile($base, $type, $admin) to find the file.
  2. If the file is not found, returns null.
  3. Gets the base URL from $sys['abs_url'] (or computes it from $_SERVER if not set).
  4. Combines the base URL and the path, removing extra slashes.
  5. Returns a ready string like https://example.com/themes/mytheme/modules/page/page.news.tpl.

2.2. Function Parameters

function cot_tpl_url($base, $type = 'module', $admin = null)
  • $base — the template name (string with dots or array of parts). For example, 'page.news' or ['page', 'news'].
  • $type — the extension type: 'plug', 'module', 'core'.
  • $admin — if true, it will search in the admin theme; if null, auto‑detection by name.

2.3. Examples of Calling in Templates

Inside any .tpl file, you can call the function via the {PHP|...} tag and output the result as text:

<!-- Show the URL of the page template -->
<p>Page template: {PHP|cot_tpl_url('page')}</p>

<!-- Show the URL of a specific category template -->
<p>Template for category "News": {PHP|cot_tpl_url(['page', 'news'])}</p>

<!-- For a plugin -->
<p>Template for plugin recentitems: {PHP|cot_tpl_url('recentitems', 'plug')}</p>

You can also call the function in the PHP code of an extension:

$url = cot_tpl_url('forums.editpost');
echo "Template path: " . $url;

It is not recommended to create a link like <a href="{PHP|cot_tpl_url('page')}">Open</a>, because the browser cannot correctly open a .tpl file. Instead, output the path as text or in a title/data-* attribute for storage.

 

Correct syntax:

   Calling a function (via the pipe symbol |): {PHP|function_name(arguments)}
   Example call in a template: {PHP|cot_debug_tpl_url()}

   Access to a PHP global variable (via dot): {PHP.variable_name}
   Example in a template: {PHP.sys.abs_url} (for $sys['abs_url'])

   Template variable: {VAR_NAME}
   Example in a template: {TPL_DIR}

2.4. When to Use

This method is ideal when:

  • The template name is known in advance and does not depend on the current context.
  • You need to get the URL of a specific file to include resources (e.g., a CSS file located next to the template).
  • You are creating an admin panel where you want to show the path to the template for editing (e.g., copy the path and open the file in FTP or file manager).

Example: In the Cotonti admin panel, you can display a list of template files with their absolute paths so that the administrator can easily find the desired file on the server.

2.5. Limitations and Peculiarities

  • Requires manual specification of the template name. If the name is unknown or determined dynamically, you will have to compute it yourself.
  • Does not automatically detect the current template. If you need to know which template is used for the current page, this method is not suitable.
  • Depends on the correctness of the cot_tplfile() search. If the file is not found (e.g., due to a typo), the function will return null.

Chapter 3. Method 2: The cot_debug_tpl_url() Function – Automatic Detection of the Current Template

3.1. Purpose

The cot_debug_tpl_url() function solves the problem of determining the current template in which it is called. This is especially useful during debugging: you insert the function call anywhere in a .tpl file (e.g., in the footer) and see the full URL of that file without knowing its name in advance.

This approach does not require editing the core and is independent of a specific module or plugin.

3.2. How It Works: debug_backtrace() and Reflection API

The function uses two important PHP features:

  1. debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT) – returns the call stack as an array. Thanks to the DEBUG_BACKTRACE_PROVIDE_OBJECT flag, each frame contains the object key if the call occurred inside a method of some object. In our case, when cot_debug_tpl_url() is called inside a template, it executes in the context of an XTemplate method (e.g., parse() or text()). Therefore, the stack will definitely have a frame with an XTemplate object.
  2. Reflection API – allows access to protected and private properties of an object. The path to the template file is stored in a private property of the XTemplate object. Using ReflectionObject, we iterate over possible property names (filename, file, tpl_name, template) and retrieve the value.

Algorithm:

  • Get the base URL.
  • Get the call stack.
  • Look for a frame with an XTemplate object in the stack.
  • Extract the template file path from that object (using Reflection).
  • Build the absolute URL and return it.

3.3. Usage Examples

In any .tpl file:

<!-- Output the current template as text -->
<div>Current template: {PHP|cot_debug_tpl_url()}</div>

<!-- Use in a data-* attribute for JavaScript -->
<body data-tpl="{PHP|cot_debug_tpl_url()}">

For debugging, this call is often placed in footer.tpl or header.tpl so that you can see which template is loaded on each page. Do not make it a link – it is just text.

3.4. When to Use

  • During development and debugging – when you need to quickly understand which template file is responsible for the current block of the page.
  • When building developer tools – for example, a panel that highlights the template name.
  • When the template name is unknown or determined dynamically (e.g., depending on category or user).

3.5. Limitations and Recommendations

  • Performance. The function uses debug_backtrace(), which can slow down execution when called frequently. It is not recommended to call it in a loop on a production site. Use only for debugging or in admin mode.
  • Dependence on the internal structure of XTemplate. If in the future the property storing the path is renamed, the function may stop working. Therefore, it includes a fallback iteration over all properties with substrings file or tpl.
  • Accuracy. The function returns the last XTemplate object found in the stack, which usually corresponds to the currently processed template. However, in some cases (e.g., nested templates) it may return a different one. For most debugging tasks, this is sufficient.

Chapter 4. Method 3: Assigning the Path to a Template Tag via $t->assign()

4.1. Purpose

This method is used by extension developers (modules, plugins) when the path to the template has already been obtained in PHP code to create an XTemplate object. Instead of calling any functions in the template, we pass the path as a regular template variable. This is the most explicit and controlled way.

4.2. Implementation Example in PHP Code

Consider a fragment from the real market module:

// 1. Define the parts of the template name
$tpl_ExtCode = 'market';          // module code
$tpl_PartExt = 'edit';            // template part (action)
$tpl_PartExtSecond = Cot::$structure['market'][$item['fieldmrkt_cat']]['tpl']; // extra part from structure

// 2. Get the path to the template file
$extTplFile = cot_tplfile(
    [
        $tpl_ExtCode,
        $tpl_PartExt,
        $tpl_PartExtSecond
    ],
    'module',
    true
);

// 3. Check if the file was found
if (empty($extTplFile)) {
    cot_error('Template not found');
}

// 4. Save the path to a variable
$tpl_Path = $extTplFile;

// 5. Create an XTemplate object
$t = new XTemplate($extTplFile);

// ... further processing ...

// 6. Assign the path to the template
$t->assign('TPL_PATH', $tpl_Path);

As a result, the template variable {TPL_PATH} becomes available, containing the relative path to the template file.

4.3. Output in Template

In the corresponding .tpl file (e.g., market.edit.tpl), you can output the path:

<!-- Simply output the path -->
<p>Template path: {TPL_PATH}</p>

<!-- Use in a data-* attribute -->
<div class="debug-info" data-tpl="{TPL_PATH}">

Note that {TPL_PATH} contains a relative path (without the base URL). To get the absolute URL, you can either form the full URL in PHP code beforehand, or use the combination {PHP.sys.abs_url}/{TPL_PATH} in the template.

4.4. When to Use

  • Inside extensions, when you are already working with an XTemplate object and want to pass additional information to the template.
  • For creating utility templates (e.g., admin panels) where you need to output information about the template itself.
  • When maximum control over what is passed to the template is required, without extra calculations in the template.

4.5. Advantages and Disadvantages

Advantages:

  • Full explicitness: you define the variable and its value yourself.
  • Does not require Reflection or backtrace, works fast.
  • You can pass not only the path but also any other metadata (name, parts, etc.).
  • Compatible with all versions of PHP and Cotonti.

Disadvantages:

  • Requires modifying the PHP code of the extension for each template where it is needed.
  • Not universal: if you want to insert template information into a common footer.tpl, you will have to pass the path in every PHP controller to the corresponding XTemplate object.

Chapter 5. Comparison of Methods

Criteriacot_tpl_url()cot_debug_tpl_url()$t->assign('TPL_PATH', ...)
Automatic detection of current templateNo, requires nameYesNo, set in PHP
FlexibilityAllows specifying any templateOnly currentDepends on code
PerformanceHigh (call to cot_tplfile)Low (backtrace + Reflection)High
PHP version dependencyNoRequires PHP 8.1+ (without setAccessible)No
Where to useAnywhere in template or PHPAny template for debuggingIn extension PHP code
Requires core modificationNoNoNo
Return formatAbsolute URLAbsolute URLRelative path (usually)
Convenience for layout designersNeed to know template nameJust insert a callNeeds developer to add variable

Recommendations:

  • If you are developing an extension and want to show the template path inside it – use Method 3 (assign).
  • If you need to quickly debug the current page and find out which template is used – use Method 2 (cot_debug_tpl_url).
  • If you need to get the URL of a specific template by name (e.g., for display in documentation or passing to configuration) – use Method 1 (cot_tpl_url).

Chapter 6. Practical Scenarios and Recommendations

6.1. Layout Debugging

Task: A layout designer is editing a theme and wants to see which .tpl file is responsible for a particular block of the page.

Solution: Insert the following code into footer.tpl (or header.tpl):

<div class="debug-tpl">
    Current template: {PHP|cot_debug_tpl_url()}
</div>

This will allow you to see the path to the current template on any page of the site. Remember to remove or hide this block after finishing work.

6.2. Including Template Assets

Task: In the plugin template recentitems.tpl, you need to include a CSS file located alongside the template in the theme folder.

Solution with Method 3 (preferred): In PHP code, get the URL of the template folder and assign it to the template.

$tpl_dir = dirname(cot_tplfile('recentitems', 'plug'));
$t->assign('TPL_DIR', $tpl_dir);

In the template:

<link rel="stylesheet" href="{PHP.sys.abs_url}/{TPL_DIR}/css/recentitems.css">

Using cot_tpl_url() for such purposes is less reliable because the path may be dynamic.

 

An alternative approach, where the full URL is formed in PHP code:

$tpl_dir = dirname(cot_tplfile('recentitems', 'plug'));
$t->assign('RECENTITEMS_CSS_URL', $sys['abs_url'] . $tpl_dir . '/css/recentitems.css');


In the template:

<link rel="stylesheet" href="{RECENTITEMS_CSS_URL}">

6.3. Creating Documentation

Task: On a utility page, you need to display a list of all used templates with their absolute paths (for copying).

Solution: Use cot_tpl_url() for each known template:

$templates = [
    'index', 'page', 'page.list', 'forums.topics', 'users.profile'
];
foreach ($templates as $tpl_name) {
    $url = cot_tpl_url($tpl_name);
    echo "Template $tpl_name: $url<br>";
}

6.4. Developing Extensions

Task: In the market module, you need to show the path to the currently edited template in the admin section.

Solution: Use Method 3, as shown in the example above. In PHP code, get the path via cot_tplfile(), store it in a variable, and pass it to the template via $t->assign().

Additional tip: If you want the variable to be available in all templates of the module, you can assign it at the beginning of the controller and use it in each subtemplate.


Chapter 7. Placing Functions in system/functions.custom.php

7.1. What Is functions.custom.php

Cotonti provides the ability to add user-defined functions without modifying the core. For this purpose, the file system/functions.custom.php is used. If such a file exists, Cotonti automatically loads it during initialisation. This allows developers to add their own functions that will be available throughout the system, including templates.

7.2. Including the File

To add the functions cot_tpl_url() and cot_debug_tpl_url(), follow these steps:

  1. Create the file system/functions.custom.php if it does not already exist.
  2. Open the file and add the function code (provided in Appendix A or C).
  3. Save the file.

Cotonti will automatically detect this file and include it on startup. No additional actions are required for inclusion.

Important: Do not edit the system/functions.php file directly, as it will be overwritten when Cotonti is updated. Always place your custom functions in functions.custom.php.

7.3. Organization Recommendations

  • Keep all user-defined functions in a single file functions.custom.php for easier maintenance.
  • Use unique prefixes for function names to avoid conflicts with the core and extensions.
  • Add documentation to each function (PHPDoc comments) for easier understanding.
  • Always check if a function is already defined before declaring it (use if (!function_exists('...'))).

Example file structure:

<?php
/**
 * Cotonti custom functions
 */

if (!function_exists('cot_tpl_url')) {
    function cot_tpl_url($base, $type = 'module', $admin = null) {
        // ...
    }
}

if (!function_exists('cot_debug_tpl_url')) {
    function cot_debug_tpl_url() {
        // ...
    }
}

Conclusion

Cotonti provides a flexible template system, and obtaining the template path can be done in different ways depending on the context:

  • cot_tpl_url() – for getting the URL of a specific template by name.
  • cot_debug_tpl_url() – for automatic detection of the current template (handy for debugging).
  • $t->assign() – for explicitly passing the path to the template from extension PHP code.

Each method has its strengths. Developers are advised to combine them depending on the task. Layout designers will most often benefit from the second method (for quick debugging) and the first (for including resources if the template is known). When developing extensions, the third method is the most appropriate, as it gives full control and does not depend on global state.

Placing user-defined functions in system/functions.custom.php ensures that they will not be lost when updating the engine and will be available everywhere.


Appendix A. Full Function Listings

A.1. cot_tpl_url()

/**
 * Returns the absolute URL to the template file.
 *
 * Uses cot_tplfile() to search for the file and adds the site base URL.
 *
 * @param string|array $base  Template name (as in cot_tplfile)
 * @param string       $type  Extension type: 'plug', 'module' or 'core'
 * @param bool|null    $admin Whether to use the admin theme (default auto-detect)
 * @return string|null Absolute URL to the template, or null if not found
 */
function cot_tpl_url($base, $type = 'module', $admin = null)
{
    // Get the file path via the standard function
    $filePath = cot_tplfile($base, $type, $admin);
    if ($filePath === null) {
        return null;
    }

    // Determine the site base URL
    global $sys;
    $absUrl = isset($sys['abs_url']) ? $sys['abs_url'] : '';

    if (empty($absUrl)) {
        // If base URL is not set, compute from $_SERVER
        $absUrl = 'http' . (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['SCRIPT_NAME']), '/') . '/';
    }

    // Remove extra slashes
    if (preg_match('#^(/|[A-Za-z]:[\\\\/])#', $filePath)) {
        // If the path is absolute (starts with '/' or 'C:\'), return null
        return null;
    }

    return rtrim($absUrl, '/') . '/' . ltrim($filePath, '/');
}

A.2. cot_debug_tpl_url()

/**
 * Returns the absolute URL of the current template file.
 *
 * The function analyses the call stack, finds the XTemplate object
 * that is currently processing the template, extracts the template file
 * path via Reflection API, and adds the site base URL.
 *
 * @return string|null Absolute URL of the current template, or null if unable to determine.
 */
function cot_debug_tpl_url()
{
    global $sys;

    // Base URL
    $absUrl = isset($sys['abs_url']) ? rtrim($sys['abs_url'], '/') : '';

    // Get call stack with objects
    $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);

    foreach ($backtrace as $frame) {
        if (isset($frame['object']) && $frame['object'] instanceof XTemplate) {
            $tplFile = null;
            $ref = new ReflectionObject($frame['object']);

            // List of possible property names with the template path
            $candidateProperties = ['filename', 'file', 'tpl_name', 'template'];

            foreach ($candidateProperties as $propName) {
                if ($ref->hasProperty($propName)) {
                    $prop = $ref->getProperty($propName);
                    // In PHP 8.1+ setAccessible() is not needed
                    $tplFile = $prop->getValue($frame['object']);
                    break;
                }
            }

            // Fallback: search for a property with 'file' or 'tpl' in the name
            if ($tplFile === null) {
                foreach ($ref->getProperties() as $prop) {
                    $name = $prop->getName();
                    if (stripos($name, 'file') !== false || stripos($name, 'tpl') !== false) {
                        $tplFile = $prop->getValue($frame['object']);
                        break;
                    }
                }
            }

            if (!empty($tplFile)) {
                return $absUrl . '/' . ltrim($tplFile, '/');
            }
        }
    }

    return null;
}

Appendix B. Usage Examples in Different Modules

News list page (module page)

In the page.list.tpl file, you can insert:

<!-- Show the path to the current template -->
<div class="debug">Template: {PHP|cot_debug_tpl_url()}</div>

<!-- Show the URL of the "page" template -->
<div>Common template URL: {PHP|cot_tpl_url('page.list')}</div>

Forum – topics

In forums.topics.tpl:

<!-- Automatic path -->
<p>Current template: {PHP|cot_debug_tpl_url()}</p>

Comments plugin

In the plugin PHP code:

$tpl_path = cot_tplfile('comments', 'plug');
$t->assign('COMMENTS_TPL_PATH', $tpl_path);

In the template:

<footer>Comments: {COMMENTS_TPL_PATH}</footer>

Appendix C. Code to Place in functions.custom.php

Below is the full code that you can copy into the system/functions.custom.php file.

<?php
/**
 * Cotonti custom functions
 */

if (!function_exists('cot_tpl_url')) {
    /**
     * Returns the absolute URL to the template file.
     *
     * @param string|array $base  Template name (as in cot_tplfile)
     * @param string       $type  Extension type: 'plug', 'module' or 'core'
     * @param bool|null    $admin Whether to use the admin theme (default auto-detect)
     * @return string|null Absolute URL to the template, or null if not found
     */
    function cot_tpl_url($base, $type = 'module', $admin = null)
    {
        // Get the file path via the standard function
        $filePath = cot_tplfile($base, $type, $admin);
        if ($filePath === null) {
            return null;
        }

        // Determine the site base URL
        global $sys;
        $absUrl = isset($sys['abs_url']) ? $sys['abs_url'] : '';

        if (empty($absUrl)) {
            // If base URL is not set, compute from $_SERVER
            $absUrl = 'http' . (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['SCRIPT_NAME']), '/') . '/';
        }

        // Remove extra slashes
        if (preg_match('#^(/|[A-Za-z]:[\\\\/])#', $filePath)) {
            // If the path is absolute (starts with '/' or 'C:\'), return null
            return null;
        }

        return rtrim($absUrl, '/') . '/' . ltrim($filePath, '/');
    }
}

if (!function_exists('cot_debug_tpl_url')) {
    /**
     * Returns the absolute URL of the current template file.
     *
     * @return string|null Absolute URL of the current template, or null if unable to determine.
     */
    function cot_debug_tpl_url()
    {
        global $sys;

        // Base URL
        $absUrl = isset($sys['abs_url']) ? rtrim($sys['abs_url'], '/') : '';

        // Get call stack with objects
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);

        foreach ($backtrace as $frame) {
            if (isset($frame['object']) && $frame['object'] instanceof XTemplate) {
                $tplFile = null;
                $ref = new ReflectionObject($frame['object']);

                // List of possible property names with the template path
                $candidateProperties = ['filename', 'file', 'tpl_name', 'template'];

                foreach ($candidateProperties as $propName) {
                    if ($ref->hasProperty($propName)) {
                        $prop = $ref->getProperty($propName);
                        // In PHP 8.1+ setAccessible() is not needed
                        $tplFile = $prop->getValue($frame['object']);
                        break;
                    }
                }

                // Fallback: search for a property with 'file' or 'tpl' in the name
                if ($tplFile === null) {
                    foreach ($ref->getProperties() as $prop) {
                        $name = $prop->getName();
                        if (stripos($name, 'file') !== false || stripos($name, 'tpl') !== false) {
                            $tplFile = $prop->getValue($frame['object']);
                            break;
                        }
                    }
                }

                if (!empty($tplFile)) {
                    return $absUrl . '/' . ltrim($tplFile, '/');
                }
            }
        }

        return null;
    }
}

After saving the file, the functions will be available throughout Cotonti, including templates.

We hope this guide helps you work effectively with Cotonti templates. Use the suggested methods according to your tasks.



Reviews

No reviews yet


Comments (0)

No comments yet
Only registered users can post new comments

Page Discussion in Telegram

Content author

webitproff

Online

Sodium Carbonate

Last logged: 2026-08-20 12:58

About me briefly
Support and development of web projects on the CMF Cotonti: private messengers via the website, open and closed small social networks, trading platforms and marketplaces, freelance and services exchange portal, catalogs of goods from wholesale suppliers, dropshipping platforms, online stores, and much more.
View developments and download
Public portfolio of my works and developments
Telegram for messages
@webitproff
Telegram channel
@s/aBuyFILE
  • Page published: 2026-08-20 10:12
  • Last update: 2026-08-20 11:53
  • Language: