web_10 #30

Merged
Andrei-10 merged 10 commits from web_10 into master 2 months ago
  1. 118
      .gitignore
  2. 4
      wp-content/themes/cosmopet-timber/.gitattributes
  3. 35
      wp-content/themes/cosmopet-timber/.github/PULL_REQUEST_TEMPLATE.md
  4. 76
      wp-content/themes/cosmopet-timber/.github/workflows/test.yml
  5. 4
      wp-content/themes/cosmopet-timber/.gitignore
  6. 11
      wp-content/themes/cosmopet-timber/404.php
  7. 7
      wp-content/themes/cosmopet-timber/LICENSE
  8. 36
      wp-content/themes/cosmopet-timber/README.md
  9. 39
      wp-content/themes/cosmopet-timber/archive.php
  10. 0
      wp-content/themes/cosmopet-timber/assets/fonts/.gitkeep
  11. 0
      wp-content/themes/cosmopet-timber/assets/images/.gitkeep
  12. 5
      wp-content/themes/cosmopet-timber/assets/scripts/site.js
  13. 0
      wp-content/themes/cosmopet-timber/assets/styles/.gitkeep
  14. 18
      wp-content/themes/cosmopet-timber/author.php
  15. 75
      wp-content/themes/cosmopet-timber/composer.json
  16. 19
      wp-content/themes/cosmopet-timber/functions.php
  17. 10
      wp-content/themes/cosmopet-timber/humans.txt
  18. 27
      wp-content/themes/cosmopet-timber/index.php
  19. 17
      wp-content/themes/cosmopet-timber/page.php
  20. 32
      wp-content/themes/cosmopet-timber/phpcs.xml.dist
  21. 15
      wp-content/themes/cosmopet-timber/phpstan.neon
  22. 14
      wp-content/themes/cosmopet-timber/phpunit.xml
  23. BIN
      wp-content/themes/cosmopet-timber/screenshot.png
  24. 18
      wp-content/themes/cosmopet-timber/search.php
  25. 20
      wp-content/themes/cosmopet-timber/single.php
  26. 186
      wp-content/themes/cosmopet-timber/src/StarterSite.php
  27. 5
      wp-content/themes/cosmopet-timber/src/style.css
  28. 5
      wp-content/themes/cosmopet-timber/style.css
  29. 28
      wp-content/themes/cosmopet-timber/tests/bootstrap.php
  30. 64
      wp-content/themes/cosmopet-timber/tests/test-timber-starter-theme.php
  31. 43
      wp-content/themes/cosmopet-timber/views/layouts/base.twig
  32. 32
      wp-content/themes/cosmopet-timber/views/partials/comment-form.twig
  33. 19
      wp-content/themes/cosmopet-timber/views/partials/comment.twig
  34. 1
      wp-content/themes/cosmopet-timber/views/partials/footer.twig
  35. 9
      wp-content/themes/cosmopet-timber/views/partials/head.twig
  36. 12
      wp-content/themes/cosmopet-timber/views/partials/menu.twig
  37. 44
      wp-content/themes/cosmopet-timber/views/partials/pagination.twig
  38. 16
      wp-content/themes/cosmopet-timber/views/partials/tease-post.twig
  39. 9
      wp-content/themes/cosmopet-timber/views/partials/tease.twig
  40. 5
      wp-content/themes/cosmopet-timber/views/templates/404.twig
  41. 15
      wp-content/themes/cosmopet-timber/views/templates/archive.twig
  42. 7
      wp-content/themes/cosmopet-timber/views/templates/author.twig
  43. 16
      wp-content/themes/cosmopet-timber/views/templates/index.twig
  44. 12
      wp-content/themes/cosmopet-timber/views/templates/page.twig
  45. 18
      wp-content/themes/cosmopet-timber/views/templates/search.twig
  46. 17
      wp-content/themes/cosmopet-timber/views/templates/single-password.twig
  47. 37
      wp-content/themes/cosmopet-timber/views/templates/single.twig
  48. 12
      wp-content/themes/cosmopet/functions.php
  49. 202
      wp-content/themes/cosmopet/modules/footer/module-ajax-controller.php
  50. 181
      wp-content/themes/cosmopet/modules/footer/module-controller.php
  51. 9
      wp-content/themes/cosmopet/modules/layout/assets/css/gp-style-core.css
  52. 11
      wp-content/themes/cosmopet/modules/layout/assets/img/svg/main/black-x.svg
  53. 20
      wp-content/themes/cosmopet/modules/layout/assets/js/gp-main.js
  54. 3
      wp-content/themes/cosmopet/modules/shop/components/cart/assets/js/cart.js
  55. 172
      wp-content/themes/cosmopet/modules/shop/components/checkout/assets/js/script.js
  56. 5
      wp-content/themes/cosmopet/modules/shop/components/single-product/assets/css/gp-style-core.css
  57. 10
      wp-content/themes/cosmopet/modules/shop/components/single-product/component-template.twig
  58. 5
      wp-content/themes/cosmopet/modules/shop/module-ajax-controller.php
  59. 29
      wp-content/themes/cosmopet/static/front-page/js/main.js
  60. 0
      wp-content/themes/cosmopet/static/front-page/js/materialize.min.js
  61. 12
      wp-content/themes/cosmopet/templates/footer.twig
  62. 17
      wp-content/themes/cosmopet/templates/front-page/template-front-page.php
  63. 25
      wp-content/themes/cosmopet/templates/modal/basket.twig
  64. 48
      wp-content/themes/cosmopet/templates/pet-card.twig
  65. 184
      wp-content/themes/cosmopet/templates/profile/profile.twig
  66. 24
      wp-content/themes/cosmopet/templates/shop/cart-bottom.twig
  67. 2
      wp-content/themes/cosmopet/templates/shop/checkout.twig

118
.gitignore vendored

@ -1,11 +1,15 @@
# ---> WordPress
# Wordpress - ignore core, configuration, examples, uploads and logs.
# https://github.com/github/gitignore/blob/main/WordPress.gitignore
# htaccess
.htaccess
# GP | SEO
sitemap*.xml
!robots.txt
yandex_*.html
google_*.html
yandex_turbo.xml
turbo_yandex.xml
# Core
#
# Note: if you want to stage/commit WP core files
# you can delete this whole section/until Configuration.
/wp-admin/
/wp-content/index.php
/wp-content/languages
@ -20,6 +24,11 @@
# Configuration
wp-config.php
wp-config-sample.php
#plugins
wp-content/plugins/*
/wp-content/plugins/*
# Example themes
/wp-content/themes/twenty*/
@ -29,26 +38,85 @@ wp-config.php
# Uploads
/wp-content/uploads/
!/wp-content/uploads/elementor
/wp-content/uploads-webpc/
# Log files
*.log
# htaccess
/.htaccess
/*/.htaccess
# vendor files in themes
/wp-content/themes/*/vendor
# All plugins
#
# Note: If you wish to whitelist plugins,
/wp-content/plugins
/wp-content/backups-dup-lite
/wp-content/ai1wm-backups
/wp-content/uploads-webpc
# All themes
#
# Note: If you wish to whitelist themes,
# uncomment the next line
#/wp-content/themes
# GP | Files ext
*.sql
*.tgz
*.tar.gz
*.tar
*.rar
*.zip
*.mp3
*.mp4
*.webm
*.mov
*.MOV
*.wav
*.flv
*.db
*.psd
*.pdf
*.doc
*.docx
*.txt
*.text
*.log
*.config
*.xml
*.tbk
*.csv
*.json
*.BAK
# GP | Dirs & files
bower_components/
node_modules/
nbproject/
cache/
.cache/
phpMyAdmin-*
timthumb_cache/
webstat/
.idea/
.tmb/
.csscomb.json
sftp-config.json
bower.json
.bowerrc
backup_rsync/
.bash_history
.idea/
.fleet/
.DS_Store
.config/
.bash*
.vim*
test/
test*.php
gp-test*/
gp-test*.php
*/ewww/
.*_lock
db.php
*/w3tc*
*/wpvivid*
*/mu-plugins/
vendor/
wp-content/webp*
# GP | Duplicator
dup-installer/
*archive.daf
installer*
wp-content/backups-dup-lite/
# GP | Query Monitor
wp-content/db.php
# Node-js скрипт для индексации 100 url в сутки
.google-indexing/

@ -1,4 +0,0 @@
/.gitattributes export-ignore
/.github export-ignore
/tests export-ignore
/phpunit.xml

