Задать вопрос
  • Можно ли мои вариации товара задать сразу всем товарам wooccomerce?

    Если у всех одинаковые вариации, зачем товары вариативными делали?

    Плагин не знаю, кодом можно пробежать по каждому товару и добавить по вариации.
    Ответ написан
  • Как вывести на первое место комбинацию с количеством?

    В настройках магазина есть флажок "скрывать отсутствующие "
    Ответ написан
  • Имеется ли плагин для вордпресса, который автоматом выбирает картинки по тайтлу при добавлении в запись?

    Такое не встречал,
    Но писал код подгрузки картинок из определенной папки, добавление их в медиа-библиотеку, и подключение к постам (к товарам Woocommerce) по соответствию артикула и в названии картинки.

    Если будете править, то вот
    php
    <?php 
    
    /**
    *	Класс для подключения изображения к товару
    */
    class Hml_Img_Connector {
    	
    	/**
    	*	
    	*/
    	public static function init(){
    		
    		add_action('tesp_show_widget', array('Hml_Img_Connector', 'get_html_widget') );
    		
    		// подключаем ajax хуки
    		if( defined('DOING_AJAX') && DOING_AJAX ){
    			add_action('wp_ajax_img_connector_dostep', array('Hml_Img_Connector', 'dostep_ajax_handler') );
    		}
    						
    	}
    	
    	public static function dostep_ajax_handler(){
    
    		$imgs = self::get_array_images(TEST__PLUGIN_DIR . 'imgs/');
    		
    		// сортировка по убыванию
    		usort($imgs, function($a, $b){
    			    if ($a['name'] == $b['name']) {
    					return 0;
    				}
    				return ($a['name'] > $b['name']) ? -1 : 1;
    		});
    
    		$msgs = self::process_images($imgs, 2);
    		
    		$aAns = array('left'=>count($imgs), 'msgs'=>$msgs);
    
    		echo json_encode($aAns);
    		
    		wp_die(); 
    		
    	}
    
    	/**
    	 * Запускает процесс подключения картинок
    	 * 
    	 */
    	private static function process_images(&$imgs, $step){
    
    		$msgs = array();
    
    		if ( $step < 1 ) { $step = 1; }
    		
    		for ($i = count($imgs) - 1; $i >= 0 ; $i--) {
    			$sku = '9999';
    
    			// отделяем все, что после символа "_"
    			$fn = explode( '_', $imgs[$i]['name'])[0];
    			$sku_parts = explode('-', $fn);
    			if (count($sku_parts) >= 4 && '111' == $sku_parts[3] ) {
    				$sku = implode( '-', array_slice($sku_parts, 0,4) );
    			} else {
    				$sku = implode( '-', array_slice($sku_parts, 0,3) );
    			}
    			// $sku = substr($imgs[$i]['name'], 0, 12);
    
    			$id = wc_get_product_id_by_sku($sku);
    
    			if ( !$id ){
    
    				$msgs[] = $imgs[$i]['name']. ' - ошибка, артикул "' . $sku . '" не найден.';
    				$edir = dirname(dirname($imgs[$i]['path'])) . '/notfound/';
    				$newpath = $edir . $imgs[$i]['name'];
    				if ( is_dir($edir) ) {
    					rename($imgs[$i]['path'],  $newpath);	
    				} else {
    					if ( mkdir($edir) ) {
    						rename($imgs[$i]['path'],  $newpath);							
    					} else {
    						@unlink( $imgs[$i]['path'] );
    					}
    				}
    
    			} else {
    				$media_id = self::atach_image($imgs[$i], $id);
    				if( is_wp_error($media_id) ) {
    					$msgs[] = $imgs[$i]['name']. ' - ошибка загрузки.';
    				} else {
    					$msgs[] = $imgs[$i]['name']. ' - успешно.';				
    				}
    				
    				array_pop($imgs);
    				$step --;
    				if ( 0 == $step ) break;
    			}
    		}
    		return $msgs;
    	}
    	
    	/**
    	* собираем все файлы картинок в директории
    	*/
    	private static function get_array_images($dir){
    		$ret = array();
    		
    		if ($handle = opendir($dir)) {
    
    			while (false !== ($file = readdir($handle))) { 
    				$fullpath = $dir .  $file;
    				if ( !is_dir( $fullpath ) ) {
    					$ext = pathinfo($fullpath)['extension'];
    					if ( 'jpg' == strtolower($ext) ) {
    						$ret[] =  array('name' => $file, 'path' => $fullpath);
    					}
    				}
    			}
    			clearstatcache();	// очистка кэша
    			closedir($handle); 
    		}
    		return $ret;
    	}
    	
    	
    
    	/**
    	 *	By Pytex
    	 * Добавляет картинку в медиабиблиотеку и 
    	 * прикрепляет ее к посту как миниатюру, если не задано
    	 * или в галерею поста
    	 *
    	 * @param  string  $img 
    	 * @param  number  $post_id
    	 */
    	private static function atach_image( $img, $post_id ) {
    		
    		// Установим данные файла
    		$file_array = array();
    		 
    		// Получаем имя файла
    		$file_array['name'] = $img['name'] ;
    		$file_array['tmp_name'] = $img['path'];
    		 
    		// загружаем файл
    		$media_id = media_handle_sideload( $file_array, $post_id);
    		 
    		// Проверяем на наличие ошибок
    		if( !is_wp_error($media_id) ) {
    		 
    			// Файл сохранён и добавлен в медиатеку WP. 
    			
    			$thumbnail_id = get_post_thumbnail_id( $post_id );
    			// Если нет прикрепленной миниатюры 
    			if ( !$thumbnail_id ){
    				// назначаем в качестве обложки
    				set_post_thumbnail($post_id, $media_id);
    			} else {
    				$media = get_attached_media('image', $post_id);
    				$imgs = array_diff(array_keys($media), array($thumbnail_id));
    				update_post_meta($post_id, '_product_image_gallery', implode(',', $imgs));
    			}		
    		}
    		return $media_id;
    	}
    
    	/**
    	*  Выводит на экран форму запуска процесса добавления картинок
    	*/
    	public static function get_html_widget(){
    
    		?>
    		<form action="" method="POST">
    			<h4>Подключение картинок</h4>
    			<table>
    				<tr>
    					<td>Затраченное время:</td>
    					<td><span id="time-elapsed" class="tsb-value"></span></td></tr>
    				<tr>
    					<td>Осталось времени:</td>
    					<td><span id="time-left" class="tsb-value"></span></td></tr>
    				<tr>
    					<td>Осталось обработать файлов:</td>
    					<td><span id="files-left" class="tsb-value"></span></td></tr>
    			</table>
    			<br/>
    			<?php
    				echo '<input type="button" id="btn-start-parsing" value="Запустить разбор картинок" class="button button-primary" ' ;?>
    		</form>
    		<div id="status-msg"></div>
    		<?php
    		require_once( 'img-connector-js.php' );
    	}
    	
    }
    
    Hml_Img_Connector::init();


    т.к. процедура долгая, код написан как обработчик периодических ajax запросов
    просто стучитесь с админки в этот код

    js
    <script type="text/javascript" >
    	var gIMGCONNApp = {
    			nTimerID 	: 0,		// Идентификатор таймера
    			nTimerInt	: 2000,		// Интервал таймера
    			bIsFree	 	: true,		// Сервер закончил! можно делать след. шаг
    			nStep 	 	: 10,		// Количество обработки записей за один шаг
    			nTimeStart	: 0			// время cтарта генерации xml
    		};
    		
    	jQuery(document).ready(function($) {
    		
    		//получаем идентификатор элемента состояния
    		var objProc = document.getElementById("files-left");
    			// Если не определен то выход
    			if(objProc == null){	return false;	}
    		
    		$("#btn-start-parsing").click(function(){
    			// начать повторы с интервалом 2 сек
    			gIMGCONNApp.nTimerID = setInterval(timer_tick, gIMGCONNApp.nTimerInt);
    			// Сохраняем временную точку старта
    			gIMGCONNApp.nTimeStart = getSecondsToday();
    			timeStatusBarInvalidate(0);
    			//var date = new Date();
    			//console.log(date);
    		});
    	});
    	
    	
    	
    	// получаем кол-во сегунд от начала суток
    	function getSecondsToday() {
    		var d = new Date();
    		return d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds();
    	};
    	
    	// Обработчик прерываний таймера
    	function timer_tick(){
    		if (gIMGCONNApp.bIsFree){ sendAjaxStep(); }
    		//console.log('timer_tick');
    	};
    	
    	function sendAjaxStep(){
    		gIMGCONNApp.bIsFree = false;
    		var data = {
    			action: 'img_connector_dostep',
    			step: gIMGCONNApp.nStep
    		};
    		
    		// с версии 2.8 'ajaxurl' всегда определен в админке
    		jQuery.post( ajaxurl, data, function(response, status) {
    			if (status == 'success'){
    				//console.log('Получено с сервера: ' + response + ': Статус: ' + status +'\n');
    				var rsp = JSON.parse(response);
    				//console.log(rsp);
    				//document.getElementById("ew-processed-value").innerText = rsp['completed'];
    				// обновление прогерсс бара
    				// processInvalidate(rsp['completed']);
    				timeStatusBarInvalidate(rsp['left']);
    				jQuery("#files-left").text(rsp['left']);
    				printMessages(rsp['msgs']);			
    				gIMGCONNApp.bIsFree = true;
    				if (rsp['left'] == 0) { 
    					clearInterval(gIMGCONNApp.nTimerID);
    					//jQuery("#btn-download-xml").css({display: "inline-block"});
    				}
    			}
    		})
    	};
    
    	function printMessages(arrMsgs){
    		var s = '';
    		
    		for (var i = 0; i < arrMsgs.length; i++) {
    			s += arrMsgs[i] + '<br/>';
    		}
    		jQuery("#status-msg").prepend(s);
    	}
    
    	function timeStatusBarInvalidate(completed){
    		var nTimeNow = getSecondsToday();
    		
    		if (nTimeNow < gIMGCONNApp.nTimeStart){
    			nTimeNow += 86400; }	// =24*60*60
    		var nTimeElapsed = nTimeNow - gIMGCONNApp.nTimeStart;
    		
    		// var nTimeLeft = 0;
    		// if(completed > 0){
    			// nTimeLeft = nTimeElapsed*(100-completed)/completed; }
    		
    		// var sBarText = "Затраченное время: " + formatTime(nTimeElapsed) + 
    					   // "; Осталось времени: " + formatTime(nTimeLeft);
    		jQuery("#time-elapsed").text(formatTime(nTimeElapsed));
    		// jQuery("#time-left").text(formatTime(nTimeLeft));
    	};
    	
    	function formatTime(secnum){
    		secnum = Math.floor(secnum);
    		var hours   = Math.floor(secnum / 3600);
    		var minutes = Math.floor((secnum - (hours * 3600)) / 60);
    		var seconds = secnum - (hours * 3600) - (minutes * 60);
    
    		if (hours   < 10) {hours   = "0"+hours;}
    		if (minutes < 10) {minutes = "0"+minutes;}
    		if (seconds < 10) {seconds = "0"+seconds;}
    		return hours+' : '+minutes+' : '+seconds;
    	};
    	
    	function processInvalidate(percent){
    		document.getElementById('progress-text').innerHTML = percent + ' %';
    		document.getElementById('progress-bar').style.width = percent * 7 + 'px';
    	};
    	
    </script>


    Для запуска отображения формы в админке просто добавьте код do_action('tesp_show_widget'); в нужное админки.
    Ответ написан
    Комментировать
  • Как вывести Кросселы через цикл Woocommerce?

    1. Подключаетесь к хуку того места где нужно выводить
    2. Пробегаетесь по содержимому корзины и собираете ID добавленных товаров
    3. Делаете произвольный запрос в базу и создаете пользовательский цикл вывода. Почитать можно в кодексе или здесь
    4. Выводите свой html
    Ответ написан
    Комментировать
  • Как добавить доп. поля в форму добавления постов в WordPress?

    Если я правильно понял задачу, то Advanced Custom Fields - это то что Вам поможет
    Ответ написан
    Комментировать
  • Как вывести баннер в цикле продуктов woocommerce?

    Так а что мешает кинуть обработчик 'woocommerce_shop_loop' и считать обращения и на пятом или десятом вставлять свой код?
    Ответ написан
  • Как в Woocommerce изменить сумму заказа?

    Ну как решение, можно из калькулятора js передавать сумму без учёта стоимости товара, т.е. только надбавку или скидку. Потом на сервере добавлять её в заказ как отдельный пункт расхода. Тогда все последующие этапы оплаты будут учитывать её.
    Используйте для этого хук woocommerce_cart_calculate_fees
    Ответ написан
    Комментировать
  • Как закэшировать отдельный шаблон wordpress?

    По поводу плагина wp fastest cache не знаю, но в плагине WpSuperCashe есть такая опция, которая позволяет кэшировать разные страницы для мобильной и десктопной версии
    Ответ написан
    Комментировать
  • Как спарсить сайт, если на нем JavaScript'ы, которые перекидывают на главную страницу?

    Скорее всего на главную страницу Вас перекидывает потому, что Вы не авторизованы.

    Сделайте первый запрос на главную страницу, сохраните куку, затем идите по нужным страницам.
    Ответ написан
  • Как вывести значения php массива?

    Вы распечатали содержимое объекта
    Для вывода его данных смотрите документацию или файл с описанием класса.

    В ответе выше, Вам дали ссылку на страницу форума, где предлагают написать дочерний класс. Если Вы пошли этим путем, то обязательно изучите родительский класс. Так, что путь верный, только обходной.

    В тегах к вопросу надо было прописать тег woocommerce
    Ответ написан
    Комментировать
  • Как выводить полный контент продуктов в категории woocommerce?

    Править шаблон или заменять хуками вывод конкретного значения
    Какой использовать хук - надо смотреть в шаблоне вывода товара на странице архива.
    Это файл \plugins\woocommerce\templates\content-product.php
    Или здесь
    Ответ написан
    Комментировать
  • Макрос который для каждого значение в ячейке до и после добавляет текст?

    И в чем Вам здесь помощь нужна?
    Где пример Вашей наработки, в которой у Вас что то не получается?
    Ответ написан
  • Как отправить содержимое корзины на почту с помощью cf7?

    Ну если без cf7, то кодом сформировать текст письма и через функцию wp_mail отправить.
    Если загляните внутрь функции, там есть интересные хуки для корректировки данных отправителя.
    Ответ написан
  • Как карточку товара Woocommerce поделить на три колонки?

    Загляните в шаблон "wp-content/plugins/woocommerce/templates/content-single-product.php" или если он у Вас переопределен в Вашей теме, тогда "wp-content/themes/Ваша-тема/woocommerce/content-single-product.php"
    Там прописаны основные теги разметки карточки товара
    Если он переопределен, то там и можно править, иначе можете подключиться к какому-то из хуков и добавить свой с содержимым.
    Правда придется переписать все основные стили.
    Ответ написан
  • Как выводить рекомендуемые товары WooCommerce в карточке товара?

    Создайте новый сайдбар, добавьте в него виджет с отображением рекомендуемых товаров, ввыведите сайдбар в шаблоне карточки товара.
    Нужный виджет посмотреть можно здесь
    Ответ написан
  • Как в Wordpress получить обратно данные после передачи из ajax в php?

    Вот урок по ajax в wordpress.
    Сделайте все, что пишет автор и я думаю вопрос отпадет.
    Внимание - это все для WordPress.
    Ответ написан
    Комментировать
  • Woocommerce Custom Sale Tag работает?

    Или же, если есть другой способ создания уникальных надписей для товаров,

    Файл шаблона который отвечает за вывод надписи скидки называется sale-flash.php.
    Загляните в него. он очень простой. И меняйте все что хотите с любыми условиями и минимальной нагрузкой.

    Плагин к сожалению не знаю, но точно должен быть.
    Ответ написан
    Комментировать
  • Как оптимизировать код в VBA?

    1-е
    Оживить Excel (т.е. избавить его от зависания) Вы можете путем добавления перед каждой инструкцией "next ..." команды "DoEvents". Но хочу предупредить, что это увеличит общее время выполнения всего кода, т.е. эта команда заставляет Excel останавливать Ваш код и обрабатывать действия пользователя или системные, которые к этому моменту накопились.
    Пример
    ...
        DoEvents
    next x
    ...


    2-е
    Вам надо избавиться от частого обращения к ячейкам. Это делается путем копирования всего дампа данных за один раз.
    вместо
        For i = 1 To rows
            arrStreet(i - 1) = Cells(i, 71)
            arrHouse(i - 1) = Cells(i, 15)
            arrCampus(i - 1) = Cells(i, 34)
        Next i
    
    Используем
            'таким образом мы убираем цикл длиной в 180к *3 обращений к листу
            ' если протестировать затраты времени только на этом участке, экономия будет колоссальная
            arrStreet = range(Cells(1, 71), Cells(rows, 71))
            arrHouse = range(Cells(1, 15), Cells(rows, 15))
            arrCampus = range(Cells(1, 34), Cells(rows, 34))
            
           ' Но т.к. теперь мы имеем 2х мерные массивы, их надо обратить в одномерные, т.к. последующий код использует одномерные.
           arrStreet = WorksheetFunction.Transpose(arrStreet)
           arrHouse = WorksheetFunction.Transpose(arrHouse )
           arrCampus = WorksheetFunction.Transpose(arrCampus )


    3-е
    Далее по коду идут постоянные обращения к ячейкам внутри вложенных циклов
    5cc2af9e419d8174137510.jpeg

    В общем надо проанализировать алгоритм и убрать все циклические обращения к ячейкам. Заменить их обращениями к массивам, которые предварительно будут заполнены копированием дампов (как показано выше).
    Далее (возможно?!, если позволит алгоритм) уменьшить количество циклов за счет сортировки исходных данных и бинарного поиска по массивам.
    Для справки: Бинарный поиск находит данные примерно за 7-8 обращений к массиву, тогда как простой перебор (который организован у Вас) делает в худшем случае 180к обращений.

    Здесь есть простор для оптимизации.
    И сделайте бэкап перед редактированием.
    Ответ написан
    3 комментария
  • При подключении ajax-ом файла php выдается 500 ошибка?

    В начало файла добавьте строку и должно заработать
    require($_SERVER['DOCUMENT_ROOT'].'/wp-load.php');

    Если есть желание разобраться то почитать можно здесь, и заглянуть внутрь файла "/wp-admin/admin-ajax.php"
    Ответ написан
    1 комментарий