{"id":16461569,"url":"https://github.com/975l/sitebundle","last_synced_at":"2025-10-27T10:31:02.742Z","repository":{"id":62498831,"uuid":"123609092","full_name":"975L/SiteBundle","owner":"975L","description":"Groups common files and settings to create a website","archived":false,"fork":false,"pushed_at":"2025-01-26T13:07:47.000Z","size":889,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-26T14:05:50.272Z","etag":null,"topics":["legal-notice","legal-texts","symfony","symfony-bundle","website"],"latest_commit_sha":null,"homepage":"https://975l.com/en/pages/site-bundle","language":"Twig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/975L.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":null,"patreon":"LaurentMarquet","open_collective":"laurent-marquet","ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":"https://buymeacoff.ee/laurentmarquet"}},"created_at":"2018-03-02T17:25:12.000Z","updated_at":"2025-01-26T13:07:49.000Z","dependencies_parsed_at":"2024-01-29T21:47:51.631Z","dependency_job_id":"57d3acb7-705c-4f5d-996b-daccbbb4f6ad","html_url":"https://github.com/975L/SiteBundle","commit_stats":null,"previous_names":[],"tags_count":140,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/975L%2FSiteBundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/975L%2FSiteBundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/975L%2FSiteBundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/975L%2FSiteBundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/975L","download_url":"https://codeload.github.com/975L/SiteBundle/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238480618,"owners_count":19479521,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["legal-notice","legal-texts","symfony","symfony-bundle","website"],"created_at":"2024-10-11T11:08:41.216Z","updated_at":"2025-10-27T10:31:02.736Z","avatar_url":"https://github.com/975L.png","language":"Twig","funding_links":["https://patreon.com/LaurentMarquet","https://opencollective.com/laurent-marquet","https://buymeacoff.ee/laurentmarquet"],"categories":[],"sub_categories":[],"readme":"# SiteBundle\n\n**-- README IS NOT REALLY UP TO DATE ;( --**\n\nSiteBundle does the following:\n\n- Defines a layout used to display the web pages,\n- Variables are used to display data linked to website, name, etc.,\n- Allows to add Matomo javascript by just set url and id,\n- Allows to add CookieConsent by just adding its data,\n- Allows to have templates to override TwigBundle/Exception templates,\n- Allows to use pre-defined Terms of use, Terms of sales, etc.\n\n## Bundle installation\n\n### Step 1: Download the Bundle\n\nUse [Composer](https://getcomposer.org) to install the library\n\n```bash\n    composer require c975L/site-bundle\n```\n\n### Step 2: Configure the Bundle\n\nv2.0+ of c975LSiteBundle uses [c975L/ConfigBundle](https://github.com/975L/ConfigBundle) to manage configuration parameters. Use the Route \"/site/config\" with the proper user role to modify them.\n\nUpgrading from v1.x? **Check UPGRADE.md**\n\n### Step 3: Enable the Routes\n\nThen, enable the routes by adding them to the `config/routes.yaml` file of your project:\n\n```yml\nc975_l_site:\n    resource: \"@c975LSiteBundle/Controller/\"\n    type: annotation\n    prefix: /\n    #Multilingual website use the following\n    #prefix: /{_locale}\n    #defaults:   { _locale: '%locale%' }\n    #requirements:\n    #    _locale: en|fr|es\n```\n\n### Step 4: install assets to web folder\n\nInstall assets by running\n\n```bash\nphp bin/console assets:install --symlink\n```\n\nIt will create a link from folder `Resources/public/` in your web folder. These files are used in the `layout.html.twig`.\n\n### How to use\n\nYou **must** create a file named `layout.html.twig` in your `app/Resources/views/` that extends `@c975LSite/layout.html.twig`, so simply add this `{% extends '@c975LSite/layout.html.twig' %}` at its top.\n\nSiteBundle use the following variables which are page-based, meaning that they change for each page. If you want to use them, simply declare them on each page that extend your `app/Resources/views/layout.html.twig`.\n\n```twig\n{% set title = 'YOUR_PAGE_TITLE' %}\n{% set description = 'YOUR_PAGE_DESCRIPTION' %}\n```\n\nNote: If you use [c975L/PageEdit](https://github.com/975L/PageEditBundle) the variables are already passed to `layout.html.twig`.\n\n### Override a block\n\nYou can override any block in the template, to do so, simply add the following in your `app/Resources/views/layout.html.twig`:\n\n```twig\n{% block share %}\n    {# You can also use {{ parent() }} #}\n    {# YOUR_OWN_TEXT #}\n{% endblock %}\n```\n\nHave a look at `Resources/views/layout.html.twig`, to see all available blocks.\n\n### Disable a block\n\nTo disable a block, simply add the following in your `app/Resources/views/layout.html.twig`:\n\n```twig\n{% block share %}\n{% endblock %}\n```\n\nHave a look at `Resources/views/layout.html.twig`, to see all available blocks.\n\n### Use the display variable\n\nIn your `app/Resources/views/layout.html.twig` you can use the following to include (or not) templates:\n\n```twig\n{% if display == 'pdf' %}\n    {% include 'header-pdf.html.twig' %}\n{% else %}\n    {% include 'header.html.twig' %}\n{% endif %}\n```\n\nif `display` is not defined, hten it's define to `html`.\n\n### Matomo javascript\n\nYou can easily add a call to matomo by adding the following in your `app/Resources/views/layout.html.twig`:\n\n```twig\n{%\n    set matomo = {\n        'id': YOUR_MATOMO_ID,\n        'url': 'YOUR_MATOMO_URL'\n    }\n%}\n```\n\n### CookieConsent\n\nYou can easily add a call to CookieConsent by adding the following in your `app/Resources/views/layout.html.twig`\n\n```twig\n{%\n    set cookieConsent = {\n        'message': 'YOUR TEXT',\n        'dismiss': 'YOUR_DISMISS_TEXT',\n        'link': 'YOUR_COOKIES_POLICY_LINK_TEXT',\n        'href': 'YOUR_COOKIES_POLICY_LINK'\n    }\n%}\n{# or use the texts defined in SiteBundle #}\n{%\n    set cookieConsent = {\n        'message': 'text.cookies_banner'|trans,\n        'dismiss': 'text.cookies_dismiss'|trans,\n        'link': 'label.cookies_policy'|trans,\n        'href': 'YOUR_COOKIES_POLICY_LINK'\n    }\n%}\n```\n\n### Alternate languages\n\nYou can define the meta `\u003clink rel=\"alternate\" hreflang=\"YOUR_LANGUAGE\" href=\"URL_WITH_ALTERNATE_LANGUAGE\"\u003e` by setting a `languagesAlt` array in your `app/Resources/views/layout.html.twig`\n\n```twig\n{%\nset languagesAlt = {\n    en: { title: 'English' },\n    fr: { title: 'Français' },\n    es: { title: 'Español' }\n    }\n%}\n```\n\nIt will replace the current language by the ones set in `languagesAlt` using the following scheme `https://example.com/LANGUAGE/pages/XXX`.\n\nHaving this array set, you can also use `navbarLanguagesDropdownMenu.html.twig` in your navbar to display a dropdown menu to select available languages.\n\n### ogImage\n\nYou can define an ogImage to use on page basis, with the following code:\n\n```twig\n{% set ogImage = absolute_url(asset('PATH_TO_YOUR_IMAGE')) %}\n```\n\n### Animations\n\nThere's a css file in `public/css/` that you can link to to use some animations\n\n```twig\n\u003clink rel=\"stylesheet\" href=\"bundles/c975lsite/css/animations.min.css\"\u003e\n```\n\n### Error pages\n\nYou can also use the templates for common error pages. For this, you need to follow [How to Customize Error Pages](http://symfony.com/doc/current/controller/error_pages.html) to create the structure `app/Resources/TwigBundle/views/Exception` and files for each type of error. Of course you can still stop at the level of overidding `TwigBundle/Exception`, but if you want to use the pre-defined error templates, do the following:\n\nThe types of error covered by SiteBundle are:\n\n- error\n- error401\n- error403\n- error404\n- error410\n- error500\n\nIn each file copy/paste the following code:\n\n```twig\n{% extends 'layout.html.twig' %}\n\n{% block content %}\n    {# Take care to modify the error code in the included template name, i.e. \"404\" given here #}\n    {% include('@c975LSite/Exception/error404.html.twig') %}\n{% endblock %}\n\n{% block share %}\n{% endblock %}\n```\n\n### Add stylesheets\n\nTo add stylesheets, simply add the following  in your `app/Resources/views/layout.html.twig`:\n\n```twig\n{% block stylesheets %}\n    {{ parent() }}\n    {# Of course you can provide the full \"link\" html data #}\n{% endblock %}\n```\n\n### Add javascripts\n\nTo add javascripts, simply add the following  in your `app/Resources/views/layout.html.twig`:\n\n```twig\n{% block javascripts %}\n    {{ parent() }}\n   {# Of course you can provide the full \"script\" html data #}\n{% endblock %}\n```\n\n## Full layout example\n\nYou can use this full layout example as a basis for your project:\n\n```twig\n{% extends '@c975LSite/layout.html.twig' %}\n\n{%\nset languagesAlt = {\n    en: { title: 'English' },\n    fr: { title: 'Français' },\n    es: { title: 'Español' }\n    }\n%}\n{%\n    set matomo = {\n        'id': YOUR_MATOMO_ID,\n        'url': 'YOUR_MATOMO_URL'\n    }\n%}\n{%\n    set cookieConsent = {\n        'message': 'text.cookies_banner'|trans,\n        'dismiss': 'text.cookies_dismiss'|trans,\n        'link': 'label.cookies_policy'|trans,\n        'href': 'YOUR_COOKIES_POLICY_LINK'\n    }\n%}\n\n{# Meta #}\n{% block meta %}\n    {{ parent() }}\n{# Facebook app_id #}\n    \u003cmeta property=\"fb:app_id\" content=\"YOUR_FACEBOOK_APP_ID\"\u003e\n{% endblock %}\n\n{# Css #}\n{% block stylesheets %}\n    {{ parent() }}\n{% endblock %}\n\n{# Navigation #}\n{% block navigation %}\n    {{ include('navbar.html.twig') }}\n{% endblock %}\n\n{# Title #}\n{% block title %}\n    {% if app.request.get('_route') != null %}\n        \u003ch1\u003e\n            {{ title }}\n        \u003c/h1\u003e\n    {% endif %}\n{% endblock %}\n\n{# Container #}\n{% block container %}\n    \u003cdiv class=\"container\"\u003e\n        {% block content %}\n        {% endblock %}\n    \u003c/div\u003e\n{% endblock %}\n\n{# Share #}\n{% block share %}\n    {# YOUR SHARING TOOL  #}\n{% endblock %}\n\n{# Footer #}\n{% block footer %}\n    {{ include('footer.html.twig') }}\n{% endblock %}\n\n{# Javascript #}\n{% block javascripts %}\n    {{ parent() }}\n{% endblock %}\n```\n\n## Use pre-defined models\n\nThere are two ways to use the pre-defined models, `include` or `embed`, both are based on country an language: `{% include '@c975LSite/models/COUNTRY/LANGUAGE/terms-of-sales.html.twig' %}`. You can see an example below for `Terms of sale` for `France` in `fr` (french).\n\nIf you have a **multlingual website** you can call by ommitting the language `{% include '@c975LSite/models/COUNTRY/terms-of-sales.html.twig' %}`, SiteBundle will check if your current language is available and will display it, or will display the default language if not.\n\n## Use whole file (include)\n\nYou want to use the whole file, place this code in your template:\n\n```twig\n{% extends 'YOUR_LAYOUT.html.twig' %}\n\n{% trans_default_domain 'site' %}\n{# Title value is made of 'label.' + name of page, replacing \"-\" by \"_\" #}\n{# i.e. page 'terms-of-sales' gives title = 'label.terms_of_sales' #}\n{% set title = 'label.terms_of_sales'|trans %}\n\n{% block content %}\n    {# set the defined data (indicated at the top of the template file) before including #}\n    {% set latestUpdate = '2018-03-08' %}\n\n    {% include '@c975LSite/models/france/fr/terms-of-sales.html.twig' %}\n\n    {# You can your own data at the end #}\n    \u003ch2\u003eAchat de crédits\u003c/h2\u003e\n    \u003cp class=\"text-justify\"\u003e\n        L’achat de crédits ...\n    \u003c/p\u003e\n{% endblock %}\n```\n\n### Select blocks (embed)\n\nYou want to select the displayed blocks, place this code in your template. **Note** that you have to specify the language in the `embed` function:\n\n```twig\n{% extends 'YOUR_LAYOUT.html.twig' %}\n\n{% trans_default_domain 'site' %}\n{% set title = 'label.terms_of_sales'|trans %}\n\n{% block content %}\n    {# set the defined data (indicated at the top of the template file) before including #}\n    {% set latestUpdate = '2018-03-08' %}\n\n    {% embed '@c975LSite/models/france/fr/terms-of-sales.html.twig' %}\n        {# Then you can disable block #}\n        {% block acceptation %}\n        {% endblock %}\n\n        {# Or append information to it #}\n        {% block acceptation %}\n            {{ parent() }}\n            Your added content\n        {% endblock %}\n\n        {# Or replace content #}\n        {% block acceptation %}\n            Your replacing content\n        {% endblock %}\n    {% endembed %}\n{% endblock %}\n\n```\n\n### Available models\n\nYou can find below a table containing all the models available per country and language. **Feel free to update them, add translations or countries.** By convention files are named using \"-\" with the english name.\n\n| Model          | France |\n|---             |---     |\n| Cookies        | fr     |\n| Copyright      | fr     |\n| Legal notice   | fr     |\n| Privacy policy | fr     |\n| Tems of sales  | fr     |\n| Tems of use    | fr     |\n\nTo facilitate reading, models are also available in Markdown format. If you do a modification, you can use Command `php bin/console models:twig2md` to convert Twig models templates to their Markdown equivalent.\n\nIf this project **help you to reduce time to develop**, you can sponsor me via the \"Sponsor\" button at the top :)\n\n### AssetController\n\nYou can use this route to serve an asset file, by using the following code in your Twig template: `{{ path('asset_file', {'file': 'your/path/your_file.ext[.ext2]'}) }}`.\n\nfile name can contain uppercase, lowercase, accented letters, \"-\", \"_\", \"/\", \"\\\", only spaces are not allowed. You can also use 2 file extensions.\n\nThis will be helpful if you want to give access to your assets to registered users. You simply need to add `- { path: ^/your/path, roles: ROLE_USER }` to `config/packages/security.yaml` \u003e `access_control`part. And you can add an http basic authentication on the asset folder itself.\n\n### DownloadController\n\nYou can use this route to force the download of an asset file, by using the following code in your Twig template: `{{ path('download_file', {'file': 'your/path/your_file.ext[.ext2]'}) }}`.\n\nfile name can contain uppercase, lowercase, accented letters, \"-\", \"_\", \"/\", \"\\\", only spaces are not allowed. You can also use 2 file extensions.\n\nThis will be helpful in case of text files like json or whatever.nt to give access to your assets to registered users. You can also protect your route by adding `- { path: ^/your/path, roles: ROLE_USER }` to `config/packages/security.yaml` \u003e `access_control`part. And you can add an http basic authentication on the download folder itself.\n\n### Twig Components\n\nSome Twig components are available, check `templates/components` to see them. An example of use is in each component file.\n\n\n### Resize image\n\nIf you want to resize an image, you can do the following:\n\n```php\nuse c975L\\SiteBundle\\Service\\ServiceImageInterface;\n\nclass YourClass\n{\n    private $imageService;\n\n    public yourMethod(ServiceImageInterface $imageService)\n    {\n        //Do your stuff...\n\n        //Resizes image\n        $imageService-\u003eresize($file, string $folder, string $filename, string $format = 'jpg', int $finalHeight = 400, int $compression = 75, bool $square = false, $stamp = null);\n    }\n}\n```\n\n### Create Flash message\n\nIf you want to create a flash message, you can do the following:\n\n```php\nuse c975L\\SiteBundle\\Service\\ServiceToolsInterface;\n\nclass YourClass\n{\n    private $toolsService;\n\n    public yourMethod(ServiceToolsInterface $toolsService)\n    {\n        //Do your stuff...\n\n        //Create flash\n        $toolsService-\u003ecreateFlash(string $translationDomain = null, string $text, string $style = 'success', array $options = array());\n    }\n}\n```\n\n## `.sh` scripts\n\nThese scripts are not directly related to Symfony but to its production steps for `GitHookPostUpdate.sh` and its backup `BackupXXX.sh`. **They are programmed to work on the Synfony 4(flex) structure AND on a GNU/Linux server. You can find more information on them below.\n\n### GitHookPostUpdate.sh\n\nThis script is to be run after the Git repository has been updated (via `git pull`), for this, it's call should be placed in the `.git/hooks/post-update` file with the following code:\n\n```bash\n#!/bin/bash\nFolder=\"$( cd \"$(dirname \"${BASH_SOURCE[0]}\")\"; pwd -P )\";\n#YOUR_PHP_VERSION is the name of the php binary you will use i.e. `php-7.3`\nsource $Folder/../../PATH_TO_ROOT_FOLDER/vendor/c975l/site-bundle/Scripts/GitHookPostUpdate.sh YOUR_PHP_VERSION;\nexit 0\n```\n\n### ImportSqlFile.sh\n\nThis script is useful if you store some SQL queries in a file to allow bulk import directly to MySql server. The script will rename the imported file (must be \"/var/tmp/sqlFile.sql\") before processing, to avoid collisions, and will rename it, after, with date and time. You can then simply add a new cron with the following code:\n\n```bash\nMAILTO=YOUR_EMAIL_ADDRESS\n*/20    *       *       *       *       bash ~/run.as/httpdocs/vendor/c975l/site-bundle/Scripts/ImportSqlFile.sh 1\u003e /dev/null\n```\n\nIt will also delete files older than 7 days. It uses the data define in `/config/backup_config.cnf`, see below.\n\n### BackupXXX.sh\n\nThese scripts helps for the backup of a website, they are detailed below. The backup files are stored in `/var/backup/{year}/[year-month]/{year-month-day}`. The files are named using the following scheme: \"[MYSQL|WEBSITE]_-_NAME_-_YYYY-MM-DD_-_HH-II_-_[WithoutArchives|Archives|Complete|Partial].tar.bz2\".\n\nYou can include them in a crontab like in the following to execute each hour between 06 and 22 at the 15 minute:\n\n```bash\nMAILTO=YOUR_EMAIL_ADDRESS\n15       6-22       *       *       *       bash /server_path_website/vendor/c975l/site-bundle/Scripts/BackupXXX.sh\n```\n\nAn email wil be sent via cron on each error and only once a day (at the hour specified in config file, see below) to sum up the backup actions.\n\nYou have to create a config file `/config/backup_config.cnf` with the following data (without space) **Keep in mind to add this file to your `.gitignore`**:\n\n```txt\n[client]\nuser=DB_USER\npassword=DB_PASSWORD\nhost=DB_HOST\n[config]\nwebsite=WEBSITE_NAME\ndatabase=DATABASE_NAME\nday=DAY_FOR_COMPLETE_BACKUP\nhour=HOUR_FOR_COMPLETE_BACKUP This hour has to be one of which the cron will be launched otherwise it will never be reached\n```\n\n### BackupServer.sh\n\nThis script groups calls for `BackupMysql.sh` and `BackupFiles.sh` to allow only one crontab but they can be called individually.\n\n### BackupMysql.sh\n\nThis script makes a backup of the tables in MySql server. All the tables are mysqldumped (one by one, to allow restore table by table) at each run, except those named with `_archives` which occurs once a day at the hour specified in `/config/backup_config.cnf`. There is also a mysqldump of the whole database, at the same hour specified as for `*_archives`, to allow a restore with only one file. The format used for the naming is \"NAME_-_TABLE.sql\".\n\n### BackupFolders.sh\n\nThis script makes a backup of the `public` folder. There is a complete backup once a week and a partial backup (only new and newer files) other times.\nYou can specify a list of patterns to exclude, separated with lines break, in a file named `/config/backup_exclude.cnf` i.e `*/folder_to_exclude`.\n\n## Twig Extensions\n\nUsing the provided Twig extension `RouteExists` you can check via `{% if route_exists('YOUR_ROUTE_TO_CHECK') %}` if the Route is available.\n\nUsing the provided Twig extension `TemplateExists` you can check via `{% if template_exists('YOUR_TEMPLATE_TO_CHECK') %}` if the template is available.\n\n## Lists\n\nYou can use the provided lists:\n\n- extensions\n- bots\nto check against. They can be called by the following code (requires [c975L/ConfigBundle](https://github.com/975L/ConfigBUndle)):\n\n```php\nuse c975L\\ConfigBundle\\Service\\ConfigServiceInterface;\n\nclass YourClass\n{\n    private $configService;\n\n    public function __construct(ConfigServiceInterface $configService)\n    {\n        $this-\u003econfigService = $configService;\n    }\n\n    public function yourMethod()\n    {\n        $extensions = file($this-\u003econfigService-\u003egetContainerParameter('kernel.project_dir') . '/../vendor/c975l/site-bundle/Lists/extensions.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);\n        if (in_array('txt', $extensions)) {\n            //Do your stuff\n        }\n    }\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F975l%2Fsitebundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F975l%2Fsitebundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F975l%2Fsitebundle/lists"}