Cotonti https://www.cotonti.com Open Source PHP Content Management Framework Cotonti en Mon, 26 Jan 2026 10:15:34 -0000 Reading Time Plugin Reading Time lets you add estimated page reading time to your Cotonti posts.

Install and configure

  1. Download plugin from the repository, unpack the contents and upload to the plugins folder of the remote server.
  2. Configure plugin settings (field lists, reading speed & optional tags) as needed.
  3. Place TPL-tags in the templates.

TPL-tags generated by the plugin:

All TPL-tags are included in the array produced by the cot_generate_pagetags() function:

  • READING_TIME ("XX minutes" format)
  • READING_TIME_DIG ("XX" format)
  • READING_TIME_TXT ("minutes" format)

Additional pagetags:

  • LENGTH_META_TITLE (length of meta title)
  • LENGTH_META_DESC (length of meta description)
  • LENGTH_TITLE (length of page title)
  • LENGTH_DESCRIPTION (length of page description)
  • LENGTH_TEXT (length of page text)

You can place those in the corresponding templates using prefixes PAGE_, PAGE_ROW_, LIST_ROW_ etc.

]]>
Fri, 16 Jan 2026 09:49:00 -0000
CKEditor 4 Since Cotonti 0.9.26+ we are having CKEditor 5 in the box. Those of you guys who prefer to stick with version 4 can download it as a separate plugin using different name - ckeditor4. This way you will not overwrite it while applying officlal update where the folder with CKE5 is named 'ckeditor'.

Installation:

  1. Download, upload to the plugins folder and install via admin panel
  2. Select ckeditor4 parser in the HTML Parser plugin config
]]>
Mon, 22 Dec 2025 11:12:00 -0000
Faker What is FakerPHP used for?

The FakerPHP library is used to generate fake data for testing and debugging purposes via its properties called formatters. The Faker plugin utilizes the library to generate fake:

  • pages.
  • comments.
  • user accounts.

Installation

  1. Install FakerPHP via Composer: composer require fakerphp/faker
  2. Copy the 'faker' folder to your Cotonti plugins folder.
  3. Install it via Administration / Extensions.
  4. Configure path to FakerPHP and Locale via plugin config

Use

The following options are available to generate fake pages:

  • number of pages to create,
  • page title length,
  • page description length,
  • page_text length,
  • page section.

Page date is set randomly between the first user registration date and the current date.

The following options are available to generate fake comments:

  • number of comments to create,
  • comment text length.

Comment date is set randomly between the first user registration date and the current date. Target page is selected randomly.

The following options are available to generate fake user accounts:

  • number of accounts to create,
  • user group.

Credits

  • Francois Zaninotto for his Faker library
  • Twibie for the first Cotonti implementation
]]>
Sun, 14 Dec 2025 15:18:00 -0000
Top Tags This is a simple plugin-function that is used to output most popular hashtags with the following options:

  1. Customizable output template
  2. Variable number of hashtags
  3. Optional caching

Installation is simple:

  • Download plugin
  • Upload it into the plugins folder
  • Install plugin from within the admin panel
  • Place callback function(s) & customize output template(s)

Callback function

The plugin outputs hashtags via sedby_toptags() function with the following arguments:

sedby_toptags($tpl = 'toptags', $items = 10, $tt_cache = '' $tt_ttl = 0)
  • $tpl defines template file (default toptags.tpl comes with the plugin package);
  • $items defines number of hashtags;
  • $tt_cache and $tt_ttl (if used together) turn on caching for the period of time in seconds specified by $tt_ttl.

Note: the function can use memory cache only if it is enabled in the config.php:

$cfg['cache'] = true;

Otherwise it will generate the output code each time the function is called.

]]>
Fri, 28 Nov 2025 16:42:00 -0000
Varnish Cache plugin Supercharge your Cotonti website with Varnish Cache integration! This plugin seamlessly connects your Cotonti CMS with Varnish Cache, a powerful HTTP accelerator that dramatically improves website performance and reduces server load. Features include auto.

Copy the unarchived file to /plugins/ in the root directory.

Go to the plugins section in the admin panel and activate Varnish Cache.

 

Enter Varnish cache ports in plugin settings.

defaults:

Varnish host:127.0.0.0.1

Varnish admin port:80

Admin port:6082

Server port:6081

Github page: https://github.com/slaweally/Cotonti-varnish-cache/

Author: Ali Çömez / Slaweally

]]>
Mon, 23 Jun 2025 12:37:00 -0000
Reactions İcon

 

Reactions plugin allows users to give emoji-based reactions to content on pages, forums and comments.

It offers fast installation and seamless integration thanks to its fully compatible structure with Cotonti infrastructure.
Daily and per-user limit options.

Installation:
Upload the downloaded file to the plugins folder -> Admin Panel -> Plugins -> reactions -> install

Then add the plugin tags where you want the reactions to appear (such as page - forum):
Forums;
{FORUMS_POSTS_ROW_REACTIONS_BUTTONS}
{FORUMS_POSTS_ROW_REACTIONS_COUNTS}

Pages;
{PAGE_REACTIONS_BUTTONS}
{PAGE_REACTIONS_COUNTS}

You can make updates to the css file according to your request and adapt it to your own theme.

 

]]>
Sun, 27 Apr 2025 10:23:00 -0000
Nexus Cotonti theme Nexus. Modern and mobile-friendly.

Author: Rootali

Github: https://github.com/Cotonti-Themes/nexus

Install

  • Download and copy the "nexus" folder into the "themes" folder of your website.
  • Set $cfg['defaulttheme'] = 'nexus'; in the datas/config.php file.

Theme Github:

Rootali: https://github.com/slaweallx/Nexus

Cotonti Theme: https://github.com/Cotonti-Themes/nexus

]]>
Tue, 22 Apr 2025 11:22:00 -0000
Turkish (TR) Language Pack for Cotonti Siena Turkish (TR) language pack for Cotonti Siena 0.9.25

Github: https://github.com/Cotonti-Langs/turkish


Please contact me by PM if you have any suggestions or corrections of this translation.

Installation:
1. Unpack the downloaded archive.
2. Copy the folders from the archive to the root directory of your website.
3. Open datas/config.php
4. Find

$cfg['defaultlang'] = 'en';

5.Replace

$cfg['defaultlang'] = 'tr';

 

]]>
Wed, 02 Apr 2025 04:38:43 -0000
Cloudflare Turnstile

Features

  • Protects user registration, login, and comments from spam bots.
  • Simple integration into existing Cotonti forms.
  • Admin-configurable through Cotonti admin panel.
  • Modern and secure user verification without compromising user experience.

Requirements

  • Cotonti Siena v0.9.25 or later
  • Cloudflare Turnstile Site Key and Secret Key (Get keys here)

Installation

  • Upload the plugin folder turnstile into your Cotonti plugins directory: Setup is very simple, just add the following validation field to login and input fields like register, comment.

         <!-- Cloudflare Turnstile Captcha -->
         <!-- IF {USERS_AUTH_VERIFY_IMG} -->
         <tr>
             <td colspan="2" class="textcenter">
                 {USERS_AUTH_VERIFY_IMG}
                 {USERS_AUTH_VERIFY_INPUT}
             </td>
         </tr>
         <!-- ENDIF -->
    

     

    Github: Cloudflare Turnstile Plugin

    Plugin Page: Cotonti Cloudflare Turnstile Plugin

]]>
Sat, 08 Mar 2025 05:12:00 -0000
Accepting payments Accepting payments.

When developing e-commerce extensions, such as an online store, paid services or consultations, etc., you need to arrange payment acceptance, which will be convenient to use.

This can be implemented using the "Payments" module.

This module can be integrated with any online payment system: PayPal, UKassa, bank payment systems, etc.
To create a payment, add the following code in the controller of your extension after the order is generated:

$amount = 500; // Payment amount. Pennies are transferred as a fractional part.
$area = 'orderType'; // type of payment (order or service code)
$options = [
    // Optional. When paying for periodic services, if the period is not stored 
    // in your extension, the expiration date of the paid service can be stored 
    // in this field.
    'time' => $months * 30 * 24 * 60 * 60,
    
    // Optional. Description or purpose of the payment.
    'desc' => 'Order description',
    
    // Optional. The order ID on the side of the extension being developed or the user ID.
    // Can be used to identify the payment by your extension.
    'code' => $orderId,
    
    // Optional. Where to redirect the user after successful payment.
    // If not specified, the user will be redirected to their payment history.
    // https://domain.tld/payments?m=balance&n=history
    'redirect' => cot_url('extension-code', ['m' => 'orders', 'id' => $orderId], '', true)
]

cot_payments_create_order($area, $amount, $options);

A pair of values $area and $options['code'] should uniquely identify the payment so that your extension can correctly automatically activate the paid service after payment.

The cot_payments_create_order() function will create a payment and redirect the user to the payment page, where the user will be able to select one of the installed payment system plugins and make a payment.

After making the payment, the user will be redirected to a page with his payments history and there will be shown a message about a successful payment or an error.

Payments

If the $options['redirect'], parameter was passed when creating the payment, then in case of successful payment, user will be redirected to the specified url.

At the moment when the payment status changes to "Paid" the payments.payment.success hook is triggered.
Your extension should handle this hook to automatically activate the paid service. An array with payment data is available to the hook handler. This is an array with data from the cot_payments table containing the payment record being processed..

Please note that this hook is usually called at the moment when the payment system calls the web-hook with payment notification. The request is made from the  payment system's server  and the user making the payment has nothing to do with this request and the session of this user is unavailable at this moment. Therefore, the handler of this hook should not output any data or headers and should not make any redirects.

To display any information to the user, you need to use the URL passed through $options['redirect'], if the standard one is not enough. Usually, when a user goes on this URL, the payment has already been processed and the result can be displayed to the user.

To test your extension integration with the payment module, you can use the Nullbilling plugin. It is a plugin with a test payment system that does not make any payments, but simulates a successful payment.

Connecting payment systems

You can add a new payment system by installing the appropriate plugin. If there is no ready-made one, then you can write your own.

Let's consider creating such a plugin.

The plugin must register itself as a payment system plugin. To do this, it must process the payments.billing.register hook and add its data to the $cot_billings array. For example, like this:

if (
    Cot::$cfg['plugin']['myPaymentSystem']['on']
    && !empty(Cot::$cfg['plugin']['myPaymentSystem']['apiKey'])
    && !empty(Cot::$cfg['plugin']['myPaymentSystem']['secret'])
) {
    $cot_billings['myPaymentSystem'] = [
        'plug' => 'myPaymentSystem',
        'title' => Cot::$L['tbank_title'],
        'icon' => Cot::$cfg['plugins_dir'] . '/myPaymentSystem/images/logo.png',
    ];
}

If the payment system sends payment notification (web-hook) using the POST method, it is necessary to disable xss protection for the web-hook handler, otherwise Cotonti will not accept the request from the payment system. To do this, you need to make the input hook handler with the following code:

