From 2d3a7878c3e6fe94116f6269e6dd4bbaa4b91701 Mon Sep 17 00:00:00 2001 From: maksim Date: Fri, 6 Jun 2025 23:11:54 +0300 Subject: [PATCH] temp commit for merge --- robots.txt | 91 + wp-content/themes/cosmopet/composer-setup.php | 1748 +++++++++++++++++ wp-content/themes/cosmopet/functions.php | 384 +++- .../global-functions/core-functions.php | 261 +++ .../global-functions/multilang-functions.php | 1615 ++++++++++++++- .../global-functions/multisite-functions.php | 208 +- wp-content/themes/cosmopet/home.php | 1 + .../blog/assets/css/gp-style-desktop.css | 2 + .../single/assets/css/gp-style-desktop.css | 334 +++- .../single/assets/css/gp-style-tablet.css | 83 + .../footer/assets/css/gp-style-desktop.css | 50 +- .../modules/footer/module-controller.php | 174 ++ .../cosmopet/modules/forms/assets/js/form.js | 10 +- .../modules/forms/module-ajax-controller.php | 4 +- .../modules/forms/module-controller.php | 60 +- .../header/assets/css/gp-style-desktop.css | 8 +- .../layout/assets/css/gp-style-core.css | 238 ++- .../modules/layout/assets/js/gp-cabinet.js | 67 - .../modules/layout/assets/js/gp-form.js | 494 +++-- .../modules/layout/assets/js/gp-main.js | 12 + .../assets/css/gp-style-core.css | 946 ++------- .../single-product/assets/js/gp-product.js | 44 +- .../single-product/component-template.twig | 13 +- wp-content/themes/cosmopet/page.php | 20 + .../cosmopet/static/front-page/css/style.css | 4 + .../cosmopet/static/front-page/js/main.js | 55 +- .../cosmopet/templates/blog/blog-page.twig | 839 ++++++++ .../cosmopet/templates/blog/most-read.twig | 33 +- .../themes/cosmopet/templates/footer.twig | 155 +- .../templates/front-page/front-page.twig | 11 +- .../themes/cosmopet/templates/header.twig | 51 +- .../themes/cosmopet/templates/layout.twig | 44 + .../themes/cosmopet/templates/modal.twig | 2 + .../themes/cosmopet/templates/page.twig | 1 + .../themes/cosmopet/templates/pet-card.twig | 81 + .../cosmopet/templates/shop/bestsellers.twig | 16 +- .../templates/shop/cart-contents.twig | 2 +- .../cosmopet/templates/shop/review-order.twig | 14 +- .../archive-product/archive-product.twig | 12 +- 39 files changed, 6849 insertions(+), 1338 deletions(-) create mode 100644 robots.txt create mode 100644 wp-content/themes/cosmopet/composer-setup.php delete mode 100644 wp-content/themes/cosmopet/modules/layout/assets/js/gp-cabinet.js create mode 100644 wp-content/themes/cosmopet/templates/blog/blog-page.twig create mode 100644 wp-content/themes/cosmopet/templates/pet-card.twig diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..1beb5d3 --- /dev/null +++ b/robots.txt @@ -0,0 +1,91 @@ +User-agent: * +Disallow: /cgi-bin +Disallow: /? +Disallow: /wp- +Disallow: /wp/ +Disallow: *?s= +Disallow: *&s= +Disallow: /search/ +Disallow: /author/ +Disallow: /users/ +Disallow: */trackback +Disallow: */feed +Disallow: */rss +Disallow: */embed +Disallow: */wlwmanifest.xml +Disallow: /xmlrpc.php +Allow: */uploads +<<<<<<< HEAD +Sitemap: https://cosmopet.ru/sitemap_index.xml +======= +Sitemap: https://cosmopet.ae/sitemap_index.xml +>>>>>>> 2323f31 (Fix | bug fix) + +User-agent: GoogleBot +Disallow: /cgi-bin +Disallow: /? +Disallow: /wp- +Disallow: /wp/ +Disallow: *?s= +Disallow: *&s= +Disallow: /search/ +Disallow: /author/ +Disallow: /users/ +Disallow: */trackback +Disallow: */feed +Disallow: */rss +Disallow: */embed +Disallow: */wlwmanifest.xml +Disallow: /xmlrpc.php +Disallow: *utm*= +Disallow: *etext*= +Disallow: *?add-to-cart* +Disallow: *?per_page* +Disallow: *?per_row* +Disallow: *openstat= +Allow: */uploads +Allow: /*/*.js +Allow: /*/*.css +Allow: /wp-*.png +Allow: /wp-*.jpg +Allow: /wp-*.jpeg +Allow: /wp-*.gif +Allow: /wp-admin/admin-ajax.php +<<<<<<< HEAD +Sitemap: https://cosmopet.ru/sitemap_index.xml +======= +Sitemap: https://cosmopet.ae/sitemap_index.xml +>>>>>>> 2323f31 (Fix | bug fix) + +User-agent: Yandex +Disallow: /cgi-bin +Disallow: /? +Disallow: /wp- +Disallow: /wp/ +Disallow: *?s= +Disallow: *&s= +Disallow: /search/ +Disallow: /author/ +Disallow: /users/ +Disallow: */trackback +Disallow: */feed +Disallow: */rss +Disallow: */embed +Disallow: */wlwmanifest.xml +Disallow: /xmlrpc.php +Allow: */uploads +Allow: /*/*.js +Allow: /*/*.css +Allow: /wp-*.png +Allow: /wp-*.jpg +Allow: /wp-*.jpeg +Allow: /wp-*.gif +Allow: /wp-admin/admin-ajax.php +<<<<<<< HEAD +Sitemap: https://cosmopet.ru/sitemap_index.xml +======= +Sitemap: https://cosmopet.ae/sitemap_index.xml +>>>>>>> 2323f31 (Fix | bug fix) + +Clean-Param: utm_source&utm_medium&utm_campaign&etext&add-to-cart&per_page&per_row&from&attribute_pa_weight&attribute_pa_ves-upakovki +Clean-Param: openstat \ No newline at end of file diff --git a/wp-content/themes/cosmopet/composer-setup.php b/wp-content/themes/cosmopet/composer-setup.php new file mode 100644 index 0000000..a5efbed --- /dev/null +++ b/wp-content/themes/cosmopet/composer-setup.php @@ -0,0 +1,1748 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +setupEnvironment(); +process(is_array($argv) ? $argv : array()); + +/** + * Initializes various values + * + * @throws RuntimeException If uopz extension prevents exit calls + */ +function setupEnvironment() +{ + ini_set('display_errors', 1); + + if (extension_loaded('uopz') && !(ini_get('uopz.disable') || ini_get('uopz.exit'))) { + // uopz works at opcode level and disables exit calls + if (function_exists('uopz_allow_exit')) { + @uopz_allow_exit(true); + } else { + throw new RuntimeException('The uopz extension ignores exit calls and breaks this installer.'); + } + } + + $installer = 'ComposerInstaller'; + + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + if ($version = getenv('COMPOSERSETUP')) { + $installer = sprintf('Composer-Setup.exe/%s', $version); + } + } + + define('COMPOSER_INSTALLER', $installer); +} + +/** + * Processes the installer + */ +function process($argv) +{ + // Determine ANSI output from --ansi and --no-ansi flags + setUseAnsi($argv); + + $help = in_array('--help', $argv) || in_array('-h', $argv); + if ($help) { + displayHelp(); + exit(0); + } + + $check = in_array('--check', $argv); + $force = in_array('--force', $argv); + $quiet = in_array('--quiet', $argv); + $channel = 'stable'; + if (in_array('--snapshot', $argv)) { + $channel = 'snapshot'; + } elseif (in_array('--preview', $argv)) { + $channel = 'preview'; + } elseif (in_array('--1', $argv)) { + $channel = '1'; + } elseif (in_array('--2', $argv)) { + $channel = '2'; + } elseif (in_array('--2.2', $argv)) { + $channel = '2.2'; + } + $disableTls = in_array('--disable-tls', $argv); + $installDir = getOptValue('--install-dir', $argv, false); + $version = getOptValue('--version', $argv, false); + $filename = getOptValue('--filename', $argv, 'composer.phar'); + $cafile = getOptValue('--cafile', $argv, false); + + if (!checkParams($installDir, $version, $cafile)) { + exit(1); + } + + $ok = checkPlatform($warnings, $quiet, $disableTls, true); + + if ($check) { + // Only show warnings if we haven't output any errors + if ($ok) { + showWarnings($warnings); + showSecurityWarning($disableTls); + } + exit($ok ? 0 : 1); + } + + if ($ok || $force) { + if ($channel === '1' && !$quiet) { + out('Warning: You forced the install of Composer 1.x via --1, but Composer 2.x is the latest stable version. Updating to it via composer self-update --stable is recommended.', 'error'); + } + + $installer = new Installer($quiet, $disableTls, $cafile); + if ($installer->run($version, $installDir, $filename, $channel)) { + showWarnings($warnings); + showSecurityWarning($disableTls); + exit(0); + } + } + + exit(1); +} + +/** + * Displays the help + */ +function displayHelp() +{ + echo << $value) { + $next = $key + 1; + if (0 === strpos($value, $opt)) { + if ($optLength === strlen($value) && isset($argv[$next])) { + return trim($argv[$next]); + } else { + return trim(substr($value, $optLength + 1)); + } + } + } + + return $default; +} + +/** + * Checks that user-supplied params are valid + * + * @param mixed $installDir The required istallation directory + * @param mixed $version The required composer version to install + * @param mixed $cafile Certificate Authority file + * + * @return bool True if the supplied params are okay + */ +function checkParams($installDir, $version, $cafile) +{ + $result = true; + + if (false !== $installDir && !is_dir($installDir)) { + out("The defined install dir ({$installDir}) does not exist.", 'info'); + $result = false; + } + + if (false !== $version && 1 !== preg_match('/^\d+\.\d+\.\d+(\-(alpha|beta|RC)\d*)*$/', $version)) { + out("The defined install version ({$version}) does not match release pattern.", 'info'); + $result = false; + } + + if (false !== $cafile && (!file_exists($cafile) || !is_readable($cafile))) { + out("The defined Certificate Authority (CA) cert file ({$cafile}) does not exist or is not readable.", 'info'); + $result = false; + } + return $result; +} + +/** + * Checks the platform for possible issues running Composer + * + * Errors are written to the output, warnings are saved for later display. + * + * @param array $warnings Populated by method, to be shown later + * @param bool $quiet Quiet mode + * @param bool $disableTls Bypass tls + * @param bool $install If we are installing, rather than diagnosing + * + * @return bool True if there are no errors + */ +function checkPlatform(&$warnings, $quiet, $disableTls, $install) +{ + getPlatformIssues($errors, $warnings, $install); + + // Make openssl warning an error if tls has not been specifically disabled + if (isset($warnings['openssl']) && !$disableTls) { + $errors['openssl'] = $warnings['openssl']; + unset($warnings['openssl']); + } + + if (!empty($errors)) { + // Composer-Setup.exe uses "Some settings" to flag platform errors + out('Some settings on your machine make Composer unable to work properly.', 'error'); + out('Make sure that you fix the issues listed below and run this script again:', 'error'); + outputIssues($errors); + return false; + } + + if (empty($warnings) && !$quiet) { + out('All settings correct for using Composer', 'success'); + } + return true; +} + +/** + * Checks platform configuration for common incompatibility issues + * + * @param array $errors Populated by method + * @param array $warnings Populated by method + * @param bool $install If we are installing, rather than diagnosing + * + * @return bool If any errors or warnings have been found + */ +function getPlatformIssues(&$errors, &$warnings, $install) +{ + $errors = array(); + $warnings = array(); + + if ($iniPath = php_ini_loaded_file()) { + $iniMessage = PHP_EOL.'The php.ini used by your command-line PHP is: ' . $iniPath; + } else { + $iniMessage = PHP_EOL.'A php.ini file does not exist. You will have to create one.'; + } + $iniMessage .= PHP_EOL.'If you can not modify the ini file, you can also run `php -d option=value` to modify ini values on the fly. You can use -d multiple times.'; + + if (ini_get('detect_unicode')) { + $errors['unicode'] = array( + 'The detect_unicode setting must be disabled.', + 'Add the following to the end of your `php.ini`:', + ' detect_unicode = Off', + $iniMessage + ); + } + + if (extension_loaded('suhosin')) { + $suhosin = ini_get('suhosin.executor.include.whitelist'); + $suhosinBlacklist = ini_get('suhosin.executor.include.blacklist'); + if (false === stripos($suhosin, 'phar') && (!$suhosinBlacklist || false !== stripos($suhosinBlacklist, 'phar'))) { + $errors['suhosin'] = array( + 'The suhosin.executor.include.whitelist setting is incorrect.', + 'Add the following to the end of your `php.ini` or suhosin.ini (Example path [for Debian]: /etc/php5/cli/conf.d/suhosin.ini):', + ' suhosin.executor.include.whitelist = phar '.$suhosin, + $iniMessage + ); + } + } + + if (!function_exists('json_decode')) { + $errors['json'] = array( + 'The json extension is missing.', + 'Install it or recompile php without --disable-json' + ); + } + + if (!extension_loaded('Phar')) { + $errors['phar'] = array( + 'The phar extension is missing.', + 'Install it or recompile php without --disable-phar' + ); + } + + if (!extension_loaded('filter')) { + $errors['filter'] = array( + 'The filter extension is missing.', + 'Install it or recompile php without --disable-filter' + ); + } + + if (!extension_loaded('hash')) { + $errors['hash'] = array( + 'The hash extension is missing.', + 'Install it or recompile php without --disable-hash' + ); + } + + if (!extension_loaded('iconv') && !extension_loaded('mbstring')) { + $errors['iconv_mbstring'] = array( + 'The iconv OR mbstring extension is required and both are missing.', + 'Install either of them or recompile php without --disable-iconv' + ); + } + + if (!ini_get('allow_url_fopen')) { + $errors['allow_url_fopen'] = array( + 'The allow_url_fopen setting is incorrect.', + 'Add the following to the end of your `php.ini`:', + ' allow_url_fopen = On', + $iniMessage + ); + } + + if (extension_loaded('ionCube Loader') && ioncube_loader_iversion() < 40009) { + $ioncube = ioncube_loader_version(); + $errors['ioncube'] = array( + 'Your ionCube Loader extension ('.$ioncube.') is incompatible with Phar files.', + 'Upgrade to ionCube 4.0.9 or higher or remove this line (path may be different) from your `php.ini` to disable it:', + ' zend_extension = /usr/lib/php5/20090626+lfs/ioncube_loader_lin_5.3.so', + $iniMessage + ); + } + + if (version_compare(PHP_VERSION, '5.3.2', '<')) { + $errors['php'] = array( + 'Your PHP ('.PHP_VERSION.') is too old, you must upgrade to PHP 5.3.2 or higher.' + ); + } + + if (version_compare(PHP_VERSION, '5.3.4', '<')) { + $warnings['php'] = array( + 'Your PHP ('.PHP_VERSION.') is quite old, upgrading to PHP 5.3.4 or higher is recommended.', + 'Composer works with 5.3.2+ for most people, but there might be edge case issues.' + ); + } + + if (!extension_loaded('openssl')) { + $warnings['openssl'] = array( + 'The openssl extension is missing, which means that secure HTTPS transfers are impossible.', + 'If possible you should enable it or recompile php with --with-openssl' + ); + } + + if (extension_loaded('openssl') && OPENSSL_VERSION_NUMBER < 0x1000100f) { + // Attempt to parse version number out, fallback to whole string value. + $opensslVersion = trim(strstr(OPENSSL_VERSION_TEXT, ' ')); + $opensslVersion = substr($opensslVersion, 0, strpos($opensslVersion, ' ')); + $opensslVersion = $opensslVersion ? $opensslVersion : OPENSSL_VERSION_TEXT; + + $warnings['openssl_version'] = array( + 'The OpenSSL library ('.$opensslVersion.') used by PHP does not support TLSv1.2 or TLSv1.1.', + 'If possible you should upgrade OpenSSL to version 1.0.1 or above.' + ); + } + + if (!defined('HHVM_VERSION') && !extension_loaded('apcu') && ini_get('apc.enable_cli')) { + $warnings['apc_cli'] = array( + 'The apc.enable_cli setting is incorrect.', + 'Add the following to the end of your `php.ini`:', + ' apc.enable_cli = Off', + $iniMessage + ); + } + + if (!$install && extension_loaded('xdebug')) { + $warnings['xdebug_loaded'] = array( + 'The xdebug extension is loaded, this can slow down Composer a little.', + 'Disabling it when using Composer is recommended.' + ); + + if (ini_get('xdebug.profiler_enabled')) { + $warnings['xdebug_profile'] = array( + 'The xdebug.profiler_enabled setting is enabled, this can slow down Composer a lot.', + 'Add the following to the end of your `php.ini` to disable it:', + ' xdebug.profiler_enabled = 0', + $iniMessage + ); + } + } + + if (!extension_loaded('zlib')) { + $warnings['zlib'] = array( + 'The zlib extension is not loaded, this can slow down Composer a lot.', + 'If possible, install it or recompile php with --with-zlib', + $iniMessage + ); + } + + if (defined('PHP_WINDOWS_VERSION_BUILD') + && (version_compare(PHP_VERSION, '7.2.23', '<') + || (version_compare(PHP_VERSION, '7.3.0', '>=') + && version_compare(PHP_VERSION, '7.3.10', '<')))) { + $warnings['onedrive'] = array( + 'The Windows OneDrive folder is not supported on PHP versions below 7.2.23 and 7.3.10.', + 'Upgrade your PHP ('.PHP_VERSION.') to use this location with Composer.' + ); + } + + if (extension_loaded('uopz') && !(ini_get('uopz.disable') || ini_get('uopz.exit'))) { + $warnings['uopz'] = array( + 'The uopz extension ignores exit calls and may not work with all Composer commands.', + 'Disabling it when using Composer is recommended.' + ); + } + + ob_start(); + phpinfo(INFO_GENERAL); + $phpinfo = ob_get_clean(); + if (preg_match('{Configure Command(?: *| *=> *)(.*?)(?:|$)}m', $phpinfo, $match)) { + $configure = $match[1]; + + if (false !== strpos($configure, '--enable-sigchild')) { + $warnings['sigchild'] = array( + 'PHP was compiled with --enable-sigchild which can cause issues on some platforms.', + 'Recompile it without this flag if possible, see also:', + ' https://bugs.php.net/bug.php?id=22999' + ); + } + + if (false !== strpos($configure, '--with-curlwrappers')) { + $warnings['curlwrappers'] = array( + 'PHP was compiled with --with-curlwrappers which will cause issues with HTTP authentication and GitHub.', + 'Recompile it without this flag if possible' + ); + } + } + + // Stringify the message arrays + foreach ($errors as $key => $value) { + $errors[$key] = PHP_EOL.implode(PHP_EOL, $value); + } + + foreach ($warnings as $key => $value) { + $warnings[$key] = PHP_EOL.implode(PHP_EOL, $value); + } + + return !empty($errors) || !empty($warnings); +} + + +/** + * Outputs an array of issues + * + * @param array $issues + */ +function outputIssues($issues) +{ + foreach ($issues as $issue) { + out($issue, 'info'); + } + out(''); +} + +/** + * Outputs any warnings found + * + * @param array $warnings + */ +function showWarnings($warnings) +{ + if (!empty($warnings)) { + out('Some settings on your machine may cause stability issues with Composer.', 'error'); + out('If you encounter issues, try to change the following:', 'error'); + outputIssues($warnings); + } +} + +/** + * Outputs an end of process warning if tls has been bypassed + * + * @param bool $disableTls Bypass tls + */ +function showSecurityWarning($disableTls) +{ + if ($disableTls) { + out('You have instructed the Installer not to enforce SSL/TLS security on remote HTTPS requests.', 'info'); + out('This will leave all downloads during installation vulnerable to Man-In-The-Middle (MITM) attacks', 'info'); + } +} + +/** + * colorize output + */ +function out($text, $color = null, $newLine = true) +{ + $styles = array( + 'success' => "\033[0;32m%s\033[0m", + 'error' => "\033[31;31m%s\033[0m", + 'info' => "\033[33;33m%s\033[0m" + ); + + $format = '%s'; + + if (isset($styles[$color]) && USE_ANSI) { + $format = $styles[$color]; + } + + if ($newLine) { + $format .= PHP_EOL; + } + + printf($format, $text); +} + +/** + * Returns the system-dependent Composer home location, which may not exist + * + * @return string + */ +function getHomeDir() +{ + $home = getenv('COMPOSER_HOME'); + if ($home) { + return $home; + } + + $userDir = getUserDir(); + + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + return $userDir.'/Composer'; + } + + $dirs = array(); + + if (useXdg()) { + // XDG Base Directory Specifications + $xdgConfig = getenv('XDG_CONFIG_HOME'); + if (!$xdgConfig) { + $xdgConfig = $userDir . '/.config'; + } + + $dirs[] = $xdgConfig . '/composer'; + } + + $dirs[] = $userDir . '/.composer'; + + // select first dir which exists of: $XDG_CONFIG_HOME/composer or ~/.composer + foreach ($dirs as $dir) { + if (is_dir($dir)) { + return $dir; + } + } + + // if none exists, we default to first defined one (XDG one if system uses it, or ~/.composer otherwise) + return $dirs[0]; +} + +/** + * Returns the location of the user directory from the environment + * @throws RuntimeException If the environment value does not exists + * + * @return string + */ +function getUserDir() +{ + $userEnv = defined('PHP_WINDOWS_VERSION_MAJOR') ? 'APPDATA' : 'HOME'; + $userDir = getenv($userEnv); + + if (!$userDir) { + throw new RuntimeException('The '.$userEnv.' or COMPOSER_HOME environment variable must be set for composer to run correctly'); + } + + return rtrim(strtr($userDir, '\\', '/'), '/'); +} + +/** + * @return bool + */ +function useXdg() +{ + foreach (array_keys($_SERVER) as $key) { + if (strpos($key, 'XDG_') === 0) { + return true; + } + } + + if (is_dir('/etc/xdg')) { + return true; + } + + return false; +} + +function validateCaFile($contents) +{ + // assume the CA is valid if php is vulnerable to + // https://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html + if ( + PHP_VERSION_ID <= 50327 + || (PHP_VERSION_ID >= 50400 && PHP_VERSION_ID < 50422) + || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50506) + ) { + return !empty($contents); + } + + return (bool) openssl_x509_parse($contents); +} + +class Installer +{ + private $quiet; + private $disableTls; + private $cafile; + private $displayPath; + private $target; + private $tmpFile; + private $tmpCafile; + private $baseUrl; + private $algo; + private $errHandler; + private $httpClient; + private $pubKeys = array(); + private $installs = array(); + + /** + * Constructor - must not do anything that throws an exception + * + * @param bool $quiet Quiet mode + * @param bool $disableTls Bypass tls + * @param mixed $cafile Path to CA bundle, or false + */ + public function __construct($quiet, $disableTls, $caFile) + { + if (($this->quiet = $quiet)) { + ob_start(); + } + $this->disableTls = $disableTls; + $this->cafile = $caFile; + $this->errHandler = new ErrorHandler(); + } + + /** + * Runs the installer + * + * @param mixed $version Specific version to install, or false + * @param mixed $installDir Specific installation directory, or false + * @param string $filename Specific filename to save to, or composer.phar + * @param string $channel Specific version channel to use + * @throws Exception If anything other than a RuntimeException is caught + * + * @return bool If the installation succeeded + */ + public function run($version, $installDir, $filename, $channel) + { + try { + $this->initTargets($installDir, $filename); + $this->initTls(); + $this->httpClient = new HttpClient($this->disableTls, $this->cafile); + $result = $this->install($version, $channel); + + // in case --1 or --2 is passed, we leave the default channel for next self-update to stable + if (1 === preg_match('{^\d+$}D', $channel)) { + $channel = 'stable'; + } + + if ($result && $channel !== 'stable' && !$version && defined('PHP_BINARY')) { + $null = (defined('PHP_WINDOWS_VERSION_MAJOR') ? 'NUL' : '/dev/null'); + @exec(escapeshellarg(PHP_BINARY) .' '.escapeshellarg($this->target).' self-update --'.$channel.' --set-channel-only -q > '.$null.' 2> '.$null, $output); + } + } catch (Exception $e) { + $result = false; + } + + // Always clean up + $this->cleanUp($result); + + if (isset($e)) { + // Rethrow anything that is not a RuntimeException + if (!$e instanceof RuntimeException) { + throw $e; + } + out($e->getMessage(), 'error'); + } + return $result; + } + + /** + * Initialization methods to set the required filenames and composer url + * + * @param mixed $installDir Specific installation directory, or false + * @param string $filename Specific filename to save to, or composer.phar + * @throws RuntimeException If the installation directory is not writable + */ + protected function initTargets($installDir, $filename) + { + $this->displayPath = ($installDir ? rtrim($installDir, '/').'/' : '').$filename; + $installDir = $installDir ? realpath($installDir) : getcwd(); + + if (!is_writeable($installDir)) { + throw new RuntimeException('The installation directory "'.$installDir.'" is not writable'); + } + + $this->target = $installDir.DIRECTORY_SEPARATOR.$filename; + $this->tmpFile = $installDir.DIRECTORY_SEPARATOR.basename($this->target, '.phar').'-temp.phar'; + + $uriScheme = $this->disableTls ? 'http' : 'https'; + $this->baseUrl = $uriScheme.'://getcomposer.org'; + } + + /** + * A wrapper around methods to check tls and write public keys + * @throws RuntimeException If SHA384 is not supported + */ + protected function initTls() + { + if ($this->disableTls) { + return; + } + + if (!in_array('sha384', array_map('strtolower', openssl_get_md_methods()))) { + throw new RuntimeException('SHA384 is not supported by your openssl extension'); + } + + $this->algo = defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'SHA384'; + $home = $this->getComposerHome(); + + $this->pubKeys = array( + 'dev' => $this->installKey(self::getPKDev(), $home, 'keys.dev.pub'), + 'tags' => $this->installKey(self::getPKTags(), $home, 'keys.tags.pub') + ); + + if (empty($this->cafile) && !HttpClient::getSystemCaRootBundlePath()) { + $this->cafile = $this->tmpCafile = $this->installKey(HttpClient::getPackagedCaFile(), $home, 'cacert-temp.pem'); + } + } + + /** + * Returns the Composer home directory, creating it if required + * @throws RuntimeException If the directory cannot be created + * + * @return string + */ + protected function getComposerHome() + { + $home = getHomeDir(); + + if (!is_dir($home)) { + $this->errHandler->start(); + + if (!mkdir($home, 0777, true)) { + throw new RuntimeException(sprintf( + 'Unable to create Composer home directory "%s": %s', + $home, + $this->errHandler->message + )); + } + $this->installs[] = $home; + $this->errHandler->stop(); + } + return $home; + } + + /** + * Writes public key data to disc + * + * @param string $data The public key(s) in pem format + * @param string $path The directory to write to + * @param string $filename The name of the file + * @throws RuntimeException If the file cannot be written + * + * @return string The path to the saved data + */ + protected function installKey($data, $path, $filename) + { + $this->errHandler->start(); + + $target = $path.DIRECTORY_SEPARATOR.$filename; + $installed = file_exists($target); + $write = file_put_contents($target, $data, LOCK_EX); + @chmod($target, 0644); + + $this->errHandler->stop(); + + if (!$write) { + throw new RuntimeException(sprintf('Unable to write %s to: %s', $filename, $path)); + } + + if (!$installed) { + $this->installs[] = $target; + } + + return $target; + } + + /** + * The main install function + * + * @param mixed $version Specific version to install, or false + * @param string $channel Version channel to use + * + * @return bool If the installation succeeded + */ + protected function install($version, $channel) + { + $retries = 3; + $result = false; + $infoMsg = 'Downloading...'; + $infoType = 'info'; + + while ($retries--) { + if (!$this->quiet) { + out($infoMsg, $infoType); + $infoMsg = 'Retrying...'; + $infoType = 'error'; + } + + if (!$this->getVersion($channel, $version, $url, $error)) { + out($error, 'error'); + continue; + } + + if (!$this->downloadToTmp($url, $signature, $error)) { + out($error, 'error'); + continue; + } + + if (!$this->verifyAndSave($version, $signature, $error)) { + out($error, 'error'); + continue; + } + + $result = true; + break; + } + + if (!$this->quiet) { + if ($result) { + out(PHP_EOL."Composer (version {$version}) successfully installed to: {$this->target}", 'success'); + out("Use it: php {$this->displayPath}", 'info'); + out(''); + } else { + out('The download failed repeatedly, aborting.', 'error'); + } + } + return $result; + } + + /** + * Sets the version url, downloading version data if required + * + * @param string $channel Version channel to use + * @param false|string $version Version to install, or set by method + * @param null|string $url The versioned url, set by method + * @param null|string $error Set by method on failure + * + * @return bool If the operation succeeded + */ + protected function getVersion($channel, &$version, &$url, &$error) + { + $error = ''; + + if ($version) { + if (empty($url)) { + $url = $this->baseUrl."/download/{$version}/composer.phar"; + } + return true; + } + + $this->errHandler->start(); + + if ($this->downloadVersionData($data, $error)) { + $this->parseVersionData($data, $channel, $version, $url); + } + + $this->errHandler->stop(); + return empty($error); + } + + /** + * Downloads and json-decodes version data + * + * @param null|array $data Downloaded version data, set by method + * @param null|string $error Set by method on failure + * + * @return bool If the operation succeeded + */ + protected function downloadVersionData(&$data, &$error) + { + $url = $this->baseUrl.'/versions'; + $errFmt = 'The "%s" file could not be %s: %s'; + + if (!$json = $this->httpClient->get($url)) { + $error = sprintf($errFmt, $url, 'downloaded', $this->errHandler->message); + return false; + } + + if (!$data = json_decode($json, true)) { + $error = sprintf($errFmt, $url, 'json-decoded', $this->getJsonError()); + return false; + } + return true; + } + + /** + * A wrapper around the methods needed to download and save the phar + * + * @param string $url The versioned download url + * @param null|string $signature Set by method on successful download + * @param null|string $error Set by method on failure + * + * @return bool If the operation succeeded + */ + protected function downloadToTmp($url, &$signature, &$error) + { + $error = ''; + $errFmt = 'The "%s" file could not be downloaded: %s'; + $sigUrl = $url.'.sig'; + $this->errHandler->start(); + + if (!$fh = fopen($this->tmpFile, 'w')) { + $error = sprintf('Could not create file "%s": %s', $this->tmpFile, $this->errHandler->message); + + } elseif (!$this->getSignature($sigUrl, $signature)) { + $error = sprintf($errFmt, $sigUrl, $this->errHandler->message); + + } elseif (!fwrite($fh, $this->httpClient->get($url))) { + $error = sprintf($errFmt, $url, $this->errHandler->message); + } + + if (is_resource($fh)) { + fclose($fh); + } + $this->errHandler->stop(); + return empty($error); + } + + /** + * Verifies the downloaded file and saves it to the target location + * + * @param string $version The composer version downloaded + * @param string $signature The digital signature to check + * @param null|string $error Set by method on failure + * + * @return bool If the operation succeeded + */ + protected function verifyAndSave($version, $signature, &$error) + { + $error = ''; + + if (!$this->validatePhar($this->tmpFile, $pharError)) { + $error = 'The download is corrupt: '.$pharError; + + } elseif (!$this->verifySignature($version, $signature, $this->tmpFile)) { + $error = 'Signature mismatch, could not verify the phar file integrity'; + + } else { + $this->errHandler->start(); + + if (!rename($this->tmpFile, $this->target)) { + $error = sprintf('Could not write to file "%s": %s', $this->target, $this->errHandler->message); + } + chmod($this->target, 0755); + $this->errHandler->stop(); + } + + return empty($error); + } + + /** + * Parses an array of version data to match the required channel + * + * @param array $data Downloaded version data + * @param mixed $channel Version channel to use + * @param false|string $version Set by method + * @param mixed $url The versioned url, set by method + */ + protected function parseVersionData(array $data, $channel, &$version, &$url) + { + foreach ($data[$channel] as $candidate) { + if ($candidate['min-php'] <= PHP_VERSION_ID) { + $version = $candidate['version']; + $url = $this->baseUrl.$candidate['path']; + break; + } + } + + if (!$version) { + $error = sprintf( + 'None of the %d %s version(s) of Composer matches your PHP version (%s / ID: %d)', + count($data[$channel]), + $channel, + PHP_VERSION, + PHP_VERSION_ID + ); + throw new RuntimeException($error); + } + } + + /** + * Downloads the digital signature of required phar file + * + * @param string $url The signature url + * @param null|string $signature Set by method on success + * + * @return bool If the download succeeded + */ + protected function getSignature($url, &$signature) + { + if (!$result = $this->disableTls) { + $signature = $this->httpClient->get($url); + + if ($signature) { + $signature = json_decode($signature, true); + $signature = base64_decode($signature['sha384']); + $result = true; + } + } + + return $result; + } + + /** + * Verifies the signature of the downloaded phar + * + * @param string $version The composer versione + * @param string $signature The downloaded digital signature + * @param string $file The temp phar file + * + * @return bool If the operation succeeded + */ + protected function verifySignature($version, $signature, $file) + { + if (!$result = $this->disableTls) { + $path = preg_match('{^[0-9a-f]{40}$}', $version) ? $this->pubKeys['dev'] : $this->pubKeys['tags']; + $pubkeyid = openssl_pkey_get_public('file://'.$path); + + $result = 1 === openssl_verify( + file_get_contents($file), + $signature, + $pubkeyid, + $this->algo + ); + + // PHP 8 automatically frees the key instance and deprecates the function + if (PHP_VERSION_ID < 80000) { + openssl_free_key($pubkeyid); + } + } + + return $result; + } + + /** + * Validates the downloaded phar file + * + * @param string $pharFile The temp phar file + * @param null|string $error Set by method on failure + * + * @return bool If the operation succeeded + */ + protected function validatePhar($pharFile, &$error) + { + if (ini_get('phar.readonly')) { + return true; + } + + try { + // Test the phar validity + $phar = new Phar($pharFile); + // Free the variable to unlock the file + unset($phar); + $result = true; + + } catch (Exception $e) { + if (!$e instanceof UnexpectedValueException && !$e instanceof PharException) { + throw $e; + } + $error = $e->getMessage(); + $result = false; + } + return $result; + } + + /** + * Returns a string representation of the last json error + * + * @return string The error string or code + */ + protected function getJsonError() + { + if (function_exists('json_last_error_msg')) { + return json_last_error_msg(); + } else { + return 'json_last_error = '.json_last_error(); + } + } + + /** + * Cleans up resources at the end of the installation + * + * @param bool $result If the installation succeeded + */ + protected function cleanUp($result) + { + if (!$result) { + // Output buffered errors + if ($this->quiet) { + $this->outputErrors(); + } + // Clean up stuff we created + $this->uninstall(); + } elseif ($this->tmpCafile) { + @unlink($this->tmpCafile); + } + } + + /** + * Outputs unique errors when in quiet mode + * + */ + protected function outputErrors() + { + $errors = explode(PHP_EOL, ob_get_clean()); + $shown = array(); + + foreach ($errors as $error) { + if ($error && !in_array($error, $shown)) { + out($error, 'error'); + $shown[] = $error; + } + } + } + + /** + * Uninstalls newly-created files and directories on failure + * + */ + protected function uninstall() + { + foreach (array_reverse($this->installs) as $target) { + if (is_file($target)) { + @unlink($target); + } elseif (is_dir($target)) { + @rmdir($target); + } + } + + if ($this->tmpFile !== null && file_exists($this->tmpFile)) { + @unlink($this->tmpFile); + } + } + + public static function getPKDev() + { + return <<message) { + $this->message .= PHP_EOL; + } + $this->message .= preg_replace('{^file_get_contents\(.*?\): }', '', $msg); + } + + /** + * Starts error-handling if not already active + * + * Any message is cleared + */ + public function start() + { + if (!$this->active) { + set_error_handler(array($this, 'handleError')); + $this->active = true; + } + $this->message = ''; + } + + /** + * Stops error-handling if active + * + * Any message is preserved until the next call to start() + */ + public function stop() + { + if ($this->active) { + restore_error_handler(); + $this->active = false; + } + } +} + +class NoProxyPattern +{ + private $composerInNoProxy = false; + private $rulePorts = array(); + + public function __construct($pattern) + { + $rules = preg_split('{[\s,]+}', $pattern, null, PREG_SPLIT_NO_EMPTY); + + if ($matches = preg_grep('{getcomposer\.org(?::\d+)?}i', $rules)) { + $this->composerInNoProxy = true; + + foreach ($matches as $match) { + if (strpos($match, ':') !== false) { + list(, $port) = explode(':', $match); + $this->rulePorts[] = (int) $port; + } + } + } + } + + /** + * Returns true if NO_PROXY contains getcomposer.org + * + * @param string $url http(s)://getcomposer.org + * + * @return bool + */ + public function test($url) + { + if (!$this->composerInNoProxy) { + return false; + } + + if (empty($this->rulePorts)) { + return true; + } + + if (strpos($url, 'http://') === 0) { + $port = 80; + } else { + $port = 443; + } + + return in_array($port, $this->rulePorts); + } +} + +class HttpClient { + + /** @var null|string */ + private static $caPath; + + private $options = array('http' => array()); + private $disableTls = false; + + public function __construct($disableTls = false, $cafile = false) + { + $this->disableTls = $disableTls; + if ($this->disableTls === false) { + if (!empty($cafile) && !is_dir($cafile)) { + if (!is_readable($cafile) || !validateCaFile(file_get_contents($cafile))) { + throw new RuntimeException('The configured cafile (' .$cafile. ') was not valid or could not be read.'); + } + } + $options = $this->getTlsStreamContextDefaults($cafile); + $this->options = array_replace_recursive($this->options, $options); + } + } + + public function get($url) + { + $context = $this->getStreamContext($url); + $result = file_get_contents($url, false, $context); + + if ($result && extension_loaded('zlib')) { + $decode = false; + foreach ($http_response_header as $header) { + if (preg_match('{^content-encoding: *gzip *$}i', $header)) { + $decode = true; + continue; + } elseif (preg_match('{^HTTP/}i', $header)) { + $decode = false; + } + } + + if ($decode) { + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + $result = zlib_decode($result); + } else { + // work around issue with gzuncompress & co that do not work with all gzip checksums + $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,'.base64_encode($result)); + } + + if (!$result) { + throw new RuntimeException('Failed to decode zlib stream'); + } + } + } + + return $result; + } + + protected function getStreamContext($url) + { + if ($this->disableTls === false) { + if (PHP_VERSION_ID < 50600) { + $this->options['ssl']['SNI_server_name'] = parse_url($url, PHP_URL_HOST); + } + } + // Keeping the above mostly isolated from the code copied from Composer. + return $this->getMergedStreamContext($url); + } + + protected function getTlsStreamContextDefaults($cafile) + { + $ciphers = implode(':', array( + 'ECDHE-RSA-AES128-GCM-SHA256', + 'ECDHE-ECDSA-AES128-GCM-SHA256', + 'ECDHE-RSA-AES256-GCM-SHA384', + 'ECDHE-ECDSA-AES256-GCM-SHA384', + 'DHE-RSA-AES128-GCM-SHA256', + 'DHE-DSS-AES128-GCM-SHA256', + 'kEDH+AESGCM', + 'ECDHE-RSA-AES128-SHA256', + 'ECDHE-ECDSA-AES128-SHA256', + 'ECDHE-RSA-AES128-SHA', + 'ECDHE-ECDSA-AES128-SHA', + 'ECDHE-RSA-AES256-SHA384', + 'ECDHE-ECDSA-AES256-SHA384', + 'ECDHE-RSA-AES256-SHA', + 'ECDHE-ECDSA-AES256-SHA', + 'DHE-RSA-AES128-SHA256', + 'DHE-RSA-AES128-SHA', + 'DHE-DSS-AES128-SHA256', + 'DHE-RSA-AES256-SHA256', + 'DHE-DSS-AES256-SHA', + 'DHE-RSA-AES256-SHA', + 'AES128-GCM-SHA256', + 'AES256-GCM-SHA384', + 'AES128-SHA256', + 'AES256-SHA256', + 'AES128-SHA', + 'AES256-SHA', + 'AES', + 'CAMELLIA', + 'DES-CBC3-SHA', + '!aNULL', + '!eNULL', + '!EXPORT', + '!DES', + '!RC4', + '!MD5', + '!PSK', + '!aECDH', + '!EDH-DSS-DES-CBC3-SHA', + '!EDH-RSA-DES-CBC3-SHA', + '!KRB5-DES-CBC3-SHA', + )); + + /** + * CN_match and SNI_server_name are only known once a URL is passed. + * They will be set in the getOptionsForUrl() method which receives a URL. + * + * cafile or capath can be overridden by passing in those options to constructor. + */ + $options = array( + 'ssl' => array( + 'ciphers' => $ciphers, + 'verify_peer' => true, + 'verify_depth' => 7, + 'SNI_enabled' => true, + ) + ); + + /** + * Attempt to find a local cafile or throw an exception. + * The user may go download one if this occurs. + */ + if (!$cafile) { + $cafile = self::getSystemCaRootBundlePath(); + } + if (is_dir($cafile)) { + $options['ssl']['capath'] = $cafile; + } elseif ($cafile) { + $options['ssl']['cafile'] = $cafile; + } else { + throw new RuntimeException('A valid cafile could not be located automatically.'); + } + + /** + * Disable TLS compression to prevent CRIME attacks where supported. + */ + if (version_compare(PHP_VERSION, '5.4.13') >= 0) { + $options['ssl']['disable_compression'] = true; + } + + return $options; + } + + /** + * function copied from Composer\Util\StreamContextFactory::initOptions + * + * Any changes should be applied there as well, or backported here. + * + * @param string $url URL the context is to be used for + * @return resource Default context + * @throws \RuntimeException if https proxy required and OpenSSL uninstalled + */ + protected function getMergedStreamContext($url) + { + $options = $this->options; + + // Handle HTTP_PROXY/http_proxy on CLI only for security reasons + if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy']))) { + $proxy = parse_url(!empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']); + } + + // Prefer CGI_HTTP_PROXY if available + if (!empty($_SERVER['CGI_HTTP_PROXY'])) { + $proxy = parse_url($_SERVER['CGI_HTTP_PROXY']); + } + + // Override with HTTPS proxy if present and URL is https + if (preg_match('{^https://}i', $url) && (!empty($_SERVER['HTTPS_PROXY']) || !empty($_SERVER['https_proxy']))) { + $proxy = parse_url(!empty($_SERVER['https_proxy']) ? $_SERVER['https_proxy'] : $_SERVER['HTTPS_PROXY']); + } + + // Remove proxy if URL matches no_proxy directive + if (!empty($_SERVER['NO_PROXY']) || !empty($_SERVER['no_proxy']) && parse_url($url, PHP_URL_HOST)) { + $pattern = new NoProxyPattern(!empty($_SERVER['no_proxy']) ? $_SERVER['no_proxy'] : $_SERVER['NO_PROXY']); + if ($pattern->test($url)) { + unset($proxy); + } + } + + if (!empty($proxy)) { + $proxyURL = isset($proxy['scheme']) ? $proxy['scheme'] . '://' : ''; + $proxyURL .= isset($proxy['host']) ? $proxy['host'] : ''; + + if (isset($proxy['port'])) { + $proxyURL .= ":" . $proxy['port']; + } elseif (strpos($proxyURL, 'http://') === 0) { + $proxyURL .= ":80"; + } elseif (strpos($proxyURL, 'https://') === 0) { + $proxyURL .= ":443"; + } + + // check for a secure proxy + if (strpos($proxyURL, 'https://') === 0) { + if (!extension_loaded('openssl')) { + throw new RuntimeException('You must enable the openssl extension to use a secure proxy.'); + } + if (strpos($url, 'https://') === 0) { + throw new RuntimeException('PHP does not support https requests through a secure proxy.'); + } + } + + // http(s):// is not supported in proxy + $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL); + + $options['http'] = array( + 'proxy' => $proxyURL, + ); + + // add request_fulluri for http requests + if ('http' === parse_url($url, PHP_URL_SCHEME)) { + $options['http']['request_fulluri'] = true; + } + + // handle proxy auth if present + if (isset($proxy['user'])) { + $auth = rawurldecode($proxy['user']); + if (isset($proxy['pass'])) { + $auth .= ':' . rawurldecode($proxy['pass']); + } + $auth = base64_encode($auth); + + $options['http']['header'] = "Proxy-Authorization: Basic {$auth}\r\n"; + } + } + + if (isset($options['http']['header'])) { + $options['http']['header'] .= "Connection: close\r\n"; + } else { + $options['http']['header'] = "Connection: close\r\n"; + } + if (extension_loaded('zlib')) { + $options['http']['header'] .= "Accept-Encoding: gzip\r\n"; + } + $options['http']['header'] .= "User-Agent: ".COMPOSER_INSTALLER."\r\n"; + $options['http']['protocol_version'] = 1.1; + $options['http']['timeout'] = 600; + + return stream_context_create($options); + } + + /** + * This method was adapted from Sslurp. + * https://github.com/EvanDotPro/Sslurp + * + * (c) Evan Coury + * + * For the full copyright and license information, please see below: + * + * Copyright (c) 2013, Evan Coury + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + public static function getSystemCaRootBundlePath() + { + if (self::$caPath !== null) { + return self::$caPath; + } + + // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that. + // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. + $envCertFile = getenv('SSL_CERT_FILE'); + if ($envCertFile && is_readable($envCertFile) && validateCaFile(file_get_contents($envCertFile))) { + return self::$caPath = $envCertFile; + } + + // If SSL_CERT_DIR env variable points to a valid certificate/bundle, use that. + // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. + $envCertDir = getenv('SSL_CERT_DIR'); + if ($envCertDir && is_dir($envCertDir) && is_readable($envCertDir)) { + return self::$caPath = $envCertDir; + } + + $configured = ini_get('openssl.cafile'); + if ($configured && strlen($configured) > 0 && is_readable($configured) && validateCaFile(file_get_contents($configured))) { + return self::$caPath = $configured; + } + + $configured = ini_get('openssl.capath'); + if ($configured && is_dir($configured) && is_readable($configured)) { + return self::$caPath = $configured; + } + + $caBundlePaths = array( + '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) + '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package) + '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package) + '/usr/local/share/certs/ca-root-nss.crt', // FreeBSD (ca_root_nss_package) + '/usr/ssl/certs/ca-bundle.crt', // Cygwin + '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package + '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option) + '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat? + '/etc/ssl/cert.pem', // OpenBSD + '/usr/local/etc/ssl/cert.pem', // FreeBSD 10.x + '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package + '/usr/local/etc/openssl@1.1/cert.pem', // OS X homebrew, openssl@1.1 package + '/opt/homebrew/etc/openssl@3/cert.pem', // macOS silicon homebrew, openssl@3 package + '/opt/homebrew/etc/openssl@1.1/cert.pem', // macOS silicon homebrew, openssl@1.1 package + ); + + foreach ($caBundlePaths as $caBundle) { + if (@is_readable($caBundle) && validateCaFile(file_get_contents($caBundle))) { + return self::$caPath = $caBundle; + } + } + + foreach ($caBundlePaths as $caBundle) { + $caBundle = dirname($caBundle); + if (is_dir($caBundle) && glob($caBundle.'/*')) { + return self::$caPath = $caBundle; + } + } + + return self::$caPath = false; + } + + public static function getPackagedCaFile() + { + return << 'error', + 'text' => esc_html__('Invalid email format', 'woodmart') + )); + } + wp_die(); +} + +/** + * Send Verification Code + * Generates a random code, encrypts it, stores it in a cookie, and sends it via email. + */ +add_action('wp_ajax_send_code', 'send_code'); +add_action('wp_ajax_nopriv_send_code', 'send_code'); + +function send_code() { + $email = $_POST['email']; + + // Generate a random 4-digit code + $string = rand(1234, 9999); + $ciphering = "AES-128-CTR"; + $options = 0; + $iv = '1234567891011121'; + $encryption = openssl_encrypt($string, $ciphering, SECRET, $options, $iv); + + // Store encrypted code in a cookie for 5 minutes + setcookie('login_code', $encryption, time() + 60 * 5, '/'); + + // Prepare email content based on language + if (function_exists('pll_current_language') && pll_current_language() === 'ru') { + $subject = "Проверочный код Cosmopet -" . $string; + $message = "Привет, это Cosmopet.\n +Держите проверочный код!\n +" . $string; + } else { + $subject = "Cosmopet Verification Code -" . $string; + $message = "Hello, this is CosmoPet.\n +Here's your verification code!\n +" . $string; + } + + // Remove email filters for consistent sending + remove_all_filters('wp_mail_from'); + remove_all_filters('wp_mail_from_name'); + $headers = array( + 'From: Cosmopet ', + 'content-type: text/html; charset=utf-8', + ); + + // Send email + wp_mail($email, $subject, $message, $headers); + + wp_die(); +} + +/** + * Check Verification Code + * Validates the user-entered code, logs in or registers the user. + */ +add_action('wp_ajax_check_code', 'check_code'); +add_action('wp_ajax_nopriv_check_code', 'check_code'); + +function check_code() { + header("Content-Type: application/json"); + + $code = $_POST['code']; + $email = $_POST['email']; + + // Generate a random 12-character password + $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@#!()'; + $pass = array(); + $alphaLength = strlen($alphabet) - 1; + for ($i = 0; $i < 12; $i++) { + $n = rand(0, $alphaLength); + $pass[] = $alphabet[$n]; + } + $pass = implode($pass); + + // Check if verification code cookie exists + if (isset($_COOKIE['login_code'])) { + $string = $_COOKIE['login_code']; + $ciphering = "AES-128-CTR"; + $options = 0; + $iv = '1234567891011121'; + $decryption = openssl_decrypt($string, $ciphering, SECRET, $options, $iv); + + if ($decryption === $code) { + if (email_exists($email)) { + // Log in existing user + $user_id = get_user_by('login', $email)->ID; + if (empty($user_id)) { + $user_id = get_user_by('email', $email)->ID; + } + wp_set_password($pass, $user_id); + wp_signon( + array( + 'user_login' => $email, + 'user_password' => $pass, + 'remember' => 'on', + ) + ); + + echo json_encode(array( + 'status' => 'success_auth' + )); + if (function_exists('update_field')) { + update_field('activated', true, 'user_' . $user_id); // Requires ACF + } + exit(); + } else { + // Register new user + $user_id = wp_create_user($email, $pass, $email); + wp_update_user([ + 'ID' => $user_id, + 'user_email' => $email + ]); + + wp_set_auth_cookie($user_id, true); + echo json_encode(array( + 'status' => 'success_reg' + )); + if (function_exists('update_field')) { + update_field('activated', true, 'user_' . $user_id); // Requires ACF + } + exit(); + } + } else { + echo json_encode(array( + 'status' => 'error', + 'text' => esc_html__('Invalid code', 'woodmart') + )); + exit(); + } + } else { + echo json_encode(array( + 'status' => 'error', + 'text' => esc_html__('The code hasexpired', 'woodmart') + )); + exit(); + } + wp_die(); +} + +/** + * Logout Redirect + * Redirects to the homepage after user logout. + */ +add_action('wp_logout', 'logout_redirect'); + +function logout_redirect() { + wp_redirect('/'); + exit(); +} + add_filter( 'woocommerce_price_trim_zeros', '__return_true' ); function add_comment_like() { @@ -979,4 +1138,207 @@ function change_wbw_filter_button_text($text) { add_filter('wbw_filter_reset_button_text', 'change_wbw_reset_button_text'); function change_wbw_reset_button_text($text) { return 'Сбросить'; -} \ No newline at end of file +} + + +add_action('wp_ajax_get_cart_fragment', 'get_cart_fragment_callback'); +add_action('wp_ajax_nopriv_get_cart_fragment', 'get_cart_fragment_callback'); + +function get_cart_fragment_callback() { + // Проверяем nonce для безопасности + check_ajax_referer('woocommerce-cart', 'security', false); + + // Получаем содержимое корзины + ob_start(); + wc_get_template('shop/cart-contents.twig', [], '', get_template_directory() . '/templates/'); + $contents = ob_get_clean(); + + // Получаем футер корзины + ob_start(); + wc_get_template('modal-basket-footer.twig', [], '', get_template_directory() . '/templates/'); + $footer = ob_get_clean(); + + // Получаем данные корзины + $cart = WC()->cart; + $count = $cart->get_cart_contents_count(); + $total = $cart->get_total('raw'); // Числовая сумма + $total_html = wc_cart_totals_order_total_html(); // Форматированная сумма + + wp_send_json_success([ + 'contents' => $contents, + 'footer' => $footer, + 'count' => $count, + 'total' => $total_html, + 'total_raw' => $total + ]); +} + +add_action('template_redirect', 'custom_redirect_cart_page'); +function custom_redirect_cart_page() { + if (is_cart()) { + wp_redirect(home_url('/')); + exit; + } +} + +add_action('wp_enqueue_scripts', 'remove_woocommerce_styles_on_checkout', 9999); +function remove_woocommerce_styles_on_checkout() { + // Проверяем, что мы на странице чекаута + if (function_exists('is_checkout') && is_checkout() && !is_order_received_page()) { + wp_deregister_style('woocommerce-layout'); + wp_deregister_style('woocommerce-smallscreen'); + wp_deregister_style('woocommerce-general'); + + // Дополнительно: отключить другие стили WooCommerce + wp_dequeue_style('select2'); + wp_deregister_style('select2'); + } +} + + + +// Добавляем hreflang теги для cosmopet.shop +add_action('wp_head', 'custom_hreflang_shop', 6); +function custom_hreflang_shop() { + if (!is_admin() && function_exists('pll_get_post') && function_exists('pll_languages_list')) { + // Защищаем от дублирования + static $hreflang_added = false; + if ($hreflang_added) { + return; + } + $hreflang_added = true; + + // Домены для языков + $ru_domain = 'https://cosmopet-test-ru.cp.good-production.xyz'; + $en_domain = 'https://cosmopet-test-ae.cp.good-production.xyz'; + + // Текущий пост/страница + $current_post_id = get_the_ID(); + if (!$current_post_id) { + // Для случаев, когда get_the_ID() не работает (например, архивы) + $current_path = trailingslashit($_SERVER['REQUEST_URI']); + $query_string = $_SERVER['QUERY_STRING'] ? '?' . $_SERVER['QUERY_STRING'] : ''; + $ru_url = $ru_domain . $current_path . $query_string; + $en_url = $en_domain . $current_path . $query_string; + } else { + // Получаем переводы поста/страницы + $ru_post_id = pll_get_post($current_post_id, 'ru'); + $en_post_id = pll_get_post($current_post_id, 'en'); + + // Формируем URL с учетом перевода и параметров запроса + $query_string = $_SERVER['QUERY_STRING'] ? '?' . $_SERVER['QUERY_STRING'] : ''; + + $ru_url = $ru_post_id ? get_permalink($ru_post_id) . $query_string : $ru_domain . trailingslashit($_SERVER['REQUEST_URI']) . $query_string; + $en_url = $en_post_id ? get_permalink($en_post_id) . $query_string : $en_domain . trailingslashit($_SERVER['REQUEST_URI']) . $query_string; + } + + // Выводим hreflang-теги + echo '' . "\n"; + echo '' . "\n"; + } +} + +add_action('wp_head', 'custom_checkout_padding'); +function custom_checkout_padding() { + // Проверяем, что это страница Checkout + if (is_checkout() && !is_admin()) { + ?> + + user_email . time()); // Generate a unique activation key + update_field('uuid', $activation_key, 'user_' . get_current_user_id()); // Save the key in user meta + + $activation_link = home_url("/activate/$activation_key"); + + if(pll_current_language() === 'ru'){ + $subject = "Активация аккаунта COSMOPET -".$string; + $message = " Остался последний шаг!\n +Пройдите по ссылке для активации аккаунта:\n +".$activation_link; + } else { + $subject = "Account activation COSMOPET -".$string; + $message = "Last step!\n + Follow the link to activate your account\n +".$activation_link; + } + + wp_mail($user->user_email, $subject, $message); +} + + + +add_action('init', 'custom_register_activation_endpoint'); + +function custom_register_activation_endpoint() { + add_rewrite_rule('^activate/([^/]*)/?', 'index.php?activation_key=$matches[1]', 'top'); + add_rewrite_tag('%activation_key%', '([^&]+)'); +} + + +add_action('template_redirect', 'custom_handle_activation_request'); + + + +add_action('template_redirect', 'custom_handle_activation_request'); + +function get_user_by_acf_field_value($field_value) { + // Prepare the arguments for WP_User_Query + $args = array( + 'meta_query' => array( + array( + 'key' => 'uuid', // Change to your ACF field key + 'value' => $field_value, + 'compare' => '=', // You can use other comparison operators if needed + ), + ), + ); + + // Execute the query + $user_query = new WP_User_Query($args); + + // Check for results + if (!empty($user_query->get_results())) { + return $user_query->get_results(); // Returns an array of WP_User objects + } else { + return null; // No users found + } +} + +function custom_handle_activation_request() { + if (get_query_var('activation_key')) { + $activation_key = sanitize_text_field(get_query_var('activation_key')); + + $users = get_user_by_acf_field_value($activation_key); + + if ($users) { + foreach ($users as $user) { + $user->set_bio(); + // delete_user_meta($user->ID, 'uuid'); // Clean up the activation key + update_field('uuid', '', 'user_' . $user->ID); + update_field('activated', true, 'user_' . $user->ID); + wp_set_auth_cookie($user->ID); + wp_redirect('/my-account/'); // Redirect to the homepage or a custom page + var_dump($user); + exit; + } + } + + } +} + diff --git a/wp-content/themes/cosmopet/global-functions/core-functions.php b/wp-content/themes/cosmopet/global-functions/core-functions.php index a4abe2d..d917072 100644 --- a/wp-content/themes/cosmopet/global-functions/core-functions.php +++ b/wp-content/themes/cosmopet/global-functions/core-functions.php @@ -1,2 +1,263 @@ array( + 'name' => 'Питомцы', // Основное название типа записи + 'singular_name' => 'Питомец', // отдельное название записи типа Book + 'add_new' => 'Добавить нового', + 'add_new_item' => 'Добавить нового питомца', + 'edit_item' => 'Редактировать питомца', + 'new_item' => 'Новый питомец', + 'view_item' => 'Посмотреть питомца', + 'search_items' => 'Найти питомца', + 'not_found' => 'Питомцев не найдено', + 'not_found_in_trash' => 'В корзине книг не найдено', + 'parent_item_colon' => '', + 'menu_name' => 'Питомцы' + + ), + 'public' => false, + 'show_ui' => true, + 'supports' => array('title','editor') +) ); +} + +function get_pet_card($item){ +?> + +
+
+
+
+
+ +
+
+ +