@ -1,35 +0,0 @@
<!--
First off, hello!
Thanks for submitting a PR. We love/welcome PRs (especially if it's your first).
-->
<!-- Remove this if no related tickets exist. -->
<!-- You can add the related ticket numbers here using #. Example: #2471 -->
Related:
- Ticket 1
- Ticket 2
## Issue
<!-- Description of the problem that this code change is solving -->
## Solution
<!-- Description of the solution that this code changes are introducing to the application. -->
## Impact
<!-- What impact will this have on the current codebase, performance, backwards compatibility? -->
## Usage Changes
<!-- Are there are any usage changes that we need to know about? If so, list them here so that we can integrate it in the release notes and developers know what usage changes are associated to your PR.
-->
## Considerations
<!-- As we do not live in an ideal world it's worth to share your thought on how we could make the solution even better. -->
## Testing
<!-- Are unit tests included? If they need to be written, please provide pseudo code for a scenario that fails without your code, but succeeds with it -->

@ -1,76 +0,0 @@
name: Timber starter theme tests
on:
push:
branches:
- '1.x'
- '2.x'
pull_request:
types:
- opened
- synchronize
- ready_for_review
# Cancel previous workflow run groups that have not completed.
concurrency:
# Group workflow runs by workflow name, along with the head branch ref of the pull request
# or otherwise the branch or tag ref.
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
phpunit:
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
matrix:
php: ['8.1', '8.2']
wp: ['latest']
multisite: ['0', '1']
extensions: ['gd']
experimental: [false]
include:
# PHP 8.2 / experimental
- php: '8.2'
wp: 'trunk'
dependency-version: 'highest'
multisite: '0'
experimental: true
# PHP 8.3 / experimental
- php: '8.3'
wp: 'trunk'
dependency-version: 'highest'
multisite: '0'
experimental: true
# Coverage
- php: '8.1'
wp: 'latest'
dependency-version: 'highest'
multisite: '0'
experimental: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: composer:v2
extensions: curl, date, dom, iconv, json, libxml, gd
- name: Setup problem matchers for PHP
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
- name: Setup problem matchers for PHPUnit
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
- uses: ramsey/composer-install@v3
- name: Run tests
run: composer run test
env:
WP_MULTISITE: ${{ matrix.multisite }}

@ -1,4 +0,0 @@
/composer.lock
/vendor/
/wordpress/
.phpunit.result.cache

@ -1,11 +0,0 @@
<?php
/**
* The template for the 404 page
*/
namespace App;
use Timber\Timber;
$context = Timber::context();
Timber::render( 'templates/404.twig', $context );

@ -1,7 +0,0 @@
Copyright (c) 2012-2024 Timber team
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -1,36 +0,0 @@
# The Timber Starter Theme
[![Build Status](https://travis-ci.com/timber/starter-theme.svg?branch=master)](https://travis-ci.com/github/timber/starter-theme)
[![Packagist Version](https://img.shields.io/packagist/v/timber/starter-theme?include_prereleases)](https://packagist.org/packages/timber/starter-theme)
The "_s" for Timber: a dead-simple theme that you can build from. The primary purpose of this theme is to provide a file structure rather than a framework for markup or styles. Configure your SASS files, scripts, and task runners however you would like!
## Installing the theme
Follow the guide on [how to Install Timber using the Starter Theme](https://timber.github.io/docs/v2/installation/installation/#use-the-starter-theme).
Then,
1. Rename the theme folder to something that makes sense for your website. You could keep the name `timber-starter-theme` but the point of a starter theme is to make it your own!
2. Activate the theme in the WordPress Dashboard under **Appearance → Themes**.
3. Do your thing! And read [the docs](https://timber.github.io/docs/).
## The `StarterSite` class
In **functions.php**, we call `new StarterSite();`. The `StarterSite` class sits in the **src** folder. You can update this class to add functionality to your theme. This approach is just one example for how you could do it.
The **src** folder would be the right place to put your classes that [extend Timber’s functionality](https://timber.github.io/docs/v2/guides/extending-timber/).
Small tip: You can make use of Composer’s [autoloading functionality](https://getcomposer.org/doc/04-schema.md#psr-4) to automatically load your PHP classes when they are requested instead of requiring one by one in **functions.php**.
## What else is there?
- `assets/` is where you can keep your front-end scripts, styles, or images. In other words, your Sass files, JS files, fonts, and SVGs would live here.
- `views/` contains all of your Twig templates. These pretty much correspond 1 to 1 with the PHP files that respond to the WordPress template hierarchy. At the end of each PHP template, you’ll notice a `Timber::render()` function whose first parameter is the Twig file where that data (or `$context`) will be used. Just an FYI.
- `tests/` ... basically don’t worry about (or remove) this unless you know what it is and want to.
## Other Resources
* [Twig for Timber Cheatsheet](https://notlaura.com/the-twig-for-timber-cheatsheet/)
* [Timber and Twig Reignited My Love for WordPress](https://css-tricks.com/timber-and-twig-reignited-my-love-for-wordpress/) on CSS-Tricks
* [A real live Timber theme](https://github.com/laras126/yuling-theme).

@ -1,39 +0,0 @@
<?php
/**
* The template for displaying Archive pages.
*
* Used to display archive-type pages if nothing more specific matches a query.
* For example, puts together date-based pages if no date.php file exists.
*
* Learn more: https://developer.wordpress.org/themes/basics/template-hierarchy/
*/
namespace App;
use Timber\Timber;
$templates = [ 'templates/archive.twig', 'templates/index.twig' ];
$title = 'Archive';
if ( is_day() ) {
$title = 'Archive: ' . get_the_date( 'D M Y' );
} elseif ( is_month() ) {
$title = 'Archive: ' . get_the_date( 'M Y' );
} elseif ( is_year() ) {
$title = 'Archive: ' . get_the_date( 'Y' );
} elseif ( is_tag() ) {
$title = single_tag_title( '', false );
} elseif ( is_category() ) {
$title = single_cat_title( '', false );
} elseif ( is_post_type_archive() ) {
$title = post_type_archive_title( '', false );
array_unshift( $templates, 'templates/archive-' . get_post_type() . '.twig' );
}
$context = Timber::context(
[
'title' => $title,
]
);
Timber::render( $templates, $context );

@ -1,5 +0,0 @@
jQuery( document ).ready( function( $ ) {
// Your JavaScript goes here
});

@ -1,18 +0,0 @@
<?php
/**
* The template for displaying Author Archive pages
*
* Methods for TimberHelper can be found in the /lib sub-directory
*/
namespace App;
use Timber\Timber;
$context = Timber::context();
if ( isset( $context['author'] ) ) {
$context['title'] = sprintf( __( 'Archive of %s', 'timber-starter' ), $context['author']->name() );
}
Timber::render( [ 'templates/author.twig', 'templates/archive.twig' ], $context );

@ -1,75 +0,0 @@
{
"name": "timber/starter-theme",
"description": "Starter theme to build a Timber theme",
"type":"wordpress-theme",
"license": "MIT",
"authors": [
{
"name": "Erik van der Bas",
"email": "erik@basedonline.nl",
"homepage": "https://basedonline.nl"
},
{
"name": "Lukas Gächter",
"email": "lukas.gaechter@mind.ch",
"homepage": "https://www.mind.ch"
},
{
"name": "Nicolas Lemoine",
"email": "nico@n5s.dev",
"homepage": "https://n5s.dev"
},
{
"name": "Jared Novack",
"email": "jared@upstatement.com",
"homepage": "https://upstatement.com"
},
{
"name": "Timber Community",
"homepage": "https://github.com/timber/timber"
}
],
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org"
}
],
"require": {
"timber/timber": "^2.1"
},
"require-dev": {
"automattic/wordbless": "^0.4.2",
"yoast/wp-test-utils": "^1.0",
"wp-coding-standards/wpcs": "^3.1",
"phpcompatibility/php-compatibility": "^9",
"szepeviktor/phpstan-wordpress": "^1.3",
"10up/phpcs-composer": "^3.0"
},
"extra": {
"installer-paths": {
"vendor/automattic/wordbless/": [
"automattic/wordbless"
]
},
"wordpress-install-dir": "wordpress"
},
"config": {
"allow-plugins": {
"roots/wordpress-core-installer": true,
"composer/installers": true,
"dealerdirect/phpcodesniffer-composer-installer": true
}
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"scripts": {
"test": "phpunit",
"cs": "@php ./vendor/bin/phpcs --colors -s -p -v ./",
"cs:fix": "@php ./vendor/bin/phpcbf --colors -s -p -v ./",
"phpstan": "@php ./vendor/bin/phpstan analyse"
}
}

@ -1,19 +0,0 @@
<?php
/**
* Functions and definitions
*
* @link https://developer.wordpress.org/themes/basics/theme-functions/
* @link https://github.com/timber/starter-theme
*/
namespace App;
use Timber\Timber;
// Load Composer dependencies.
require_once __DIR__ . '/vendor/autoload.php';
Timber::init();
new StarterSite();

@ -1,10 +0,0 @@
## Team
Your name or company
https://yoursite.example
@your_twitter_handle
## Site
Software: Built with [Timber](https://upstatement.com/timber/) by Upstatement

@ -1,27 +0,0 @@
<?php
/**
* The main template file
*
* This is the most generic template file in a WordPress theme
* and one of the two required files for a theme (the other being style.css).
* It is used to display a page when nothing more specific matches a query.
* E.g., it puts together the home page when no home.php file exists.
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*/
use Timber\Timber;
$templates = [ 'templates/index.twig' ];
if ( is_home() ) {
array_unshift( $templates, 'templates/front-page.twig', 'templates/home.twig' );
}
$context = Timber::context(
[
'foo' => 'bar',
]
);
Timber::render( $templates, $context );

@ -1,17 +0,0 @@
<?php
/**
* The template for displaying all pages.
*
* This is the template that displays all pages by default.
* Please note that this is the WordPress construct of pages
* and that other 'pages' on your WordPress site will use a
* different template.
*/
namespace App;
use Timber\Timber;
$context = Timber::context();
Timber::render( 'templates/page.twig', $context );

@ -1,32 +0,0 @@
<?xml version="1.0"?>
<ruleset>
<!-- Files or directories to check -->
<file>.</file>
<exclude-pattern>*/node_modules/*</exclude-pattern>
<exclude-pattern>*/wordpress/*</exclude-pattern>
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/resources/*</exclude-pattern>
<exclude-pattern>*/dist/*</exclude-pattern>
<exclude-pattern>*/tests/*</exclude-pattern>
<!-- Path to strip from the front of file paths inside reports (displays shorter paths) -->
<arg name="basepath" value="." />
<!-- Set a minimum PHP version for PHPCompatibility -->
<config name="testVersion" value="8.1-" />
<!-- Use 10up's phpcs ruleset -->
<rule ref="10up-Default">
<exclude name="Squiz.Commenting.FileComment.MissingPackageTag"/>
<exclude name="WordPress.WP.I18n.MissingTranslatorsComment"/>
</rule>
<!-- Set the text domain to timber-starter -->
<rule ref="WordPress.WP.I18n">
<properties>
<property name="text_domain" type="array" value="timber-starter"/>
</properties>
</rule>
</ruleset>

@ -1,15 +0,0 @@
parameters:
editorUrl: 'vscode://file/%%file%%:%%line%%'
level: 5 # Increase until "max"
paths:
- src/
- %currentWorkingDirectory%/
excludePaths:
- tests/*
- docs/*
- vendor/*
- wordpress/*
ignoreErrors:
includes:
- vendor/szepeviktor/phpstan-wordpress/extension.neon

@ -1,14 +0,0 @@
<phpunit
bootstrap="tests/bootstrap.php"
backupGlobals="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
>
<testsuites>
<testsuite name="all">
<directory prefix="test-" suffix=".php">./tests/</directory>
</testsuite>
</testsuites>
</phpunit>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

@ -1,18 +0,0 @@
<?php
/**
* Search results page
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*/
use Timber\Timber;
$templates = [ 'templates/search.twig', 'templates/archive.twig', 'templates/index.twig' ];
$context = Timber::context(
[
'title' => 'Search results for ' . get_search_query(),
]
);
Timber::render( $templates, $context );

@ -1,20 +0,0 @@
<?php
/**
* The Template for displaying all single posts
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*/
namespace App;
use Timber\Timber;
$context = Timber::context();
$post = $context['post'];
$templates = [ 'templates/single-' . $post->post_type . '.twig', 'templates/single.twig' ];
if ( post_password_required( $post->ID ) ) {
$templates = 'templates/single-password.twig';
}
Timber::render( $templates, $context );

@ -1,186 +0,0 @@
<?php
/**
* StarterSite class
* This class is used to add custom functionality to the theme.
*/
namespace App;
use Timber\Site;
use Timber\Timber;
use Twig\Environment;
use Twig\TwigFilter;
/**
* Class StarterSite.
*/
class StarterSite extends Site {
/**
* StarterSite constructor.
*/
public function __construct() {
add_action( 'after_setup_theme', [ $this, 'theme_supports' ] );
add_action( 'init', [ $this, 'register_post_types' ] );
add_action( 'init', [ $this, 'register_taxonomies' ] );
add_filter( 'timber/context', [ $this, 'add_to_context' ] );
add_filter( 'timber/twig/filters', [ $this, 'add_filters_to_twig' ] );
add_filter( 'timber/twig/functions', [ $this, 'add_functions_to_twig' ] );
add_filter( 'timber/twig/environment/options', [ $this, 'update_twig_environment_options' ] );
parent::__construct();
}
/**
* This is where you can register custom post types.
*/
public function register_post_types() {}
/**
* This is where you can register custom taxonomies.
*/
public function register_taxonomies() {}
/**
* This is where you add some context.
*
* @param array $context context['this'] Being the Twig's {{ this }}
*/
public function add_to_context( $context ) {
$context['foo'] = 'bar';
$context['stuff'] = 'I am a value set in your functions.php file';
$context['notes'] = 'These values are available everytime you call Timber::context();';
$context['menu'] = Timber::get_menu( 'primary_navigation' );
$context['site'] = $this;
return $context;
}
/**
* This is where you can add your theme supports.
*/
public function theme_supports() {
// Register navigation menus
register_nav_menus(
[
'primary_navigation' => _x( 'Main menu', 'Backend - menu name', 'timber-starter' ),
]
);
// Add default posts and comments RSS feed links to head.
add_theme_support( 'automatic-feed-links' );
/*
* Let WordPress manage the document title.
* By adding theme support, we declare that this theme does not use a
* hard-coded <title> tag in the document head, and expect WordPress to
* provide it for us.
*/
add_theme_support( 'title-tag' );
/*
* Enable support for Post Thumbnails on posts and pages.
*
* @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
*/
add_theme_support( 'post-thumbnails' );
/*
* Switch default core markup for search form, comment form, and comments
* to output valid HTML5.
*/
add_theme_support(
'html5',
[
'comment-form',
'comment-list',
'gallery',
'caption',
]
);
/*
* Enable support for Post Formats.
*
* See: https://codex.wordpress.org/Post_Formats
*/
add_theme_support(
'post-formats',
[
'aside',
'image',
'video',
'quote',
'link',
'gallery',
'audio',
]
);
add_theme_support( 'menus' );
}
/**
* This would return 'foo bar!'.
*
* @param string $text being 'foo', then returned 'foo bar!'
*/
public function myfoo( $text ) {
$text .= ' bar!';
return $text;
}
/**
* This is where you can add your own functions to twig.
*
* @link https://timber.github.io/docs/v2/hooks/filters/#timber/twig/filters
* @param array $filters an array of Twig filters.
*/
public function add_filters_to_twig( $filters ) {
$additional_filters = [
'myfoo' => [
'callable' => [ $this, 'myfoo' ],
],
];
return array_merge( $filters, $additional_filters );
}
/**
* This is where you can add your own functions to twig.
*
* @link https://timber.github.io/docs/v2/hooks/filters/#timber/twig/functions
* @param array $functions an array of existing Twig functions.
*/
public function add_functions_to_twig( $functions ) {
$additional_functions = [
'get_theme_mod' => [
'callable' => 'get_theme_mod',
],
];
return array_merge( $functions, $additional_functions );
}
/**
* Updates Twig environment options.
*
* @see https://twig.symfony.com/doc/2.x/api.html#environment-options
*
* @param array $options an array of environment options
*
* @return array
*/
public function update_twig_environment_options( $options ) {
// $options['autoescape'] = true;
return $options;
}
}

@ -1,5 +0,0 @@
/*
* Theme Name: Cosmopet Theme
* Description: Boilerplate Theme for Cosmopet site
* Author: Good Production
*/

@ -1,5 +0,0 @@
/*
* Theme Name: Cosmopet Theme
* Description: Boilerplate Theme for Cosmopet site
* Author: Good Production
*/

@ -1,28 +0,0 @@
<?php
use WorDBless\Load;
if (! file_exists(dirname(__DIR__) . '/wordpress/wp-content')) {
mkdir(dirname(__DIR__) . '/wordpress/wp-content');
}
if (! file_exists(dirname(__DIR__) . '/wordpress/wp-content/themes')) {
mkdir(dirname(__DIR__) . '/wordpress/wp-content/themes');
}
copy(
dirname(__DIR__) . '/vendor/automattic/wordbless/src/dbless-wpdb.php',
dirname(__DIR__) . '/wordpress/wp-content/db.php'
);
$theme_base_name = basename(dirname(__DIR__));
$src = realpath(dirname(dirname(__DIR__)) . '/' . $theme_base_name);
$dest = dirname(__DIR__) . '/wordpress/wp-content/themes/' . $theme_base_name;
if ( is_dir($src) && ! file_exists($dest) ) {
symlink($src, $dest);
}
require_once dirname(__DIR__) . '/vendor/autoload.php';
Load::load();

@ -1,64 +0,0 @@
<?php
use Timber\Timber;
use WorDBless\BaseTestCase;
class TestTimberStarterTheme extends BaseTestCase
{
public function set_up()
{
switch_theme(basename(dirname(__DIR__)) . '/theme');
require dirname(__DIR__) . '/functions.php';
Timber::$dirname = array_merge((array) Timber::$dirname, ['../views']);
Timber::$dirname = array_unique(Timber::$dirname);
// WorDBless includes wp-settings.php
do_action('after_setup_theme');
parent::set_up();
}
function tear_down()
{
parent::tear_down();
switch_theme('twentytwenty');
}
function testTimberExists()
{
$context = Timber::context();
$this->assertTrue(is_array($context));
}
function testFunctionsPHP()
{
$context = Timber::context();
$this->assertEquals('App\StarterSite', get_class($context['site']));
$this->assertTrue(current_theme_supports('post-thumbnails'));
$this->assertEquals('bar', $context['foo']);
}
function testLoading()
{
$str = Timber::compile('partials/tease.twig');
$this->assertStringStartsWith('<article class="tease tease-" id="tease-">', $str);
$this->assertStringEndsWith('</article>', $str);
}
/**
* Helper test to output current twig version
*/
function testTwigVersion()
{
$version = Timber::compile_string("{{ version }}", ['version' => Twig\Environment::VERSION]);
$this->assertEquals(Twig\Environment::VERSION, $version);
}
// function testTwigFilter() {
// $str = Timber::compile_string('{{ "foo"|myfoo }}');
// $this->assertEquals('foo bar!', $str);
// }
}

@ -1,43 +0,0 @@
<!DOCTYPE html>
<html {{ site.language_attributes }}>
{% block head %}
{% include 'partials/head.twig' %}
{% endblock %}
<body class="{{ body_class }}">
{{ function('wp_body_open') }}
<a class="skip-link screen-reader-text" href="#content">{{ _e('Skip to content') }}</a>
<header class="header">
{% block header %}
<div class="wrapper">
<h1 class="hdr-logo">
<a class="hdr-logo-link" href="{{ site.url }}">{{ site.name }}</a>
</h1>
<nav id="nav-main" class="nav-main">
{% include 'partials/menu.twig' with {
items: menu.get_items
} %}
</nav>
<!-- #nav -->
</div>
{% endblock %}
</header>
<section id="content" class="content-wrapper">
{% if title %}
<h1>{{ title }}</h1>
{% endif %}
<div class="wrapper">
{% block content %}
Sorry, no content
{% endblock %}
</div>
</section>
{% block footer %}
{% include 'partials/footer.twig' %}
{% endblock %}
{{ function('wp_footer') }}
{% do action('get_footer') %}
</body>
</html>

@ -1,32 +0,0 @@
<div class="comment-form">
<h3>Add comment</h3>
<form class="comment-form" method="post" action="{{ site.link ~ '/wp-comments-post.php' }}">
{% if user %}
<input type="hidden" name="email" value="{{ user.email }}" />
<input type="hidden" name="author" value="{{ user.name }}" />
<input type="hidden" name="url" value="{{ user.link }}" />
{% else %}
<label>
Email<br />
<input required name="email" type="email" id="email" />
</label>
<label>
Name<br />
<input required name="author" type="text" />
</label>
<label>
Website<br />
<input name="url" type="url" />
</label>
{% endif %}
<label>
Comment<br />
<textarea placeholder="Leave a comment..." name="comment" cols="60" rows="3"></textarea>
</label>
<input name="comment_post_ID" value="{{ post.id }}" type="hidden" />
<input name="comment_parent" value="{{ comment.id|default('0') }}" type="hidden" />
<button type="submit" name="Submit" class="btn">Send</button>
<button type="reset">Cancel</button>
<p>Your comment will be revised by the site if needed.</p>
</form>
</div>

@ -1,19 +0,0 @@
<div class="blog-comment" id="blog-comment-{{ comment.id }}">
<h5 class="comment-author">{{ comment.author.name }} says</h5>
<div class="comment-content">{{ comment.content|wpautop }}</div>
<section class="comment-box">
{% include 'partials/comment-form.twig' %}
{% if post.comments %}
<h4>replies</h4>
<div class="comments">
{% for cmt in comment.children %}
{% include 'partials/comment.twig' with {
comment: cmt
} %}
{% endfor %}
</div>
{% endif %}
</section>
</div>

@ -1 +0,0 @@
<footer id="footer">Copyright {{ 'now'|date('Y') }}</footer>

@ -1,9 +0,0 @@
<head>
<meta charset="{{ site.charset }}" />
<link rel="stylesheet" href="{{ site.theme.link }}/style.css" type="text/css" media="screen" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="author" href="{{ site.theme.link }}/humans.txt" />
<link rel="profile" href="http://gmpg.org/xfn/11" />
{% do action('get_header') %}
{{ function('wp_head') }}
</head>

@ -1,12 +0,0 @@
{% if menu %}
<ul>
{% for item in items %}
<li class="{{ item.classes|join(' ') }}">
<a target="{{ item.target }}" href="{{ item.link }}">{{ item.title }}</a>
{% include 'partials/menu.twig' with {
items: item.children
} %}
</li>
{% endfor %}
</ul>
{% endif %}

@ -1,44 +0,0 @@
{% if posts.pagination.pages is not empty %}
<nav class="pagination-block">
<ul class="pagination">
{# First #}
{% if (posts.pagination.pages|first) and posts.pagination.pages|first.current != true %}
<li class="first btn">
<a href="{{ posts.pagination.pages|first.link }}">First</a>
</li>
{% else %}
<li class="first btn disabled"><button disabled>First</button></li>
{% endif %}
{# Previous #}
{% if posts.pagination.prev %}
<li class="prev btn"><a href="{{ posts.pagination.prev.link }}">Previous</a></li>
{% else %}
<li class="prev btn disabled"><button disabled>Previous</button></li>
{% endif %}
{# Pages #}
{% for page in posts.pagination.pages %}
{% if page.link %}
<li><a href="{{ page.link }}" class="{{ page.class }}">{{ page.title }}</a></li>
{% else %}
<li class="current"><span class="{{ page.class }}">{{ page.title }}</span></li>
{% endif %}
{% endfor %}
{# Next #}
{% if posts.pagination.next %}
<li class="next btn"><a href="{{ posts.pagination.next.link }}">Next</a></li>
{% else %}
<li class="next btn disabled"><button disabled>Next</button></li>
{% endif %}
{# Last #}
{% if (posts.pagination.pages|last) and posts.pagination.pages|last.current != true %}
<li class="last btn"><a href="{{ posts.pagination.pages|last.link }}">Last</a></li>
{% else %}
<li class="last btn disabled"><button disabled>Last</button></li>
{% endif %}
</ul>
</nav>
{% endif %}

@ -1,16 +0,0 @@
{% extends 'partials/tease.twig' %}
{% block content %}
<h2 class="h2"><a href="{{ post.link }}">{{ post.title }}</a></h2>
<p>
{{
post.excerpt({
words: 5,
read_more: 'Keep reading'
})
}}
</p>
{% if post.thumbnail.src %}
<img src="{{ post.thumbnail.src }}" />
{% endif %}
{% endblock %}

@ -1,9 +0,0 @@
<article class="tease tease-{{ post.type }}" id="tease-{{ post.id }}">
{% block content %}
<h2 class="h2"><a href="{{ post.link }}">{{ post.title }}</a></h2>
<p>{{ post.excerpt }}</p>
{% if post.thumbnail %}
<img src="{{ post.thumbnail.src }}" />
{% endif %}
{% endblock %}
</article>

@ -1,5 +0,0 @@
{% extends 'layouts/base.twig' %}
{% block content %}
Sorry, we couldn't find what you're looking for.
{% endblock %}

@ -1,15 +0,0 @@
{% extends 'layouts/base.twig' %}
{% block content %}
{% for post in posts %}
{% include ['partials/tease-' ~ post.type ~ '.twig', 'partials/tease.twig'] %}
{% endfor %}
{% include 'partials/pagination.twig' with {
pagination: posts.pagination({
show_all: false,
mid_size: 3,
end_size: 2
})
} %}
{% endblock %}

@ -1,7 +0,0 @@
{% extends 'layouts/base.twig' %}
{% block content %}
{% for post in posts %}
{% include ['partials/tease-' ~ post.type ~ '.twig', 'partials/tease.twig'] %}
{% endfor %}
{% endblock %}

@ -1,16 +0,0 @@
{% extends 'layouts/base.twig' %}
{% block content %}
<h2>{{ foo }}</h2>
{% for post in posts %}
{% include ['partials/tease-' ~ post.type ~ '.twig', 'partials/tease.twig'] %}
{% endfor %}
{% include 'partials/pagination.twig' with {
pagination: posts.pagination({
show_all: false,
mid_size: 3,
end_size: 2
})
} %}
{% endblock %}

@ -1,12 +0,0 @@
{% extends 'layouts/base.twig' %}
{% block content %}
<div class="content-wrapper">
<article class="post-type-{{ post.type }}" id="post-{{ post.id }}">
<section class="article-content">
<h1 class="article-h1">{{ post.title }}</h1>
<div class="article-body">{{ post.content }}</div>
</section>
</article>
</div>
{% endblock %}

@ -1,18 +0,0 @@
{# see `templates/archive.twig` for an alternative strategy of extending templates #}
{% extends 'layouts/base.twig' %}
{% block content %}
<div class="content-wrapper">
{% for post in posts %}
{% include ['partials/tease-' ~ post.type ~ '.twig', 'partials/tease.twig'] %}
{% endfor %}
{% include 'partials/pagination.twig' with {
pagination: posts.pagination({
show_all: false,
mid_size: 3,
end_size: 2
})
} %}
</div>
{% endblock %}

@ -1,17 +0,0 @@
{% extends 'layouts/base.twig' %}
{% block content %}
<form class="password-form"
action="{{ site.link }}/wp-login.php?action=postpass"
method="post">
<label for="pwbox-{{ post.id }}">Password:</label>
<input class="password-box"
name="post_password"
id="pwbox-{{ post.id }}"
type="password"
placeholder="Password"
size="20"
maxlength="20" />
<input class="password-btn" type="submit" name="Submit" value="Submit" />
</form>
{% endblock %}

@ -1,37 +0,0 @@
{% extends 'layouts/base.twig' %}
{% block content %}
<div class="content-wrapper">
<article class="post-type-{{ post.type }}" id="post-{{ post.id }}">
<img src="{{ post.thumbnail.src|resize(1200, 300) }}" />
<section class="article-content">
<h1 class="article-h1">{{ post.title }}</h1>
<p class="blog-author">
<span>By</span>
<a href="{{ post.author.path }}">{{ post.author.name }}</a>
<span>&bull;</span>
<time datetime="{{ post.date|date('Y-m-d H:i:s') }}">{{ post.date }}</time>
</p>
<div class="article-body">{{ post.content }}</div>
</section>
<section class="comment-box">
<div class="comments">
{% if post.comments %}
<h3>comments</h3>
{% for cmt in post.comments %}
{% include 'partials/comment.twig' with {
comment: cmt
} %}
{% endfor %}
{% endif %}
</div>
{% if post.comment_status == 'closed' %}
<p>comments for this post are closed</p>
{% else %}
{% include 'partials/comment-form.twig' %}
{% endif %}
</section>
</article>
</div>
{% endblock %}

@ -24,11 +24,11 @@ add_filter( 'timber/integrations', function ( array $integrations ): array {
return $integrations;
} );
function theme_enqueue_scripts() {
// Swiper
wp_enqueue_script( 'gp-front-page-materialize', get_template_directory_uri() . '/modules/layout/assets/js/materialize.min.js', array(), null, true );
}
add_action('wp_enqueue_scripts', 'theme_enqueue_scripts');
// function theme_enqueue_scripts() {
// // Swiper
// wp_enqueue_script( 'gp-front-page-materialize', get_template_directory_uri() . '/modules/layout/assets/js/materialize.min.js', array(), null, true );
// }
// add_action('wp_enqueue_scripts', 'theme_enqueue_scripts');
add_action('timber/init', function() {
@ -434,7 +434,7 @@ require_once('modules/blog/module-ajax-controller.php');
require_once('modules/forms/module-ajax-controller.php');
require_once('modules/shop/module-ajax-controller.php');
require_once('modules/profile/module-ajax-controller.php');
require_once('modules/footer/module-ajax-controller.php');
add_action('wp', 'my_custom_checkout_code');
function my_custom_checkout_code() {

@ -0,0 +1,202 @@
<?php
// Динамическое определение BOT_USERNAME
$site_url = site_url();
if ($site_url === 'https://cosmopet-test-ru.cp.good-production.xyz') {
define('BOT_USERNAME', 'cosmopet_test_RU_bot');
} elseif ($site_url === 'https://cosmopet-test-ae.cp.good-production.xyz') {
define('BOT_USERNAME', 'cosmopet_test_AE_bot');
} else {
define('BOT_USERNAME', 'cosmopet_test_default_bot'); // Фallback на случай других доменов
}
// Функция получения данных Telegram
function getTelegramUserData() {
if (isset($_SESSION['tg_user'])) {
return $_SESSION['tg_user'];
}
return false;
}
// Функция вывода Telegram Widget
function tgWidget() {
if (!is_user_logged_in()) {
?>
<div id="telegram-widget-container"></div>
<?php
} else {
$current_user = wp_get_current_user();
echo "<h1>Hello, " . esc_html($current_user->display_name) . "!</h1>";
echo "<p><a href='" . wp_logout_url() . "'>Log out</a></p>";
}
}
function tgScript(){
$bot_username = BOT_USERNAME;
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
var s = document.createElement('script');
s.src = 'https://telegram.org/js/telegram-widget.js?2';
s.async = true;
s.setAttribute('data-telegram-login', '<?php echo $bot_username?>');
s.setAttribute('data-size', 'large');
s.setAttribute('data-onauth', 'onTelegramAuth(user)');
s.setAttribute('data-request-access', 'write');
document.getElementById('telegram-widget-container').appendChild(s);
});
</script>
<?php
}
// Обработчик авторизации через Telegram
add_action('wp_ajax_ontelegramauth', 'onTelegramAuth');
add_action('wp_ajax_nopriv_ontelegramauth', 'onTelegramAuth');
function onTelegramAuth() {
// Получаем данные от Telegram
$auth_data = [
'id' => sanitize_text_field($_POST['userid']),
'first_name' => sanitize_text_field($_POST['fname']),
'last_name' => sanitize_text_field($_POST['lname']),
'username' => sanitize_text_field($_POST['username'] ?? ''),
];
if (!$auth_data['id']) {
wp_die(json_encode(['status' => 'error', 'message' => 'Invalid Telegram data']));
}
// Проверяем существование пользователя по tg_account
$users = get_users([
'meta_key' => 'tg_account',
'meta_value' => $auth_data['id'],
'number' => 1
]);
$password = wp_generate_password(12, true, false); // Генерация безопасного пароля
if ($users) {
// Существующий пользователь
$user = $users[0];
wp_set_password($password, $user->ID);
$login = wp_signon([
'user_login' => $user->user_login,
'user_password' => $password,
'remember' => true
]);
if (!is_wp_error($login)) {
session_start();
$_SESSION['tg_user'] = $auth_data;
session_write_close();
wp_die(json_encode(['status' => 'success', 'redirect' => admin_url()]));
}
} else {
// Новый пользователь
$username = sanitize_user($auth_data['username'] ?: $auth_data['first_name'] . '_' . $auth_data['last_name'], true);
$username = wp_slash($username); // Экранируем для безопасности
$user_id = wp_create_user($username, $password, $username . '@telegram.com');
if (!is_wp_error($user_id)) {
wp_update_user([
'ID' => $user_id,
'display_name' => $auth_data['first_name'] . ' ' . $auth_data['last_name'],
'first_name' => $auth_data['first_name'],
'last_name' => $auth_data['last_name']
]);
add_user_meta($user_id, 'tg_account', $auth_data['id']);
add_user_meta($user_id, 'tg_username', $auth_data['username']);
$login = wp_signon([
'user_login' => $username,
'user_password' => $password,
'remember' => true
]);
if (!is_wp_error($login)) {
session_start();
$_SESSION['tg_user'] = $auth_data;
session_write_close();
wp_die(json_encode(['status' => 'success', 'redirect' => admin_url()]));
}
}
}
wp_die(json_encode(['status' => 'error', 'message' => 'Login failed']));
}
// Функция привязки Telegram к существующему пользователю
add_action('wp_ajax_linktelegram', 'linkTelegram');
add_action('wp_ajax_nopriv_linktelegram', 'linkTelegram');
function linkTelegram() {
if (!is_user_logged_in()) {
wp_die(json_encode(['status' => 'error', 'message' => 'Not logged in']));
}
$tg_id = sanitize_text_field($_POST['userid']);
$user_id = get_current_user_id();
add_user_meta($user_id, 'tg_account', $tg_id);
wp_update_user([
'ID' => $user_id,
'first_name' => sanitize_text_field($_POST['fname']),
'last_name' => sanitize_text_field($_POST['lname'])
]);
wp_die(json_encode(['status' => 'success']));
}
// Функция обновления email
add_action('wp_ajax_email_link', 'emailLink');
add_action('wp_ajax_nopriv_email_link', 'emailLink');
function emailLink() {
if (!is_user_logged_in()) {
wp_die(json_encode(['status' => 'error', 'message' => 'Not logged in']));
}
$email = sanitize_email($_POST['email']);
$user_id = get_current_user_id();
if (email_exists($email)) {
wp_die(json_encode(['status' => 'error', 'message' => 'Email is already registered']));
}
wp_update_user(['ID' => $user_id, 'user_email' => $email]);
wp_die(json_encode(['status' => 'success']));
}
// Добавление и настройка колонки Telegram
add_filter('manage_users_columns', 'add_tg_account_column');
function add_tg_account_column($columns) {
$columns['tg_username'] = 'Telegram';
return $columns;
}
add_action('manage_users_custom_column', 'add_tg_account_column_content', 10, 3);
function add_tg_account_column_content($value, $column_name, $user_id) {
if ('tg_username' == $column_name) {
$tg_username = get_user_meta($user_id, 'tg_username', true);
return $tg_username ? '<a href="https://t.me/' . esc_attr($tg_username) . '" target="_blank">@' . esc_html($tg_username) . '</a>' : '<span style="color:#ccc;">не указан</span>';
}
return $value;
}
add_filter('manage_users_sortable_columns', 'make_tg_account_column_sortable');
function make_tg_account_column_sortable($columns) {
$columns['tg_username'] = 'tg_username';
return $columns;
}
add_action('pre_get_users', 'handle_tg_account_sorting');
function handle_tg_account_sorting($query) {
if (!is_admin() || !$query->is_main_query()) return;
if ('tg_username' === $query->get('orderby')) {
$query->set('meta_key', 'tg_username');
$query->set('orderby', 'meta_value');
}
}

@ -9,184 +9,3 @@ add_filter('timber/context', function($context) {
return $context;
});
// Динамическое определение BOT_USERNAME
$site_url = site_url();
if ($site_url === 'https://cosmopet-test-ru.cp.good-production.xyz') {
define('BOT_USERNAME', 'cosmopet_test_RU_bot');
} elseif ($site_url === 'https://cosmopet-test-ae.cp.good-production.xyz') {
define('BOT_USERNAME', 'cosmopet_test_AE_bot');
} else {
define('BOT_USERNAME', 'cosmopet_test_default_bot'); // Фallback на случай других доменов
}
// Функция получения данных Telegram
function getTelegramUserData() {
if (isset($_SESSION['tg_user'])) {
return $_SESSION['tg_user'];
}
return false;
}
// Функция вывода Telegram Widget
function tgWidget() {
if (!is_user_logged_in()) {
$bot_username = BOT_USERNAME;
$html = '<script async src="https://telegram.org/js/telegram-widget.js?2" data-telegram-login="' . esc_attr($bot_username) . '" data-size="large" data-onauth="onTelegramAuth(user)" data-request-access="write"></script>';
echo $html;
} else {
$current_user = wp_get_current_user();
$html = "<h1>Hello, " . esc_html($current_user->display_name) . "!</h1>";
$html .= "<p><a href='" . wp_logout_url() . "'>Log out</a></p>";
echo $html;
}
}
// Обработчик авторизации через Telegram
add_action('wp_ajax_ontelegramauth', 'onTelegramAuth');
add_action('wp_ajax_nopriv_ontelegramauth', 'onTelegramAuth');
function onTelegramAuth() {
// Получаем данные от Telegram
$auth_data = [
'id' => sanitize_text_field($_POST['id']),
'first_name' => sanitize_text_field($_POST['first_name']),
'last_name' => sanitize_text_field($_POST['last_name']),
'username' => sanitize_text_field($_POST['username'] ?? ''),
'photo_url' => sanitize_text_field($_POST['photo_url'] ?? '')
];
if (!$auth_data['id']) {
wp_die(json_encode(['status' => 'error', 'message' => 'Invalid Telegram data']));
}
// Проверяем существование пользователя по tg_account
$users = get_users([
'meta_key' => 'tg_account',
'meta_value' => $auth_data['id'],
'number' => 1
]);
$password = wp_generate_password(12, true, false); // Генерация безопасного пароля
if ($users) {
// Существующий пользователь
$user = $users[0];
wp_set_password($password, $user->ID);
$login = wp_signon([
'user_login' => $user->user_login,
'user_password' => $password,
'remember' => true
]);
if (!is_wp_error($login)) {
session_start();
$_SESSION['tg_user'] = $auth_data;
session_write_close();
wp_die(json_encode(['status' => 'success', 'redirect' => admin_url()]));
}
} else {
// Новый пользователь
$username = sanitize_user($auth_data['username'] ?: $auth_data['first_name'] . '_' . $auth_data['last_name'], true);
$username = wp_slash($username); // Экранируем для безопасности
$user_id = wp_create_user($username, $password, $username . '@telegram.com');
if (!is_wp_error($user_id)) {
wp_update_user([
'ID' => $user_id,
'display_name' => $auth_data['first_name'] . ' ' . $auth_data['last_name'],
'first_name' => $auth_data['first_name'],
'last_name' => $auth_data['last_name']
]);
add_user_meta($user_id, 'tg_account', $auth_data['id']);
add_user_meta($user_id, 'tg_username', $auth_data['username']);
$login = wp_signon([
'user_login' => $username,
'user_password' => $password,
'remember' => true
]);
if (!is_wp_error($login)) {
session_start();
$_SESSION['tg_user'] = $auth_data;
session_write_close();
wp_die(json_encode(['status' => 'success', 'redirect' => admin_url()]));
}
}
}
wp_die(json_encode(['status' => 'error', 'message' => 'Login failed']));
}
// Функция привязки Telegram к существующему пользователю
add_action('wp_ajax_linktelegram', 'linkTelegram');
add_action('wp_ajax_nopriv_linktelegram', 'linkTelegram');
function linkTelegram() {
if (!is_user_logged_in()) {
wp_die(json_encode(['status' => 'error', 'message' => 'Not logged in']));
}
$tg_id = sanitize_text_field($_POST['userid']);
$user_id = get_current_user_id();
add_user_meta($user_id, 'tg_account', $tg_id);
wp_update_user([
'ID' => $user_id,
'first_name' => sanitize_text_field($_POST['fname']),
'last_name' => sanitize_text_field($_POST['lname'])
]);
wp_die(json_encode(['status' => 'success']));
}
// Функция обновления email
add_action('wp_ajax_email_link', 'emailLink');
add_action('wp_ajax_nopriv_email_link', 'emailLink');
function emailLink() {
if (!is_user_logged_in()) {
wp_die(json_encode(['status' => 'error', 'message' => 'Not logged in']));
}
$email = sanitize_email($_POST['email']);
$user_id = get_current_user_id();
if (email_exists($email)) {
wp_die(json_encode(['status' => 'error', 'message' => 'Email is already registered']));
}
wp_update_user(['ID' => $user_id, 'user_email' => $email]);
wp_die(json_encode(['status' => 'success']));
}
// Добавление и настройка колонки Telegram
add_filter('manage_users_columns', 'add_tg_account_column');
function add_tg_account_column($columns) {
$columns['tg_username'] = 'Telegram';
return $columns;
}
add_action('manage_users_custom_column', 'add_tg_account_column_content', 10, 3);
function add_tg_account_column_content($value, $column_name, $user_id) {
if ('tg_username' == $column_name) {
$tg_username = get_user_meta($user_id, 'tg_username', true);
return $tg_username ? '<a href="https://t.me/' . esc_attr($tg_username) . '" target="_blank">@' . esc_html($tg_username) . '</a>' : '<span style="color:#ccc;">не указан</span>';
}
return $value;
}
add_filter('manage_users_sortable_columns', 'make_tg_account_column_sortable');
function make_tg_account_column_sortable($columns) {
$columns['tg_username'] = 'tg_username';
return $columns;
}
add_action('pre_get_users', 'handle_tg_account_sorting');
function handle_tg_account_sorting($query) {
if (!is_admin() || !$query->is_main_query()) return;
if ('tg_username' === $query->get('orderby')) {
$query->set('meta_key', 'tg_username');
$query->set('orderby', 'meta_value');
}
}

@ -1270,14 +1270,11 @@ textarea{
}
.toggle::after{
content: '';
position: absolute;
top: 24px;
right: 0;
width: 24px;
aspect-ratio: 1;
background-image: url(../img/svg/main/black-x.svg);
transform: rotate(45deg);
transition: transform .2s;
@ -2178,3 +2175,9 @@ textarea{
}
.modal__button--center{
margin-right: auto;
margin-left: auto;
display: block;
width: max-content;
}

@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_2483)">
<path d="M18 6L6 18" stroke="#121212" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 6L18 18" stroke="#121212" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1_2483">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 455 B

@ -450,26 +450,6 @@ if (document.querySelector('.header').classList.contains('white')) {
// });
// });
var slider = carousel_init();
function carousel_init() {
var carousel = document.querySelectorAll('.carousel');
var options = {
numVisible: window.innerWidth > 421 ? 5 : 3,
indicators: false // Removed dots
};
var instances = M.Carousel.init(carousel, options);
document.querySelectorAll('.about_slider_nav').forEach(btn => {
btn.addEventListener('click', function (e) {
if (e.target.closest('button').classList.contains('next')) {
instances[0].next();
} else {
instances[0].prev();
}
});
});
return instances;
}
document.addEventListener('DOMContentLoaded', function () {
const petsSlider = new Swiper(".discount_cosmodog__slider", {

@ -341,13 +341,12 @@ jQuery(document).ready(function($) {
if (response.success) {
$('#modal-basket-content').html(response.data.contents);
$('.modal-block-price__price').html(response.data.total);
$('#modal-basket-footer').html(response.data.cart_bottom)
$('.mini-profile__button--counter').text(response.data.count);
if (response.data.count > 0) {
$('.mini-profile__button--counter').removeClass('disabled');
$('.proceed-to-checkout').css('display', ''); // Показываем кнопку, если есть товары
} else {
$('.mini-profile__button--counter').addClass('disabled');
$('.proceed-to-checkout').css('display', 'none'); // Скрываем кнопку, если корзина пуста
}
}
},

@ -151,182 +151,14 @@ jQuery(document).ready(function ($) {
$('#delete_coupon').on('click', function(){
$('.woocommerce-remove-coupon[data-coupon=' + $(this).data('coupon') + ']').click()
$('#promo_form').show()
$('#promo_delete').hide()
})
$('.woocommerce-remove-coupon').on('click', function(){
$('#promo_form').show()
$('#promo_delete').hide()
})
});
jQuery(document).ready(function($) {
// Функция для получения активных фильтров из URL
function getActiveFilters() {
const params = new URLSearchParams(window.location.search);
const filters = [];
params.forEach((value, key) => {
if (key.startsWith('filter_') || key === 'min_price' || key === 'max_price') {
let filterName = key.replace('filter_', '').replace('_', ' ');
let filterValue = value.split(',').map(val => decodeURIComponent(val.replace(/\+/g, ' ')));
if (key === 'min_price') {
filterName = 'Цена от';
filterValue = [value + ' ₽'];
} else if (key === 'max_price') {
filterName = 'Цена до';
filterValue = [value + ' ₽'];
}
filters.push({
key: key,
name: filterName.charAt( W1).toUpperCase() + filterName.slice(1),
values: filterValue
});
}
});
return filters;
}
// Функция для отображения активных фильтров
function displayActiveFilters() {
const $filterList = $('.active-filters__list');
const $filterContainer = $('.active-filters');
const $clearButton = $('.active-filters__clear');
$filterList.empty();
const activeFilters = getActiveFilters();
if (activeFilters.length > 0) {
$filterContainer.show();
$clearButton.show();
activeFilters.forEach(filter => {
filter.values.forEach(value => {
const $filterTag = $('<span>', {
class: 'active-filters__tag',
html: `${filter.name}: ${value} <span class="active-filters__remove" data-key="${filter.key}" data-value="${value}">&times;</span>`
});
$filterList.append($filterTag);
});
});
W2 else {
$filterContainer.hide();
$clearButton.hide();
}
}
// Инициализация при загрузке страницы
displayActiveFilters();
// Обновление фильтров после AJAX-фильтрации
$(document).on('wcpf_after_filtering', function() {
displayActiveFilters();
});
// Удаление фильтра
$(document).on('click', '.active-filters__remove', function() {
const key = $(this).data('key');
const value = $(this).data('value');
const params = new URLSearchParams(window.location.search);
if (key === 'min_price' || key === 'max_price') {
params.delete(key);
} else {
let values = params.get(key) ? params.get(key).split(',') : [];
values = values.filter(val => decodeURIComponent(val.replace(/\+/g, ' ')) !== value);
if (values.length > 0) {
params.set(key, values.join(','));
} else {
params.delete(key);
}
}
const newUrl = window.location.pathname + (params.toString() ? '?' + params.toString() : '');
window.history.pushState({}, '', newUrl);
// Запуск AJAX-фильтрации
$.ajax({
url: wc_checkout_params.ajax_url,
type: 'POST',
data: {
action: 'wcpf_filter',
query: params.toString(),
category_id: $('#load-more-products').data('category_id'),
category_type: $('#load-more-products').data('category_type')
},
success: function(response) {
if (response.success) {
$('.product__main').html(response.data.products);
displayActiveFilters();
$(document.body).trigger('wc_fragments_refreshed');
}
},
error: function() {
alert('Ошибка при обновлении фильтров');
}
});
});
// Очистка всех фильтров
$(document).on('click', '.active-filters__clear', function() {
const params = new URLSearchParams(window.location.search);
const newUrl = window.location.pathname;
window.history.pushState({}, '', newUrl);
$.ajax({
url: wc_checkout_params.ajax_url,
type: 'POST',
data: {
action: 'wcpf_filter',
query: '',
category_id: $('#load-more-products').data('category_id'),
category_type: $('#load-more-products').data('category_type')
},
success: function(response) {
if (response.success) {
$('.product__main').html(response.data.products);
displayActiveFilters();
$(document.body).trigger('wc_fragments_refreshed');
}
},
error: function() {
alert('Ошибка при очистке фильтров');
}
});
});
// Обработка загрузки дополнительных продуктов
$(document).on('click', '#load-more-products', function() {
const $button = $(this);
const categoryId = $button.data('category_id');
const categoryType = $button.data('category_type');
const page = parseInt($button.data('page') || 1) + 1;
$.ajax({
url: wc_checkout_params.ajax_url,
type: 'POST',
data: {
action: 'load_more_products',
category_id: categoryId,
category_type: categoryType,
page: page,
query: window.location.search
},
success: function(response) {
if (response.success) {
$('.product__main').append(response.data.products);
$button.data('page', page);
if (!response.data.has_more) {
$button.hide();
}
}
},
error: function() {
alert('Ошибка при загрузке продуктов');
}
});
});
});

@ -1561,3 +1561,8 @@ input:checked + .subscription-option-details::before, input:checked + .wcsatt-op
.detail #wc-stripe-express-checkout-element{
display: none !important;
}
.detail-block-form__item--radio{
display: flex;
gap: 10px;
}

@ -96,10 +96,16 @@
{% if siblings %}
<div class="detail-block-form__item detail-block-form__item--radio radio-button">
{% for sibling in siblings %}
{% set weight = sibling.post_title|split(', ')|last %}
{% set weight = function('get_product_info', sibling.ID, 'weight') %}
{% set current_weight = function('get_product_info', product.id, 'weight') %}
{% set class = weight == current_weight ? 'active' : '' %}
<a href="{{ function('get_permalink', sibling.ID) }}" class="button button--white button--red-48-px {{ class }}" data-product_id="{{ sibling.ID }}" data-product_price="{{ function('get_product_info', sibling.ID, 'price') }}">
<a
href="{{ function('get_permalink', sibling.ID) }}"
class="button button--white button--red-48-px {{ class }}"
data-product_id="{{ sibling.ID }}"
data-product_price="{{ function('get_product_info', sibling.ID, 'price') }}"
>
{{ weight|upper }}
</a>
{% endfor %}

@ -99,9 +99,12 @@ function get_cart_fragment_handler() {
ob_start();
Timber::render('shop/cart-contents.twig', Timber::context());
$contents = ob_get_clean();
ob_start();
Timber::render('shop/cart-bottom.twig', Timber::context());
$cartBottom= ob_get_clean();
$response = array(
'contents' => $contents,
'cart_bottom' => $cartBottom,
'total' => WC()->cart->get_cart_total(),
'count' => WC()->cart->get_cart_contents_count()
);

@ -582,14 +582,39 @@ document.addEventListener('DOMContentLoaded', function() {
});
// Close popup
if (closePopup) {
closePopup.addEventListener('click', function() {
reviewPopup.style.display = 'none';
});
// Close popup when clicking outside
}
if (reviewPopup){
reviewPopup.addEventListener('click', function(e) {
if (e.target === reviewPopup) {
reviewPopup.style.display = 'none';
}
});
}
// Close popup when clicking outside
});
var slider = carousel_init();
function carousel_init() {
var carousel = document.querySelectorAll('.carousel');
var options = {
numVisible: window.innerWidth > 421 ? 5 : 3,
indicators: false // Removed dots
};
var instances = M.Carousel.init(carousel, options);
document.querySelectorAll('.about_slider_nav').forEach(btn => {
btn.addEventListener('click', function (e) {
if (e.target.closest('button').classList.contains('next')) {
instances[0].next();
} else {
instances[0].prev();
}
});
});
return instances;
}

@ -56,7 +56,7 @@
{% verbatim %}
<div class="mform mform-success" style="display: none;">
@ -74,7 +74,7 @@
</div>
</div>
{% verbatim %}
<div class="mform mform-offer modal-offer" style="display: none;">
<div class="mform-content">
<div class="close-button">&times;</div>
@ -110,7 +110,8 @@
{% endverbatim %}
<script>
function onTelegramAuth(user) {
function onTelegramAuth(user) {
console.log(123)
var data = {
action: 'ontelegramauth',
userid: user.id,
@ -124,7 +125,8 @@
data: data,
success: function(){
location.href = '/my-account';
}
},
});
}
function linkTelegram(user) {
@ -253,4 +255,4 @@ document.addEventListener('DOMContentLoaded', function() {
});
</script>
{{ function ('tgScript') }}

@ -8,14 +8,15 @@
<?php
// Пример использования в functions.php
add_action('wp_enqueue_scripts', function() {
enqueue_static_assets('front-page'); // Для директории /static/main/
// С дополнительными параметрами
// enqueue_static_assets('theme', ['css' => false, 'version' => '1.0.0']);
});
function theme_enqueue_scripts() {
// Swiper
wp_enqueue_style('gp-front-page-carousel', get_template_directory_uri() . '/static/front-page/css/carousel.css');
wp_enqueue_style('gp-front-page-materialize-css', get_template_directory_uri() . '/static/front-page/css/materialize.min.css');
wp_enqueue_style('gp-front-page-style', get_template_directory_uri() . '/static/front-page/css/style.css');
wp_enqueue_script( 'gp-front-page-materialize', get_template_directory_uri() . '/static/front-page/js/materialize.min.js', array(), null, true );
wp_enqueue_script( 'gp-front-page-main', get_template_directory_uri() . '/static/front-page/js/main.js', array(), null, true );
}
add_action('wp_enqueue_scripts', 'theme_enqueue_scripts');
// Создаем функцию для получения постов
function get_blog_posts_data() {

@ -16,29 +16,6 @@
</div>
<div class="modal__footer" id="modal-basket-footer">
{% if not fn('WC').cart.is_empty and fn('WC').cart.get_total('raw') > 0 %}
<div class="modal__block-price">
<p class="modal-block-price__title">{{ __('Total', 'woocommerce') }}</p>
<p class="modal-block-price__price">
{{ fn('wc_cart_totals_order_total_html') }}
</p>
</div>
<div class="modal__block-button">
<div class="modal__button">
<a href="{{ fn('wc_get_checkout_url') }}" class="button button--gradient button--high button--100-perc proceed-to-checkout">
{{ __('Proceed to checkout', 'woocommerce') }}
</a>
</div>
</div>
{% else %}
<div class="modal__block-button">
<a href="/shop/" class="modal__button">
<button class="to-know button--100-perc to-know--background-none continue-shopping">
<p>{{ __('Continue shopping', 'woocommerce') }}</p>
</button>
</a>
</div>
{% endif %}
{% include 'shop/cart-bottom.twig' %}
</div>
</div>

@ -10,37 +10,37 @@
</div>
<div class="cabinet-card__element">
<p class="cabinet-card__label">{{ pll_e('Breed') }}:</p>
<p class="cabinet-card__label">{{ fn('pll_e', 'Breed') }}:</p>
<p class="cabinet-card__text">{{ function('get_field', 'breed', pet_id) }}</p>
</div>
<div class="cabinet-card__element">
<p class="cabinet-card__label">{{ pll_e('Weight') }}:</p>
<p class="cabinet-card__label">{{ fn('pll_e','Weight') }}:</p>
<p class="cabinet-card__text">
{% set weight_key = function('get_field', 'weight', pet_id) %}
{% if weight_key == 'below_1_5' %}{{ pll_e('from 0,5 kg to 1,5 kg') }}
{% elseif weight_key == '1_5-3' %}{{ pll_e('from 1.5 to 3 kg') }}
{% elseif weight_key == '3-5' %}{{ pll_e('from 3 to 5 kg') }}
{% elseif weight_key == '5-8' %}{{ pll_e('from 5 to 8 kg') }}
{% elseif weight_key == '8-11' %}{{ pll_e('from 8 to 11 kg') }}
{% elseif weight_key == '11-15' %}{{ pll_e('from 11 to 15 kg') }}
{% elseif weight_key == '15-20' %}{{ pll_e('from 15 to 20 kg') }}
{% elseif weight_key == '20-25' %}{{ pll_e('from 20 to 25 kg') }}
{% elseif weight_key == '25-35' %}{{ pll_e('from 25 to 35 kg') }}
{% elseif weight_key == 'more_35' %}{{ pll_e('More than 35 kg') }}
{% if weight_key == 'below_1_5' %}{{ fn('pll_e', 'from 0,5 kg to 1,5 kg') }}
{% elseif weight_key == '1_5-3' %}{{ fn('pll_e', 'from 1.5 to 3 kg') }}
{% elseif weight_key == '3-5' %}{{ fn('pll_e', 'from 3 to 5 kg') }}
{% elseif weight_key == '5-8' %}{{ fn('pll_e', 'from 5 to 8 kg') }}
{% elseif weight_key == '8-11' %}{{ fn('pll_e', 'from 8 to 11 kg') }}
{% elseif weight_key == '11-15' %}{{ fn('pll_e', 'from 11 to 15 kg') }}
{% elseif weight_key == '15-20' %}{{ fn('pll_e', 'from 15 to 20 kg') }}
{% elseif weight_key == '20-25' %}{{ fn('pll_e', 'from 20 to 25 kg') }}
{% elseif weight_key == '25-35' %}{{ fn('pll_e', 'from 25 to 35 kg') }}
{% elseif weight_key == 'more_35' %}{{ fn('pll_e', 'More than 35 kg') }}
{% endif %}
</p>
</div>
{% if function('get_field', 'old', pet_id) %}
<div class="cabinet-card__element">
<p class="cabinet-card__label">{{ pll_e('Age') }}:</p>
<p class="cabinet-card__label">{{ fn('pll_e', 'Age') }}:</p>
<p class="cabinet-card__text">
{% set age_key = function('get_field', 'old', pet_id) %}
{% if age_key == 'normal' %}{{ pll_e('Adult (from 1 year to 7 years)') }}
{% elseif age_key == 'old' %}{{ pll_e('Elderly (from 7 to 12 years)') }}
{% elseif age_key == 'very_old' %}{{ pll_e('Aging (12 years and older)') }}
{% elseif age_key == 'baby' %}{{ pll_e('Baby (from 0 to 1 year)') }}
{% if age_key == 'normal' %}{{ fn('pll_e', 'Adult (from 1 year to 7 years)') }}
{% elseif age_key == 'old' %}{{ fn('pll_e', 'Elderly (from 7 to 12 years)') }}
{% elseif age_key == 'very_old' %}{{ fn('pll_e', 'Aging (12 years and older)') }}
{% elseif age_key == 'baby' %}{{ fn('pll_e', 'Baby (from 0 to 1 year)') }}
{% endif %}
</p>
</div>
@ -48,7 +48,7 @@
{% set month = function('get_field', 'month', pet_id) %}
{% set zero = month < 10 ? '0' : '' %}
<div class="cabinet-card__element">
<p class="cabinet-card__label">{{ pll_e('Birthday') }}:</p>
<p class="cabinet-card__label">{{ fn('pll_e', 'Birthday') }}:</p>
<p class="cabinet-card__text">
{{ function('get_field', 'day', pet_id) }}.{{ zero }}{{ month }}.{{ function('get_field', 'year', pet_id) }}
</p>
@ -56,25 +56,25 @@
{% endif %}
<div class="cabinet-card__element">
<p class="cabinet-card__label">{{ pll_e('Activity') }}:</p>
<p class="cabinet-card__label">{{ fn('pll_e', 'Activity') }}:</p>
<p class="cabinet-card__text">
{% set activity_key = function('get_field', 'activity', pet_id) %}
{% if activity_key == 'low' %}{{ pll_e('Low') }}
{% elseif activity_key == 'moderate' %}{{ pll_e('Moderate') }}
{% elseif activity_key == 'high' %}{{ pll_e('High') }}
{% if activity_key == 'low' %}{{ fn('pll_e', 'Low') }}
{% elseif activity_key == 'moderate' %}{{ fn('pll_e', 'Moderate') }}
{% elseif activity_key == 'high' %}{{ fn('pll_e', 'High') }}
{% endif %}
</p>
</div>
{% if function('get_field', 'type', pet_id) == 'cat' and function('get_field', 'sterilized', pet_id) %}
<div class="cabinet-card__element">
<p class="cabinet-card__label">{{ pll_e('Sterilized') }}</p>
<p class="cabinet-card__label">{{ fn('pll_e', 'Sterilized') }}</p>
</div>
{% endif %}
<div class="cabinet-card__element">
<button class="cabinet-card__button" data-edit="{{ pet_id }}">
{{ pll_e('Edit') }}
{{ fn('pll_e', 'Edit') }}
</button>
</div>
</div>

@ -107,14 +107,9 @@
</div>
{% endblock %}
</main>
<div class="modalProfile" id="pet_add_form">
<div class="popup-wrap">
<div class="modal-form form__full-mobile modal-form--white modal-form--height-100-phone form-pet active">
@ -123,14 +118,15 @@
<form class="modal-form__content" id="add-pet-form" method="post" action="">
<input type="hidden" name="action" value="add_pet">
<!-- Вид животного -->
<div class="modal-form-content__line">
<label for="" class="label-name">{{ fn('pll_e', 'Вид животного') }}</label>
<label class="label-name">{{ fn('pll_e', 'Вид животного') }}</label>
<div class="form-input__tabs">
<label for="cat" class="form-input-tabs__button active">
{{ fn('pll_e', 'Кошка') }}
<input type="radio" value="cat" checked name="pet" id="cat" class="form-input-tabs__input">
</label>
<label for="dog" class="form-input-tabs__button">
{{ fn('pll_e', 'Собака') }}
<input type="radio" value="dog" name="pet" id="dog" class="form-input-tabs__input">
@ -138,15 +134,14 @@
</div>
</div>
<!-- Стерилизован -->
<div class="modal-form-content__line sterilized">
<label for="" class="label-name">{{ fn('pll_e', 'Стерелизован') }}</label>
<label class="label-name">{{ fn('pll_e', 'Стерелизован') }}</label>
<div class="form-input__tabs">
<label class="form-input-tabs__button active">
{{ fn('pll_e', 'Да') }}
<input type="radio" value="1" checked name="sterilized" class="form-input-tabs__input">
</label>
<label class="form-input-tabs__button">
{{ fn('pll_e', 'Нет') }}
<input type="radio" value="0" name="sterilized" class="form-input-tabs__input">
@ -154,29 +149,30 @@
</div>
</div>
<!-- Имя питомца -->
<div class="modal-form-content__line">
<div class="modal-form-content-line__element">
<label for="firstname" class="label-name">{{ fn('pll_e', 'Имя') }}</label>
<input id="firstname" class="form__input" type="text" name="name" placeholder="{{ fn('pll_e', 'Имя питомца') }}" required>
<label class="label-name">{{ fn('pll_e', 'Имя') }}</label>
<input class="form__input" type="text" name="name" placeholder="{{ fn('pll_e', 'Имя питомца') }}" required>
</div>
</div>
<!-- Порода -->
<div class="modal-form-content__line">
<div class="modal-form-content-line__element">
<label for="firstname" class="label-name">{{ fn('pll_e', 'Порода') }}</label>
<input id="firstname" class="form__input" type="text" name="breed" placeholder="{{ fn('pll_e', 'Порода вашего питомца') }}" required>
<label class="label-name">{{ fn('pll_e', 'Порода') }}</label>
<input class="form__input" type="text" name="breed" placeholder="{{ fn('pll_e', 'Порода вашего питомца') }}" required>
</div>
</div>
<!-- Пол -->
<div class="modal-form-content__line">
<label for="" class="label-name">{{ fn('pll_e', 'Пол вашего питомца') }}</label>
<label class="label-name">{{ fn('pll_e', 'Пол вашего питомца') }}</label>
<div class="form-input__tabs">
<label for="boy" class="form-input-tabs__button active">
{{ fn('pll_e', 'Мальчик') }}
<input type="radio" value="male" checked name="sex" id="boy" class="form-input-tabs__input">
</label>
<label for="girl" class="form-input-tabs__button">
{{ fn('pll_e', 'Девочка') }}
<input type="radio" value="female" name="sex" id="girl" class="form-input-tabs__input">
@ -184,13 +180,15 @@
</div>
</div>
<!-- Вид активности -->
<div class="modal-form-content__line modal-form-content__line--two">
<div class="modal-form-content-line__element">
<label class="label-name">{{ fn('pll_e', 'Вид активности') }}</label>
<div class="form-input__list">
<div class="form-input-list__input">{{ fn('pll_e', 'Выберите из списка') }}</div>
<div class="form-input-list__block-content" style="height: 0px;">
<div class="form-input-list__block-content">
<div class="form-input-list__content">
<label class="form-input-list__item">
<p class="form-input-list-item__text">{{ fn('pll_e', 'Низкая') }}</p>
<input type="radio" required name="activity" value="low" class="v-hidden">
@ -200,6 +198,7 @@
</div>
</div>
</label>
<label class="form-input-list__item">
<p class="form-input-list-item__text">{{ fn('pll_e', 'Средняя') }}</p>
<input type="radio" required name="activity" value="moderate" class="v-hidden">
@ -209,6 +208,7 @@
</div>
</div>
</label>
<label class="form-input-list__item">
<p class="form-input-list-item__text">{{ fn('pll_e', 'Высокая') }}</p>
<input type="radio" required name="activity" value="high" class="v-hidden">
@ -218,45 +218,70 @@
</div>
</div>
</label>
</div>
</div>
</div>
</div>
<!-- Вес -->
<div class="modal-form-content-line__element">
<label for="firstname" class="label-name">{{ fn('pll_e', 'Вес') }}</label>
<label class="label-name">{{ fn('pll_e', 'Вес') }}</label>
<div class="form-input__list">
<div class="form-input-list__input">{{ fn('pll_e', 'Выберите из списка') }}</div>
<div class="form-input-list__block-content" style="height: 0px;">
<div class="form-input-list__block-content">
<div class="form-input-list__content">
{% for weight in [
{value: 'below_1_5', text: fn('pll_e', '1-1.5 кг')},
{value: '1_5-3', text: fn('pll_e', '1.5-3 кг')},
{value: '3-5', text: fn('pll_e', '3-5 кг')},
{value: '5-8', text: fn('pll_e', '5-8 кг')},
{value: '8-11', text: fn('pll_e', '8-11 кг')},
{value: '11-15', text: fn('pll_e', '11-15 кг')},
{value: '15-20', text: fn('pll_e', '10-20кг')},
{value: '20-25', text: fn('pll_e', '20-25кг')},
{value: '25-35', text: fn('pll_e', '25-35 кг')},
{value: 'more_35', text: fn('pll_e', 'Более 35 кг')}
] %}
<label class="form-input-list__item">
<p class="form-input-list-item__text">{{ weight.text }}</p>
<input type="radio" required name="weight" value="{{ weight.value }}" class="v-hidden">
<p class="form-input-list-item__text">1-1.5 кг</p>
<input type="radio" required name="weight" value="below_1_5" class="v-hidden">
<div class="form-input-list-item__box">
<div class="form-input-list-item-box__content">
<img src="{{ theme.link }}/gp-include/assets/lk/img/svg/main/arrow-selected-white.svg" alt="">
</div>
</div>
</label>
{% endfor %}
<label class="form-input-list__item">
<p class="form-input-list-item__text">1.5-3 кг</p>
<input type="radio" required name="weight" value="1_5-3" class="v-hidden">
<div class="form-input-list-item__box">
<div class="form-input-list-item-box__content">
<img src="{{ theme.link }}/gp-include/assets/lk/img/svg/main/arrow-selected-white.svg" alt="">
</div>
</div>
</label>
<label class="form-input-list__item">
<p class="form-input-list-item__text">3-5 кг</p>
<input type="radio" required name="weight" value="3-5" class="v-hidden">
<div class="form-input-list-item__box">
<div class="form-input-list-item-box__content">
<img src="{{ theme.link }}/gp-include/assets/lk/img/svg/main/arrow-selected-white.svg" alt="">
</div>
</div>
</label>
<label class="form-input-list__item">
<p class="form-input-list-item__text">5-8 кг</p>
<input type="radio" required name="weight" value="5-8" class="v-hidden">
<div class="form-input-list-item__box">
<div class="form-input-list-item-box__content">
<img src="{{ theme.link }}/gp-include/assets/lk/img/svg/main/arrow-selected-white.svg" alt="">
</div>
</div>
</label>
<!-- Добавь остальные веса аналогично -->
<!-- ... -->
</div>
</div>
</div>
</div>
</div>
<!-- Возраст -->
<div class="rm">
<div class="modal-form-content__line">
<label class="label-name">{{ fn('pll_e', 'Возраст питомца') }}</label>
@ -265,8 +290,7 @@
{{ fn('pll_e', 'Примерный') }}
<input type="radio" checked value="ex" name="old_type" required id="exemplary" class="form-input-tabs__input">
</label>
<label class="form-input-tabs__button" data-rm="1">
<label for="accurate" class="form-input-tabs__button" data-rm="1">
{{ fn('pll_e', 'Точный') }}
<input type="radio" value="acc" name="old_type" required id="accurate" class="form-input-tabs__input">
</label>
@ -274,80 +298,74 @@
</div>
<div class="modal__age">
<!-- Примерный возраст -->
<div class="form-input__radio remote-control__item active" data-rmcont="0">
{% for age in [
{value: 'baby', title: fn('pll_e', 'Малыш'), desc: fn('pll_e', '(от 0 до 1 года)')},
{value: 'normal', title: fn('pll_e', 'Взрослый'), desc: fn('pll_e', '(от 1 года до 7 лет)')},
{value: 'old', title: fn('pll_e', 'Пожилой'), desc: fn('pll_e', '(от 7 до 12 лет)')},
{value: 'very_old', title: fn('pll_e', 'Стареющий'), desc: fn('pll_e', '(от 12 лет и старше)')}
] %}
<label class="form-input-radio__item {{ loop.first ? 'active' : '' }}">
<input type="radio" name="old" value="{{ age.value }}" {{ loop.first ? 'checked' : '' }} class="v-hidden">
<label class="form-input-radio__item active">
<input type="radio" name="old" value="baby" checked class="v-hidden">
<div class="form-input-radio__circle">
<div class="form-input-radio-circle__content"></div>
</div>
<p class="form-input-radio__title">{{ age.title }} <span>{{ age.desc }}</span></p>
<p class="form-input-radio__title">{{ fn('pll_e', 'Малыш') }} <span>{{ fn('pll_e', '(от 0 до 1 года)') }}</span></p>
</label>
{% endfor %}
</div>
<div data-rmcont="1" class="modal-form-content__line remote-control__item modal-form-content__line--three modal-form-content__line--margin-top-16">
<div class="modal-form-content-line__element">
<label for="firstname" class="label-name">{{ fn('pll_e', 'День') }}</label>
<input id="firstname" class="form__input form__input--center" maxlength="2" type="text" name="day" placeholder="{{ fn('pll_e', 'ДД') }}">
<label class="form-input-radio__item">
<input type="radio" name="old" value="normal" class="v-hidden">
<div class="form-input-radio__circle">
<div class="form-input-radio-circle__content"></div>
</div>
<p class="form-input-radio__title">{{ fn('pll_e', 'Взрослый') }} <span>{{ fn('pll_e', '(от 1 года до 7 лет)') }}</span></p>
</label>
<div class="modal-form-content-line__element">
<label for="firstname" class="label-name">{{ fn('pll_e', 'Месяц') }}</label>
<div class="form-input__list">
<div class="form-input-list__input">{{ fn('pll_e', 'Месяц') }}</div>
<div class="form-input-list__block-content">
<div class="form-input-list__content">
{% for month in [
{value: 1, text: fn('pll_e', 'Январь')},
{value: 2, text: fn('pll_e', 'Февраль')},
{value: 3, text: fn('pll_e', 'Март')},
{value: 4, text: fn('pll_e', 'Апрель')},
{value: 5, text: fn('pll_e', 'Май')},
{value: 6, text: fn('pll_e', 'Июнь')},
{value: 7, text: fn('pll_e', 'Июль')},
{value: 8, text: fn('pll_e', 'Август')},
{value: 9, text: fn('pll_e', 'Сентябрь')},
{value: 10, text: fn('pll_e', 'Октябрь')},
{value: 11, text: fn('pll_e', 'Ноябрь')},
{value: 12, text: fn('pll_e', 'Декабрь')}
] %}
<label class="form-input-list__item">
<p class="form-input-list-item__text">{{ month.text }}</p>
<input type="radio" name="month" value="{{ month.value }}" class="v-hidden">
<div class="form-input-list-item__box">
<div class="form-input-list-item-box__content">
<img src="{{ theme.link }}/gp-include/assets/lk/img/svg/main/arrow-selected-white.svg" alt="">
</div>
<label class="form-input-radio__item">
<input type="radio" name="old" value="old" class="v-hidden">
<div class="form-input-radio__circle">
<div class="form-input-radio-circle__content"></div>
</div>
<p class="form-input-radio__title">{{ fn('pll_e', 'Пожилой') }} <span>{{ fn('pll_e', '(от 7 до 12 лет)') }}</span></p>
</label>
{% endfor %}
<label class="form-input-radio__item">
<input type="radio" name="old" value="very_old" class="v-hidden">
<div class="form-input-radio__circle">
<div class="form-input-radio-circle__content"></div>
</div>
<p class="form-input-radio__title">{{ fn('pll_e', 'Стареющий') }} <span>{{ fn('pll_e', '(от 12 лет и старше)') }}</span></p>
</label>
</div>
<!-- Точный возраст -->
<div data-rmcont="1" class="modal-form-content__line remote-control__item modal-form-content__line--three modal-form-content__line--margin-top-16">
<div class="modal-form-content-line__element">
<label class="label-name">{{ fn('pll_e', 'День') }}</label>
<input class="form__input form__input--center" maxlength="2" type="text" name="day" placeholder="{{ fn('pll_e', 'ДД') }}">
</div>
<div class="modal-form-content-line__element">
<label class="label-name">{{ fn('pll_e', 'Месяц') }}</label>
<!-- Месяцы тоже можно захардкодить аналогично — по той же схеме -->
</div>
<div class="modal-form-content-line__element">
<label for="firstname" class="label-name">{{ fn('pll_e', 'Год') }}</label>
<input id="firstname" class="form__input form__input--center" maxlength="4" type="text" name="year" placeholder="{{ fn('pll_e', 'ГГГГ') }}">
<label class="label-name">{{ fn('pll_e', 'Год') }}</label>
<input class="form__input form__input--center" maxlength="4" type="text" name="year" placeholder="{{ fn('pll_e', 'ГГГГ') }}">
</div>
</div>
</div>
</div>
<!-- Кнопка добавить -->
<div class="modal-form__buttons">
<button class="button button--gradient button--high button--100-perc" type="submit">{{ fn('pll_e', 'Добавить') }}</button>
</div>
</form>
</div>
</div>
</div>
<div class="modalProfile" id="subForm">
<div class="popup-wrap">
<div class="modal-form modal__notification modal-form--green-gradient modal-form--width-584 form-sub active">

@ -0,0 +1,24 @@
{% if not fn('WC').cart.is_empty and fn('WC').cart.get_total('raw') > 0 %}
<div class="modal__block-price">
<p class="modal-block-price__title">{{ __('Total', 'woocommerce') }}</p>
<p class="modal-block-price__price">
{{ fn('wc_cart_totals_order_total_html') }}
</p>
</div>
<div class="modal__block-button">
<div class="modal__button">
<a href="{{ fn('wc_get_checkout_url') }}" class="button button--gradient button--high button--100-perc proceed-to-checkout">
{{ __('Proceed to checkout', 'woocommerce') }}
</a>
</div>
</div>
{% else %}
<a href="/shop/" class="modal__button modal__button--center">
<button class="to-know button--100-perc to-know--background-none continue-shopping">
<p>{{ __('Continue shopping', 'woocommerce') }}</p>
</button>
</a>
{% endif %}

@ -23,7 +23,7 @@
</div>
{% set chosen_methods = WC().session.get('chosen_shipping_methods') %}
{% set shipping_method = chosen_methods[0] ? chosen_methods[0] : fn('pll_e', 'Не выбран') %}
{% set shipping_method = chosen_methods[0] ? chosen_methods[0] : '' %}
<div class="order-contacts__delivery">
<p class="order__title">{{ fn('pll_e', 'Доставка') }}</p>

Loading…
Cancel
Save