if (
    isset($_GET['e'])
    && $_GET['e'] === 'myPaymentSystem'
    && isset($_GET['a'])
    && $_GET['a'] === 'notify'
    && $_SERVER['REQUEST_METHOD'] === 'POST'
) {
    define('COT_NO_ANTIXSS', 1) ;
    Cot::$cfg['referercheck'] = false;
}

Add $_GET parameters for which the payment notification (web-hook) handler is available to the if condition.

The plugin has a standalone hook handler, but it does not output any data to the user, but uses it for other purposes. The "Open" button for this plugin is not needed in the admin panel in the list of extensions. Let's put it away. To do this, add the code to the admin.extensions.plug.list.loop hook handler:

if ($type === COT_EXT_TYPE_PLUGIN && $code === 'myPaymentSystem') {
    $t->assign([
        'ADMIN_EXTENSIONS_JUMPTO_URL' => null,
    ]);
}

And to admin.extensions.details hook:

if ($type === COT_EXT_TYPE_PLUGIN && $code === 'myPaymentSystem') {
    $standalone = null;
    $t->assign([
        'ADMIN_EXTENSIONS_JUMPTO_URL' => $standalone,
    ]);
}

If you need to display any reference information for the site administrator on the plugin settings page in the admin panel, for example, the settings that need to be made in the personal account of the payment system itself, use the admin.config.edit.tags hook

if ($o === COT_EXT_TYPE_PLUGIN && $p === 'myPaymentSystem') {
    $adminHelp = '... Справка по настройке платежной системы ...';
}

And will make the standalone hook handler. It solves 2 tasks, depending on the passed parameters:

1) On the payment method selection page, when clicking on the payment system link, the user is redirecting to this page. The GET parameter pid  contains the local payment ID in the cot_payments table.

Get the payment data:

// Get payment ID
$paymentId = cot_import('pid', 'G', 'INT');
if (!$paymentId) {
    cot_die_message(404);
}

// Get pyment data from DB
$payment = PaymentRepository::getById($paymentId);
if (!$payment) {
    cot_die_message(404);
}

// Check if the payment status allows to make a payment
cot_block(in_array($payment['pay_status'], PaymentDictionary::ALLOW_PAYMENT_STATUSES, true));

The further scenario depends on the API of the payment system. It usually consists of the following: send a request to the payment system to initialize the payment on its side. In response, the payment system returns the URL to which the user must be redirected to make the payment.

Many payment systems allow to transfer URLs in the payment initialization parameters, where needed to redirect the user after payment. You can get them using the following methods: successful payment url - PaymentService::getSuccessUrl($PaymentId) and the fail payment URL - PaymentService::getFailUrl($paymentId).

Before redirecting the user to the payment system's website to make a payment, set the local payment status "In progress" and specify which payment system processes the payment.

PaymentService::setStatus(
    $paymentId,
    PaymentDictionary::STATUS_PROCESS,
    'myPaymentSystem',
    PaymentDictionary::METHOD_CARD,
    $psPaymentId
);

The last 2 parameters are optional. The penultimate one indicates that the payment will be made with bank card, and the last one is the payment identifier passed to the payment system.

Some payment systems require you to pass a unique payment ID each time. And in the case when the payment failed and the user tries to pay again, the old payment ID is no longer accepted. For such payment systems, your plugin must generate a unique payment ID. For example, like this:

$psPaymentId = $paymentId . '-' . time();

We save it in the cot_payments table, passing the 5th parameter to PaymentService::setStatus().

2) When a user makes a payment on the payment system's website, before returning the user back to your site, the payment system sends a payment notification (web hook) with the payment status. It needs to be processed. There is no need to do this in the standalone hook, you can also do it in the ajax hook.

When the notification from the payment system has been processed and the checks have been completed in accordance with the documentation for the payment system, it is necessary to set the local payment status to the "Paid"

PaymentService::setStatus(
    $paymentId,
    PaymentDictionary::STATUS_PAID,
    'myPaymentSystem',
    null,
    null,
    $transactionId
)

here we skip the parameters $paymentMethod, $paymentSystemPaymentId - they were set earlier. But we pass $transactionId (optional) - the identifier of the transaction (or payment) on the payment system side. Most payment systems pass it with payment notification (web-hook).

]]>
Mon, 07 Oct 2024 18:16:00 -0000
Using captcha in extensions When developing an extension, it is often necessary to display some form to unregistered users: a feedback form, "order a call", ask a question to support, etc. Such forms can be filled out and sent to the server by spam bots, thereby filling the database with garbage. A captcha is a very effective way to protect against such bots.

It makes no sense to require registered users to fill out a captcha because bots cannot log in to the site and "spam" all forms. Therefore, you need to display the captcha only in those forms that can be filled by the guests.

Using a captcha in your extensions is pretty simple.

To display a captcha in any form:

Add such code to the your extension's controller:

// Initialize the template engine
$t = new XTemplate($pathToTemlateFile);

// ... some code of your extension ...

// Check if user is not logged in and at least one captcha is installed on the site:
if (Cot::$usr['id'] === 0 && !empty($cot_captcha)) {
	// Output captcha to the template
	$t->assign(cot_generateCaptchaTags(null, 'rverify', 'FEEDBACK_FORM_'));
}

Add tags to the template for captcha output:

<!-- IF {FEEDBACK_FORM_VERIFY_IMG} -->
<div>
	{FEEDBACK_FORM_VERIFY_IMG} {FEEDBACK_FORM_VERIFY_INPUT}
</div>	
<!-- ENDIF -->

And finally, when processing the data sent by the user, you need to check whether the captcha is filled in correctly:

if (Cot::$usr['id'] === 0 && !empty($cot_captcha)) {
	$rverify = cot_import('rverify', 'P', 'TXT');
	if (!cot_captcha_validate($rverify)) {
		// The captcha is not filled correctly
		cot_error('captcha_verification_failed', 'rverify');
	}
}
]]>
Mon, 07 Oct 2024 04:56:00 -0000
SecurImage Captcha

Securimage CAPTCHA plugin for Cotonti CMF. Protects your site from spam bots with image captcha.

Uses the Securimage class (from Drew Phillips)

Authors:

Github: https://github.com/Alex300/SecurImageCaptcha-for-Cotonti

Plugin page on author's site: https://lily-software.com/free-scripts/cotonti-securImage-captcha

Opportunities:

  • You can use this captcha wherever it is used on your site: in the registration form, comments, feedback, etc.
  • The image can be updated without reloading the page
  • Those who cannot read the code can listen to the voice code

A sample of the captcha's work can be viewed, for example, in the registration form of this site.

Installation:

  • copy the captcha folder from the archive to the plugins folder on your hosting
  • install the plugin in the ite admin panel
  • in the site admin panel, under Configuration -> Security -> Captcha, select default "Captcha"

To change the image settings (font, size, background image, noises, etc.), edit the file /inc/imageshow.php

Using captchas in your plugins:

Similar to using any other captcha.

 

]]>
Sun, 06 Oct 2024 05:33:00 -0000
Freelance Exchange bundle Freelance Exchange bundle for CMF Cotonti. With this bundle, you can organize any exchange to search for performers for various jobs. Its  functionality provides flexible options for operation and further development.

Authors: Bulat Yusupov и CMSWorks team, Cotonti team
GitHub: https://github.com/Cotonti-Extensions/freelance

Main features

User accounts with their personal pages (contact information is displayed on the personal page, as well as lists of published projects, works in the portfolio and in the marketplace); Catalog of jobs (job projects), the ability to publish jobs. Jobs search with filtering by region and keywords; Catalog of freelancers and employers sorted by specialization; Payment module with internal user accounts and the ability to replenish and pay for services; Included payment systems: Interkassa, Robokassa and WebMoney (separate plugins) and the ability to easily connect other payment systems; Paid service "PRO account"; Paid service "Paid place on the main page" (Users who have paid for this service are displayed on the main page of the exchange); Secure payment service; Reviews and ratings.

Extensions from this bundle can be installed on existing sites and used individually and only those ones that you need.

Or you can prepare a "build" that will use the built-in Cotonti installer to selectively install extensions from this bundle with the standard Cotonti extensions. This particular option is described below.

Preparing for install

This is not a ready to use website build. To install it, you need the current version of CMF Cotonti, which can be downloaded in the Download section.

  • Download Cotonti. Unpack the archive into the directory of the future site.
  • Download Freelance Exchange bundle and unpack it into the same directory in which Cotonti is unpacked.
  • Set the write permissions for folders and subfolders in the /data directory: /datas/avatars, /data/cache (and all subfolders), /datas/extflds, /datas/photos, /datas/thumbs, /datas/users

Install

  • Open your browser and follow the link: http://your-domain.tld/install.php (replace your-domain.tld with your domain)
  • Follow the on-screen instructions until the installation is complete. During installation, select the flance installation script and bootlance theme.
  • During installation, you will be prompted to select modules and plugins. The most basic extensions that are necessary for the operation of the exchange are ticked, but you can also select the rest if necessary.
  • In the file datas/config.php set the option $cfg['customfuncs'] = true;
  • Be sure to configure the Usergroupselector plugin if your site will divide users into different groups, for example, employers and freelancers. In the settings of this plugin, you need to specify which groups will be available for users to choose when registering or in the profile. If you need to create another user group, then go to the "Users" section of the admin panel.
  • In order to be able to attach files and images to projects (as well as to suggestions in the description and in the portfolio), you must also install the Mavatars and Mavatarslance plugins, which also come as part of the bundle.
  • Initially, your site will be empty. You can create your own categories yourself in the "Structure" section of the admin panel.

Learn more about the possibilities of the Freelance Exchange bundle

Jobs

Projects module

Any user can publish their job project on the site. In the job project, you can specify the location, city, price, section in the catalog (area of activity), the title of the project and its description. You can also attach various files to the project description. Freelancers who are interested in the published job can leave their suggestions on the job project page. The employer can choose the contractor or refuse the project to any Freelancer who left an offer. An employer or Freelancer who has submitted a job project proposal can correspond directly on the project page.

Marketplace

Market module
A sectionforplacingready-to-sellgoodsorservices of the user.Eachproductcontains:title,description,imageandprice. Also, allproducts/services are categorizedin the catalogforeasysearch.

Accepting payments

Payments module

This module is a universal mechanism that allows you to accept payments on your site.

Payments are accepted through Robokassa, Interkassa and WebMoney systems. Connecting other payment systems should not cause serious difficulties for developers.

You can use this module to accept payments in your extensions.

In addition, optionally, each user can have their own personal account on the site with which they can pay for paid services.

Users Portfolios

Folio module
Allows users to exhibit their work as a portfolio. Optionally, the works can be pre-moderated before publication.

Secure settlement system (Risk-free transactions)

Sbr plugin
The plugin allows you to organize on the Freelance Exchange website the opportunity for users to make transactions with each other with full coordination of all stages of work. In this case, the transaction budget is reserved on the website account before the start of all work and is paid to the Contractor after acceptance of the results of work on each stage of the transaction. In case of disputes, either party may contact the arbitration commission (the site administration). The Arbitration commission, by analyzing the internal correspondence on the transaction, makes an appropriate decision on the payment of the work performed to the Contractor, or on the return of the budget for the stage of the transaction to the Customer. The commission may also decide on a partial payment to the parties. In this way, all parties to the transaction are protected.