+
+ +
+

:

+

+
+
+

:

+

+
+ +
+

:

+

+
+ + + +
+

:

+

+
+ +
+

:

+

+
+ +
+

+ +
+ +
+ +
+
+
+ admin_url('admin-ajax.php'), +// 'nonce' => wp_create_nonce('wc_checkout_nonce') +// ]); +// } +// } + +// // AJAX-обработчик для обновления количества +// add_action('wp_ajax_update_cart_quantity', 'update_cart_quantity_callback'); +// add_action('wp_ajax_nopriv_update_cart_quantity', 'update_cart_quantity_callback'); +// function update_cart_quantity_callback() { +// check_ajax_referer('wc_checkout_nonce', 'nonce'); + +// $cart_item_key = sanitize_text_field($_POST['cart_item_key']); +// $quantity = intval($_POST['quantity']); + +// if ($quantity > 0) { +// WC()->cart->set_quantity($cart_item_key, $quantity); +// } else { +// WC()->cart->remove_cart_item($cart_item_key); +// } + +// WC()->cart->calculate_totals(); + +// // Подготовка фрагментов +// $fragments = []; + +// // Обновление списка товаров +// ob_start(); +// wc_get_template('checkout/form-checkout.php', [], '', get_template_directory() . '/woocommerce/'); +// $fragments['.order-your__products'] = ob_get_clean(); + +// // Обновление секции итогов +// ob_start(); +// woocommerce_checkout_coupon_form(); +// woocommerce_order_review(); +// $fragments['.order-your__calculation'] = ob_get_clean(); + +// // Подготовка цен для каждого товара +// $item_prices = []; +// foreach (WC()->cart->get_cart() as $item_key => $item) { +// $item_prices[$item_key] = WC()->cart->get_product_subtotal($item['data'], $item['quantity']); +// } + +// wp_send_json_success([ +// 'fragments' => $fragments, +// 'item_prices' => $item_prices, +// 'cart_total' => WC()->cart->get_cart_total() +// ]); +// } + +// // AJAX-обработчик для удаления товара +// add_action('wp_ajax_remove_cart_item', 'remove_cart_item_callback'); +// add_action('wp_ajax_nopriv_remove_cart_item', 'remove_cart_item_callback'); +// function remove_cart_item_callback() { +// check_ajax_referer('wc_checkout_nonce', 'nonce'); + +// $cart_item_key = sanitize_text_field($_POST['cart_item_key']); +// WC()->cart->remove_cart_item($cart_item_key); +// WC()->cart->calculate_totals(); + +// // Подготовка фрагментов +// $fragments = []; + +// // Обновление списка товаров +// ob_start(); +// wc_get_template('checkout/form-checkout.php', [], '', get_template_directory() . '/woocommerce/'); +// $fragments['.order-your__products'] = ob_get_clean(); + +// // Обновление секции итогов +// ob_start(); +// woocommerce_checkout_coupon_form(); +// woocommerce_order_review(); +// $fragments['.order-your__calculation'] = ob_get_clean(); + +// wp_send_json_success([ +// 'fragments' => $fragments, +// 'cart_total' => WC()->cart->get_cart_total() +// ]); +// } + + diff --git a/wp-content/themes/cosmopet/global-functions/multilang-functions.php b/wp-content/themes/cosmopet/global-functions/multilang-functions.php index 015ff51..f7ff4b3 100644 --- a/wp-content/themes/cosmopet/global-functions/multilang-functions.php +++ b/wp-content/themes/cosmopet/global-functions/multilang-functions.php @@ -1,94 +1,1527 @@ - скидку!', 'Узнайте о нас больше и получите скидку!'); - pll_register_string ('Это миф!', 'Это миф!'); - pll_register_string ('Это правда!', 'Это правда!'); - pll_register_string ('Правда', 'Правда'); - pll_register_string ('Миф', 'Миф'); - pll_register_string ('Далее', 'Далее'); - pll_register_string ('ваш результат', 'ваш результат'); - pll_register_string ('Скопировать', 'Скопировать'); - pll_register_string ('Скопировано', 'Скопировано'); - pll_register_string ('В магазин', 'В магазин'); - pll_register_string ('Наш блог', 'Наш блог'); - pll_register_string ('Новости рынка кормов и экологии, полезные статьи о здоровье домашних животных', 'Новости рынка кормов и экологии, полезные статьи о здоровье домашних животных'); - pll_register_string ('ЭТАПЫ ПРОИЗВОД­СТВА', 'ЭТАПЫ ПРОИЗВОД­СТВА'); - pll_register_string ('Этапы производс­тва корма', 'Этапы производс­тва корма'); - pll_register_string ('Все статьи', 'Все статьи'); - pll_register_string ('Узнать больше', 'Узнать больше'); - pll_register_string ('Продукция', 'Продукция'); - pll_register_string ('Фильтры', 'Фильтры'); - pll_register_string ('Новинка', 'Новинка'); - pll_register_string ('Распродажа %', 'Распродажа %'); - pll_register_string ('Купить', 'Купить'); - pll_register_string ('Подробнее', 'Подробнее'); - pll_register_string ('Объем', 'Объем'); - pll_register_string ('Количество', 'Количество'); - pll_register_string ('Добавить в корзину', 'Добавить в корзину'); - pll_register_string ('Применить', 'Применить'); - pll_register_string ('Сбросить фильтры', 'Сбросить фильтры'); - pll_register_string('cosmopet_bestsellers_title', 'BESTSELLERS', 'CosmoPet Theme Bestsellers'); - pll_register_string('cosmopet_previous_products', 'Previous products', 'CosmoPet Theme Bestsellers'); - pll_register_string('cosmopet_next_products', 'Next products', 'CosmoPet Theme Bestsellers'); - pll_register_string('cosmopet_view_product', 'View product:', 'CosmoPet Theme Bestsellers'); - pll_register_string('cosmopet_product_image', 'Product image:', 'CosmoPet Theme Bestsellers'); - pll_register_string('cosmopet_buy_button', 'Buy', 'CosmoPet Theme Bestsellers'); - pll_register_string('cosmopet_all_products', 'All products', 'CosmoPet Theme Bestsellers'); - pll_register_string('cosmopet_no_products', 'No bestsellers found', 'CosmoPet Theme Bestsellers'); - pll_register_string('cosmopet_back_to_catalog', 'к каталогу', 'Product Detail'); - pll_register_string('cosmopet_sale_tag', 'Распродажа %', 'Product Detail'); - pll_register_string('cosmopet_add_to_cart', 'Добавить в корзину', 'Product Detail'); - pll_register_string('cosmopet_description', 'ОПИСАНИЕ', 'Product Detail'); - pll_register_string('cosmopet_composition', 'СОСТАВ', 'Product Detail'); - pll_register_string('cosmopet_feeding_recommendations', 'РЕКОМЕНДАЦИИ ПО КОРМЛЕНИЮ', 'Product Detail'); - pll_register_string('cosmopet_nutritional_value', 'ПИЩЕВАЯ ЦЕННОСТЬ', 'Product Detail'); - pll_register_string('cosmopet_vitamins_per_kg', 'ВИТАМИНЫ НА КГ', 'Product Detail'); - pll_register_string('cosmopet_nutritional_additives_per_kg', 'ПИТАТЕЛЬНЫЕ ДОБАВКИ НА КГ', 'Product Detail'); - pll_register_string('cosmopet_energy_value_per_100g', 'ЭНЕРГЕТИЧЕСКАЯ ЦЕННОСТЬ НА 100 ГРАММ', 'Product Detail'); - pll_register_string('cosmopet_important', 'Важно', 'Product Detail'); - pll_register_string('cosmopet_you_may_also_like', 'вашему питомцу может понравиться', 'Product Detail'); - pll_register_string('cosmopet_new_product', 'Новинка', 'Product Detail'); - pll_register_string('cosmopet_buy', 'Купить', 'Product Detail'); - pll_register_string('cosmopet_volume', 'Объем', 'Product Detail'); - pll_register_string('cosmopet_quantity', 'Количество', 'Product Detail'); - pll_register_string('cosmopet_details', 'Подробнее', 'Product Detail'); +add_action('init', function () { + if (function_exists('pll_register_string')) { + // Массив строк с переводами + $strings = [ + [ + 'name' => 'Темы', + 'string' => 'Темы', + 'translations' => [ + 'ru' => 'Темы', + 'en' => 'Topics', + ], + 'group' => 'General', + ], + [ + 'name' => 'САМЫЕ ЧИТАЕМЫЕ', + 'string' => 'САМЫЕ ЧИТАЕМЫЕ', + 'translations' => [ + 'ru' => 'САМЫЕ ЧИТАЕМЫЕ', + 'en' => 'MOST READ', + ], + 'group' => 'General', + ], + [ + 'name' => 'время чтения', + 'string' => 'время чтения', + 'translations' => [ + 'ru' => 'время чтения', + 'en' => 'reading time', + ], + 'group' => 'General', + ], + [ + 'name' => 'ВСЕ СТАТЬИ', + 'string' => 'ВСЕ СТАТЬИ', + 'translations' => [ + 'ru' => 'ВСЕ СТАТЬИ', + 'en' => 'ALL ARTICLES', + ], + 'group' => 'General', + ], + [ + 'name' => 'ПРЕДЛОЖИТЕ СТАТЬЮ ИЛИ СТАНЬТЕ АВТОРОМ', + 'string' => 'ПРЕДЛОЖИТЕ СТАТЬЮ ИЛИ СТАНЬТЕ АВТОРОМ', + 'translations' => [ + 'ru' => 'ПРЕДЛОЖИТЕ СТАТЬЮ ИЛИ СТАНЬТЕ АВТОРОМ', + 'en' => 'SUGGEST AN ARTICLE OR BECOME AN AUTHOR', + ], + 'group' => 'General', + ], + [ + 'name' => 'НАПИШИТЕ НАМ', + 'string' => 'НАПИШИТЕ НАМ', + 'translations' => [ + 'ru' => 'НАПИШИТЕ НАМ', + 'en' => 'WRITE TO US', + ], + 'group' => 'General', + ], + [ + 'name' => 'COSMO тема редакции', + 'string' => 'COSMO тема редакции', + 'translations' => [ + 'ru' => 'COSMO тема редакции', + 'en' => 'COSMO editor\'s choice', + ], + 'group' => 'General', + ], + [ + 'name' => 'мин.', + 'string' => 'мин.', + 'translations' => [ + 'ru' => 'мин.', + 'en' => 'min.', + ], + 'group' => 'General', + ], + [ + 'name' => 'Форма обратной связи', + 'string' => 'Форма обратной связи', + 'translations' => [ + 'ru' => 'Форма обратной связи', + 'en' => 'Contact Form', + ], + 'group' => 'General', + ], + [ + 'name' => 'Ваше имя', + 'string' => 'Ваше имя', + 'translations' => [ + 'ru' => 'Ваше имя', + 'en' => 'Your name', + ], + 'group' => 'General', + ], + [ + 'name' => 'Эл.почта', + 'string' => 'Эл.почта', + 'translations' => [ + 'ru' => 'Эл.почта', + 'en' => 'Email', + ], + 'group' => 'General', + ], + [ + 'name' => 'Текст обращения', + 'string' => 'Текст обращения', + 'translations' => [ + 'ru' => 'Текст обращения', + 'en' => 'Message text', + ], + 'group' => 'General', + ], + [ + 'name' => 'Отправить', + 'string' => 'Отправить', + 'translations' => [ + 'ru' => 'Отправить', + 'en' => 'Send', + ], + 'group' => 'General', + ], + [ + 'name' => 'Чат бот с ветеринаром', + 'string' => 'Чат бот с ветеринаром', + 'translations' => [ + 'ru' => 'Чат бот с ветеринаром', + 'en' => 'Chatbot with a veterinarian', + ], + 'group' => 'General', + ], + [ + 'name' => 'К клькулятор рациона', + 'string' => 'Калькулятор рациона', + 'translations' => [ + 'ru' => 'Калькулятор рациона', + 'en' => 'Diet Calculator', + ], + 'group' => 'General', + ], + [ + 'name' => 'ПОКАЗАТЬ ЕЩЁ', + 'string' => 'ПОКАЗАТЬ ЕЩЁ', + 'translations' => [ + 'ru' => 'ПОКАЗАТЬ ЕЩЁ', + 'en' => 'SHOW MORE', + ], + 'group' => 'General', + ], + [ + 'name' => 'ВСЕ', + 'string' => 'ВСЕ', + 'translations' => [ + 'ru' => 'ВСЕ', + 'en' => 'ALL', + ], + 'group' => 'General', + ], + [ + 'name' => 'читать статью', + 'string' => 'читать статью', + 'translations' => [ + 'ru' => 'читать статью', + 'en' => 'read article', + ], + 'group' => 'General', + ], + [ + 'name' => 'Блог', + 'string' => 'Блог', + 'translations' => [ + 'ru' => 'Блог', + 'en' => 'Blog', + ], + 'group' => 'General', + ], + [ + 'name' => 'Главная', + 'string' => 'Главная', + 'translations' => [ + 'ru' => 'Главная', + 'en' => 'Home', + ], + 'group' => 'General', + ], + [ + 'name' => 'Подпишитесь, чтобы быть в курсе деятельности Cosmopet и узнавать о наших, предложениях. Обещаем не заваливать вас бесполезными письмами. А за подписку дарим -25% на весь ассортимент нашей продукции', + 'string' => 'Подпишитесь, чтобы быть в курсе деятельности Cosmopet и узнавать о наших, предложениях. Обещаем не заваливать вас бесполезными письмами. А за подписку дарим -25% на весь ассортимент нашей продукции', + 'translations' => [ + 'ru' => 'Подпишитесь, чтобы быть в курсе деятельности Cosmopet и узнавать о наших, предложениях. Обещаем не заваливать вас бесполезными письмами. А за подписку дарим -25% на весь ассортимент нашей продукции', + 'en' => 'Subscribe to stay updated on Cosmopet activities and learn about our offers. We promise not to spam you with useless emails. And for subscribing, we offer a -25% discount on our entire product range', + ], + 'group' => 'General', + ], + [ + 'name' => 'Подписываясь на рассылку, я даю согласие на обработку персональных данных, на получение рекламных сообщений и новостей о товарах и услугах', + 'string' => 'Подписываясь на рассылку, я даю согласие на обработку персональных данных, на получение рекламных сообщений и новостей о товарах и услугах', + 'translations' => [ + 'ru' => 'Подписываясь на рассылку, я даю согласие на обработку персональных данных, на получение рекламных сообщений и новостей о товарах и услугах', + 'en' => 'By subscribing to the newsletter, I consent to the processing of personal data and receiving promotional messages and news about products and services', + ], + 'group' => 'General', + ], + [ + 'name' => 'подписаться', + 'string' => 'подписаться', + 'translations' => [ + 'ru' => 'подписаться', + 'en' => 'subscribe', + ], + 'group' => 'General', + ], + [ + 'name' => 'Узнайте о нас больше и получите скидку!', + 'string' => 'Узнайте о нас больше и получите скидку!', + 'translations' => [ + 'ru' => 'Узнайте о нас больше и получите скидку!', + 'en' => 'Learn more about us and get a discount!', + ], + 'group' => 'General', + ], + [ + 'name' => 'Это миф!', + 'string' => 'Это миф!', + 'translations' => [ + 'ru' => 'Это миф!', + 'en' => 'It\'s a myth!', + ], + 'group' => 'General', + ], + [ + 'name' => 'Это правда!', + 'string' => 'Это правда!', + 'translations' => [ + 'ru' => 'Это правда!', + 'en' => 'It\'s true!', + ], + 'group' => 'General', + ], + [ + 'name' => 'Правда', + 'string' => 'Правда', + 'translations' => [ + 'ru' => 'Правда', + 'en' => 'True', + ], + 'group' => 'General', + ], + [ + 'name' => 'Миф', + 'string' => 'Миф', + 'translations' => [ + 'ru' => 'Миф', + 'en' => 'Myth', + ], + 'group' => 'General', + ], + [ + 'name' => 'Далее', + 'string' => 'Далее', + 'translations' => [ + 'ru' => 'Далее', + 'en' => 'Next', + ], + 'group' => 'General', + ], + [ + 'name' => 'ваш результат', + 'string' => 'ваш результат', + 'translations' => [ + 'ru' => 'ваш результат', + 'en' => 'your result', + ], + 'group' => 'General', + ], + [ + 'name' => 'Скопировать', + 'string' => 'Скопировать', + 'translations' => [ + 'ru' => 'Скопировать', + 'en' => 'Copy', + ], + 'group' => 'General', + ], + [ + 'name' => 'Скопировано', + 'string' => 'Скопировано', + 'translations' => [ + 'ru' => 'Скопировано', + 'en' => 'Copied', + ], + 'group' => 'General', + ], + [ + 'name' => 'В магазин', + 'string' => 'В магазин', + 'translations' => [ + 'ru' => 'В магазин', + 'en' => 'To the store', + ], + 'group' => 'General', + ], + [ + 'name' => 'Наш блог', + 'string' => 'Наш блог', + 'translations' => [ + 'ru' => 'Наш блог', + 'en' => 'Our blog', + ], + 'group' => 'General', + ], + [ + 'name' => 'Новости рынка кормов и экологии, полезные статьи о здоровье домашних животных', + 'string' => 'Новости рынка кормов и экологии, полезные статьи о здоровье домашних животных', + 'translations' => [ + 'ru' => 'Новости рынка кормов и экологии, полезные статьи о здоровье домашних животных', + 'en' => 'News on the pet food and ecology market, helpful articles on pet health', + ], + 'group' => 'General', + ], + [ + 'name' => 'ЭТАПЫ ПРОИЗВОД­СТВА', + 'string' => 'ЭТАПЫ ПРОИЗВОД­СТВА', + 'translations' => [ + 'ru' => 'ЭТАПЫ ПРОИЗВОД­СТВА', + 'en' => 'PRODUCTION STAGES', + ], + 'group' => 'General', + ], + [ + 'name' => 'Этапы производс­тва корма', + 'string' => 'Этапы производс­тва корма', + 'translations' => [ + 'ru' => 'Этапы производс­тва корма', + 'en' => 'Pet food production stages', + ], + 'group' => 'General', + ], + [ + 'name' => 'Все статьи', + 'string' => 'Все статьи', + 'translations' => [ + 'ru' => 'Все статьи', + 'en' => 'All articles', + ], + 'group' => 'General', + ], + [ + 'name' => 'Узнать больше', + 'string' => 'Узнать больше', + 'translations' => [ + 'ru' => 'Узнать больше', + 'en' => 'Learn more', + ], + 'group' => 'General', + ], + [ + 'name' => 'Продукция', + 'string' => 'Продукция', + 'translations' => [ + 'ru' => 'Продукция', + 'en' => 'Products', + ], + 'group' => 'General', + ], + [ + 'name' => 'Фильтры', + 'string' => 'Фильтры', + 'translations' => [ + 'ru' => 'Фильтры', + 'en' => 'Filters', + ], + 'group' => 'General', + ], + [ + 'name' => 'Новинка', + 'string' => 'Новинка', + 'translations' => [ + 'ru' => 'Новинка', + 'en' => 'New', + ], + 'group' => 'General', + ], + [ + 'name' => 'Распродажа %', + 'string' => 'Распродажа %', + 'translations' => [ + 'ru' => 'Распродажа %', + 'en' => 'Sale %', + ], + 'group' => 'General', + ], + [ + 'name' => 'Купить', + 'string' => 'Купить', + 'translations' => [ + 'ru' => 'Купить', + 'en' => 'Buy', + ], + 'group' => 'General', + ], + [ + 'name' => 'Подробнее', + 'string' => 'Подробнее', + 'translations' => [ + 'ru' => 'Подробнее', + 'en' => 'Details', + ], + 'group' => 'General', + ], + [ + 'name' => 'Объем', + 'string' => 'Объем', + 'translations' => [ + 'ru' => 'Объем', + 'en' => 'Volume', + ], + 'group' => 'General', + ], + [ + 'name' => 'Количество', + 'string' => 'Количество', + 'translations' => [ + 'ru' => 'Количество', + 'en' => 'Quantity', + ], + 'group' => 'General', + ], + [ + 'name' => 'Добавить в корзину', + 'string' => 'Добавить в корзину', + 'translations' => [ + 'ru' => 'Добавить в корзину', + 'en' => 'Add to cart', + ], + 'group' => 'General', + ], + [ + 'name' => 'Применить', + 'string' => 'Применить', + 'translations' => [ + 'ru' => 'Применить', + 'en' => 'Apply', + ], + 'group' => 'General', + ], + [ + 'name' => 'Сбросить фильтры', + 'string' => 'Сбросить фильтры', + 'translations' => [ + 'ru' => 'Сбросить фильтры', + 'en' => 'Reset filters', + ], + 'group' => 'General', + ], + [ + 'name' => 'cosmopet_bestsellers_title', + 'string' => 'BESTSELLERS', + 'translations' => [ + 'ru' => 'БЕСТСЕЛЛЕРЫ', + 'en' => 'BESTSELLERS', + ], + 'group' => 'CosmoPet Theme Bestsellers', + ], + [ + 'name' => 'cosmopet_previous_products', + 'string' => 'Previous products', + 'translations' => [ + 'ru' => 'Предыдущие товары', + 'en' => 'Previous products', + ], + 'group' => 'CosmoPet Theme Bestsellers', + ], + [ + 'name' => 'cosmopet_next_products', + 'string' => 'Next products', + 'translations' => [ + 'ru' => 'Следующие товары', + 'en' => 'Next products', + ], + 'group' => 'CosmoPet Theme Bestsellers', + ], + [ + 'name' => 'cosmopet_view_product', + 'string' => 'View product:', + 'translations' => [ + 'ru' => 'Посмотреть товар:', + 'en' => 'View product:', + ], + 'group' => 'CosmoPet Theme Bestsellers', + ], + [ + 'name' => 'cosmopet_product_image', + 'string' => 'Product image:', + 'translations' => [ + 'ru' => 'Изображение товара:', + 'en' => 'Product image:', + ], + 'group' => 'CosmoPet Theme Bestsellers', + ], + [ + 'name' => 'cosmopet_buy_button', + 'string' => 'Buy', + 'translations' => [ + 'ru' => 'Купить', + 'en' => 'Buy', + ], + 'group' => 'CosmoPet Theme Bestsellers', + ], + [ + 'name' => 'cosmopet_all_products', + 'string' => 'All products', + 'translations' => [ + 'ru' => 'Все товары', + 'en' => 'All products', + ], + 'group' => 'CosmoPet Theme Bestsellers', + ], + [ + 'name' => 'cosmopet_no_products', + 'string' => 'No bestsellers found', + 'translations' => [ + 'ru' => 'Бестселлеры не найдены', + 'en' => 'No bestsellers found', + ], + 'group' => 'CosmoPet Theme Bestsellers', + ], + [ + 'name' => 'cosmopet_back_to_catalog', + 'string' => 'к каталогу', + 'translations' => [ + 'ru' => 'к каталогу', + 'en' => 'to catalog', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_sale_tag', + 'string' => 'Распродажа %', + 'translations' => [ + 'ru' => 'Распродажа %', + 'en' => 'Sale %', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_add_to_cart', + 'string' => 'Добавить в корзину', + 'translations' => [ + 'ru' => 'Добавить в корзину', + 'en' => 'Add to cart', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_description', + 'string' => 'ОПИСАНИЕ', + 'translations' => [ + 'ru' => 'ОПИСАНИЕ', + 'en' => 'DESCRIPTION', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_composition', + 'string' => 'СОСТАВ', + 'translations' => [ + 'ru' => 'СОСТАВ', + 'en' => 'COMPOSITION', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_feeding_recommendations', + 'string' => 'РЕКОМЕНДАЦИИ ПО КОРМЛЕНИЮ', + 'translations' => [ + 'ru' => 'РЕКОМЕНДАЦИИ ПО КОРМЛЕНИЮ', + 'en' => 'FEEDING RECOMMENDATIONS', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_nutritional_value', + 'string' => 'ПИЩЕВАЯ ЦЕННОСТЬ', + 'translations' => [ + 'ru' => 'ПИЩЕВАЯ ЦЕННОСТЬ', + 'en' => 'NUTRITIONAL VALUE', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_vitamins_per_kg', + 'string' => 'ВИТАМИНЫ НА КГ', + 'translations' => [ + 'ru' => 'ВИТАМИНЫ НА КГ', + 'en' => 'VITAMINS PER KG', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_nutritional_additives_per_kg', + 'string' => 'ПИТАТЕЛЬНЫЕ ДОБАВКИ НА КГ', + 'translations' => [ + 'ru' => 'ПИТАТЕЛЬНЫЕ ДОБАВКИ НА КГ', + 'en' => 'NUTRITIONAL ADDITIVES PER KG', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_energy_value_per_100g', + 'string' => 'ЭНЕРГЕТИЧЕСКАЯ ЦЕННОСТЬ НА 100 ГРАММ', + 'translations' => [ + 'ru' => 'ЭНЕРГЕТИЧЕСКАЯ ЦЕННОСТЬ НА 100 ГРАММ', + 'en' => 'ENERGY VALUE PER 100 GRAMS', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_important', + 'string' => 'Важно', + 'translations' => [ + 'ru' => 'Важно', + 'en' => 'Important', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_you_may_also_like', + 'string' => 'вашему питомцу может понравиться', + 'translations' => [ + 'ru' => 'вашему питомцу может понравиться', + 'en' => 'your pet may like', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_new_product', + 'string' => 'Новинка', + 'translations' => [ + 'ru' => 'Новинка', + 'en' => 'New', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_buy', + 'string' => 'Купить', + 'translations' => [ + 'ru' => 'Купить', + 'en' => 'Buy', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_volume', + 'string' => 'Объем', + 'translations' => [ + 'ru' => 'Объем', + 'en' => 'Volume', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_quantity', + 'string' => 'Количество', + 'translations' => [ + 'ru' => 'Количество', + 'en' => 'Quantity', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'cosmopet_details', + 'string' => 'Подробнее', + 'translations' => [ + 'ru' => 'Подробнее', + 'en' => 'Details', + ], + 'group' => 'Product Detail', + ], + [ + 'name' => 'reviews_title', + 'string' => 'Customer Reviews', + 'translations' => [ + 'ru' => 'Отзывы клиентов', + 'en' => 'Customer Reviews', + ], + 'group' => 'Reviews Section', + ], + [ + 'name' => 'show_more', + 'string' => 'Show more', + 'translations' => [ + 'ru' => 'Показать больше', + 'en' => 'Show more', + ], + 'group' => 'Reviews Section', + ], + [ + 'name' => 'default_reviewer_name', + 'string' => 'Anastasia', + 'translations' => [ + 'ru' => 'Анастасия', + 'en' => 'Anastasia', + ], + 'group' => 'Reviews Section', + ], + [ + 'name' => 'default_reviewer_role', + 'string' => 'dog owner', + 'translations' => [ + 'ru' => 'владелец собаки', + 'en' => 'dog owner', + ], + 'group' => 'Reviews Section', + ], + [ + 'name' => 'default_review_excerpt', + 'string' => 'Just wanted to say thank you - your treats are amazing!', + 'translations' => [ + 'ru' => 'Хочу сказать спасибо - ваши лакомства потрясающие!', + 'en' => 'Just wanted to say thank you - your treats are amazing!', + ], + 'group' => 'Reviews Section', + ], + [ + 'name' => 'default_review_full_1', + 'string' => 'She loves the lamb one - tasty, safe, and it even works great as a dental treat!', + 'translations' => [ + 'ru' => 'Ей очень нравится с ягненком - вкусно, безопасно, и даже отлично подходит как лакомство для зубов!', + 'en' => 'She loves the lamb one - tasty, safe, and it even works great as a dental treat!', + ], + 'group' => 'Reviews Section', + ], + [ + 'name' => 'default_review_full_2', + 'string' => 'And the salmon sandwich in the tube is our go-to. We never leave the house without it. Perfect for walks and training!', + 'translations' => [ + 'ru' => 'А сэндвич с лососем в тюбике - наш фаворит. Мы не выходим из дома без него. Идеально для прогулок и тренировок!', + 'en' => 'And the salmon sandwich in the tube is our go-to. We never leave the house without it. Perfect for walks and training!', + ], + 'group' => 'Reviews Section', + ], + [ + 'name' => 'default_review_full_3', + 'string' => 'So glad we found you!', + 'translations' => [ + 'ru' => 'Так рады, что нашли вас!', + 'en' => 'So glad we found you!', + ], + 'group' => 'Reviews Section', + ], + [ + 'name' => 'ВАША ЗАЯВКА ПРИНЯТА!', + 'string' => 'ВАША ЗАЯВКА ПРИНЯТА!', + 'translations' => [ + 'ru' => 'ВАША ЗАЯВКА ПРИНЯТА!', + 'en' => 'YOUR REQUEST HAS BEEN RECEIVED!', + ], + 'group' => 'General', + ], + [ + 'name' => 'Спасибо! Сообщение успешно отправлено.', + 'string' => 'Спасибо! Сообщение успешно отправлено.', + 'translations' => [ + 'ru' => 'Спасибо! Сообщение успешно отправлено.', + 'en' => 'Thank you! The message has been successfully sent.', + ], + 'group' => 'General', + ], + [ + 'name' => 'Наш менеджер скоро свяжемся с вами
для уточнения деталей.', + 'string' => 'Наш менеджер скоро свяжемся с вами
для уточнения деталей.', + 'translations' => [ + 'ru' => 'Наш менеджер скоро свяжемся с вами
для уточнения деталей.', + 'en' => 'Our manager will contact you soon
to clarify the details.', + ], + 'group' => 'General', + ], + [ + 'name' => 'Вернуться на сайт', + 'string' => 'Вернуться на сайт', + 'translations' => [ + 'ru' => 'Вернуться на сайт', + 'en' => 'Return to the site', + ], + 'group' => 'General', + ], + [ + 'name' => 'Link email', + 'string' => 'Link email', + 'translations' => [ + 'ru' => 'Привязать email', + 'en' => 'Link email', + ], + 'group' => 'General', + ], + [ + 'name' => 'Linked accounts', + 'string' => 'Linked accounts', + 'translations' => [ + 'ru' => 'Привязанные аккаунты', + 'en' => 'Linked accounts', + ], + 'group' => 'General', + ], + [ + 'name' => 'Добавить питомца', + 'string' => 'Добавить питомца', + 'translations' => [ + 'ru' => 'Добавить питомца', + 'en' => 'Add a pet', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Вид животного', + 'string' => 'Вид животного', + 'translations' => [ + 'ru' => 'Вид животного', + 'en' => 'Type of animal', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Кошка', + 'string' => 'Кошка', + 'translations' => [ + 'ru' => 'Кошка', + 'en' => 'Cat', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Собака', + 'string' => 'Собака', + 'translations' => [ + 'ru' => 'Собака', + 'en' => 'Dog', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Стерелизован', + 'string' => 'Стерелизован', + 'translations' => [ + 'ru' => 'Стерелизован', + 'en' => 'Sterilized', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Да', + 'string' => 'Да', + 'translations' => [ + 'ru' => 'Да', + 'en' => 'Yes', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Нет', + 'string' => 'Нет', + 'translations' => [ + 'ru' => 'Нет', + 'en' => 'No', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Имя', + 'string' => 'Имя', + 'translations' => [ + 'ru' => 'Имя', + 'en' => 'Name', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Имя питомца', + 'string' => 'Имя питомца', + 'translations' => [ + 'ru' => 'Имя питомца', + 'en' => 'Pet name', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Порода', + 'string' => 'Порода', + 'translations' => [ + 'ru' => 'Порода', + 'en' => 'Breed', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Порода вашего питомца', + 'string' => 'Порода вашего питомца', + 'translations' => [ + 'ru' => 'Порода вашего питомца', + 'en' => 'Your pet\'s breed', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Пол вашего питомца', + 'string' => 'Пол вашего питомца', + 'translations' => [ + 'ru' => 'Пол вашего питомца', + 'en' => 'Your pet\'s gender', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Мальчик', + 'string' => 'Мальчик', + 'translations' => [ + 'ru' => 'Мальчик', + 'en' => 'Male', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Девочка', + 'string' => 'Девочка', + 'translations' => [ + 'ru' => 'Девочка', + 'en' => 'Female', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Вид активности', + 'string' => 'Вид активности', + 'translations' => [ + 'ru' => 'Вид активности', + 'en' => 'Activity level', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Выберите из списка', + 'string' => 'Выберите из списка', + 'translations' => [ + 'ru' => 'Выберите из списка', + 'en' => 'Select from list', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Низкая', + 'string' => 'Низкая', + 'translations' => [ + 'ru' => 'Низкая', + 'en' => 'Low', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Средняя', + 'string' => 'Средняя', + 'translations' => [ + 'ru' => 'Средняя', + 'en' => 'Moderate', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Высокая', + 'string' => 'Высокая', + 'translations' => [ + 'ru' => 'Высокая', + 'en' => 'High', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Вес', + 'string' => 'Вес', + 'translations' => [ + 'ru' => 'Вес', + 'en' => 'Weight', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '1-1.5 кг', + 'string' => '1-1.5 кг', + 'translations' => [ + 'ru' => '1-1.5 кг', + 'en' => '1-1.5 kg', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '1.5-3 кг', + 'string' => '1.5-3 кг', + 'translations' => [ + 'ru' => '1.5-3 кг', + 'en' => '1.5-3 kg', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '3-5 кг', + 'string' => '3-5 кг', + 'translations' => [ + 'ru' => '3-5 кг', + 'en' => '3-5 kg', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '5-8 кг', + 'string' => '5-8 кг', + 'translations' => [ + 'ru' => '5-8 кг', + 'en' => '5-8 kg', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '8-11 кг', + 'string' => '8-11 кг', + 'translations' => [ + 'ru' => '8-11 кг', + 'en' => '8-11 kg', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '11-15 кг', + 'string' => '11-15 кг', + 'translations' => [ + 'ru' => '11-15 кг', + 'en' => '11-15 kg', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '10-20кг', + 'string' => '10-20кг', + 'translations' => [ + 'ru' => '10-20кг', + 'en' => '10-20 kg', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '20-25кг', + 'string' => '20-25кг', + 'translations' => [ + 'ru' => '20-25кг', + 'en' => '20-25 kg', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '25-35 кг', + 'string' => '25-35 кг', + 'translations' => [ + 'ru' => '25-35 кг', + 'en' => '25-35 kg', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Более 35 кг', + 'string' => 'Более 35 кг', + 'translations' => [ + 'ru' => 'Более 35 кг', + 'en' => 'More than 35 kg', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Возраст питомца', + 'string' => 'Возраст питомца', + 'translations' => [ + 'ru' => 'Возраст питомца', + 'en' => 'Pet age', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Примерный', + 'string' => 'Примерный', + 'translations' => [ + 'ru' => 'Примерный', + 'en' => 'Approximate', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Точный', + 'string' => 'Точный', + 'translations' => [ + 'ru' => 'Точный', + 'en' => 'Exact', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Малыш', + 'string' => 'Малыш', + 'translations' => [ + 'ru' => 'Малыш', + 'en' => 'Baby', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '(от 0 до 1 года)', + 'string' => '(от 0 до 1 года)', + 'translations' => [ + 'ru' => '(от 0 до 1 года)', + 'en' => '(from 0 to 1 year)', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Взрослый', + 'string' => 'Взрослый', + 'translations' => [ + 'ru' => 'Взрослый', + 'en' => 'Adult', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '(от 1 года до 7 лет)', + 'string' => '(от 1 года до 7 лет)', + 'translations' => [ + 'ru' => '(от 1 года до 7 лет)', + 'en' => '(from 1 to 7 years)', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Пожилой', + 'string' => 'Пожилой', + 'translations' => [ + 'ru' => 'Пожилой', + 'en' => 'Senior', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '(от 7 до 12 лет)', + 'string' => '(от 7 до 12 лет)', + 'translations' => [ + 'ru' => '(от 7 до 12 лет)', + 'en' => '(from 7 to 12 years)', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Стареющий', + 'string' => 'Стареющий', + 'translations' => [ + 'ru' => 'Стареющий', + 'en' => 'Aging', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => '(от 12 лет и старше)', + 'string' => '(от 12 лет и старше)', + 'translations' => [ + 'ru' => '(от 12 лет и старше)', + 'en' => '(12 years and older)', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'День', + 'string' => 'День', + 'translations' => [ + 'ru' => 'День', + 'en' => 'Day', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'ДД', + 'string' => 'ДД', + 'translations' => [ + 'ru' => 'ДД', + 'en' => 'DD', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Месяц', + 'string' => 'Месяц', + 'translations' => [ + 'ru' => 'Месяц', + 'en' => 'Month', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Январь', + 'string' => 'Январь', + 'translations' => [ + 'ru' => 'Январь', + 'en' => 'January', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Февраль', + 'string' => 'Февраль', + 'translations' => [ + 'ru' => 'Февраль', + 'en' => 'February', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Март', + 'string' => 'Март', + 'translations' => [ + 'ru' => 'Март', + 'en' => 'March', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Апрель', + 'string' => 'Апрель', + 'translations' => [ + 'ru' => 'Апрель', + 'en' => 'April', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Май', + 'string' => 'Май', + 'translations' => [ + 'ru' => 'Май', + 'en' => 'May', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Июнь', + 'string' => 'Июнь', + 'translations' => [ + 'ru' => 'Июнь', + 'en' => 'June', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Июль', + 'string' => 'Июль', + 'translations' => [ + 'ru' => 'Июль', + 'en' => 'July', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Август', + 'string' => 'Август', + 'translations' => [ + 'ru' => 'Август', + 'en' => 'August', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Сентябрь', + 'string' => 'Сентябрь', + 'translations' => [ + 'ru' => 'Сентябрь', + 'en' => 'September', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Октябрь', + 'string' => 'Октябрь', + 'translations' => [ + 'ru' => 'Октябрь', + 'en' => 'October', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Ноябрь', + 'string' => 'Ноябрь', + 'translations' => [ + 'ru' => 'Ноябрь', + 'en' => 'November', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Декабрь', + 'string' => 'Декабрь', + 'translations' => [ + 'ru' => 'Декабрь', + 'en' => 'December', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Год', + 'string' => 'Год', + 'translations' => [ + 'ru' => 'Год', + 'en' => 'Year', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'ГГГГ', + 'string' => 'ГГГГ', + 'translations' => [ + 'ru' => 'ГГГГ', + 'en' => 'YYYY', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Добавить', + 'string' => 'Добавить', + 'translations' => [ + 'ru' => 'Добавить', + 'en' => 'Add', + ], + 'group' => 'Pet Form', + ], + [ + 'name' => 'Подписка на корм', + 'string' => 'Подписка на корм', + 'translations' => [ + 'ru' => 'Подписка на корм', + 'en' => 'Feed Subscription', + ], + 'group' => 'Subscription Form', + ], + [ + 'name' => 'Спасибо за интерес к нашему новому виду услуг, данная функция находится в разработке, если вы хотите узнать первыми о запуске подпишитесь на рассылку.', + 'string' => 'Спасибо за интерес к нашему новому виду услуг, данная функция находится в разработке, если вы хотите узнать первыми о запуске подпишитесь на рассылку.', + 'translations' => [ + 'ru' => 'Спасибо за интерес к нашему новому виду услуг, данная функция находится в разработке, если вы хотите узнать первыми о запуске подпишитесь на рассылку.', + 'en' => 'Thank you for your interest in our new service. This feature is under development; subscribe to our newsletter to be the first to know about its launch.', + ], + 'group' => 'Subscription Form', + ], + [ + 'name' => 'Хочу попробовать первым!', + 'string' => 'Хочу попробовать первым!', + 'translations' => [ + 'ru' => 'Хочу попробовать первым!', + 'en' => 'I want to try it first!', + ], + 'group' => 'Subscription Form', + ], + [ + 'name' => 'Хочу быть первым!', + 'string' => 'Хочу быть первым!', + 'translations' => [ + 'ru' => 'Хочу быть первым!', + 'en' => 'I want to be the first!', + ], + 'group' => 'Subscription Form', + ], + + // User Edit Form Strings + [ + 'name' => 'Изменить мои данные', + 'string' => 'Изменить мои данные', + 'translations' => [ + 'ru' => 'Изменить мои данные', + 'en' => 'Edit My Data', + ], + 'group' => 'User Edit Form', + ], + [ + 'name' => 'Имя', + 'string' => 'Имя', + 'translations' => [ + 'ru' => 'Имя', + 'en' => 'Name', + ], + 'group' => 'User Edit Form', + ], + [ + 'name' => 'Ваше имя', + 'string' => 'Ваше имя', + 'translations' => [ + 'ru' => 'Ваше имя', + 'en' => 'Your name', + ], + 'group' => 'User Edit Form', + ], + [ + 'name' => 'Имя введено неверно', + 'string' => 'Имя введено неверно', + 'translations' => [ + 'ru' => 'Имя введено неверно', + 'en' => 'Name entered incorrectly', + ], + 'group' => 'User Edit Form', + ], + [ + 'name' => 'Фамилия', + 'string' => 'Фамилия', + 'translations' => [ + 'ru' => 'Фамилия', + 'en' => 'Last Name', + ], + 'group' => 'User Edit Form', + ], + [ + 'name' => 'Ваша фамилия', + 'string' => 'Ваша фамилия', + 'translations' => [ + 'ru' => 'Ваша фамилия', + 'en' => 'Your last name', + ], + 'group' => 'User Edit Form', + ], + [ + 'name' => 'Фамилия введена неверно', + 'string' => 'Фамилия введена неверно', + 'translations' => [ + 'ru' => 'Фамилия введена неверно', + 'en' => 'Last name entered incorrectly', + ], + 'group' => 'User Edit Form', + ], + [ + 'name' => 'Телефон', + 'string' => 'Телефон', + 'translations' => [ + 'ru' => 'Телефон', + 'en' => 'Phone', + ], + 'group' => 'User Edit Form', + ], + [ + 'name' => 'Номер введён неверно', + 'string' => 'Номер введён неверно', + 'translations' => [ + 'ru' => 'Номер введён неверно', + 'en' => 'Phone number entered incorrectly', + ], + 'group' => 'User Edit Form', + ], + [ + 'name' => 'Сохранить', + 'string' => 'Сохранить', + 'translations' => [ + 'ru' => 'Сохранить', + 'en' => 'Save', + ], + 'group' => 'User Edit Form', + ], + [ + 'name' => 'Отмена', + 'string' => 'Отмена', + 'translations' => [ + 'ru' => 'Отмена', + 'en' => 'Cancel', + ], + 'group' => 'User Edit Form', + ], + ]; + + // Регистрация строк + foreach ($strings as $string) { + pll_register_string($string['name'], $string['string'], $string['group']); + } - pll_register_string('reviews_title', 'Customer Reviews', 'Reviews Section'); - pll_register_string('show_more', 'Show more', 'Reviews Section'); - pll_register_string('default_reviewer_name', 'Anastasia', 'Reviews Section'); - pll_register_string('default_reviewer_role', 'dog owner', 'Reviews Section'); - pll_register_string('default_review_excerpt', 'Just wanted to say thank you - your treats are amazing!', 'Reviews Section'); - pll_register_string('default_review_full_1', 'She loves the lamb one - tasty, safe, and it even works great as a dental treat!', 'Reviews Section'); - pll_register_string('default_review_full_2', 'And the salmon sandwich in the tube is our go-to. We never leave the house without it. Perfect for walks and training!', 'Reviews Section'); - pll_register_string('default_review_full_3', 'So glad we found you!', 'Reviews Section'); - pll_register_string ('ВАША ЗАЯВКА ПРИНЯТА!', 'ВАША ЗАЯВКА ПРИНЯТА!'); - pll_register_string ('Спасибо! Сообщение успешно отправлено.', 'Спасибо! Сообщение успешно отправлено.'); - pll_register_string ('Наш менеджер скоро свяжемся с вами
для уточнения деталей.', 'Наш менеджер скоро свяжемся с вами
для уточнения деталей.'); - pll_register_string ('Вернуться на сайт', 'Вернуться на сайт'); - -}); + // Добавление переводов через фильтр + add_filter('pll_translations', function ($translations) use ($strings) { + foreach ($strings as $string) { + $translations[$string['name']] = $string['translations']; + } + return $translations; + }); + } + pll_register_string('Подписка от', 'Подписка от', 'Theme'); + pll_register_string('Сумма:', 'Сумма:', 'Theme'); + pll_register_string('Следующий платеж:', 'Следующий платеж:', 'Theme'); + pll_register_string('Нет', 'Нет', 'Theme'); + pll_register_string('Детали подписки', 'Детали подписки', 'Theme'); + pll_register_string('Детали недоступны', 'Детали недоступны', 'Theme'); + pll_register_string('У вас нет активных подписок.', 'У вас нет активных подписок.', 'Theme'); + pll_register_string('Перейти в профиль', 'Перейти в профиль', 'Theme'); + pll_register_string('Заказы', 'Заказы', 'Theme'); + pll_register_string('Подписки', 'Подписки', 'Theme'); + pll_register_string('Подписка №', 'Подписка №', 'Theme'); + pll_register_string('Статус', 'Статус', 'Theme'); + pll_register_string('Дата подписки', 'Дата подписки', 'Theme'); + pll_register_string('Дата последнего заказа', 'Дата последнего заказа', 'Theme'); + pll_register_string('Следующий платеж', 'Следующий платеж', 'Theme'); + pll_register_string('Способ оплаты', 'Способ оплаты', 'Theme'); + pll_register_string('Товары:', 'Товары:', 'Theme'); + pll_register_string('Сумма', 'Сумма', 'Theme'); + pll_register_string('месяц', 'месяц', 'Theme'); + pll_register_string('Доставка', 'Доставка', 'Theme'); + pll_register_string('Бесплатно', 'Бесплатно', 'Theme'); + pll_register_string('Итого', 'Итого', 'Theme'); + pll_register_string('Доставка:', 'Доставка:', 'Theme'); + pll_register_string('Адрес доставки', 'дрес доставки', 'Theme'); + pll_register_string('Начните вводить адрес', 'ачните вводить адрес', 'Theme'); + pll_register_string('Адрес введен неверно', 'Адрес введен неверно', 'Theme'); + pll_register_string('Комментарий для доставки', 'Комментарий для доставки', 'Theme'); + pll_register_string('Для службы доставки', 'Для службы доставки', 'Theme'); + pll_register_string('Комментарий введен неверно', 'Комментарий введен неверно', 'Theme'); + pll_register_string('Отменить подписку', 'Отменить подписку', 'Theme'); + pll_register_string('Подписка не найдена.', 'Подписка не найдена.', 'Theme'); + pll_register_string('Перейти в профиль', 'Перейти в профиль', 'Theme'); + pll_register_string('Заказы', 'Заказы', 'Theme'); + pll_register_string('Подписки', 'Подписки', 'Theme'); + pll_register_string('Не указан', 'Не указан', 'Theme'); + pll_register_string('месяц', 'месяц', 'Theme'); +}); \ No newline at end of file diff --git a/wp-content/themes/cosmopet/global-functions/multisite-functions.php b/wp-content/themes/cosmopet/global-functions/multisite-functions.php index 70b4810..b8b3cd8 100644 --- a/wp-content/themes/cosmopet/global-functions/multisite-functions.php +++ b/wp-content/themes/cosmopet/global-functions/multisite-functions.php @@ -1,23 +1,185 @@ - defined('SITE_DOMAIN') ? SITE_DOMAIN : null, - ]; - - return $context; -}); - - - + defined('SITE_DOMAIN') ? SITE_DOMAIN : null, + ]; + + return $context; +}); + + +// Отключаем канонические ссылки и hreflang от Yoast SEO +add_filter('wpseo_canonical', '__return_false'); +add_filter('wpseo_opengraph_url', '__return_false'); // Отключаем OG URL +add_filter('wpseo_add_x_default_hreflang', '__return_false'); // Отключаем hreflang от Yoast +add_filter('wpseo_disable_adjacent_rel_links', '__return_true'); // Отключаем соседние rel-ссылки + +// Добавляем каноническую ссылку +add_action('wp_head', 'custom_canonical_url', 5); +function custom_canonical_url() { + if (!is_admin()) { + // Защищаем от дублирования + static $canonical_added = false; + if ($canonical_added) { + return; + } + $canonical_added = true; + + // Формируем текущий URL без лишних параметров + $current_url = trailingslashit(home_url($_SERVER['REQUEST_URI'])); + // Удаляем возможные параметры запроса, если они не нужны + $current_url = strtok($current_url, '?'); + echo '' . "\n"; + } +} + +add_action('wp_head', 'add_facebook_pixel'); +function add_facebook_pixel() { + ?> + + + + + get_status() !== 'processing' && $order->get_status() !== 'completed') return; // Отправляем только для оплаченных заказов + + $items = []; + foreach ($order->get_items() as $item) { + $product = $item->get_product(); + $items[] = [ + 'id' => $product->get_id(), + 'name' => $product->get_name(), + 'price' => $product->get_price(), + 'quantity' => $item->get_quantity() + ]; + } + + // Получаем валюту заказа + $currency = $order->get_currency(); + ?> + + 'Неверный ID товара')); + wp_die(); + } + + $passed_validation = apply_filters('woocommerce_add_to_cart_validation', true, $product_id, $quantity); + + if ($passed_validation) { + $added = WC()->cart->add_to_cart($product_id, $quantity); + if ($added) { + error_log('Product added to cart: ' . $product_id); // Отладка + // Подготавливаем фрагменты корзины + ob_start(); + woocommerce_mini_cart(); + $mini_cart = ob_get_clean(); + + // Фрагменты для стандартной корзины и кастомного счетчика + $fragments = array( + 'div.widget_shopping_cart_content' => '
' . $mini_cart . '
', + '.mini-profile__button--counter' => '
' . WC()->cart->get_cart_contents_count() . '
' + ); + + wp_send_json_success(array( + 'message' => 'Товар успешно добавлен в корзину', + 'fragments' => apply_filters('woocommerce_add_to_cart_fragments', $fragments), + 'cart_hash' => apply_filters('woocommerce_add_to_cart_hash', WC()->cart->get_cart_hash(), array()) + )); + } else { + error_log('Failed to add product to cart: ' . $product_id); // Отладка + wp_send_json_error(array('message' => 'Не удалось добавить товар в корзину')); + } + } else { + error_log('Validation failed for product: ' . $product_id); // Отладка + wp_send_json_error(array('message' => 'Ошибка валидации товара')); + } + + wp_die(); +} \ No newline at end of file diff --git a/wp-content/themes/cosmopet/home.php b/wp-content/themes/cosmopet/home.php index 6b30a2d..1587666 100644 --- a/wp-content/themes/cosmopet/home.php +++ b/wp-content/themes/cosmopet/home.php @@ -1,4 +1,5 @@ Hello, {$first_name} {$last_name}!"; + } else { + $html = "

Hello, {$first_name} {$last_name}!

"; + } + if (isset($tg_user['photo_url'])) { + $photo_url = htmlspecialchars($tg_user['photo_url']); + $html .= ""; + } + $html .= "

Log out

"; + } else { + $bot_username = BOT_USERNAME; + $html = ''; + } + if(!is_user_logged_in()) { + echo $html; + } +} + +add_action( 'wp_ajax_ontelegramauth', 'onTelegramAuth' ); +add_action( 'wp_ajax_nopriv_ontelegramauth', 'onTelegramAuth' ); + +function onTelegramAuth(){ + $tg_id = $_POST['userid']; + $tg_username = $_POST['username']; + $user = get_users( + array( + 'meta_key' => 'tg_account', + 'meta_value' => $tg_id + ) + ); + // $user = get_users( + // array( + // 'meta_key' => 'tg_username', + // 'meta_value' => $tg_username + // ) + // ); + + // Генерация пароля + $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@#!()'; + $pass = array(); + $alphaLength = strlen($alphabet) - 1; + for ($i = 0; $i < 12; $i++) { + $n = rand(0, $alphaLength); + $pass[] = $alphabet[$n]; + } + $pass = implode($pass); + + if($user) { + $user_login = $user[0]->data->user_login; + $user_id = get_user_by( 'login', $user_login )->ID; + wp_set_password( $pass, get_user_by( 'login', $user_login )->ID ); + wp_signon( + array( + 'user_login' => $user_login, + 'user_password' => $pass, + 'remember' => 'on', + ) + ); + } else { + $user_id = wp_create_user( $tg_username, $pass, ''); + add_user_meta( $user_id, 'tg_account', $tg_id); + add_user_meta( $user_id, 'tg_username', $tg_username); + wp_update_user( [ + 'ID' => $user_id, + 'first_name' => $_POST['fname'], + 'last_name' => $_POST['lname'] + ] ); + wp_set_auth_cookie( $user_id, true ); + } + +} + +add_action( 'wp_ajax_linktelegram', 'linkTelegram' ); +add_action( 'wp_ajax_nopriv_linktelegram', 'linkTelegram' ); + +function linkTelegram(){ + $tg_id = $_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' => $_POST['fname'], + 'last_name' => $_POST['lname'] + ] ); +} + +add_action( 'wp_ajax_email_link', 'emailLink' ); +add_action( 'wp_ajax_nopriv_email_link', 'emailLink' ); +function emailLink(){ + + $email = $_POST['email']; + $user_id = get_current_user_id(); + + if(email_exists($email)){ + header("Content-Type: application/json"); + echo json_encode(array( + 'error' => esc_html__( 'Email is already registered', 'woodmart' ) + )); + exit(); + } else { + wp_update_user( [ + 'ID' => $user_id, + 'user_email' => $email + ] ); + } + + +} + + + +// Добавляем колонку Telegram в список пользователей +add_filter('manage_users_columns', 'add_tg_account_column'); +function add_tg_account_column($columns) { + $columns['tg_username'] = 'Telegram'; + return $columns; +} + +// Заполняем колонку данными +add_filter('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_account = get_user_meta($user_id, 'tg_username', true); + if ($tg_account) { + return '@' . esc_html($tg_account) . ''; + } + return 'не указан'; + } + 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'); + } +} + ?> \ No newline at end of file diff --git a/wp-content/themes/cosmopet/modules/forms/assets/js/form.js b/wp-content/themes/cosmopet/modules/forms/assets/js/form.js index c1bf685..8fa3faf 100644 --- a/wp-content/themes/cosmopet/modules/forms/assets/js/form.js +++ b/wp-content/themes/cosmopet/modules/forms/assets/js/form.js @@ -1,9 +1,13 @@ // Функция для показа модальных окон function showModal(modalClass) { + + const modal = document.querySelector('.' + modalClass); if (modal) { modal.style.display = 'flex'; + } +} // Функция для закрытия модальных окон function closeModals() { @@ -25,6 +29,7 @@ function showModal(modalClass) { // Закрытие при клике вне контента window.addEventListener('click', function(event) { + const modals = document.querySelectorAll('.mform'); modals.forEach(modal => { if (event.target === modal) { @@ -42,10 +47,10 @@ function showModal(modalClass) { modal.style.display = 'none'; } }); - }); }); + jQuery(document).ready(function($) { $('.form-process').submit(function(event) { event.preventDefault(); @@ -63,6 +68,7 @@ jQuery(document).ready(function($) { success: function(response) { closeModals() showModal('mform-success') + } }); } @@ -134,4 +140,4 @@ const localeValue = metaLocale.getAttribute('content'); errorMessages.forEach(errorMessage => { errorMessage.remove(); }); - } \ No newline at end of file + } diff --git a/wp-content/themes/cosmopet/modules/forms/module-ajax-controller.php b/wp-content/themes/cosmopet/modules/forms/module-ajax-controller.php index dacdfd5..445e0bd 100644 --- a/wp-content/themes/cosmopet/modules/forms/module-ajax-controller.php +++ b/wp-content/themes/cosmopet/modules/forms/module-ajax-controller.php @@ -13,12 +13,12 @@ add_action('wp_ajax_nopriv_contact_form', function() { }); add_action('wp_ajax_subscribe_form', function() { - $enabledHandlers = ['b24', 'email', 'mindbox']; + $enabledHandlers = ['b24', 'email']; process_form($enabledHandlers); }); add_action('wp_ajax_nopriv_subscribe_form', function() { - $enabledHandlers = ['b24', 'email', 'mindbox']; + $enabledHandlers = ['b24', 'email']; process_form($enabledHandlers); }); diff --git a/wp-content/themes/cosmopet/modules/forms/module-controller.php b/wp-content/themes/cosmopet/modules/forms/module-controller.php index b5aa7c3..144ebc3 100644 --- a/wp-content/themes/cosmopet/modules/forms/module-controller.php +++ b/wp-content/themes/cosmopet/modules/forms/module-controller.php @@ -34,43 +34,43 @@ class zohoHandler extends FormHandler { } } -class mindboxHandler extends FormHandler { - public function handle($data) { - // Отправка в стандартный обработчик (например, email) - error_log("Отправка в mindBox: " . json_encode($data)); - // if (is_string($data)) { - // parse_str($data, $parsedData); // Преобразуем строку в массив - // $data = $parsedData; - // } +// class mindboxHandler extends FormHandler { +// public function handle($data) { +// // Отправка в стандартный обработчик (например, email) +// error_log("Отправка в mindBox: " . json_encode($data)); +// // if (is_string($data)) { +// // parse_str($data, $parsedData); // Преобразуем строку в массив +// // $data = $parsedData; +// // } - // $url = 'https://api.mindbox.ru/v3/operations/async?endpointId=cosmopet.Website&operation=DobavleniePolzovatelyaSSajta'; +// // $url = 'https://api.mindbox.ru/v3/operations/async?endpointId=cosmopet.Website&operation=DobavleniePolzovatelyaSSajta'; - // $data = array( - // "email" => $data['email'], - // "subscriptions" => array( - // array( - // "pointOfContact"=> "Email" - // ), - // ), - // ); +// // $data = array( +// // "email" => $data['email'], +// // "subscriptions" => array( +// // array( +// // "pointOfContact"=> "Email" +// // ), +// // ), +// // ); - // $data_string = json_encode(array("customer" =>$data)); +// // $data_string = json_encode(array("customer" =>$data)); - // $ch = curl_init($url); +// // $ch = curl_init($url); - // curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); +// // curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); - // curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json')); +// // curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json')); - // curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); +// // curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - // $result = curl_exec($ch); +// // $result = curl_exec($ch); - // curl_close($ch); - return parent::handle($data); - } -} +// // curl_close($ch); +// return parent::handle($data); +// } +// } class emailHandler extends FormHandler { public function handle($data) { @@ -113,9 +113,9 @@ class FormHandlerFactory { if (in_array('zoho', $enabledHandlers)) { $handler = new zohoHandler($handler); } - if (in_array('mindbox', $enabledHandlers)) { - $handler = new mindboxHandler($handler); - } + // if (in_array('mindbox', $enabledHandlers)) { + // $handler = new mindboxHandler($handler); + // } if (in_array('b24', $enabledHandlers)) { $handler = new b24Handler($handler); } diff --git a/wp-content/themes/cosmopet/modules/header/assets/css/gp-style-desktop.css b/wp-content/themes/cosmopet/modules/header/assets/css/gp-style-desktop.css index 054aca4..55bf2c5 100644 --- a/wp-content/themes/cosmopet/modules/header/assets/css/gp-style-desktop.css +++ b/wp-content/themes/cosmopet/modules/header/assets/css/gp-style-desktop.css @@ -744,8 +744,8 @@ width: 0px; width: 16px; height: 16px; border-radius: 50%; - right: 30px; - bottom: 20px; + right: 3px; + bottom: 2px; font-style: normal; font-weight: 700; font-size: 9px; @@ -755,4 +755,8 @@ width: 0px; .mini-profile__button--counter.disabled{ display: none; +} + +.mini-profile__button{ + position: relative; } \ No newline at end of file diff --git a/wp-content/themes/cosmopet/modules/layout/assets/css/gp-style-core.css b/wp-content/themes/cosmopet/modules/layout/assets/css/gp-style-core.css index bdc22e3..89e55c4 100644 --- a/wp-content/themes/cosmopet/modules/layout/assets/css/gp-style-core.css +++ b/wp-content/themes/cosmopet/modules/layout/assets/css/gp-style-core.css @@ -175,11 +175,11 @@ body { height: 96px; width: 100%; resize: none; - background: var(--main_white); - border: 1px solid var(--placeholder); + background: var(--main_white) !important; + border: 1px solid var(--placeholder) !important;; padding: 12px 16px; border-radius: 20px; - color: var(--main_black); + color: var(--main_black) !important; font-size: 20px; font-weight: 400; line-height: 24px; @@ -271,6 +271,7 @@ textarea{ } } + .mform { position: fixed; top: 0; @@ -284,7 +285,9 @@ textarea{ z-index: 1000; } + .mform-content { + position: relative; width: 100%; max-width: 600px; @@ -331,7 +334,9 @@ textarea{ color: #000; } + .mform-title { + font-size: 32px; font-weight: bold; margin-bottom: 10px; @@ -340,16 +345,18 @@ textarea{ /* Стили для второго модального окна - Предложить статью */ .mform-offer .mform-content { + background-color: #d6ff9f; padding-bottom: 30px; } + .mform-subtitle { font-size: 18px; margin-bottom: 20px; } - .mform-form { + .modal-form { width: 100%; } @@ -371,6 +378,16 @@ textarea{ width: 100%; max-width: 380px; } + + .modal-offer input, textarea { + width: 100%!important; + padding: 12px 15px!important; + border: none!important; + border-radius: 20px!important; + font-size: 16px!important; + background-color: white!important; + } + /* Контейнер для текстового поля и изображения автора */ .message-container { position: relative; @@ -419,7 +436,9 @@ textarea{ /* Адаптивность */ @media (max-width: 768px) { + .mform-content { + width: 90%; padding: 30px 20px; } @@ -452,13 +471,156 @@ textarea{ } } - .wrapper { margin: 0 auto; max-width: 1600px; } +.modal { + display: none; +} +.modal.active { + display: flex!important; +} +.modal__login.active { + filter: blur(0px); +} + + /* button */ +.button{ + font-family: var(--font-family); + font-weight: 600; + font-size: 20px; + line-height: 120%; + color: var(--text-black); + + border-radius: 20px; + text-transform: none; + cursor: pointer; + } + .button--100-perc{ + width: 100%; + } + .button--white{ + padding: 11px 24px; + + text-align: center; + + background-color: var(--background-white); + border: 1px solid var(--background-black); + + transition: opacity .2s ease-out; + } + .button--white:hover{ + opacity: .8; + } + .button--white.active{ + background: var(--background-black); + color: var(--background-white); + } + .button--gradient{ + background: var(--gradient-turquoise); + border: none; + + transition: opacity .2s ease-out; + } + .button--gradient:hover{ + opacity: .8; + } + .button--base{ + padding: 12px 24px; + } + .button--high{ + height: 56px; + + padding: 16px 24px 16px 24px; + + font-weight: 700; + text-align: center; + + position: relative; + } + .button--icon{ + padding-right: 56px; + + text-align: start; + } + .button--filter::after{ + content: ''; + + position: absolute; + top: 16px; + right: 24px; + + width: 24px; + aspect-ratio: 1; + + background-image: url(../img/svg/main/filter.svg); + background-repeat: no-repeat; + background-size: contain; + } + .button--black{ + padding: 7px 15px; + + font-family: var(--font-family); + font-weight: 500; + font-size: 24px; + line-height: 133%; + color: var(--text-white); + + background: var(--background-black); + border: 1px solid var(--text-white); + } + .button--link{ + text-decoration: none; + } + .button--red-48-px{ + border-radius: 48px; + } + .to-know{ + width: 100%; + + padding: 12px; + + display: flex; + justify-content: center; + + border: none; + + transition: opacity .2s ease-out; + } + .to-know:hover{ + opacity: .8; + } + .to-know p{ + padding-bottom: 4px; + + font-family: var(--font-family); + font-weight: 700; + font-size: 20px; + line-height: 120%; + color: var(--text-black); + + border-bottom: 1px var(--text-black) solid; + + cursor: pointer; + } + .to-know--background-none{ + background: none; + } + .back{ + margin-top: 16px; + margin-left: 16px; + + padding: 8px; + padding-left: 32px; + + background: none; + border: none; + + } + /* modal */ @@ -1324,15 +1486,54 @@ textarea{ flex: 1; padding: 16px 24px; border-radius: 20px; + font-family: var(--font-family); font-weight: 600; font-size: 20px; line-height: 120%; - text-align: center; - cursor: pointer; - transition: all 0.2s ease-out; + color: var(--text-black); + + text-decoration: none; + + position: relative; + } + .back::before{ + content: ''; + + position: absolute; + top: 8px; + left: 0; + + margin-right: 8px; + + width: 24px; + height: 24px; + + background-image: url(../img/svg/main/arrow-back.svg); + } + + .back::after{ + content: ''; + + position: absolute; + bottom: 6px; + left: 0; + + width: calc(100% - 8px); + height: 1px; + + background: var(--text-black); + } + + .button--high-46{ + padding: 12px 24px; + + font-size: 20px; + font-weight: 700; + line-height: 24px; } + .modal-basket__button--continue { background: var(--background-white); border: 1px solid var(--background-black); @@ -1677,16 +1878,16 @@ textarea{ border-radius: 20px; padding: 12px 16px; - border: 1px solid var(--text-black); + border: 1px solid var(--text-black) !important; - background: var(--background-white); + background: var(--background-white) !important; - font-family: var(--font-family); + font-family: var(--font-family) !important; font-weight: 400; font-size: 20px; line-height: 120%; - color: var(--text-black); + color: var(--text-black) !important; } .form__input::placeholder{ color: var(--text-grey); @@ -1860,4 +2061,15 @@ textarea{ .wc-block-checkout__form.wc-block-components-form .wc-block-components-text-input input[type=url], .wc-block-checkout__form.wc-block-components-form .wc-blocks-components-select .wc-blocks-components-select__select{ border-radius: 10px; -} \ No newline at end of file +} + +.mt-m-3{ + margin-top: -3rem; +} + +@media (max-width: 768px) { + .mt-m-3{ + margin-top: 1rem; +} +} + diff --git a/wp-content/themes/cosmopet/modules/layout/assets/js/gp-cabinet.js b/wp-content/themes/cosmopet/modules/layout/assets/js/gp-cabinet.js deleted file mode 100644 index 1b485f7..0000000 --- a/wp-content/themes/cosmopet/modules/layout/assets/js/gp-cabinet.js +++ /dev/null @@ -1,67 +0,0 @@ -// 'use strict'; - -// import * as fun from './_gp-function.js'; - -// let widthPhoneCabinet = 1200; - -// fun.toggleOpenX('.cabinet-card__order', '.cabinet-card-order__open-detail', '.cabinet-card-order__detail', '.cabinet-card-order__block-detail'); -// fun.modalFormOpen('.form-open'); - -// fun.closeModalForm('.modal-form__close'); -// fun.closeModalForm('.modal-form__button-close'); - -// controlCabinet('.cabinet-control__button', '.cabinet', widthPhoneCabinet); - -// function controlCabinet(buttons, main, minWidth){ -// let thisWidth = window.innerWidth; -// let thisMain = document.querySelector(main); - -// let thisButtons = document.querySelectorAll(buttons); - -// thisButtons.forEach(e => { -// e.onclick = function (element){ -// let thisContent = document.querySelector(`.cabinet__${e.dataset.cabinet}`); -// let newHeight = thisContent.clientHeight + 48; -// let thisButton = element.target; - -// thisMain.style.height = `${newHeight}px` - -// if (!thisContent.classList.contains('active')) { -// thisMain.querySelector('.active').classList.remove('active'); -// thisContent.classList.add('active'); - -// setTimeout(() => { -// thisMain.style.height = 'auto'; - -// if (thisMain.querySelector('.hide')) { -// thisMain.querySelector('.hide').classList.remove('hide'); -// } - -// thisMain.querySelector('.active').classList.add('hide'); -// }, 200); -// } - -// thisButtons.forEach(e => { -// e.classList.remove('active'); -// }) -// thisButton.classList.add('active'); -// } -// }) - -// } - -// let modal = document.querySelector('.modal'); -// modal.onclick = function (eventModal) { -// let thisTarget = eventModal.target; - -// if (thisTarget.classList.contains('modal')) { -// thisTarget.classList.remove('active'); - -// if (!thisTarget.querySelector('.modal-map.active')) { -// thisTarget.querySelector('.modal-form.active').classList.remove('active'); -// }else{ -// thisTarget.querySelector('.modal-map.active').classList.remove('active'); -// } -// } -// } - diff --git a/wp-content/themes/cosmopet/modules/layout/assets/js/gp-form.js b/wp-content/themes/cosmopet/modules/layout/assets/js/gp-form.js index 9bfcdd9..4b3ca82 100644 --- a/wp-content/themes/cosmopet/modules/layout/assets/js/gp-form.js +++ b/wp-content/themes/cosmopet/modules/layout/assets/js/gp-form.js @@ -1,54 +1,54 @@ 'use strict'; -inputPhone('.form-input__phone', '.form-input-phone__icon', '.form-input-phone__code', '.form-input-phone__input', '.form-input-phone__list', 'form-input-phone-list__item', '.form-input-phone-list-item__icon', '.form-input-phone-list-item__code', 'form-input-phone-list__search'); - -function inputPhone(main, mainFlag, mainCode, input, list, selects, selectIcon, selectCode, searchInput) { - let inputs = document.querySelectorAll(main); - - inputs.forEach(e => { - let thisMainFlag = e.querySelector(mainFlag), - thisMainCode = e.querySelector(mainCode), - thisInput = e.querySelector(input), - thisList = e.querySelector(list), - thisSelects = e.querySelectorAll(`.${selects}`), - thisSearchInput = e.querySelector(`.${searchInput}`); - - thisInput.onblur = function (input) { - if (!(input.relatedTarget != null && (input.relatedTarget.classList.contains(searchInput) || input.relatedTarget.classList.contains(selects)))) { - thisList.classList.remove('active'); - } - } - - e.onclick = function (event) { - if (!event.target.classList.contains(searchInput)) { - if (thisList.classList.contains('active')) { - thisList.classList.remove('active'); - } - - thisInput.focus(); - thisList.classList.add('active'); - } - } - - thisSelects.forEach(e => { - let newIcon = e.querySelector(selectIcon), - newCode = e.querySelector(selectCode); - - e.onclick = function (event) { - event.preventDefault(); - thisMainFlag.style.cssText = `background-image:url("${newIcon.src}");`; - thisMainCode.textContent = newCode.textContent; +// inputPhone('.form-input__phone', '.form-input-phone__icon', '.form-input-phone__code', '.form-input-phone__input', '.form-input-phone__list', 'form-input-phone-list__item', '.form-input-phone-list-item__icon', '.form-input-phone-list-item__code', 'form-input-phone-list__search'); + +// function inputPhone(main, mainFlag, mainCode, input, list, selects, selectIcon, selectCode, searchInput) { +// let inputs = document.querySelectorAll(main); + +// inputs.forEach(e => { +// let thisMainFlag = e.querySelector(mainFlag), +// thisMainCode = e.querySelector(mainCode), +// thisInput = e.querySelector(input), +// thisList = e.querySelector(list), +// thisSelects = e.querySelectorAll(`.${selects}`), +// thisSearchInput = e.querySelector(`.${searchInput}`); + +// thisInput.onblur = function (input) { +// if (!(input.relatedTarget != null && (input.relatedTarget.classList.contains(searchInput) || input.relatedTarget.classList.contains(selects)))) { +// thisList.classList.remove('active'); +// } +// } + +// e.onclick = function (event) { +// if (!event.target.classList.contains(searchInput)) { +// if (thisList.classList.contains('active')) { +// thisList.classList.remove('active'); +// } + +// thisInput.focus(); +// thisList.classList.add('active'); +// } +// } + +// thisSelects.forEach(e => { +// let newIcon = e.querySelector(selectIcon), +// newCode = e.querySelector(selectCode); + +// e.onclick = function (event) { +// event.preventDefault(); +// thisMainFlag.style.cssText = `background-image:url("${newIcon.src}");`; +// thisMainCode.textContent = newCode.textContent; - setTimeout(() => { - thisList.classList.remove('active'); - }, 0); - } +// setTimeout(() => { +// thisList.classList.remove('active'); +// }, 0); +// } - }) - }) -} +// }) +// }) +// } if (document.querySelector('.form-input-phone__input')) { checkPhone('.form-input-phone__input'); @@ -84,15 +84,9 @@ function inputTabs(main, button) { buttons.forEach(button => { button.onclick = function () { - if (button.classList.contains('active')) { - return ; - } - main.querySelector('.active').classList.remove('active'); button.classList.add('active'); - - button.querySelector('input').click(); } }) @@ -100,185 +94,283 @@ function inputTabs(main, button) { } -inputRadio('.form-input__radio', '.form-input-radio__item', '.form-input-radio__title', '.form-input-radio__input') +// inputRadio('.form-input__radio', '.form-input-radio__item', '.form-input-radio__title', '.form-input-radio__input') -function inputRadio(main ,item, textClass, input) { - let inputRadios = document.querySelectorAll(main); +// function inputRadio(main ,item, textClass, input) { +// let inputRadios = document.querySelectorAll(main); - inputRadios.forEach(inputRadio => { - let items = inputRadio.querySelectorAll(item), - thisInput = inputRadio.querySelector(input); +// inputRadios.forEach(inputRadio => { +// let items = inputRadio.querySelectorAll(item), +// thisInput = inputRadio.querySelector(input); - items.forEach(radio => { - let thisText = radio.querySelector(textClass).textContent; +// items.forEach(radio => { +// let thisText = radio.querySelector(textClass).textContent; - radio.onclick = function (event) { - event.preventDefault(); +// radio.onclick = function (event) { +// event.preventDefault(); - if (inputRadio.querySelector(`${item}.active`)) { - inputRadio.querySelector(`${item}.active`).classList.remove('active'); - } - thisInput.value = thisText; - radio.classList.add('active'); - } - }) - }) -} +// if (inputRadio.querySelector(`${item}.active`)) { +// inputRadio.querySelector(`${item}.active`).classList.remove('active'); +// } +// thisInput.value = thisText; +// radio.classList.add('active'); +// } +// }) +// }) +// } -listInputRadio('.form-input__list' ,'.form-input-list__item', '.form-input-list-item__text', '.form-input-list__input', '.form-input-list__content', '.form-input-list__block-content'); +// listInputRadio('.form-input__list' ,'.form-input-list__item', '.form-input-list-item__text', '.form-input-list__content', '.form-input-list__block-content'); -function listInputRadio(main ,item, textClass, input, content, block) { - let listInputRadios = document.querySelectorAll(main); +// function listInputRadio(main ,item, textClass, input, content, block) { +// let listInputRadios = document.querySelectorAll(main); - listInputRadios.forEach(listInputRadio => { - let thisInput = listInputRadio.querySelector(input), - items = listInputRadio.querySelectorAll(item), - thisContent = listInputRadio.querySelector(content), - thisBlock = listInputRadio.querySelector(block); +// listInputRadios.forEach(listInputRadio => { +// let thisInput = listInputRadio.querySelector(input), +// items = listInputRadio.querySelectorAll(item), +// thisContent = listInputRadio.querySelector(content), +// thisBlock = listInputRadio.querySelector(block); - thisInput.onclick = function () { - thisBlock.classList.add('active'); - thisBlock.style.height = '192px'; - } +// // thisInput.onclick = function () { +// // thisBlock.classList.add('active'); +// // thisBlock.style.height = '192px'; +// // } - thisInput.onblur = function(){ - thisBlock.classList.remove('active'); - thisBlock.style.height = '0px'; - }; +// // thisInput.onblur = function(){ +// // thisBlock.classList.remove('active'); +// // thisBlock.style.height = '0px'; +// // }; - items.forEach(item => { - item.onclick = function (event) { - event.preventDefault(); - let newText = item.querySelector(textClass).textContent; +// items.forEach(item => { +// item.onclick = function (event) { +// event.preventDefault(); +// let newText = item.querySelector(textClass).textContent; - thisInput.value = newText; +// thisInput.value = newText; - if (thisContent.querySelector('.active')) { - thisContent.querySelector('.active').classList.remove('active'); - } - - item.classList.add('active'); - } - }) - }) -} +// if (thisContent.querySelector('.active')) { +// thisContent.querySelector('.active').classList.remove('active'); +// } -remoteControl('.form-input__remote-control', '.form-input-tabs__button'); -remoteControl('.modal-map__control', '.modal-map-control__item'); - -function remoteControl(main, button) { - let mains = document.querySelectorAll(main); - - mains.forEach(main => { - let subjectClass = main.dataset.content, - subject = document.querySelector(`.${subjectClass}`), - buttons = Array.from(main.querySelectorAll(button)); - - main.addEventListener('click', function (eventMain) { - setTimeout(() => { - let indexActive = buttons.findIndex((button, index) => { - if (button.classList.contains('active')) { - return true; - } - }); - if(subject.children[indexActive].classList.contains('active')){ - return ; - } - - subject.querySelector('.remote-control__item.active').classList.remove('active'); - subject.children[indexActive].classList.add('active'); - - let mandatorys = subject.querySelectorAll('.mandatory'); - - mandatorys.forEach(mandatory => { - if (mandatory.required) { - mandatory.required = false; - }else{ - mandatory.required = true; - } - }) - }, 0); - }) - }) -} +// item.classList.add('active'); +// } +// }) +// }) +// } -formCheck('.modal-form__content', 'input[type=submit]'); -formCheck('.modal-map__form', 'input[type=submit]'); -function formCheck(form, submit) { - let forms = document.querySelectorAll(form); +// remoteControl('.form-input__remote-control', '.form-input-tabs__button'); +// remoteControl('.modal-map__control', '.modal-map-control__item'); - forms.forEach(form => { - let thisSubmit = form.querySelector(submit); +// function remoteControl(main, button) { +// let mains = document.querySelectorAll(main); - thisSubmit.onclick = function () { - form.classList.add('check') - } - - }) -} +// console.log(mains); + -inputPhoneNoFlag('.no-flag'); +// mains.forEach(main => { +// let subjectClass = main.dataset.content, +// subject = document.querySelector(`.${subjectClass}`), +// buttons = Array.from(main.querySelectorAll(button)); -function inputPhoneNoFlag(input){ - let inputs = document.querySelectorAll(input); + - inputs.forEach(input => { - let code = '+' + input.dataset.code; +// main.addEventListener('mousedown', function (eventMain) { +// setTimeout(() => { +// let indexActive = buttons.findIndex((button, index) => { +// if (button.classList.contains('active')) { +// return true; +// } +// }); + +// subject.querySelector('.remote-control__item.active').classList.remove('active'); +// subject.children[indexActive].classList.add('active'); +// }, 0); +// }) +// }) +// } + +// formCheck('.modal-form__content', 'input[type=submit]'); +// formCheck('.modal-map__form', 'input[type=submit]'); + +// function formCheck(form, submit) { +// let forms = document.querySelectorAll(form); + +// forms.forEach(form => { +// let thisSubmit = form.querySelector(submit); + +// thisSubmit.onclick = function () { +// form.classList.add('check') +// } - input.onfocus = function () { - if (input.value == '') { - input.value = code; - } - } - - input.addEventListener('input', function(event) { - let text = event.target.value; - let length = text.length; - let newSymbol = event.data; - - if (isNaN(event.data) || event.data == ' ') { - event.target.value = text.slice(0, -1); - return; - } - - if (length == 3 || length == 7 || length == 11) { - if (newSymbol != null) { - event.target.value = text.slice(0, -1) + ' ' + newSymbol; +// }) +// } + + +jQuery('.form-input-list__item').on('click', function(){ + var value = jQuery(this).find('p').html() + var content = jQuery(this).closest('.form-input-list__block-content') + jQuery(content).prev().html(value) + jQuery(content).removeClass('active').css('height', '0px') +}) + +jQuery('.form-input-list__input').on('click', function(){ + // jQuery(this).next().toggleClass('active') + if(!jQuery(this).next().hasClass('active')){ + jQuery('.form-input-list__block-content').removeClass('active').css('height', '0px') + jQuery(this).next().css('height', '192px').addClass('active') + } + else{ + jQuery(this).next().css('height', '0px').removeClass('active') + } + +}) + +jQuery(document).mouseup(function(e){ + var container = jQuery(".modal-form-content-line__element"); + if(!container.is(e.target) && container.has(e.target).length === 0){ + jQuery('.form-input-list__block-content').removeClass('active').css('height', '0px') + } + }); + + + + + jQuery('#add-pet-form').on('submit', function(e) { + e.preventDefault(); // предотвращаем стандартное поведение формы + var data = jQuery(this).serialize() + jQuery(this).find('button[type="submit"]').addClass('loading').attr('disabled', true) + jQuery.ajax({ + type: 'POST', + url: woocommerce_params.ajax_url, + data: data, // отправляем данные формы + complete: function(response) { + location.reload(true) } - } - + }); + }); + + jQuery('.edit-pet-form').on('submit', function(e) { + e.preventDefault(); // предотвращаем стандартное поведение формы + var data = jQuery(this).serialize() + jQuery(this).find('button[type="submit"]').addClass('loading').attr('disabled', true) + jQuery.ajax({ + type: 'POST', + url: woocommerce_params.ajax_url, + data: data, // отправляем данные формы + complete: function(response) { + location.reload(true) + } + }); + }); + jQuery('.form-input-list__item').on('click', function(){ + jQuery(this).closest('.form-input-list__content').find('.form-input-list__item').removeClass('active') + jQuery(this).addClass('active') + }) + jQuery('.form-input-radio__item').on('click', function(){ + jQuery(this).closest('.form-input__radio').find('.form-input-radio__item').removeClass('active') + jQuery(this).addClass('active') }) - }) -} - - -inputCheck('.form-agreement__check'); - -function inputCheck(className) { - let checks = document.querySelectorAll(className); - checks.forEach(check => { - let square = check.querySelector('.form-agreement__square'), - input = check.querySelector('input'); - square.onclick = function () { - input.click(); + jQuery('.cabinet-card__block-add-pets').on('click', function(){ + + jQuery('#pet_add_form').addClass('active') + }) +// jQuery('#pet-form-submit').on('click', function(e) { +// jQuery(this).closest('form').submit() +// }); + + +jQuery('.popup-wrap, .modal-form__close, .modal-form__button-close').on('click', function(e){ + if (e.target == this){ + jQuery(this).closest('.modalProfile').removeClass('active') + } + }) + jQuery('.close-btn').on('click', function(e){ + jQuery(this).closest('.modalProfile').removeClass('active') + }) + + jQuery('input[name="pet"]').on('change', function( + + ){ + var block = jQuery(this).closest('form').find('.sterilized') + if (jQuery(this).val() == 'cat'){ + jQuery(block).show() + jQuery(this).closest('form').find('input[name="sterilized"]').attr('required', true) + } + else{ + jQuery(block).hide() + jQuery(this).closest('form').find('input[name="sterilized"]').attr('required', false) + } + }) + + + jQuery('[data-edit]').on('click', function(){ + jQuery('#pet_edit_'+jQuery(this).data('edit')).addClass('active') + }) + + + +// const reset = () => { +// input.classList.remove("error"); +// errorMsg.innerHTML = ""; +// errorMsg.classList.add("hide"); +// validMsg.classList.add("hide"); +// }; + +// const showError = (msg) => { +// input.classList.add("error"); +// errorMsg.innerHTML = msg; +// errorMsg.classList.remove("hide"); +// }; + + +jQuery('.user-edit-form').on('submit', function(e) { + e.preventDefault(); // предотвращаем стандартное поведение формы + jQuery('.form-input__phone').removeClass('error') + + + var data = jQuery(this).serialize() + jQuery(this).find('button[type="submit"]').addClass('loading').attr('disabled', true) + jQuery.ajax({ + type: 'POST', + url: woocommerce_params.ajax_url, + data: data, // отправляем данные формы + complete: function(response) { + location.reload(true) + } + }); + + +}); + +jQuery('.email_approve_form, .foodSub').on('submit', function(e) { + e.preventDefault(); // предотвращаем стандартное поведение формы + var data = jQuery(this).serialize() + jQuery(this).find('button[type="submit"]').addClass('loading').attr('disabled', true) + jQuery.ajax({ + type: 'POST', + url: woocommerce_params.ajax_url, + data: data, // отправляем данные формы + complete: function(response) { + location.reload(true) } - }) -} + }); +}); +jQuery('.user-edit-open').on('click', function(){ + jQuery('#user_edit').addClass('active') +}) -inputRead('.input-read'); -function inputRead(className) { - let inputs = document.querySelectorAll(className); +jQuery('[data-rm]').on('click', function(){ + var rm = jQuery(this).closest('.rm') + jQuery(rm).find('[data-rmcont]').removeClass('active').find('input').attr('required', false) + jQuery(rm).find('[data-rmcont="' + jQuery(this).data('rm') + '"]').addClass('active').find('input').attr('required', true) +}) - inputs.forEach(input => { - input.addEventListener("input", function (event) { - let text = event.target.value; - event.target.value = text.slice(0, -1); - }) - }) -} \ No newline at end of file +jQuery('.form-sub__btn').on('click', function(){ + jQuery('#subForm').addClass('active') +}) + diff --git a/wp-content/themes/cosmopet/modules/layout/assets/js/gp-main.js b/wp-content/themes/cosmopet/modules/layout/assets/js/gp-main.js index a77fde9..13d0dd1 100644 --- a/wp-content/themes/cosmopet/modules/layout/assets/js/gp-main.js +++ b/wp-content/themes/cosmopet/modules/layout/assets/js/gp-main.js @@ -415,3 +415,15 @@ if (document.querySelector('.header').classList.contains('white')) { // scroll + + +jQuery(document).ready(function($) { + jQuery('.popup-wrap').on('click', function(e) { + if (e.target === this) { + $(this).closest('.modalProfile').removeClass('active'); + } + }); + $('.close-btn').on('click', function(e) { + $('.modalProfile').removeClass('active'); + }); +}); \ No newline at end of file diff --git a/wp-content/themes/cosmopet/modules/shop/components/single-product/assets/css/gp-style-core.css b/wp-content/themes/cosmopet/modules/shop/components/single-product/assets/css/gp-style-core.css index 1091e45..dfd284e 100644 --- a/wp-content/themes/cosmopet/modules/shop/components/single-product/assets/css/gp-style-core.css +++ b/wp-content/themes/cosmopet/modules/shop/components/single-product/assets/css/gp-style-core.css @@ -1330,814 +1330,6 @@ button{ } /* counter */ -/* modal */ -.modal{ - position: fixed; - top: 0; - left: 0; - - padding: 20px; - - width: 100%; - height: 100%; - - background: rgba(0, 0, 0, 0.25); - - z-index: 200; - - opacity: 0; - transition: opacity .2s ease-out; - pointer-events: none; - - display: flex; - justify-content: center; - align-items: center; - - overflow-y: auto; -} -.modal.active{ - opacity: 1; - pointer-events: auto; -} -.modal__notification{} -.form__button-mobile{ - display: none; -} -.modal__aside{ - position: fixed; - top: 0; - right: 0; - - width: 0; - height: 100%; - - overflow: hidden; - transition: width .4s ease-out; -} -.modal__item{ - height: 100%; - - padding: 24px; - - background: var(--background-white); - - position: relative; - - display: none; - - filter: blur(10px); - transition: filter .2s ease-out; -} -.modal__item--no-title{ - padding-top: 72px; -} -.modal__item.active{ - display: flex; - flex-direction: column; - justify-content: space-between; -} -.modal__close{ - position: absolute; - top: 32px; - right: 24px; - - width: 24px; - height: 24px; - - border: none; - background: none; -} -.modal__header{} -.modal__title{ - padding-right: 48px; - - font-family: var(--font-family); - font-weight: 700; - font-size: 36px; - line-height: 111%; - text-transform: uppercase; - color: var(--text-black); -} -.modal__small-title{ - font-family: var(--font-family); - font-weight: 700; - font-size: 24px; - line-height: 100%; - text-transform: uppercase; - color: var(--text-black); -} -.modal__text{ - margin-top: 16px; - - padding-right: 10px; - - font-family: var(--font-family); - font-weight: 400; - font-size: 20px; - line-height: 120%; - color: var(--text-0); -} -.modal__form-sub{ - margin-top: 48px; -} -.modal-form-sub__submit{ - margin-top: 64px; -} -.modal__block-button{ - margin-top: 24px; -} -.modal__button{ - margin-top: 16px; -} -.modal__button:first-child{ - margin-top: 0; -} -.modal__content{ - margin-top: 24px; -} -.modal__filter{ - width: 400px; -} -.modal__footer{ - border-top: 1px solid var(--text-6); - padding-top: 23px; -} -.modal__block-price{ - display: flex; - justify-content: space-between; - align-items: center; -} -.modal-block-price__title{ - font-family: var(--font-family); - font-weight: 600; - font-size: 20px; - line-height: 120%; - color: var(--text-black); -} -.modal-block-price__price{ - font-family: var(--font-family); - font-weight: 700; - font-size: 24px; - line-height: 100%; - text-transform: uppercase; - text-align: right; - color: var(--text-black); -} -.modal-block-price__price::after{ - content: 'Р'; -} -.modal__basket{ - width: 600px; -} -.modal__to-know, -.modal__to-know-submit{ - width: 412px; -} - -.modal-basket__item{ - padding-top: 23px; - padding-right: 15px; - padding-bottom: 24px; - - display: flex; - - border-top: 1px solid var(--background-grey); - - position: relative; -} -.modal-basket__item::before{ - content: ''; - - position: absolute; - top: 24px; - right: 6px; - - width: 24px; - aspect-ratio: 1; - - background-image: url(../img/svg/main/basket.svg); - background-repeat: no-repeat; - background-position: center; - - cursor: pointer; - - transition: opacity .2s ease-out; -} -.modal-basket__item:hover .modal-basket__item::before{ - opacity: .8; -} -.modal-basket__item--return{ - padding-right: 5px; - - display: flex; - justify-content: space-between; - align-items: center; -} -.modal-basket__item--return .modal-basket-item__title{ - padding-right: 10px; -} -.modal-basket__item--return::before{ - display: none; -} -.modal-basket-item__return{ - border-radius: 20px; - padding: 4px 24px; - - font-family: var(--font-family); - font-weight: 600; - font-size: 20px; - line-height: 120%; - color: var(--text-white); - - background: var(--background-black); - - border: none; -} -.modal-basket-item__block-image{ - width: 128px; - aspect-ratio: 1; - - display: flex; - justify-content: center; - align-items: center; -} -.modal-basket-item__image{ - width: 96px; - aspect-ratio: 1; - - object-fit: contain; -} -.modal-basket-item__content{ - margin-left: 16px; -} -.modal-basket-item__title{ - padding-right: 40px; - - font-family: var(--font-family); - font-weight: 500; - font-size: 20px; - line-height: 120%; - color: var(--text-black); -} -.modal-basket-item__sub-title{ - margin-top: 8px; - - font-family: var(--font-family); - font-weight: 700; - font-size: 12px; - line-height: 133%; - color: var(--text-black); -} -.modal-basket-item__control{ - margin-top: 24px; - - display: flex; - justify-content: space-between; - align-items: center; -} -.modal-basket-item__price{ - font-family: var(--font-family); - font-weight: 600; - font-size: 20px; - line-height: 120%; - text-align: right; - color: var(--text-black); -} -.modal-basket-item__price::after{ - content: 'Р'; - - padding-left: 4px; -} -.modal__basket .modal__header{ - height: calc(100% - 92px); - margin-bottom: -36px; -} -.modal__basket .modal__content{ - height: calc(100% - 100px); - overflow-x: hidden; - -} -.modal__basket .modal__content::-webkit-scrollbar { - width: 7px; - background-color: #f9f9fd; -} -.modal__basket .modal__content::-webkit-scrollbar-thumb { - background-color: var(--background-black); - border-radius: 2px; -} - -.modal-form{ - margin: auto; - - width: 600px; - - padding: 24px; - - border-radius: 20px; - - position: relative; - - display: none; -} -.modal-form.active{ - display: block; -} -.modal-form--white{ - border: 1px solid var(--background-black); - background: var(--background-white); -} -.modal-form--green-gradient{ - background: var(--gradient-blue); -} -.modal-form--width-584{ - width: 584px; -} -.modal-form--cdek{ - width: 836px; -} -.modal-form__close{ - position: absolute; - top: 24px; - right: 24px; - - width: 24px; - aspect-ratio: 1; - - border: none; - background: none; - background-image: url(../img/svg/main/black-x.svg); - background-repeat: no-repeat; - background-size: 24px; - background-position: center; - - transition: opacity .2s ease-out; - - z-index: 10; -} -.modal-form__close--white{ - background-image: url(../img/svg/main/white-x.svg); -} -.modal-form__close:hover{ - opacity: .8; -} -.modal-form__button-close{} -.modal-form__title{ - padding-right: 50px; - - font-family: var(--font-family); - font-weight: 700; - font-size: 26px; - line-height: 123%; - text-transform: uppercase; - color: var(--text-dark); -} -.modal-form__text--center{ - text-align: center; -} -.modal-form__text--center-pc{ - text-align: center; -} -.modal-form__title--green-gradient{ - background: var(--gradient-blue); - background-clip: text; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; -} -.modal-form__title--white{ - color: var(--text-white); -} -.modal-form__element{ - margin-top: 24px; -} -.modal-form__element--center{ - display: flex; - justify-content: center; -} -.modal-form__element--top-40{ - margin-top: 40px; -} -.modal-form__text{ - font-family: var(--font-family); - font-weight: 400; - font-size: 20px; - line-height: 120%; - color: var(--text-black); -} -.modal-form__text--weight-500{ - font-weight: 500; -} -.modal-form__text--white{ - color: var(--text-white); -} -.modal-form__img{ - width: 100%; - height: 360px; - - object-fit: contain; -} -.modal-form__content{ - margin-top: 40px; -} -.modal-form-content__line{ - margin-top: 24px; -} -.modal-form-content__line:first-child{ - margin-top: 0; -} -.modal-form-content__line--two{ - display: flex; - justify-content: space-between; -} -.modal-form-content__line--two-mobile{ - display: flex; - justify-content: space-between; -} -.modal-form-content__line--two-mobile .modal-form-content-line__element{ - width: calc(50% - 12px); -} -.modal-form-content-line__element{ - position: relative; -} -.modal-form-content-line__element--arrow::after{ - content: ''; - - position: absolute; - right: 16px; - bottom: 16px; - - width: 16px; - height: 16px; - - background-image: url(../img/svg/main/arrow-right-input.svg); - - pointer-events: none; -} -.modal-form-content__line--two .modal-form-content-line__element{ - width: calc(50% - 12px); -} -.modal-form-content__line--three{ - display: flex; -} -.modal-form-content__line--three .modal-form-content-line__element:nth-child(1){ - width: 85px; - - flex-shrink: 0; -} -.modal-form-content__line--three .modal-form-content-line__element:nth-child(2){ - margin-left: 8px; - - width: 100%; -} -.modal-form-content__line--three .modal-form-content-line__element:nth-child(3){ - margin-left: 8px; - - width: 85px; - - flex-shrink: 0; -} -.modal-form-content__line--margin-top-16{ - margin-top: 16px; -} -.modal-form__buttons{ - margin-top: 32px; -} -.modal-form__buttons--two{ - display: flex; - justify-content: space-between; - align-items: center; -} - -.modal-form__buttons--two button, -.modal-form__buttons--two input{ - width: calc(50% - 20px); -} -.modal-map{ - margin: auto; - - width: 1105px; - - display: none; - - border-radius: 24px; - border: none; -} -.modal-map.active{ - display: flex; -} -.modal-map__left{ - width: 600px; - - padding: 24px; - - position: relative; -} -.modal-map__control{ - margin: 38px -12px -12px -12px; - - display: flex; -} -.modal-map__control--delivery{ - margin-top: 12px; -} -.modal-map-control__item{ - margin: 12px; - - padding: 2px; - - width: calc(50% - 24px); - - background: var(--background-9); - border-radius: 20px; - border: none; -} -.modal-map-control__item.active{ - background: var(--gradient-blue); -} -.modal-map-control__item.active .form-input-radio__circle::before{ - content: ''; - position: absolute; - top: 4px; - left: 4px; - width: 12px; - aspect-ratio: 1; - border-radius: 50%; - background: var(--gradient-blue); -} -.modal-map-control-item__content{ - padding: 14px; - - border-radius: 18px; - - background: var(--background-white); -} -.modal-map-control-item__header{ - display: flex; - align-items: center; -} -.modal-map-control-item__circle{ - padding: 2px; - width: 20px; - aspect-ratio: 1; - border-radius: 50%; - background: var(--background-9); - position: relative; -} -.modal-map-control-item__input{ - display: none; -} -.modal-map-control-item-circle__content{ - width: 16px; - aspect-ratio: 1; - border-radius: 50%; - background: var(--background-white); -} -.modal-map-control__item.active .modal-map-control-item__circle{ - background: var(--gradient-blue); -} -.modal-map-control__item.active .modal-map-control-item__circle::before{ - content: ''; - position: absolute; - top: 4px; - left: 4px; - width: 12px; - aspect-ratio: 1; - border-radius: 50%; - background: var(--gradient-blue); -} -.modal-map-control-item__title{ - margin-left: 8px; - - font-family: var(--font-family); - font-weight: 400; - font-size: 20px; - line-height: 120%; - color: var(--text-dark); -} -.modal-map-control-item__description{ - margin-top: 16px; -} -.modal-map-control-item__time{ - font-family: var(--font-family); - font-weight: 500; - font-size: 16px; - line-height: 125%; - color: var(--text-black); - - text-align: start; -} -.modal-map-control-item__price{ - margin-top: 8px; - - font-family: var(--font-family); - font-weight: 700; - font-size: 12px; - line-height: 133%; - color: var(--text-6); - - text-align: start; -} -.modal-map__form{ - margin-top: 24px; -} -.modal-map-form__hidden{ - -} -.modal-map-form__button{ - margin-top: 83px; -} -.modal-map-form__sub-button{ - display: none; -} -.modal-map__right{ - padding: 16px 0px 16px 16px; -} -.modal-map__map{ - border: 2px solid var(--background-9); - border-radius: 16px; - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.modal-map__map iframe{ - height: 650px; -} -.modal__age{ - -} -.modal__age > div{ - display: none; -} -.modal__age > div.active{ - display: flex; -} -/* modal */ - -/* toggle */ -.toggle{ - padding-top: 26px; - padding-bottom: 25px; - - border-bottom: 1px solid var(--text-3); - - position: relative; -} -.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; - pointer-events: none; -} -.toggle.active::after{ - transform: rotate(0deg); -} -.toggle__title{ - padding-right: 30px; - - font-family: var(--font-family); - font-weight: 700; - font-size: 16px; - line-height: 125%; - color: var(--text-black); - - cursor: pointer; -} -.toggle__block-content{ - height: 0; - overflow: hidden; - - transition: height .2s ease-out; -} -.toggle__content{ - padding-top: 24px; -} -.toggle-content__item{ - margin: 12px -12px -12px -12px; - - display: flex; - align-items: center; - flex-wrap: wrap; -} -.toggle-content__item:first-child{ - margin-top: 0; -} -.toggle-content__element{ - margin: 12px; -} -.toggle-content__element--width-perc-100{ - width: 100%; -} -.toggle-content__element--width-perc-50{ - width: calc(50% - 24px); -} -.toggle__text{ - font-family: var(--font-family); - font-weight: 400; - font-size: 20px; - line-height: 120%; - color: var(--text-black); -} -/* toggle */ - -/* checkbox */ -.checkbox{ - display: flex; - align-items: center; - - cursor: pointer; -} -.checkbox__state{ - border-radius: 4px; - - width: 18px; - height: 18px; - - border: 2px solid var(--background-black); - background: var(--background-white); - - flex-shrink: 0; -} -.checkbox.active .checkbox__state{ - background-color: var(--background-black); - - background-image: url(../img/svg/main/arrow-selected-white.svg); - background-repeat: no-repeat; - background-position: center; -} -.checkbox__input{ - display: none; -} -.checkbox__label{ - padding-left: 8px; - - font-family: var(--font-family); - font-weight: 400; - font-size: 20px; - line-height: 120%; - color: var(--text-dark); - - cursor: pointer; -} -.checkbox__label a{ - color: #76ce75; - - text-decoration: none; -} -.checkbox--small{ - margin-top: 24px; -} -.checkbox--small .checkbox__label{ - padding-left: 24px; - - font-weight: 500; - font-size: 12px; - line-height: 133%; -} -/* checkbox */ - -/* radio */ -.radio{ - display: flex; - align-items: center; -} -.radio__input{ - width: 18px; - aspect-ratio: 1; - - accent-color: var(--background-black); - - cursor: pointer; -} -.radio__label{ - padding-left: 8px; - - font-family: var(--font-family); - font-weight: 400; - font-size: 20px; - line-height: 120%; - color: var(--text-dark); - - cursor: pointer; -} -/* radio */ - - -@keyframes slidein { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} .subscription{ @@ -2230,4 +1422,142 @@ button{ .cabinet-card-order-payment__price span{ font-size: 12px; +} + + + +.wcsatt-add-to-subscription-wrapper, + form.cart .quantity, + .detail__content .in-stock, + .wcsatt-options-prompt-label-subscription, + .wcsatt-options-product-dropdown { + display: none; + } + .wcsatt-options-product-wrapper { + display: block!important; + } + form.cart .single_add_to_cart_button { + margin: 8px; + min-width: 345.89px; + height: 56px; + padding: 16px 24px 16px 24px; + font-weight: 700; + text-align: center; + position: relative; + background: var(--gradient-turquoise); + border: none; + transition: opacity .2s ease-out; + font-family: var(--font-family); + font-size: 20px; + line-height: 120%; + color: var(--text-black); + border-radius: 20px; + text-transform: none; + cursor: pointer; + } + form.cart .single_add_to_cart_button:hover { + opacity: 0.8; + } + .subscription-option-details span { + color: #000; + cursor: pointer; + } + ul.wcsatt-options-product, .wcsatt-options-product-dropdown { + margin: 0; + } + .wcsatt-options-wrapper input, .wcsatt-add-to-subscription-wrapper input { + width: 18px; + aspect-ratio: 1; + accent-color: var(--background-black); + cursor: pointer; + } + .subscription-option label { + display: flex; + align-items: center; + gap: 5px; + } + + form.cart { + margin: 25px 0 -48px; + } + ul.wcsatt-options-product--hidden, .wcsatt-options-product-dropdown--hidden { + display: block!important; + } + .detail-block__form{ + margin-top: 48px; + + display: flex; + flex-direction: column; + } + + + .wcsatt-options-prompt-text{ + font-family: 'Craftwork Grotesk'; + font-style: normal; + font-weight: 700; + font-size: 20px; + line-height: 24px; + text-transform: uppercase; + color: #000000; +} + +.subscription-option-details, .wcsatt-options-prompt-action, .subs-text-title{ + font-size: 20px; + line-height: 24px; + display:flex; + gap: 12px; + align-items: center; +} +.subs-text{ + +max-width: 322px; +font-family: 'Craftwork Grotesk'; +font-style: normal; +font-weight: 500; +font-size: 16px; +line-height: 20px; +margin-bottom: 20px; +} +input:checked + .subscription-option-details::before, input:checked + .wcsatt-options-prompt-action::before{ + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M1 10C1 5.02944 5.02944 1 10 1C14.9706 1 19 5.02944 19 10C19 14.9706 14.9706 19 10 19C5.02944 19 1 14.9706 1 10Z' fill='white'/%3E%3Cpath d='M1 10C1 5.02944 5.02944 1 10 1C14.9706 1 19 5.02944 19 10C19 14.9706 14.9706 19 10 19C5.02944 19 1 14.9706 1 10Z' stroke='url(%23paint0_radial_11890_46040)' stroke-width='2'/%3E%3Ccircle cx='10' cy='10' r='6' fill='url(%23paint1_radial_11890_46040)'/%3E%3Cdefs%3E%3CradialGradient id='paint0_radial_11890_46040' cx='0' cy='0' r='1' gradientUnits='userSpaceOnUse' gradientTransform='translate(19 1) rotate(135) scale(25.4558 34.7538)'%3E%3Cstop stop-color='%23188892'/%3E%3Cstop offset='0.45' stop-color='%231EA49C'/%3E%3Cstop offset='0.9' stop-color='%2376CE75'/%3E%3Cstop offset='1' stop-color='%23BBE38D'/%3E%3C/radialGradient%3E%3CradialGradient id='paint1_radial_11890_46040' cx='0' cy='0' r='1' gradientUnits='userSpaceOnUse' gradientTransform='translate(16 4) rotate(135) scale(16.9706 23.1692)'%3E%3Cstop stop-color='%23188892'/%3E%3Cstop offset='0.45' stop-color='%231EA49C'/%3E%3Cstop offset='0.9' stop-color='%2376CE75'/%3E%3Cstop offset='1' stop-color='%23BBE38D'/%3E%3C/radialGradient%3E%3C/defs%3E%3C/svg%3E"); +} +.subscription-option-details::before, .wcsatt-options-prompt-action::before{ + content: ''; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M1 10C1 5.02944 5.02944 1 10 1C14.9706 1 19 5.02944 19 10C19 14.9706 14.9706 19 10 19C5.02944 19 1 14.9706 1 10Z' fill='white'/%3E%3Cpath d='M1 10C1 5.02944 5.02944 1 10 1C14.9706 1 19 5.02944 19 10C19 14.9706 14.9706 19 10 19C5.02944 19 1 14.9706 1 10Z' stroke='%23121212' stroke-width='2'/%3E%3C/svg%3E"); + height: 20px; width: 20px; + +} + +.wcsatt-options-wrapper input, .wcsatt-add-to-subscription-wrapper input { + aspect-ratio: 1; + accent-color: var(--background-black); + cursor: pointer; + height: 0; + width: 0; + position: absolute; + opacity: 0; +} + +.subscription-option .amount { + color: #1A1A1A; + font-weight: 600; +} + +.subscription-option del .amount { + color: #bbb; + font-weight: 400; + font-size: .8em; + +} + +.subscription-option del .woocommerce-Price-amount.amount, .subscription-option del .woocommerce-Price-currencySymbol{ + text-decoration: line-through !important; +} + +.woocommerce-Price-amount.amount{ + font-size: 1.15em; +} + +.detail #wc-stripe-express-checkout-element{ + display: none !important; } \ No newline at end of file diff --git a/wp-content/themes/cosmopet/modules/shop/components/single-product/assets/js/gp-product.js b/wp-content/themes/cosmopet/modules/shop/components/single-product/assets/js/gp-product.js index 2508270..32043ad 100644 --- a/wp-content/themes/cosmopet/modules/shop/components/single-product/assets/js/gp-product.js +++ b/wp-content/themes/cosmopet/modules/shop/components/single-product/assets/js/gp-product.js @@ -107,4 +107,46 @@ const detailCatalot = new Swiper('.detail__catalot', { }); -// detail catalog \ No newline at end of file +// detail catalog +// +// +// +jQuery(document).ready(function($) { + // Основные радио-кнопки выбора типа покупки + const $oneTimeRadio = $('input[value="no"][name="subscribe-to-action-input"]'); + const $subscribeRadio = $('input[value="yes"][name="subscribe-to-action-input"]'); + + // Все чекбоксы вариантов подписки + const $subscriptionOptions = $('.wcsatt-options-product input[type="radio"]'); + + // Обработчик для One-time + $oneTimeRadio.on('change', function() { + if ($(this).is(':checked')) { + // Снимаем выделение со всех вариантов подписки + $subscriptionOptions.prop('checked', false); + } + }); + + // Обработчик для Subscribe + $subscribeRadio.on('change', function() { + if ($(this).is(':checked')) { + // Снимаем выделение с One-time + $oneTimeRadio.prop('checked', false); + + // Если ни один вариант подписки не выбран, выбираем первый + if ($subscriptionOptions.filter(':checked').length === 0) { + $subscriptionOptions.first().prop('checked', true); + } + } + }); + + // Обработчик для вариантов подписки + $subscriptionOptions.on('change', function() { + if ($(this).is(':checked')) { + // Снимаем выделение с One-time + $oneTimeRadio.prop('checked', false); + // Активируем Subscribe + $subscribeRadio.prop('checked', true); + } + }); +}); \ No newline at end of file diff --git a/wp-content/themes/cosmopet/modules/shop/components/single-product/component-template.twig b/wp-content/themes/cosmopet/modules/shop/components/single-product/component-template.twig index c1bc729..5dfbb56 100644 --- a/wp-content/themes/cosmopet/modules/shop/components/single-product/component-template.twig +++ b/wp-content/themes/cosmopet/modules/shop/components/single-product/component-template.twig @@ -56,9 +56,9 @@ {% endif %} -

+

{{ product.get_title }} -

+

@@ -108,14 +108,9 @@ {% endif %} {% endif %} - - - + - + {{ function('do_action', 'woocommerce_' ~ product.get_type() ~ '_add_to_cart') }}

diff --git a/wp-content/themes/cosmopet/page.php b/wp-content/themes/cosmopet/page.php index ac4ba9a..747165d 100644 --- a/wp-content/themes/cosmopet/page.php +++ b/wp-content/themes/cosmopet/page.php @@ -5,6 +5,26 @@ * This is the template that renders pages using Timber (Twig). */ + +if (is_account_page() && !is_wc_endpoint_url()){ + include_module('profile'); + $orders_pg = false; + include_component('profile', 'profile'); +} +else if (is_account_page() && isset($wp->query_vars['orders'])){ + include_module('profile'); + $orders_pg = true; + include_component('profile', 'profile'); +} +elseif (is_account_page() && isset($wp->query_vars['subscriptions'])){ + include_module('profile'); + include_component('profile', 'subscriptions'); +} + +elseif (is_account_page() && isset($wp->query_vars['view-subscription'])){ + include_module('profile'); + include_component('profile', 'subscription_single'); +} $context = Timber::context(); $context['post'] = Timber::get_post(); diff --git a/wp-content/themes/cosmopet/static/front-page/css/style.css b/wp-content/themes/cosmopet/static/front-page/css/style.css index 6f02d2c..61cc78b 100644 --- a/wp-content/themes/cosmopet/static/front-page/css/style.css +++ b/wp-content/themes/cosmopet/static/front-page/css/style.css @@ -4276,4 +4276,8 @@ color: #f4f1f0; .reviews-plus{ overflow: hidden; +} + +.invisible { + visibility: hidden; } \ No newline at end of file diff --git a/wp-content/themes/cosmopet/static/front-page/js/main.js b/wp-content/themes/cosmopet/static/front-page/js/main.js index 060bcef..72c9056 100644 --- a/wp-content/themes/cosmopet/static/front-page/js/main.js +++ b/wp-content/themes/cosmopet/static/front-page/js/main.js @@ -467,6 +467,59 @@ document.addEventListener('DOMContentLoaded', function () { }); }); +// Находим все элементы с классом login-open +document.addEventListener('DOMContentLoaded', function() { + const loginButtons = document.querySelectorAll('.login-open'); + + // Добавляем обработчик события для каждой кнопки + loginButtons.forEach(button => { + button.addEventListener('click', function(event) { + event.preventDefault(); // Предотвращаем стандартное действие (если это ссылка) + + // Находим элементы модального окна + const modal = document.querySelector('.modal'); + const modalAside = document.querySelector('.modal__aside'); + const modalLogin = document.querySelector('.modal__login'); + + // Добавляем классы active + modal.classList.add('active'); + modalLogin.classList.add('active'); + + // Устанавливаем ширину для modal__aside + modalAside.style.width = '412px'; + }); + }); + + // Опционально: добавляем функцию закрытия модального окна + // Например, при клике на фон или кнопку закрытия + const closeButtons = document.querySelectorAll('.modal-close'); + const modal = document.querySelector('.modal'); + + // Закрытие по клику на кнопку закрытия + closeButtons.forEach(button => { + button.addEventListener('click', closeModal); + }); + + // Закрытие по клику на фон (если клик не на модальное окно) + modal.addEventListener('click', function(event) { + if (event.target === modal) { + closeModal(); + } + }); + + function closeModal() { + const modal = document.querySelector('.modal'); + const modalAside = document.querySelector('.modal__aside'); + const modalLogin = document.querySelector('.modal__login'); + + // Удаляем классы active + modal.classList.remove('active'); + modalLogin.classList.remove('active'); + + // Сбрасываем ширину + modalAside.style.width = ''; + } +}); document.addEventListener('DOMContentLoaded', function() { // Initialize Swiper @@ -535,4 +588,4 @@ document.addEventListener('DOMContentLoaded', function() { reviewPopup.style.display = 'none'; } }); -}); \ No newline at end of file +}); diff --git a/wp-content/themes/cosmopet/templates/blog/blog-page.twig b/wp-content/themes/cosmopet/templates/blog/blog-page.twig new file mode 100644 index 0000000..ee4340e --- /dev/null +++ b/wp-content/themes/cosmopet/templates/blog/blog-page.twig @@ -0,0 +1,839 @@ +{% extends 'layout.twig' %} + +{% block content %} +{% set bodyClass = 'bg-white' %} + +

+
+
+

+ +

+
+

+
+ +
+ +
+
+
+
+ + +
+
+
+
+
+
+ user_firstname; + $last_name = $current_user->user_lastname;?> +

+ ID, 'billing_phone', true ); + + if($first_name || $last_name): + echo $first_name . ' ' . $last_name; + else: + ?> + + + +

+
+ +
+

:

+

+ + + +

+
+ +
+

:

+ user_email): ?> +

user_email ?>

+ +

+ +

+ + +

+ + + +
+ +
+ +
+ + ID, ' Traveling', true ); + ?> +
+

:

+

+ + + + + +

+
+ +
+
+ + + + + +
+
+
+
+ + 'pets', // Тип постов + 'meta_query' => array( + array( + 'key' => 'user', // Имя метаполя + 'value' => $current_user_id, // Значение метаполя (ID текущего пользователя) + 'compare' => '=' // Условие сравнения + ) + ) + ); + + // Создаем новый объект WP_Query + $query = new \WP_Query($args); + + if ($query->have_posts()) { + // Начинаем цикл по постам + while ($query->have_posts()) { + $query->the_post(); + get_pet_card($post); + } + // Сбрасываем данные постов + wp_reset_postdata(); + } + } + ?> + +
+
+ +
+
+
+
+
+
+

+ +

+
+

+
+ +
+ +
+
+
+ + $current_user->ID, + ) ); + + if ($customer_orders): + foreach($customer_orders as $order): + $meta_data = get_post_meta($order->get_id(), 'order_data', true); + $shipping_address = $order->get_address( 'shipping' ); + ?> +
+
+
+
+
+

get_date_created()->date('Y.m.d') ?>

+

get_id() ?>

+
+
+

:

+

get_total() ?>

+
+
+
+
+ +
+
+
+

+

+ '; + echo json_decode($api->getOffices(['code' => $meta_data['office_code']])['body'])[0]->name; + ?> + + +

+
+ +
+
+ get_items() as $item_id => $item) : + $product_name = $item->get_name(); + $product_quantity = $item->get_quantity(); + $product_total = $item->get_total(); + $product = $item->get_product(); + + if ($product){ + $thumbnail = wp_get_attachment_image_src( get_post_thumbnail_id( $product->get_id() ), 'thumbnail' ); + } + else{ + $thumbnail = ''; + } + ?> +
+ + +
+
+

+ +
+ +

+ +

+
+
+ +
+ + +
+
+
+ + +
+ +
+ get_items() as $item_id => $item) : + $product = $item->get_product(); + if ($product){ + $thumbnail = wp_get_attachment_image_src( get_post_thumbnail_id( $product->get_id() ), 'thumbnail' ); + } + else{ + $thumbnail = ''; + } + ?> + + + + +
+
+
+
+
+ +
+
+

+
+
+ +

+
+
+
+ +
+
+
+ + 'pets', // Тип постов + 'meta_query' => array( + array( + 'key' => 'user', // Имя метаполя + 'value' => $current_user_id, // Значение метаполя (ID текущего пользователя) + 'compare' => '=' // Условие сравнения + ) + ) +); + +// Создаем новый объект WP_Query +$query = new \WP_Query($args); + +if ($query->have_posts()) { + // Начинаем цикл по постам + while ($query->have_posts()) { + $query->the_post(); + + switch (get_field('weight')){ + case ('below_1_5'): + $w = esc_html__('from 0,5 kg to 1,5 kg', '_pll_e' ); + break; + case ('1_5-3'): + $w = esc_html__('from 1.5 to 3 kg', '_pll_e' ); + break; + case ('3-5'): + $w = esc_html__('from 3 to 5 kg', '_pll_e' ); + break; + case ('5-8'): + $w = esc_html__('from 5 to 8 kg', '_pll_e' ); + break; + case ('8-11'): + $w = esc_html__('from 8 to 11 kg', '_pll_e' ); + break; + case ('11-15'): + $w = esc_html__('from 11 to 15 kg', '_pll_e' ); + break; + case ('15-20'): + $w = esc_html__('from 15 to 20 kg', '_pll_e' ); + break; + case ('20-25'): + $w = esc_html__('from 20 to 25 kg', '_pll_e' ); + break; + case ('25-35'): + $w = esc_html__('from 25 to 35 kg', '_pll_e' ); + break; + case ('more_35'): + $w = esc_html__('More than 35 kg', '_pll_e' ); + break; + } + switch (get_field('old')){ + case ('normal'): + $old = __('Adult (from 1 year to 7 years)', '_pll_e' ); + break; + case ('old'): + $old = __('Elderly (from 7 to 12 years)', '_pll_e' ); + break; + case ('very_old'): + $old = __('Aging (12 years and older)', '_pll_e' ); + break; + case ('baby'): + $old = __('Baby (from 0 to 1 year)', '_pll_e' ); + break; + } + switch (get_field('activity')){ + case ('low'): + $act = esc_html__('Low', '_pll_e' ); + break; + case ('moderate'): + $act = esc_html__('Moderate', '_pll_e' ); + break; + case ('high'): + $act = esc_html__('High', '_pll_e' ); + break; + } + ?> + + +
+