User roles (groups)

There are two parties involved in the traditional freelance exchange, these are freelancers and customers. But we've improved the system a bit and added the ability to expand the number of service members. Now you can create your own roles on the site and link them to user groups for which you can configure access rights to all sections of the site and define your capabilities for them.

Reviews

Any user of the service can leave feedback to other participants. The review can be either positive or negative, to choose from. Access to the publication of Reviews can be limited only within the framework of completed projects (configurable). By default, users can leave feedback to other users. If necessary, the feedback system can be configured so that reviews can be left only for completed orders, i.e., linked to the project.

User's ratings

In order to identify the most active users among the service participants, a rating system is functioning on the site. Whoever has a higher rating, that user is more visible on the site.

How points are awarded (default settings): For visiting the site: +1 point, For placing work in the portfolio: +5 points, For the status of the contractor for the project: +1 point, For receiving a rejection for the project: -1 point, For receiving a positive review: +20 points, For receiving a negative review: -20 points, For the purchase of a PRO account: +20% to the rating, For the purchase of a paid place on the main page: +20% to the rating. The specified points values can be changed in the site admin panel. The ability to display top users anywhere on the site has also been added.

Paid services

PRO (premium) account (price per month). A PRO account gives you the opportunity to stand out among other exchange participants with a special icon, as well as priority placement in the catalog of freelancers (employers); A paid place on the main page and in any other place on the site (price per placement). Ad blocks can be placed anywhere on the site and set different prices for the size of them. Placement takes place by shifting previously paid and for a period of 1 month. Prices can also be changed in the admin panel.

Categories

The site's admin panel allows you to edit categories for all parts of the site, including: Categories of projects, types of projects (for example: Regular, Vacancies, etc.), categories of freelancers, categories in the marketplace, categories of information pages of the site.

]]>
Tue, 24 Sep 2024 16:40:00 -0000
Database Introduction

Almost any web application interacts with a database. Cotonti makes this interaction simple and comprehensive.

Currently support is provided for MySQL 5.1+

Configuration

The database connection configuration is located in the application's configuration file datas/config.php. It is filled in automatically during Cotonti installation.

Running SQL Queries

You can get access to the Cotonti database connection instance with the facade class Cot. The Cotonti database object is built on top of the PDO and provides method for executing database queries and methods that simplify the construction of INSERT, UPDATE and DELETE queries.

You can execute a SQL query by taking the following steps:

  1. Create a plain SQL query;
  2. Bind parameters (optional);
  3. Call one of the SQL execution methods in PDOStatement class.

The following example shows various ways of fetching data from a database:

// Return a set of rows. Each row is an associative array of column names and values.
// an empty array is returned if the query returned no results
$posts = Cot::$db->query('SELECT * FROM post')->fetchAll();

// Return a single (first or next) row from a result set
// False is returned if the query has no result
$post = Cot::$db->query('SELECT * FROM post WHERE id=?', 1)->fetch();

// Returns a single column from the next row of a result set
// Or false if there are no more rows.
$titles = Cot::$db->query('SELECT title FROM post')->fetchColumn();
$count = Cot::$db->query('SELECT COUNT(*) FROM post')->fetchColumn();

For queries that do not return data, you should call the PDOStatement::execute() method instead. For example:

Cot::$db->query('UPDATE post SET status=1 WHERE id=1')->execute();

For INSERT, UPDATE and DELETE queries, instead of writing pure SQL, you can call the insert(), update(), delete() methods, respectively, to create the specified SQL constructs. For example:

// INSERT (table_name, column_values)
Cot::$db->insert(
    'posts', 
    [
        'titlle' => 'Lorem ipsum', 
        'text' => 'Morbi imperdiet tortor ut nisl ultricies finibus',
    ]
);
$newPostId = Cot::$db->lastInsertId();

// UPDATE (table_name, column_values, condition, params)
$condition = [
	"created_at < '" . date('Y-m-d H:i:s', time() - 3600) . "'",
	'category = :category',
];
$updatedRowsCount = Cot::$db->update(
    'posts', 
    ['status' => 1], 
    $condition, 
    ['category' => $category]
);

// DELETE (table_name, condition, params)
$deletedRowsCount = Cot::$db->delete(
    'posts', 
    'status = 0 AND category = ?', 
    $category
);

insert(), update() and delete() methods do not require escaping the table name. This will be done automatically.

insert() and update() methods do not require escaping array elements with data for insert/update.

update() and delete() methods accept a condition that can be a string with an SQL condition or an array of strings. In the case of an array, each string will be wrapped in parentheses and they are combined with the AND operator.

In the example above:

$condition = [
	"created_at < '2024-07-08 12:45:56'",
	'category = :category'
];

is equivalent to:

(created_at < '2024-07-08 12:45:56') AND (category = :category)

Binding Parameters

When creating a SQL query with parameters, you should almost always use parameter binding to prevent SQL injection attacks. For example:

$post = Cot::$db->query(
	'SELECT * FROM post WHERE category = ? AND status = ?',
	[$category, status]
)->fetch();

When executing the query, each question mark in accordance with its order will be safely replaced with the corresponding value from the array.

If the request has only one parameter, you can pass a scalar value instead of an array:

$post = Cot::$db->query('SELECT * FROM post WHERE category = ?', $category)->fetch();

You can use scalar parameters:

$post = Cot::$db->query(
	'SELECT * FROM post WHERE id = :id AND status = :status',
	['id' => $id, ':status' => status]
)->fetch();

Quoting Table and Column Names

Cot::$db->query(
    'SELECT * FROM ' . Cot::$db->quoteTableName(Cot::$db->pages) 
    . ' WHERE page_cat = ' . Cot::$db->quote($category)
)->fetchColumn();

Quoting methods:

  • Cot::$db->quoteTableName() or short version (Cot::$db->quoteT())
    Quotes a table name for use in a query. If the table name contains schema prefix, the prefix will also be properly quoted.
  • Cot::$db->quoteColumnName() or short version (Cot::$db->quoteC())
    Quotes a column name for use in a query. If the column name contains prefix, the prefix will also be properly quoted. If the column name is already quoted then this method will do nothing.
  • Cot::$db->quote()
    Quotes a string value for use in a query. It is recommended to use parameter binding instead of this method, if possible.

Database Transactions

You may use the Cot::$db->transaction() method to run a set of operations within a database transaction. If an exception is thrown within the transaction closure, the transaction will automatically be rolled back and the exception is re-thrown. If the closure executes successfully, the transaction will automatically be committed. You don't need to worry about manually rolling back or committing while using the transaction method:

Cot::$db->transaction(
	function(): void 
	{
		Cot::$db->update('posts', ['status' = 1], 'category = ?', $category);
		Cot::$db->delete('posts', 'status = 0']);
		// ... executing other SQL statements ...
	}
);

Manually Using Transactions

You can use transactions manually and have complete control over commits and rollbacks and error handling. The example above is equivalent to this:

Cot::$db->beginTransaction();
try {
    Cot::$db->update('posts', ['status' = 1], 'category = ?', $category);
    Cot::$db->delete('posts', 'status = 0']);
	// ... executing other SQL statements ...
    
    Cot::$db->commit();
} catch(\Throwable $e) {
    Cot::$db->rollBack();
	throw $e;
}

Specifying Isolation Level

Cotonti supports setting isolation levels for your transactions. By default, when starting a new transaction, it will use the default isolation level set by your database system. You can override the default isolation level as follows:

$isolationLevel = \cot\database\DataBaseDictionary::REPEATABLE_READ;

Cot::$db->transaction(
	function(): void 
	{
		....
	},
	$isolationLevel
);
 
// or

Cot::$db->beginTransaction($isolationLevel);

Handling Deadlocks

The Cot::$db->transaction() method accepts an optional third argument which defines the number of times a transaction should be retried when a deadlock occurs. Once these attempts have been exhausted, an exception will be thrown:

Cot::$db->transaction(
	function(): void 
	{
		....
	},
	$isolationLevel,
	5
);

Working with Database Schema

(section being updated)

Cotonti database object provides several methods to work with database schema:

  • tableExists($tableName) - check if table exists
  • fieldExists($tableName, $fieldName) - check if fieild exists
  • indexExists($tableName, $indexName, $indexColumns = []) - check if index exists
  • addIndex($tableName, $indexName, $indexColumns = []) - create Index. Here $indexColumns is either a string for a single column name or an array for single/multiple columns. $indexName will be used if empty.

Execution of SQL scripts

The CotDB::runScript($script, $translaction = false) method allows you to execute SQL scripts (contents of SQL files). Table names must be escaped with the MySQL escape symbol ` and have the cot_ prefix, which will be replaced with the prefix from the settings in datas/config.php.

]]>
Sun, 08 Sep 2024 14:51:00 -0000
Cotonti Siena 0.9.25 released This is a stability release that fixes bugs found after the release of 0.9.24. It is also a preparation before the 1.0 release.

Whats new:

  • Support for Php 5.x has been discontinued. The minimum Php version is 7.3
  • Database: transactions support with nesting control
  • cot_user_sqlExcludeBanned() for generate sql condition to exclude banned users. You can use it your extensions.
  • cot_generateCaptchaTags() captcha tag generation unification for the coTemplate
  • Legacy mode ($cfg['legacyMode']) to turn on deprecated features. You can use it if your extensions and/or theme are not fully compatible with the current Cotonti version. Turned off by default.
  • Many minor improvements and fixes

Read more on the release page.

Thanks to everyone who participated in the work on this release, programming and testing

 

For more detailed info see:

]]>
Tue, 03 Sep 2024 06:10:00 -0000
Cotonti Siena 0.9.25 About Siena

If you are a new to Cotonti — please read a brief info about this CMF and its requirements.

See detailed instructions for first-time install or updating guides.

 

Release info

This is a stability release that fixes bugs found after the release of 0.9.24. It is also a preparation before the 1.0 release.

Whats new:

  • Support for Php 5.x has been discontinued. The minimum Php version is 7.3
  • Database: transactions support with nesting control
  • cot_user_sqlExcludeBanned() for generate sql condition to exclude banned users. You can use it your extensions.
  • cot_generateCaptchaTags() captcha tag generation unification for the coTemplate
  • Legacy mode ($cfg['legacyMode']) to turn on deprecated features. You can use it if your extensions and/or theme are not fully compatible with the current Cotonti version. Turned off by default.
  • Many minor improvements and fixes

Template tags changes:

Unified captcha tags.

Unified pagination tags in pfs.admin.allpfs.tpl, polls.admin.tpl, comments.tools.tpl, ratings.admin.tpl, referers.admin.tpl, trashcan.admin.tpl:

{XXX_PAGINATION} -> {PAGINATION}
{XXX_PAGEPREV} -> {PREVIOUS_PAGE}
{XXX_PAGENEXT} -> {NEXT_PAGE}
{XXX_TOTALITEMS} -> {TOTAL_ENTRIES}
{XXX_ON_PAGE} -> {ENTRIES_ON_CURRENT_PAGE}

 

For more detailed info see:

 

Updating from previous versions

  • For updating from previous Siena version — see instructions here.
  • For upgrading from Genoa — see this document (you will also need files from cotonti-legacy to perform the upgrade).

 

 

]]>
Tue, 03 Sep 2024 05:58:00 -0000
Omnis Theme Omnis theme for Cotonti Siena

Omnis theme was built using Bootstrap 5.3.3 and Fontawesome Free 6.5.2. Styles are written with LESS, resulting css-files are minimized. Development and testing were done using Cotonti 0.9.25 beta, all TPL-tags comply with the new naming.

Theme Demo

Dependencies

In order to implement all theme features the following extensions shall be installed:

Official Package:

  • Index
  • Page
  • Users
  • CKEditor
  • Comments system
  • Contact
  • HTML Parser
  • HTML Purifier
  • Math Captcha (or an alternative)
  • Search
  • Tags
  • User Images

3rd party:

Once the installation is complete, create a page in the system section with alias blog and title Blog. This is where all posts will be aggregated using Pagelist plugin.

To highlight a post in the feed create a page extrafield named special_class (type input). When editing such page use specialclass in the edit form to make title bolder & image bigger.

How to use the theme

My viewpoint can be found at the Omnis officlal page (Russian). Nonetheless, since in the recent poll the majority voted for modifying ready-made themes, I see two options here:

Standard

After the installation, download Omnis plugin and load all custom lang-strings, resources and settings (like GTM container ID). This way you can update the theme from the Github repository without fearing to overwrite some of your custom data.

Naturally, you are encouraged to suggest and discuss new features that will provide new functions and capabilities to the theme.

As an Intermediate Product

Unpack css-files, modify LESS code, edit markup, install other plugins, and use Omnis to make your own modifications. No offense.

Todo

So far it's sticky header and font-packed icons.

]]>
Wed, 28 Aug 2024 08:00:00 -0000
Dark Blog Необходимые плагины :

Pagelist, Catlist, Comlist, Forman, Thanks, syntaxhighlighter, attach2, nevalidate, toplastseen, Friendly functions calls

в настройках сайта

 

 

Меню #6
{PHP.cfg.menu6} во всех файлах .tpl:    количество выводимых на главной новых статей. После превышения этого числа включается паджинация

Чтобы страница попала в этот список нужно настроить экстрополе : 

HTML для экстрополя такой (  на картинке выше ) : 

<input type="hidden" name="{$name}" value="{$value_off}" /><label><input type="checkbox" name="{$name}" value="{$value}"{$checked} /> {$title}</label>

 

После публикации статьи нужно зайти в её редактирование и установить галочку как на картинке ниже :

 

Меню #7
{PHP.cfg.menu7} во всех файлах .tpl: количество последних сообщений с форуса

 

Меню #8
{PHP.cfg.menu8} во всех файлах .tpl: количество отображаемых последних статей

 

Меню #9
{PHP.cfg.menu9} во всех файлах .tpl: оличество отображаемых последних комментариев 

 

Как выглядит  ->  здесь

]]>
Tue, 20 Aug 2024 20:17:00 -0000
Using Composer

Cotonti Siena 0.9.23 features Composer support. Composer is a tool for dependency management in PHP.

What is Composer

Composer is a dependency manager designed to simplify uploading and using 3rd party PHP libraries in your project. In instance, it can be used to add all necessary libs into an extension that is being developed.

composer.json is a text file where all side libs (packages) the project is based on are defined. Additionally it contains data on project info, PHP minimum version and required PHP extensions.

composer.lock contains a current list of all installed dependencies and their versions. The main purpose of this file is to save the complete environment in which the project is being developed and tested.

For example, if you work in a team you have to make sure that your colleague having downloaded (pull) the project from a git repository will receive the same environment and package versions that you use.

When a project is deployed to the live environment you have to make sure that it uses the same versions as in the development environment. This ensures that any location your project is deployed in is identical to the one used in the development and helps eliminate errors that might occur due to the versions updates.

Using Composer to Develop Extensions

First off, make sure that Composer is installed.

Next we will add the Guzzle client to a Cotonti extension. This ensures that both sync and async requests are sent to remote servers using the same interface. A great tool for integration with various APIs.

We will also use Flysystem to upload files into a remote storage.

These two are used only as an example with no connection between them.

Let’s begin.

We follow Guzzle installation manual to add section require into the file composer.json located in the project root:

"guzzlehttp/guzzle": "^7.8"

This would result in something like this:

"require": {
    "php": ">=5.6",
    "ext-gd": "*",
    "ext-mbstring": "*",
    "ext-json": "*",
    "ext-hash": "*",
    "ext-pdo": "*",
    "guzzlehttp/guzzle": "^7.8"
},

Next we execute the following code in the command line:

> composer update

This command updates all dependencies installed within the project to the latest version available (as per composer.json), installs new dependencies added to composer.json and removes those that no longer exist. Following that Composer updates composer.lock.

Now our HTTP client is ready for use.

Next we add the following code to our extension:

<?php

use GuzzleHttp\Client;

// Create client instance with base URI
$client = new Client(['base_uri' => 'https://foo.com/api/']);

// Send POST-request application/x-www-form-urlencoded to https://foo.com/api/test
$response = $client->request('POST', '/test', [
  'form_params' => [
      'field_name' => 'abc',
      'other_field' => '123',
      'nested_field' => [
          'nested' => 'hello',
      ],
  ],
]);

$body = $response->getBody();
echo $body;

Dead easy, is it?

Now we proceed to remote uploads.

As specified in the documentation we add section require to composer.json:

"league/flysystem": "^3.0",
"league/flysystem-aws-s3-v3": "^3.0"

Over again:

> composer update

Everything set. We can now use the library in our extension.

<?php

use Aws\S3\S3Client;
use League\Flysystem\AwsS3V3\AwsS3V3Adapter;
use League\Flysystem\Filesystem;

// For some reason AWS adapter works this way only
putenv('AWS_ACCESS_KEY_ID=my-access-key');
putenv('AWS_SECRET_ACCESS_KEY=my-secret-key');

/** @var S3ClientInterface $client */
$client = new S3Client([
    'version' => 'latest',
    'endpoint' => 'https://storage.yandexcloud.net',
    'region' => 'ru-central1',
]);

// The internal adapter
$adapter = new AwsS3V3Adapter(
    $client, // S3Client
    'test-new-bucket', // Bucket name
    'path/to/upload/dir' // path prefix
);


// FilesystemOperator готов и сконфигурирован. Можно использовать.
$fileSystem = new Filesystem($adapter);

// Запись в файл
$filesystem->write($path, $contents);

That is all. Do not forget to specify in the extension installation manual instruction to add the following lines to composer.json and run composer update:

"guzzlehttp/guzzle": "^7.8",
"league/flysystem": "^3.0",
"league/flysystem-aws-s3-v3": "^3.0"

Deploy Project into the Live Server

Our project is ready and is git-managed. Time to move it to the production server.

In the lib/vendor folder we got new subfolders with dependencies added by Composer. Let’s add them into the .gitignore – no need to use them in the repository and increase its size.

Now commit the changes and push them into the repository.

Next we login into the server via SSH and execute:

> git pull

Followed by:

> composer install

Unlike composer update this command shall install all dependencies listed in composer.lock and only the versions specified there. If this file is missing in the project root, this command shall act similar to composer update and use composer.json to install dependencies.

We’re done. You can now open the project in the browser and enjoy the result.

]]>
Fri, 24 May 2024 10:32:00 -0000
Project to Expire The time to project expiration is a string in the "2 days 18:10:45" format. The order and divider can be customized via resource string located in the inc/pte.rc.php

TPL-tags

projects.list.tpt:

...
<!-- BEGIN: PRJ_ROWS  -->
...
Project expires in: {PRJ_ROW_PTE_TO_EXPIRE}
...
<!-- END: PRJ_ROWS  -->
...

projects.tpl:

{PRJ_PTE_TO_EXPIRE}
]]>
Fri, 26 Apr 2024 05:56:00 -0000
Cotonti Siena 0.9.24.2 released Whats new:

  • СoTemplate. Support for multiple function arguments. Now you can use other tags as function arguments. You can write like this:
    {PHP|cot_url('page', 'c=news')|var_dump({PHP.L.Home}, $this, {PHP.cfg.mainurl}, {PHP|cot_url('page', 'c=news ')}, {HEADER_TITLE})}
    The $this support is left in place. You can still use function call chains.
  • СoTemplate. Strict comparison operators: === and !==
  • Fixed a bug where data from the database cache might not be loaded automatically.
  • Static cache improvements.
  • You can now use comments in Url editor's *.dat files
  • Forums API. A new function cot_forums_sqlExcludePrivateTopics() that generates an SQL condition to exclude private topics from the selection, based on the the current user's rights. You can use it in your extensions.
  • The page views counter now works even when the static page cache is enabled.
  • Captcha and posting comments by guests now work when static page cache is enabled.
  • Search. The default sorting is by date descending.
  • Fixed/added meta tags title, description and canonical url in some extensions
  • Function cot_generatePaginationTags() for uniform generation of pagination tags in extensions.
  • Extrafields. Field name validation.
  • CKEditor has been updated to version 4.22.1. In future releases, it will be replaced with version 5.
  • Refactoring of tags in templates has begun. Making tags more understandable and convenient. The old tags are kept for backward compatibility, but will be removed in the future. We recommend updating your themes.
  • The Composer folder has been moved to lib/vendor
  • 1st part of Tags plugin improvements
  • Improvements to the Recent items plugin
  • Other minor improvements
  • Fix for various errors found during operation.

Read more on the release page.

Thanks to everyone who participated in the work on this release, programming and testing

 

For more detailed info see:

]]>
Fri, 02 Feb 2024 12:43:00 -0000
Cotonti Siena 0.9.24.2 About Siena

If you are a new to Cotonti — please read a brief info about this CMF and its requirements.

See detailed instructions for first-time install or updating guides.

 

Release info

Whats new:

  • СoTemplate. Support for multiple function arguments. Now you can use other tags as function arguments. You can write like this:
    {PHP|cot_url('page', 'c=news')|var_dump({PHP.L.Home}, $this, {PHP.cfg.mainurl}, {PHP|cot_url('page', 'c=news ')}, {HEADER_TITLE})}
    The $this support is left in place. You can still use function call chains.
  • СoTemplate. Strict comparison operators: === and !==
  • Fixed a bug where data from the database cache might not be loaded automatically.
  • Static cache improvements.
  • You can now use comments in Url editor's *.dat files
  • Forums API. A new function cot_forums_sqlExcludePrivateTopics() that generates an SQL condition to exclude private topics from the selection, based on the the current user's rights. You can use it in your extensions.
  • The page views counter now works even when the static page cache is enabled.
  • Captcha and posting comments by guests now work when static page cache is enabled.
  • Search. The default sorting is by date descending.
  • Fixed/added meta tags title, description and canonical url in some extensions
  • Function cot_generatePaginationTags() for uniform generation of pagination tags in extensions.
  • Extrafields. Field name validation.
  • CKEditor has been updated to version 4.22.1. In future releases, it will be replaced with version 5.
  • Refactoring of tags in templates has begun. Making tags more understandable and convenient. The old tags are kept for backward compatibility, but will be removed in the future. We recommend updating your themes.
  • The Composer folder has been moved to lib/vendor
  • 1st part of Tags plugin improvements
  • Improvements to the Recent items plugin
  • New setting in config.php: $cfg['legacyMode']. If false, it disables all deprecated functionality.
  • Other minor improvements
  • Fix for various errors found during operation.

 

Template tags changes:

Unified captcha tags:

users.register.tpl
{USERS_REGISTER_VERIFYIMG} -> {USERS_REGISTER_VERIFY_IMG}
{USERS_REGISTER_VERIFYINPUT} -> {USERS_REGISTER_VERIFY_INPUT}

comments.tpl
{COMMENTS_FORM_VERIFYIMG} -> {COMMENTS_FORM_VERIFY_IMG}
{COMMENTS_FORM_VERIFY} -> {COMMENTS_FORM_VERIFY_INPUT}

contact.tpl
{CONTACT_FORM_VERIFY} -> {CONTACT_FORM_VERIFY_INPUT}

 

Unified pagination tags:
{<prefix>PAGINATION}
{<prefix>PREVIOUS_PAGE}
{<prefix>NEXT_PAGE}
{<prefix>CURRENT_PAGE}
{<prefix>TOTAL_ENTRIES}
{<prefix>ENTRIES_ON_CURRENT_PAGE}
{<prefix>ENTRIES_PER_PAGE}
{<prefix>TOTAL_PAGES}

<prefix> can be empty. Or not, if there are more than one paginations on the page.
For example on page.list.tpl:

{LIST_CAT_PAGINATION} for categories list and {PAGINATION} for pages list.


forums.posts.tpl
{FORUMS_POSTS_BREADCRUMBS} - new
{FORUMS_POSTS_SHORTTITLE} -> {FORUMS_POSTS_TITLE}
{FORUMS_POSTS_PAGETITLE} -> {PAGEEDIT_FORM_DESCRIPTION}


all user tags tags: {FORUMS_POSTS_ROW_USERXXX} -> {FORUMS_POSTS_ROW_USER_XXX}
e.g.
{FORUMS_POSTS_ROW_USERNAME} -> {FORUMS_POSTS_ROW_USER_NAME}
{FORUMS_POSTS_ROW_USERAVATAR} -> {FORUMS_POSTS_ROW_USER_AVATAR}
etc.

{PREVIOUS_PAGE}{PAGINATION}{NEXT_PAGE} and other pagination tags without prefix

 

polls.admin.tpl
{ADMIN_POLLS_ROW_POLL_URL_DEL} deprecated
{ADMIN_POLLS_ROW_POLL_DELETE_URL} - new
{ADMIN_POLLS_ROW_POLL_DELETE_CONFIRM_URL} - new

 

system/admin/tpl/admin.extensions.tpl
{ADMIN_EXTENSIONS_DETAILS_ROW_ORDER_INSTALLED}
{ADMIN_EXTENSIONS_DETAILS_ROW_HOOKS_INSTALLED}

 

page.list.tpl (same changes in cot_page_enum())
{LIST_CATTITLE} -> {LIST_BREADCRUMBS} - new
{LIST_BREADCRUMBS_SHORT} - new
{LIST_ROWCAT_URL} -> {LIST_CAT_ROW_URL}
{LIST_ROWCAT_TITLE} -> {LIST_CAT_ROW_TITLE}
{LIST_ROWCAT_COUNT} -> {LIST_CAT_ROW_COUNT}
{LIST_ROWCAT_DESC} -> {LIST_CAT_ROW_DESCRIPTION}

{LIST_CAT_XXX} - pagination for categories with prefix 'LIST_CAT_', e.g. {LIST_CAT_PREVIOUS_PAGE}, {LIST_CAT_PAGINATION}
And without prefix for pages list e.g. {PREVIOUS_PAGE}, {PAGINATION}.

Block LIST_ROWCAT -> LIST_CAT_ROW

{LIST_ROW_XXX} - page tags see below.


page.tpl, page.enum.tpl (from cot_generate_pagetags())
{PAGE_TITLE} now contains exactly the title, not the breadcrumbs
{PAGE_BREADCRUMBS} - new
{PAGE_LOCALSTATUS} -> {PAGE_LOCAL_STATUS}
{PAGE_SHORTTITLE} - deprecated
{PAGE_CATURL} -> {PAGE_CAT_URL}
{PAGE_CATTITLE} -> {PAGE_CAT_TITLE}
{PAGE_CATPATH} -> {PAGE_CAT_PATH}
{PAGE_CATPATH_SHORT} -> {PAGE_CAT_PATH_SHORT}
{PAGE_CATDESC} -> {PAGE_CAT_DESCRIPTION}
{PAGE_CATICON} -> {PAGE_CAT_ICON}
{PAGE_CAT_ICON_SRC} - new
{PAGE_DESC} -> {PAGE_DESCRIPTION}
{PAGE_DESC_OR_TEXT} -> {PAGE_DESCRIPTION_OR_TEXT}
{PAGE_DESC_OR_TEXT_CUT} -> {PAGE_DESCRIPTION_OR_TEXT_CUT}
{PAGE_OWNERID} -> {PAGE_OWNER_ID}
{PAGE_OWNERNAME} -> {PAGE_OWNER_NAME}
{PAGE_DATE} -> {PAGE_CREATED}
{PAGE_DATE_STAMP} -> {PAGE_CREATED_STAMP}
{PAGE_FILE_COUNT} -> {PAGE_FILE_DOWNLOADS}
{PAGE_FILE_COUNTTIMES} -> {PAGE_FILE_DOWNLOADS_TIMES}
{PAGE_COUNT} -> {PAGE_HITS}
{PAGE_NOTAVAILABLE} -> {PAGE_NOT_AVAILABLE}


page.add.tpl
{PAGEADD_FORM_DESC} -> {PAGEADD_FORM_DESCRIPTION}
{PAGEADD_FORM_OWNERID} -> {PAGEADD_FORM_OWNER_ID}

 

page.edit.tpl
{PAGEEDIT_FORM_LOCALSTATUS} -> {PAGEEDIT_FORM_LOCAL_STATUS}
{PAGEEDIT_FORM_DESC} -> {PAGEEDIT_FORM_DESCRIPTION}
{PAGEEDIT_FORM_OWNERID} -> {PAGEEDIT_FORM_OWNER_ID}
{PAGEEDIT_FORM_PAGECOUNT} -> {PAGEEDIT_FORM_HITS}
{PAGEEDIT_FORM_FILECOUNT} -> {PAGEEDIT_FORM_FILE_DOWNLOADS}


pm.list.tpl, pm.message.tpl
Pagination tags without prefix: {PREVIOUS_PAGE}{PAGINATION}{NEXT_PAGE}...

 

polls.admin.tpl
{ADMIN_POLLS_ROW_POLL_DELETE_CONFIRM_URL} - new
{ADMIN_POLLS_ROW_POLL_URL_DEL} -> {ADMIN_POLLS_ROW_POLL_DELETE_URL}


users.edit.php
{USERS_EDIT_TITLE} - now it is a page title
{USERS_EDIT_BREADCRUMBS} - new
{USERS_EDIT_DETAILSLINK} -> {USERS_EDIT_DETAILS_URL}
{USERS_EDIT_MAINGRP} -> {USERS_EDIT_MAIN_GROUP}

 

users.passrecover.tpl
{PASSRECOVER_TITLE} - now it is a page title
{PASSRECOVER_BREADCRUMBS} - new

 

users.profile.tpl
{USERS_PROFILE_TITLE} - now it is a page title
{USERS_PROFILE_BREADCRUMBS} - new
{USERS_PROFILE_DETAILSLINK} -> {USERS_PROFILE_DETAILS_URL}
{USERS_PROFILE_EDITLINK} -> {USERS_PROFILE_EDIT_URL}

 

users.tpl
Pagination tags without prefix: {PREVIOUS_PAGE}{PAGINATION}{NEXT_PAGE}...
{USERS_TOP_USERID} -> {USERS_TOP_USER_ID}
{USERS_TOP_MAINGRP} -> {USERS_TOP_MAIN_GROUP}
{USERS_TOP_REGDATE} -> {USERS_TOP_REGISTRATION_DATE}
{USERS_TOP_LOGCOUNT} -> {USERS_TOP_LOGINS_COUNT}
{USERS_TOP_GRPLEVEL} -> {USERS_TOP_GROUP_LEVEL}
{USERS_TOP_GRPTITLE} -> {USERS_TOP_GROUP_TITLE}
{USERS_TOP_POSTCOUNT} -> {USERS_TOP_POSTS_COUNT}
{USERS_TITLE} - now it is a page title
{USERS_BREADCRUMBS} - new
{USERS_TOP_FILTER_ACTION} -> {USERS_FILTERS_ACTION}
{USERS_FILTERS_PARAMS} - new
{USERS_TOP_FILTERS_COUNTRY} -> {USERS_FILTERS_COUNTRY}
{USERS_TOP_FILTERS_MAINGROUP} -> {USERS_FILTERS_MAIN_GROUP}
{USERS_TOP_FILTERS_GROUP} -> {USERS_FILTERS_GROUP}
{USERS_TOP_FILTERS_SEARCH} -> {USERS_FILTERS_SEARCH}
{USERS_TOP_FILTERS_SUBMIT} -> {USERS_FILTERS_SUBMIT}
{USERS_FILTERS_SORT}
{USERS_FILTERS_SORT_WAY_URL}
{USERS_FILTERS_SORT_WAY}


recentitems.tpl
Pagination tags without prefix: {PREVIOUS_PAGE}{PAGINATION}{NEXT_PAGE}...

 

recentitems.forums.index.tpl, recentitems.forums.tpl
{FORUM_ROW_FIRSTPOSTER} -> {FORUM_ROW_FIRST_POSTER}
{FORUM_ROW_LASTPOSTER} -> {FORUM_ROW_LAST_POSTER}
{FORUM_ROW_TIMEAGO} -> {FORUM_ROW_TIME_AGO}
{FORUM_ROW_POSTCOUNT} -> {FORUM_ROW_POSTS_COUNT}
{FORUM_ROW_CREATIONDATE} -> {FORUM_ROW_CREATED}
{FORUM_ROW_CREATIONDATE_STAMP} -> {FORUM_ROW_CREATED_STAMP}
{FORUM_ROW_REPLYCOUNT} -> {FORUM_ROW_REPLY_COUNT}
{FORUM_ROW_VIEWCOUNT} -> {FORUM_ROW_VIEWS_COUNT}
{FORUM_ROW_LASTPOSTURL} -> {FORUM_ROW_LAST_POST_URL}
{FORUM_ROW_MAXPAGES} -> {FORUM_ROW_MAX_PAGES}
{FORUM_ROW_DESC} -> {FORUM_ROW_DESCRIPTION}

First poster user tags: {FORUM_ROW_FIRST_POSTER_XXX}
Last poster user tags: {FORUM_ROW_LAST_POSTER_XXX}


recentitems.pages.tpl, recentitems.pages.index.tpl, search.tpl
see page.tpl (from cot_generate_pagetags())


tags.tpl
Pagination tags without prefix: {PREVIOUS_PAGE}{PAGINATION}{NEXT_PAGE}...

If you are not sure about the tag you need, you can use the Nemesis theme as a sample or look into the extension code that you need.
Also you can see a list of available tags and blocks on of the current template

 

For more detailed info see:

 

Updating from previous versions

  • For updating from previous Siena version — see instructions here.
  • For upgrading from Genoa — see this document (you will also need files from cotonti-legacy to perform the upgrade).

 

 

]]>
Sun, 28 Jan 2024 15:07:00 -0000
Editor.js Удобный, современный блочный редактор контента на основе Editor.js.

Github плагина: https://github.com/Edd-G/cot-editorjs

Что означает "блочный редактор"?

В отличие от классических редакторов, рабочее пространство которых состоит из одного редактируемого элемента, в блочном редакторе рабочее пространство состоит из отдельных блоков: абзацев, заголовков, изображений, галерей, списков, цитат и т. д.

В чем преимущества перед классическими?

  1. На выходе макисмально чистый и предсказуемый код: без лишних переносов строк, заполнителей, параграфов и т.д.
  2. Пользователь максимально сконцетрирован на созднии контента, точно зная, как это будет выглядеть на выходе.
  3. Есть десятки готовых к использованию блоков и простой API для создания любого блока, который вам нужен. Например, вы можете реализовать блоки для твитов, постов в Instagram, опросов, анкет и т. д.

Пример редактора

 

 

Особенности этого плагина

  1. В оригинале Editor.js на выходе дает JSON-объект с данными каждого блока. Этот плагин, по крайней мере в текущей версии, конвертирует JSON в чистый HTML, промаркированный специальными классами. Данные в базе хранятся именно в HTML.
    Я сделал это для обратной совместимости с другими редакторами, если вам вдруг вздумается переключиться на классический редактор, вы сможете легко это сделать.
  2. Плагин пока поддерживает только модуль Pages. И только 1 экземпляр редактора на странице.
  3. Плагин размечает создаваемые HTML блоки специальными классами. Если у вас уже есть контент, и вы установите данный редактор, то парсер не найдет нужных CSS классов для рабора.
    В этом случае Editor.js сам попробует разобрать HTML. В большинстве случаев это будет довольно криво.
  4. Загрузка изображений работает пока только с помощью @editorjs/simple-image. Это значит, что добавить картинку получится только бросив ссылку на нее в редактор. Конечно можно кидать ссылки локального сервера.
  5. В текущей версии не реализована загрузка файлов. По крайней мере пока не сделали API какого-то файлового менеджера.
  6. Существует проблема с предпросмотром некотрых ссылок в @editorjs/link. Это связано с тем, что ресурс по ссылке под защитой какого-то сервиса, вроде Cloudflare. 

Поддерживаемые блоки Editor.js

Подробнее о поддерживаемых блоках на Github.

Генерируемый плагином HTML

Header

<h2 class="prs-header prs_center">Lorem</h2>

Paragraph

<p class="prs-paragraph prs_center">
    <code class="inline-code">Pellentesque</code> 
    <i>malesuada fames</i> 
    <mark class="cdx-marker">tempus</mark>
</p>

Ordered List

<ol class="prs-list prs_ordered">
    <li></li>
</ol>

Table

<table class="prs-table prs_withheadings">
    <thead>
        <tr>
            <th>1</th><th>2</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>a</td><td>b</td>
        </tr>
    </tbody>
</table>

Остальные примеры на Github

Установка плагина

  1. Распакуйте в каталог плагинов
  2. Включите плагин в панели администратора
  3. Этот шаг нужен, если качали плагин в виде исходного кода с Github: запустите composer install внутри папки src в директории плагина (Composer должен быть установлен)
  4. Установите парсер разметки Editorjs в модуле конфигурации Страниц (модуль Pages)

Настройки

  1. Вы можете отключить ненужные блоки Editor.js в файле editorjs.editor.php
  2. Плагин использует свою копию HTMLpurifier. Настройте очистку данных приходящих с фронтенда с помощью правил HTML Purifier в файле sanitize-blocks-config.json Подробнее о правилах в этом файле
  3. Префикс CSS классов (по умолчанию prs) меняется в конфигурации плагина

В планах

  • Добавить выбор варианта хранения данных в базе: JSON/HTML
  • Добавить блоки для работы с изображениями и файлами
]]>
Sun, 07 Jan 2024 10:53:27 -0000
Nomerge This simple plugin lets you define forum topics where posts will not be merged. Use plugin config to specify topics number, comma-separated.

]]>
Thu, 30 Nov 2023 17:09:00 -0000
Syntax Highlighter Client side code highlighter. This is ready-to-use Cotonti port of SyntaxHighlighter by Alex Gorbatchev.

Authors:

GitHub: https://github.com/Cotonti-Extensions/syntax-highlighter

 

Installation

  • Download the plugin and extract "syntaxhighlighter" folder into your Cotonti plugins folder.
  • Go to Administration / Extensions and install the SyntaxHighlighter plugin.
  • Go to the plugin configuration and select the desired theme and set other options if you need

 

Usage

Usage with HTML parsing: To highlight source code with some specific language, use HTML tags like this:

<pre class="brush:language;">
    Your code here
</pre>

 

The list of available brushes and themes: https://github.com/syntaxhighlighter/syntaxhighlighter/wiki/Brushes-and-Themes

Plugin for CKEditor: https://ckeditor.com/cke4/addon/syntaxhighlight, https://github.com/dbrain/ckeditor-syntaxhighlight

 

Color themes

Plugin bundled with a pack of predefined color themes. But you can adjust some of it to suit you needs with Cotonti theme colors. To do that copy theme CSS file from syntaxhighlighter/lib/ folder to your theme sub folder named stylesthemes/theme-name/styles. File name shoud have prefix syntaxhighlighter-. For example custom theme file full name can be like this: themes/theme-name/styles/syntaxhighlighter-my-awesome-theme.css.
Now you can change it for your needs or create your own. All CSS files located in themes/theme-name/styles folder override default ones with same names.

 

Examples

Default theme:
SyntaxHighlighter

 

Cotonti theme:
SyntaxHighlighter Cotonti theme

]]>
Thu, 02 Nov 2023 11:06:00 -0000
Maintenance Alert How often do you forget to turn the Maintenance Mode back off once you finish updating your website? Thing is, when you’re done, there’s no indication that the website is actually blocked for unauthorized visits, including SE spiders.

Maintenance Alert is basically a global informer made to remind you to switch off Maintenance Mode.

Install as normal. No dependencies or configurations required.

When the MM is on, you get 2 indications:

  1. A standard warning in the Admin Home location
  2. Global alert message made as a Bootstrap Toast by default with a link to the Security section in the Admin Area

The alert message will appear everywhere, except the login location.

You can customize the alert message via message_alert.tpl template – for both front-end and back-end themes. To do that just put your templates in the plugins folders.

]]>
Wed, 25 Oct 2023 10:29:00 -0000
Customavatar This microplugin is used to modify default avatar picture and user avatar default class. Installation is basic. Once it is done, open plugin config and input required class (img-fluid by default) and/or change default plugin image filename if needed.

Obviously, you can do that manually by altering the relevant resource string in the userimages plugin and overwriting default avatar with your own. However, with each update you will have to do that over again.

]]>
Wed, 20 Sep 2023 16:42:00 -0000
Analogue Icon Pack Alternative icon pack for the Cotonti Siena. To be used primarily with the admin panel.

Analogue Icon Pack for Cotonti Siena

Features:

  • Solid and one-style icons
  • Fully compatible with the built-in Cotonti Siena admin panel
  • Automatic replacement for the built-in & some extra extensions
  • Easy customization via resource strings

Installation:

  1. Copy folder to the /images/icons/ folder
  2. Alter config.php as follows:
$cfg['defaulticons'] = 'analogue';	// Default icon pack

Analogue Icon Pack for Cotonti Siena
Analogue Icon Pack for Cotonti Siena
Analogue Icon Pack for Cotonti Siena

]]>
Thu, 20 Jul 2023 07:29:00 -0000
Cotonti Siena 0.9.23 released Whats new:

  • Added Composer support.
  • Added PSR-4: Autoloader for classes
  • Improved cot_mail() function to follow RFC 2822. Added support for several recipients, CC and BCC recipients and custom sender (from)
  • Added check for file existence for hooks
  • Implemented first part of logging system improvement
  • Install - prevent execution of more than 1 process at a time
  • CKEditor updated to v4.21.0
  • Plugins 'BBcode Parser' and 'MarkItUp!' are removed from standard 'box'
  • Fixed some bugs.

You can find removed plugins here: BBCode Parser and MarkItUp!

Read more on the release page.

Thanks to everyone who participated in the work on this release, programming and testing

 

For more detailed info see:

Learn more, download and don't forget to upgrade

]]>
Thu, 22 Jun 2023 09:02:00 -0000
Cotonti Siena 0.9.23 About Siena

If you are a new to Cotonti — please read a brief info about this CMF and its requirements.

See detailed instructions for first-time install or updating guides.

 

Release info

Whats new:

  • Added Composer support.
  • Added PSR-4: Autoloader for classes
  • Improved cot_mail() function to follow RFC 2822. Added support for several recipients, CC and BCC recipients and custom sender (from)
  • Added check for file existence for hooks
  • Implemented first part of logging system improvement
  • Install - prevent execution of more than 1 process at a time
  • CKEditor updated to v4.21.0
  • Plugins 'BBcode Parser' and 'MarkItUp!' are removed from standard 'box'
  • Fixed some bugs.

You can find removed plugins here: BBcode Parser and MarkItUp!

 

For more detailed info see:

 

Updating from previous versions

  • For updating from previous Siena version — see instructions here.
  • For upgrading from Genoa — see this document (you will also need files from cotonti-legacy to perform the upgrade).

 

]]>
Thu, 22 Jun 2023 08:35:00 -0000
Comlist Create comments lists (widgets) and publish them on the website. The widgets are generated using cot_comlist() function:

{PHP|cot_comlist($tpl, $items = 0, $order, $extra, $group = 0, $offset = 0, $pagination, $ajax_block, $cache_name, $cache_ttl)}

The function accepts the following parameters:

  • $tpl -- template name (comlist by default)
  • $items -- number of records (0 -- publish all)
  • $order -- SQL-sorting (com_id DESC by default)
  • $extra -- extra SQL-query
  • $group -- group comments by pages (0 by default)
  • $offset -- offset records (0 by default)
  • $pagination -- pagination parameter name for the URL
  • $ajax_block -- DOM block ID for ajax pagination
  • $cache_name -- Cache name
  • $cache_ttl -- Cache TTL

The installation is standard. The Comments plugin shall be preinstalled.

]]>
Wed, 14 Jun 2023 09:06:00 -0000
Nevalidate При регистрации нового пользователя плагин до отправки формы на сервер проверяет в базе наличие введёного имени и Email под которыми пытается зарегистрироваться пользователь и в случае если такое имя или Email уже есть то выдаёт предупреждение.

From GIT 

Просто установите плагин и пользуйтесь

]]>
Mon, 29 May 2023 07:09:00 -0000
Coding Style The following code style is used for Cotonti CMF core and official extensions development. If you want to pull-request code into the core, consider using it. We aren't forcing you to use this code style for your application based on Cotonti. Feel free to choose what suits you better.

General rules

This common rules consider all source code files in the project (HTML, PHP, CSS, JS, etc.) if other is not defined.

  • Code files MUST use only UTF-8 encoding without BOM.
  • A new line SHOULD be LF.
  • Indentation SHOULD be 4 spaces for indenting, not tabs.
  • No extra spaces at the end of lines (set up your text editor, so that it removes extra spaces when saving).

There is not a hard limit on line length. Each line of text in your code should be at most 120 characters long.  
Put the line break wherever it makes the most aesthetic sense, not necessarily the breaking point closest to 120 characters.

 

PHP guidelines

A brief view

…in addition to general rules

PHP code should follow the PSR-12, and the PSR-1 coding standards and the PSR-4 autoloading standard.

If you are using PhpStorm, it can help you to maintain the required code style. You can turn it on in SettingsEditorCode StylePHPSet fromPSR12.

  • PHP code MUST use either <?php or <?= opening tags and MUST NOT use the other tag variations such as <?.
  • In case file contains PHP only it should not have trailing ?>.
  • Use one space around all operators, except for increment/decrement, e.g. $a + $b, $string = $foo . 'bar', $i++, not $a+$b.
  • Use one space after comma $one, $two, but not $one,$two.
  • Use strict equality === (inequality !==).
  • It is recommended to enable strict typing in new files using the declare(strict_types=1); directive.
  • One-line comments should be started with // and not #.
  • Avoid using global variables. Don't use undefined variables.

Documentation

  • Refer to PHPDoc for documentation syntax.
  • Code without documentation is not allowed.
  • All class files must contain a "file-level" docblock at the top of each file and a "class-level" docblock immediately above each class.

File Header

All PHP files should contain some documentation info formatted as PHPDoc.

It is very good when the header describes the variables that are used in this file, but are defined somewhere else.

Standard header for new files (this template of the header must be included at the start of all Cotonti files):

/**
 * @package {PACKAGENAME}
 * @version {VERSION}
 * @copyright (c) 2008-2023 Cotonti Team
 * @license BSD License
 * 
 * @var array<string, mixed> $user
 * @var XTemplate $t
 */

@version is optional. For example, if you are developing some extension, you do not need to define @version tag as version info already set in extension setup file and may confuse other developers.

Classes

Do not forget to comment the class. Classes need a separate @package definition, it is the same as the header package name.

/**
 * Cotonti MySQL Database adapter class.
 * A compact extension to standard PHP PDO class with slight Cotonti-specific needs,
 * handy functions and query builder.
 * 
 * @package cotonti
 * @see http://www.php.net/manual/en/class.pdo.php
 *
 * @property-read int $affectedRows Number of rows affected by the most recent query
 * @property-read int $count Total query count
 * @property-read int $timeCount Total query execution time
 */
class MySQL extends Adapter

Methods and functions

Do not forget to comment the functions. Each function should have at least a comment of what this function does. Also, it is recommended to document the parameters too. Use @param, @return, @throws in that order.

/**
 * Returns total number of records contained in a table
 * @param string $tableName Table name
 * @return int
 * @throws Exception if the table name is exists
 */
public function countRows($tableName)

When the @param or @return attributes are redundant due to the use of native types, they can be omitted:

/**
 * Execute the job.
 */
public function handle(AudioProcessor $processor): void
{
    //
}

However, when the native type is generic, specify the generic type through the use of the @param or @return attributes:

/**
 * Get the attachments for the post.
 * @return array<int, Attachment>
 */
public function attachments(int $postId): array
{
    // ...
}

Class, Function and Variable naming

All names must be descriptive, but concise. Seeing the name of a class or variable, it should be clear what they are needed for. For example: $CurrentUser, getUserData($id).

Class names MUST be declared in PascalCase. For example: Controller, Model.

Constants MUST be declared in all upper case with underscore separators. For example: STATUS_PUBLISHED.

Directory/namespace names in lower case

We DO NOT USE underscores to denote class private properties and methods.

Variable naming

Variable names MUST be in camelCase. Each word, except the first one, must begin with a capital letter. For example: $currentUser is correct, but $current_user and $currentuser are not.

Situations when one-character variable names are allowed: language strings: $L, string resources: $R, and when the variable is an index for some looping construct.

Loop Indices:
In this case, the index of the outer loop should always be $i. If there's a loop inside that loop, its index should be $j, followed by $k, and so on. If the loop is being indexed by some already-existing variable with a meaningful name, this guideline does not apply, example:

for ($i = 0; $i < $outerSize; $i++) {
  for ($j = 0; $j < $innerSize; $j++) {
    foo($i, $j);
  }
}

Functions and methods names

Functions and methods names MUST be in camelCase. The exception is Cotonti core functions. Good function names are printLoginStatus(), getUserData(), etc.

In Cotonti we are using standard cot_ prefix for any function to avoid naming conflicts. It is standard for the core API to be reusable: cot_mailPrepareAddress($address).

But you are not forced for use cot_ prefix in your plugins, unless those functions are going to be reused as the core API. You can use your own prefix within your extension API.

Function Arguments are subject to the same guidelines as variable names.

Summary

The basic philosophy here is to not hurt code clarity for the sake of laziness. This has to be balanced by a little bit of common sense, though: printLoginStatusForAGivenUser() goes too far, for example - that function would be better named printUserLoginStatus(), or just printLoginStatus().

Types

All PHP types and values should be used lowercase. That includes true, false, null.

We use operators for type casting, not functions. And only their short forms. Put one space after the operator.

$value1 = (int) $argument1;     // right
$value2 = (bool) $argument2;    // right

$value3 = (integer) $argument3;  // wrong
$value4 = invtal($argument2, 8); // only if it is really necessary

Changing type of an existing variable is considered as a bad practice. Try not to write such code unless it is really necessary.

public function save(Transaction $transaction, int $argument2 = 100)
{
  $transaction = new Connection; // bad
  $argument2 = 200; // good
}

Strings

If string doesn't contain variables or single quotes, use single quotes.

$str = 'Like this.';

If string contains single quotes you can use double quotes to avoid extra escaping.

Variable substitution:

$str1 = "Hello $username!";
$str2 = "Hello {$username}!";

The following is not permitted:

$str3 = "Hello ${username}!";

Concatenation

Add spaces around dot when concatenating strings:

$name = 'Cotonti' . ' CMF';

When string is long format is the following:

$sql = 'SELECT * '
. 'FROM post '
. 'WHERE id = 121 ';

Arrays

For arrays we're using short array syntax.

$arr = [3, 14, 15, 'Cotonti', 'CMF'];

If there are too many elements for a single line, each element is located on a separate line. After the last element we put a comma.

$mail = [
  'to'  => 'user@domain.com',
  'from' => ['admin@site.com', 'SiteTitle'],
  'cc' => [['user2@example.com', 'User2'], 'user3@example.com', 'User4 <user4@example.com>'],
];

Control Structures

  • Control statement condition MUST have single space before and after parenthesis.
  • Operators inside of parenthesis SHOULD be separated by one space.
  • Opening brace MUST be on the same line.
  • The closing brace MUST be on the next line after the body.
  • Always use braces for single line statements.

if, elseif, else

if ($expr1) {
  // if body
} elseif ($expr2) {
  // elseif body
} else {
  // else body;
}

// The following is NOT allowed:
if (!$model && null === $event) throw new Exception('test');

The keyword elseif SHOULD be used instead of else if so that all control keywords look like single words.

Expressions in parentheses MAY be split across multiple lines, where each subsequent line is indented at least once. When doing so, the first condition MUST be on the next line. The closing parenthesis and opening brace MUST be placed together on their own line with one space between them. Boolean operators between conditions MUST always be at the beginning of the line.

if (
  $expr1
  && $expr2
) {
  // if body
}

Prefer avoiding else after return where it makes sense:

$result = $this->getResult();
if (empty($result)) {
  return false;
} else {
  // process result
}

is better as:

$result = $this->getResult();
if (empty($result)) {
  return false;
}

// process result

switch, case

A switch structure looks like the following. Note the placement of parentheses, spaces, and braces.

switch ($expr) {
  case 0:
    echo 'First case, with a break';
    break;
  case 1:
    echo 'Second case, which falls through';
    // no break
  case 2:
  case 3:
  case 4:
    echo 'Third case, return instead of break';
    return;
  default:
    echo 'Default case';
}

Ternary operator

Ternary operators should only be used to do very simple things. Preferably, they will only be used to do assignments, and not for function calls or anything complex at all. They can be harmful to readability if used incorrectly, so don't fall in love with saving typing by using them, examples:

// Bad place to use them
($i < $size && $j > $size) ? do_stuff($foo) : do_stuff($bar);

// OK place to use them
$min = ($i < $j) ? $i : $j;

Classes

The term "class" refers to all classes, interfaces, and traits.

  • The opening brace for the class MUST go on its own line; the closing brace for the class MUST go on the next line after the body.
  • Classes SHOULD be named using PascalCase.
  • Every class MUST have a documentation block that conforms to the PHPDoc.
  • There should be only one class in a single PHP file.
  • All classes should be namespaced.
  • Visibility MUST be declared on all properties and methods.
  • The extends and implements keywords MUST be declared on the same line as the class name. Lists of implements and, in the case of interfaces, extends MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one interface per line.

Properties

Public and protected variables SHOULD be declared at the top of the class before any method declarations. Private variables should also be declared at the top of the class but may be added right before the methods that are dealing with them in cases where they are only related to a small subset of the class methods.

<?php

/**
 * File doc block
 */
 
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

/**
 * Class doc block
 */
class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
  public $publicProp1;
  public $publicProp2;

  protected $protectedProp;

  private $privateProp;


  public function someMethod()
  {
    // ...
  }
}

Methods and Functions

Opening brace of a function SHOULD be on the line after the function declaration, and the closing brace MUST go on the next line following the body.

In the argument list there MUST be one space after each comma.

function foo(int $arg1, string &$arg2, array $arg3 = [])
{
  // function body
}

Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line.

public function aVeryLongMethodName(
  ClassTypeHint $arg1,
  string &$arg2,
  array $arg3 = []
) {
  // method body
}

In the methods/functions declaration, always specify the native types of arguments and return values:

// Good
/**
 * Execute the job.
 */
public function handle(AudioProcessor $processor): void
{
    //
}


// Not good
/**
 * Execute the job.
 * @param AudioProcessor processor
 * @return void
 */
public function handle($processor)
{
    //
}

// Bad
/**
 * Execute the job.
 */
public function handle($processor)
{
    //
}

When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis, there MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis. In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma.

SQL guidelines

SQL Statements are often unreadable without some formatting, since they tend to be big at times. Though the formatting of sql statements adds a lot to the readability of code. SQL statements should be formatted in the following way, basically writing keywords:

$sql = 'SELECT p.*, u.* ' 
    . 'FROM ' . Cot::$db->pages . ' AS p ' .
    . 'LEFT JOIN ' . Cot::$db->pages . ' AS u ON u.user_id = p.page_ownerid '
    . "WHERE p.page_ownerid = 1 AND p.page_cat = 'news' " 
    . 'LIMIT 10';

Use parameters to safely substitute user-supplied data into the query (even if you are sure the variable cannot contain single quotes - never trust your input):

$result = Cot::$db->query(
  'SELECT * FROM ' . Cot::$db->forum_topics . ' WHERE ft_cat = :cat  AND ft_id = :topicId',
  ['cat' => $section, 'topicId' => $param]
);

Avoid DB specific SQL

  • The not equals operator, as defined by the SQL-92 standard, is <>. != is also supported by most databases, but it's better to use <>.
  • INSERT ... ON DUPLICATE KEY UPDATE - is a MySQL specific extension to SQL.
  • Backticks ` for table and column names are MySQL specific. Better use CotDB::quoteTableName() and CotDB::quoteColumnName() or abbreviations of these methods: CotDB::quoteT(), CotDB::quoteC().

Javascript guidelines

  • Use JSDoc for classes, member variables, and methods
  • The documenting, commenting and naming rules are applicable from point 2. PHP
  • Don't use jQuery where you can do without it.
  • Use let rather than var to declare variables and const to declare constants.
  • Constants whose values are always hard-coded throughout the program are named in uppercase with an underscore as a word separator. For example: const COLOR_ORANGE = "#ffa500". Most variables are constants in a different sense: they don't change value after assignment. But with different function launches their value may vary. Such variables should use const and camelCase in the name.
  • Semicolons are always placed at the end of the line.
  • Always use strict equality === (inequality !==).

Strings

  • use single quotes: let single = 'single-quoted';.
  • If string contains single quotes you can use double quotes to avoid extra escaping.
  • For expressions substitute use backticks: alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3..

Helpful links and tools

 

Previous coding style version

]]>
Sat, 20 May 2023 06:45:00 -0000
MarkItUp! markitup

Plain BBCode content source editor using jQuery.

Authors:

Github: https://github.com/Cotonti-Extensions/markitup

 

Installation

  • Download the plugin and extract "markitup" folder into your Cotonti plugins folder.
  • Go to Administration / Extensions and install the MarkitUp! plugin.
  • Install BBCode parser plugin
  • Set default markup parser BBcode in site settings: https://domaint.tld/admin.php?m=config&n=edit&o=core&p=main or for pages module: https://domaint.tld/admin.php?m=config&n=edit&o=module&p=page

     

markitup

]]>
Sat, 06 May 2023 05:01:00 -0000
BBCode Parser Previously (0.9.22 and early) was included in the standard Cotonti package

Customizable support for BBCodes and smilies parsing. Adds BBCode parser support to the contents.

Authors: Cotonti Team

Github: https://github.com/Cotonti-Extensions/bbcode

 

BBCode ("Bulletin Board Code") is a lightweight markup language used to format messages in many Internet forum software. It was first introduced in 1998. The available "tags" of BBCode are usually indicated by square brackets ([ and ]) surrounding a keyword, and are parsed before being translated into HTML

 

Installation

  • Download the plugin and extract "bbcode" folder into your Cotonti plugins folder.
  • Install the plugin in Administration panel
  • Set default markup parser in site settings: https://domaint.tld/admin.php?m=config&n=edit&o=core&p=main or for pages module: https://domaint.tld/admin.php?m=config&n=edit&o=module&p=page
  • Optionally install the MarkItUp! editor with bbcode support

 

BBCodes examples

BBCode Example in HTML/CSS Output
[b]bolded text[/b] <strong>bolded text</strong> bolded text
[i]italicized text[/i] <em>italicized text</em> italicized text
[u]underlined text[/u] <span style="text-decoration: underline;">underlined text</span> underlined text
[s]strikethrough text[/s] <span style="text-decoration: line-through;">strikethrough text</span> strikethrough text
[center]center align[/center] <div style="text-align:center">center align</div>  
[right]right align[/right] <div style="text-align:right">right align</div>  
[justify]justify align[/justify] <div style="text-align:justify">justify align</div>  
[url=https://en.wikipedia.org]English Wikipedia[/url] <a href="https://en.wikipedia.org">English Wikipedia</a> English Wikipedia
[img]https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png[/img] <img src="https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png" />
[spoiler]Text behind the spoiler[/spoiler]    
[hide]Text for authorized users[/hide]    

and much more...

All available bbcodes you can find in the plugin admin panel https://domaint.tld/admin.php?m=other&p=bbcode. You can also add your own ones.

 
 
]]>
Sat, 06 May 2023 05:01:00 -0000
Alpha Filters The Alpha Filters plugin gives you a flexible capability to filter pages & users by letters, numbers and letter combinations (syllable-based). You can also assign your own styles to the filter span elements.

 

Authors: esclkm, Kalnov Alexey, Cotonti Team

Github: https://github.com/Alex300/cotonti-alphafilters

 

Installation

  • Unpack to your plugins folder
  • Install the plugin in AdminCP
  • Add tags to page.list.tpl and/or users.tpl
  • Customize plugin configuration if necessary

 

Example for users.tpl:

<!-- IF {PHP|cot_plugin_active('alphafilters')} AND {PHP.cfg.plugin.alphafilters.turnOnUsers} == 1 -->
<div class="margin10 small text-center">
     {PHP.L.alphafilters_byFirstLetter}:
     {ALPHAFILTER_1} {ALPHAFILTER_2}
     <!-- IF {ALPHAFILTER_3} --><br />{ALPHAFILTER_3}<!-- ENDIF -->
     {ALPHAFILTER_RESET}
</div>
<!-- ENDIF -->

 

Plugin example:

 

]]>
Mon, 01 May 2023 08:04:00 -0000
Extensions updates Recently, the project participants have updated a number of extensions:

Recent comments for Administrators, Pageavatar, Similar Pages, Table of Contents, Files module, User's recent posts, User's pages

Also the Yukon admin panel theme was updated

Added new extension and theme: User's translate и Adminkacota

Read more details on the corresponding extensions pages.
Enjoy using them :)

]]>
Thu, 20 Apr 2023 08:24:00 -0000
User's translate The plugin was created likeness of a series of User's pages, User's recent posts plugins that expand the functionality of the user's card with materials of his authorship.

This plugin allows you to display the translations that users make through the work of the i18n plugin from the base engine delivery.

 

Version: 0.0.1
GitHub: https://github.com/Dayver/usertranslate

Installation

  • Unpack and upload the files into the folder : /plugins/
  • Go into the administration panel, then the tab "Plugins", click the name of the new plugin, and at bottom of the plugin properties, select "Install all".
  • Then in the same page, check if this plugin require new tags in the skin files (.TPL)
    If yes, then open the skin file(s) with a text editor, and add the tag {USERS_DETAILS_USERTRANSLATE} in users.details.tpl .
  • This extended plugins have their own configuration entries, available by clicking the number near "Configuration" in the plugin properties, or go directly to the main configuration tab, section "Plugins".


Enjoy!

]]>
Tue, 21 Mar 2023 08:20:00 -0000
Cotonti Siena 0.9.22 released What's new:

  • Force HTTPS. If you are using HTTPS but for some reason it is not detected automatically, enable this option in config.php
  • Ability to add attributes to included JS/CSS files via the Resources class
  • Refactored and ordered icons and resources that use them
  • Detailed information about PHP installed on the server (phpinfo) has been added to the admin panel
  • CKEditor updated to version 4.20.2
  • Minor admin panel update
  • Fixed some missing lines in language files
  • There is still some code that is not adapted to php 8.1. But there is less and less of it. In this release, we continued to work on this.
  • Fixed some bugs.

The 'Table Of Contents' plugin has also been updated

There are some breaking changes and new tags in tpl files. Read more on the release page.

Thanks to everyone who participated in the work on this release, programming and testing: KortDayver, webitproffKabak and Alex300

 

For more detailed info see:

Learn more, download and upgrade

]]>
Sun, 19 Mar 2023 11:42:00 -0000
Cotonti Siena 0.9.22 About Siena

If you are a new to Cotonti — please read a brief info about this CMF and its requirements.

See detailed instructions for first-time install or updating guides.

 

Release info

Whats new:

  • Force HTTPS. If you are using HTTPS but for some reason it is not detected automatically, enable this option in config.php. Please note that during the upgrade process, the $cfg['force_https'] = FALSE (disabled by default) setting will be added to the end of the config.php
  • Ability to add attributes to included JS/CSS files via the Resources class
  • Refactored and ordered icons and resources that use them
  • Detailed information about PHP installed on the server (phpinfo) has been added to the admin panel
  • Minor admin panel update
  • CKEditor updated to version 4.20.2
  • Fixed some missing lines in language files
  • There is still some code that is not adapted to php 8.1. But there is less and less of it. In this release, we continued to work on this.
  • Fixed some bugs.

 

Breaking changes:

New tags in system/admin/tpl/admin.tpl:

  • 'ADMIN_BREADCRUMBS' - contains bread crumbs
  • 'ADMIN_TITLE' - now, as it should be, contains a title.

system/admin/tpl/admin.structure.tpl:

  • 'ADMIN_STRUCTURE_UPDATE_DEL_URL' replaced with two new tags: 'ADMIN_STRUCTURE_DELETE_URL' and 'ADMIN_STRUCTURE_DELETE_CONFIRM_URL'
  • 'ADMIN_STRUCTURE_TPLMODE' replaced with 'ADMIN_STRUCTURE_TPL'

System core info was moved to its logical location (to Other/Infos) in admin panel. So there are new tags in system/admin/tpl/admin.infos.tpl:
ADMIN_INFOS_VERSION, ADMIN_INFOS_DB_VERSION, ADMIN_INFOS_DB_TOTAL_ROWS, ADMIN_INFOS_DB_INDEXSIZE, ADMIN_INFOS_DB_DATASSIZE, ADMIN_INFOS_DB_TOTALSIZE, ADMIN_INFOS_TOTALPLUGINS, ADMIN_INFOS_TOTALHOOKS

If you use third-party themes for admin. panels - don't forget to update them

File renamed: plugins/i18n/i18n.admin.extensions.phpplugins/i18n/i18n.extension.install.done.php

 

For more detailed info see:

 

Updating from previous versions

  • For updating from previous Siena version — see instructions here.
  • For upgrading from Genoa — see this document (you will also need files from cotonti-legacy to perform the upgrade).
]]>
Sun, 19 Mar 2023 10:20:00 -0000