Все записи с тегом: php

Стандартные галереи WordPress’a можно легко приспособить под Ekko lightbox.

Ekko lightbox

Содержание статьи:

  • Замена шорткода вывода галереи.
  • CSS правки для изображений.

1. Замена шорткода вывода галереи

За основу взята стандартная функция вывода галереи WordPress:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//Модернизируем галерею
remove_shortcode('gallery');
add_shortcode('gallery', 'new_gallery_shortcode');
function new_gallery_shortcode( $attr ) {
	$post = get_post();
	static $instance = 0;
	$instance++;
	if ( ! empty( $attr['ids'] ) ) {
            if ( empty( $attr['orderby'] ) ) {
                    $attr['orderby'] = 'post__in';
            }
            $attr['include'] = $attr['ids'];
	}
	$output = apply_filters( 'post_gallery', '', $attr, $instance );
	if ( $output != '' ) {
            return $output;
	}
	$html5 = current_theme_supports( 'html5', 'gallery' );
	$atts = shortcode_atts( array(
		'order'      => 'ASC',
		'orderby'    => 'menu_order ID',
		'id'         => $post ? $post->ID : 0,
		'itemtag'    => $html5 ? 'figure'     : 'dl',
		'icontag'    => $html5 ? 'div'        : 'dt',
		'captiontag' => $html5 ? 'figcaption' : 'dd',
		'columns'    => 3,
		'size'       => 'thumbnail',
		'include'    => '',
		'exclude'    => '',
		'link'       => ''
	), $attr, 'gallery' );
	$id = intval( $atts['id'] );
	if ( ! empty( $atts['include'] ) ) {
            $_attachments = get_posts( array( 'include' => $atts['include'], 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
            $attachments = array();
            foreach ( $_attachments as $key => $val ) {
                $attachments[$val->ID] = $_attachments[$key];
            }
	} elseif ( ! empty( $atts['exclude'] ) ) {
            $attachments = get_children( array( 'post_parent' => $id, 'exclude' => $atts['exclude'], 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
	} else {
            $attachments = get_children( array( 'post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
	}
	if ( empty( $attachments ) ) {
            return '';
	}
	if ( is_feed() ) {
            $output = "\n";
            foreach ( $attachments as $att_id => $attachment ) {
                    $output .= wp_get_attachment_link( $att_id, $atts['size'], true ) . "\n";
            }
            return $output;
	}
	$itemtag = tag_escape( $atts['itemtag'] );
	$captiontag = tag_escape( $atts['captiontag'] );
	$icontag = tag_escape( $atts['icontag'] );
	$valid_tags = wp_kses_allowed_html( 'post' );
	if ( ! isset( $valid_tags[ $itemtag ] ) ) {
		$itemtag = 'dl';
	}
	if ( ! isset( $valid_tags[ $captiontag ] ) ) {
		$captiontag = 'dd';
	}
	if ( ! isset( $valid_tags[ $icontag ] ) ) {
		$icontag = 'dt';
	}
	$columns = intval( $atts['columns'] );
	$itemwidth = $columns > 0 ? floor(100/$columns) : 100;
	$float = is_rtl() ? 'right' : 'left';
	$selector = "gallery-{$instance}";
	$gallery_style = '';
	if ( apply_filters( 'use_default_gallery_style', ! $html5 ) ) {
		$gallery_style = "
		<style type='text/css'>
			#{$selector} {
				margin: auto;
			}
			#{$selector} .gallery-item {
				float: {$float};
				margin-top: 10px;
				text-align: center;
				width: {$itemwidth}%;
			}
			#{$selector} img {
				border: 2px solid #cfcfcf;
			}
			#{$selector} .gallery-caption {
				margin-left: 0;
			}
			/* see gallery_shortcode() in wp-includes/media.php */
		</style>\n\t\t";
	}
	$size_class = sanitize_html_class( $atts['size'] );
	$gallery_div = "<div id='$selector' class='gallery galleryid-{$id} gallery-columns-{$columns} gallery-size-{$size_class}'>";
        $gal_id = $id;
	$output = apply_filters( 'gallery_style', $gallery_style . $gallery_div );
	$i = 0;
	foreach ( $attachments as $id => $attachment ) {
 
		$attr = ( trim( $attachment->post_excerpt ) ) ? array( 'aria-describedby' => "$selector-$id" ) : '';
		if ( ! empty( $atts['link'] ) && 'file' === $atts['link'] ) {
                    $image_output = wp_get_attachment_link( $id, $atts['size'], false, false, false, $attr );
                    $image_output = str_replace('<a', '<a href="'. wp_get_attachment_image_url( $id, 'full' ) .'" data-toggle="lightbox" data-gallery="gallery-'. $gal_id .'"', $image_output); //Изменяем вывод ссылок на изображения
		} elseif ( ! empty( $atts['link'] ) && 'none' === $atts['link'] ) {
                    $image_output = wp_get_attachment_image( $id, $atts['size'], false, $attr );
		} else {
                    $image_output = wp_get_attachment_link( $id, $atts['size'], true, false, false, $attr );
                    $image_output = str_replace('<a', '<a href="'. wp_get_attachment_image_url( $id, 'full' ) .'" data-toggle="lightbox" data-gallery="gallery-'. $gal_id .'"', $image_output); //Изменяем вывод ссылок на изображения
		}
		$image_meta  = wp_get_attachment_metadata( $id );
		$orientation = '';
		if ( isset( $image_meta['height'], $image_meta['width'] ) ) {
                    $orientation = ( $image_meta['height'] > $image_meta['width'] ) ? 'portrait' : 'landscape';
		}
		$output .= "<{$itemtag} class='gallery-item'>";
		$output .= "
                    <{$icontag} class='gallery-icon {$orientation}'>
                            $image_output
                    </{$icontag}>";
		if ( $captiontag && trim($attachment->post_excerpt) ) {
                    $output .= "
                        <{$captiontag} class='wp-caption-text gallery-caption' id='$selector-$id'>
                        " . wptexturize($attachment->post_excerpt) . "
                        </{$captiontag}>";
		}
		$output .= "</{$itemtag}>";
		if ( ! $html5 && $columns > 0 && ++$i % $columns == 0 ) {
			$output .= '<br style="clear: both" />';
		}
	}
	if ( ! $html5 && $columns > 0 && $i % $columns !== 0 ) {
		$output .= "
			<br style='clear: both' />";
	}
	$output .= "
		</div>\n";
 
	return $output;
}

2. CSS правки для изображений

Теперь делаем сами изображения адаптивными: задаем 100% ширины и высоту авто.

1
2
3
4
5
6
7
.gallery {
    width: 100%;
}
.gallery .gallery-item .gallery-icon img {
    width: 100%!important;
    height: auto!important;
}
23 мая
Теги: ,

Фикс, позволяет изменить стандартный функционал кнопки «Добавить медиафайл», а class=’img-responsive’ делает их адаптивными под bootstrap.

1
2
3
4
5
6
7
8
9
//Адаптивные изображения
function adaptive_img_fix( $html, $id, $caption, $title, $align, $url, $size, $alt ) {
 
    $image_thumb = wp_get_attachment_image_src( $id, $size);
    $image_alt = '';
    $out_img .= '<img src="'. $image_thumb[0] .'" alt="'.$image_alt.'" class="img-responsive"/>';
    return $out_img; 
}
add_filter('image_send_to_editor', 'adaptive_img_fix', 1, 8);
Теги: ,

Кастомизация админки вордпресса, при разработке сайта под клиента, играет огромную роль. Довольно часто контактную информацию компании клиент может менять на лету, и чтобы не править каждый раз footer и header, нужно дать возможность клиенту менять эту информацию самому. На помощь нам приходит замечательный плагин CMB2. Кстати, в предыдущих статьях, мы научились создавать различные поля, типа: текст, переключатели, файл и чекбокс.

Скачать плагин CMB2

Содержание статьи:

  • Создание страницы с контактными данными.
  • Функция получения данных со страницы с контактами.
  • Показ контактных данных.

Создание страницы с контактными данными.

Следующий код создаст в админке страницу «Контакты компании» с двумя контактными телефонами, email и скриптом Яндекс карт. Используем всего два типа полей: text_medium и textarea_code. Код нужно поместить в файл function.php активной темы.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Страница контактов компании
function company_page_options() {
    $company_options = new_cmb2_box( array(
        'id'           => 'company-options',
        'title'        => esc_html__( 'Контакты компании' ),
        'object_types' => array( 'options-page' ),
        'option_key'      => 'company-options', // Ключ опций и слаг.
        'icon_url'        => 'dashicons-image-filter', //Иконка в меню
    ) );
    $company_options->add_field( array(
        'name' => esc_html__( 'Контактный телефон 1:' ), 
        'desc' => esc_html__( 'Например: +79998885522' ), 
        'id'   => 'tell1', 
        'type' => 'text_medium', 
    ) );
    $company_options->add_field( array(
        'name' => esc_html__( 'Контактный телефон 2:' ), 
        'desc' => esc_html__( 'Например: +79998885522' ), 
        'id'   => 'tell2', 
        'type' => 'text_medium', 
    ) );
    $company_options->add_field( array(
        'name' => esc_html__( 'Email:' ), 
        'desc' => esc_html__( 'Например: email@email.ru' ), 
        'id'   => 'email', 
        'type' => 'text_medium', 
    ) );
    $company_options->add_field( array(
        'name' => esc_html__( 'Скрипт Яндекс карты:' ), 
        'desc' => esc_html__( 'Генерируется по ссылке: https://yandex.ru/map-constructor/' ), 
        'id'   => 'ymap', 
        'type' => 'textarea_code', 
    ) );
}
add_action( 'cmb2_admin_init', 'company_page_options' );

Результат:

CMB2 - страницы с контактами компании в админке

Функция получения данных со страницы с контактами.

Следующая функция позволит нам получать сохраненные данные со страницы.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
add_action( 'cmb2_admin_init', 'company_page_options' );
function cp_get_option( $key = '', $default = false ) {
    if ( function_exists( 'cmb2_get_option' ) ) {
        return cmb2_get_option( 'company-options', $key, $default );
    }
    $opts = get_option( 'company-options', $default );
    $val = $default;
    if ( 'all' == $key ) {
        $val = $opts;
    } elseif ( is_array( $opts ) && array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
        $val = $opts[ $key ];
    }
    return $val;
}

Показ контактных данных.

Теперь нам осталось получить и вывести данные в нужном месте сайта, например в header.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="contacts">
    <?php 
        $tell = cp_get_option( 'tell1' );
        $tell2 = cp_get_option( 'tell2' );
        $email = cp_get_option( 'email' );
        $ymap = cp_get_option( 'ymap' );
    ?>
    <div>
        <b>Телефон 1:</b><br>
        <?php echo $tell; ?>
    </div>
    <div>
        <b>Телефон 2:</b><br>
        <?php echo $tell2; ?>
    </div>
    <div>
        <b>Email:</b><br>
        <?php echo $email; ?>
    </div>
    <div>
        <b>Яндекс карта:</b><br>
        <?php echo $ymap; ?>
    </div>
</div>

Результат:

CMB2 - страницы с контактами компании в админке

Итоги

Таким образом мы можем создавать любые страницы в админке, управляя как контентом, так и самим отображением сайта.

05 апреля
Теги: , ,

В статье рассмотрим 5 необходимых функций WordPress, которые, по моему мнению, наиболее часто участвуют в разработке.

Содержание статьи:

  • Подключение скриптов (js) и стилей (css) в functions.php.
  • Регистрация и вывод кастомного меню.
  • Регистрация и вывод собственной панели виджетов.
  • Создание пользовательского типа записи.
  • Регистрация шорткодов.
  • Бонус: mu-plugins (обязательные плагины).

1. Подключение скриптов (js) и стилей (css) в functions.php.

При разработке сайта, очень часто бывает необходимо подключить сторонний скрипт, либо файл стилей. Можно конечно пойти по старинке — прикручивать все это дело прямо в шапке (header), но с этим потом возникнут трудности при переносе на хостинг, да и в целом не красиво. Давайте узнаем как это делается на примере подключения bootstrap версии 3.3.7. Все действия делаем в файле functions.php активной темы. Сами файлы bootstrap’a будут располагаться в папке /активная_тема/bootstrap/.

1
2
3
4
5
function bootstrap_scripts() {
    wp_enqueue_style( 'bootstrap-css', get_template_directory_uri() . '/bootstrap/css/bootstrap.css', array(), '3.3.7' );
    wp_enqueue_script( 'bootstrap-js', get_template_directory_uri() . '/bootstrap/js/bootstrap.min.js', array(), '3.3.7' );
}
add_action( 'wp_enqueue_scripts', 'bootstrap_scripts' );

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

2. Регистрация и вывод кастомного меню.

Регистрация кастомных меню возможна функцией register_nav_menus(). Можно создавать сразу несколько дополнительных меню и выводить их на сайте на свое усмотрение. Следующий код следует разместить в файле functions.php активной темы.

1
2
3
4
5
6
add_action('after_setup_theme', function(){
    register_nav_menus( array(
        'main_menu' => 'Основное меню',
        'additional_menu' => 'Дополнительное меню'
    ) );
});

Таким образом, мы создали два новых меню: основное и дополнительное.

WordPress - register_nav_menus

Теперь нужно настроить их в админке и вывести на сайте. Вывод осуществляется в любом месте сайта функцией wp_nav_menu().

1
2
3
4
5
6
7
8
<?php 
    wp_nav_menu ( array (
        'theme_location'  => 'main_menu', //Идентификатор меню, мы его регистрировали ранее.
        'container' => '', //Оберточный контейнер для нашего меню. Пусто, либо false выведет меню без контейнера.
        'depth' => '2', //Сколько показывать уровней вложенности. 0 - показывать все.
        'menu_id' => 'primary-menu', //Значение id у списка меню.
    )); 
?>

3. Регистрация и вывод собственной панели виджетов.

register_sidebar() — регистрирует собственную панель виджетов.

1
2
3
4
5
6
7
8
9
10
11
12
13
add_action( 'widgets_init', 'my_widgets_panel' );
function my_widgets_panel(){
    register_sidebar( array(
        'name'          => 'Моя панель виджетов', //Название панели виджетов. 
        'id'            => "my_widgets_panel", //Идентификатор.
        'description'   => '', //Описание.
        'class'         => '', //CSS класс панели виджетов.
        'before_widget' => '', //Текст или html код, который будет показываться до панели.
        'after_widget'  => '', //Текст или html код, который будет показываться после панели.
        'before_title'  => '', //Текст перед заголовком панели.
        'after_title'   => '', //Текст после заголовка панели.
    ) );
}

Результат:

WordPress - регистрация и вывод собственной панели виджетов

Выводим в любом месте сайта с помощью следующего кода:

1
2
3
4
5
<?php
    if ( function_exists('dynamic_sidebar') ) {
        dynamic_sidebar('my_widgets_panel');
    } 
?>

4. Создание пользовательского типа записи.

Создание пользовательских типов записей подразумевает расширение функционала вордпресса. Следующий код создаст произвольные типы записей «фильмы».

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Пользовательский тип записи "фильмы"
add_action( 'init', 'create_post_type' );
function create_post_type() {
    register_post_type( 'films',
         array(
                'labels' => array(
                    'name' => _x('Фильмы', 'post type general name'), //Основное название типа записи.
                    'singular_name' => _x('Фильм', 'post type singular name'), //Название для одиночного элемента.
                    'add_new' => _x('Новый фильм', 'Event'), //Имя для кнопки создания нового элемента.
                    'add_new_item' => __('фильм'), //Имя в верхней админ панели.
                    'edit_item' => __('Редактировать фильм'), //Имя для редактирования элемента.
                    'new_item' => __('Новый фильм'), //Имя для создания нового элемента.
                    'view_item' => __('Посмотреть фильм'), //Имя для кнопки просмотра элемента.
                    'search_items' => __('Искать фильм'), //Имя для поиска по элементам.
                    'not_found' =>  __('Ничего не найдено'), //Текст для пустого результата поиска.
                    'not_found_in_trash' => __('Корзина пуста'), //Текст для пустой корзины.
                ),
                'menu_position'       => 5, //Позиция в меню.
                'menu_icon'           => 'dashicons-video-alt', //Иконка. Полный набор иконок доступен по ссылке: https://developer.wordpress.org/resource/dashicons/
                'public' => true,
                'capability_type' => 'post',
                'supports' => array( //Включаем поддержку стандартного функционала: изображения записи, цитату и тп. Все значения: title','editor','author','thumbnail','excerpt','trackbacks','custom-fields','comments','revisions','page-attributes','post-formats'.
                    'title',
                    'thumbnail',
                    'editor',
                    'excerpt',
                ),
                'has_archive'   => false,
            ));
}

Результат:

WordPress - пользовательский тип записи

Вывод таких постов возможно с помощью WP_Query, заменив post на films.

5. Регистрация шорткодов.

Шорткоды в вордпрессе позволяют выводить функции прямо в тексте статьи, массово используются плагинами (например: contact form 7, meta slider и др.) и позволяют выводить функции php или js прямо в тексте статьи. Для примера, зарегистрируем шорткод показа рекламных объявлений Adsense. Как всегда правим файл functions.php активной темы.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Регистрация шорткода Adsense
function add_adsense_shortcode() {
    return '
        <div id="google-adsense">
        <ins class="adsbygoogle"
             style="display:block; text-align:center;"
             data-ad-layout="in-article"
             data-ad-format="fluid"
             data-ad-client="ca-pub-3865389427490622"
             data-ad-slot="9907310963"></ins>
        <script>
             setTimeout(function(){(adsbygoogle = window.adsbygoogle || []).push({})}, 1000);
        </script>
        </div>
    ';
}
add_shortcode( 'adsense-article', 'add_adsense_shortcode' );

Использование:

1
[adsense-article]

Такой шорткод позволит выводить рекламу adsense в любом месте статьи.

Бонус: mu-plugins (обязательные плагины).

Мало кто знает о существовании такой полезной штуки как mu-plugins, по русски — обязательные плагины. Они работают так же как и обычные плагины за рядом отличий: обязательные плагины не требуют активации (по умолчанию активны всегда), их нельзя отключить, лежат в папке /wp-content/mu-plugins, должны состоять всего из одного файла и никогда не будут обновляться. Их использование подразумевает что сайт без их функционала работать не будет. Очень полезная штука при работе с заказчиками, которые везде суют свой нос.

WordPress - mu-plugins (обязательные плагины)

04 апреля
Теги: ,

В этой статье я намеренно опущу рассказ о циклах вордпресса (стандартном и двух дополнительных), поскольку информации о них в интернете предостаточно. Я лишь приведу приведу пример цикла на на основе WP_Query, на котором наглядно покажу способы фильтрации и кастомизации постов.

Основные понятия статьи:

  • Цикл WordPress — это цикл, который перебирает массив данных содержащих в себе информацию о каждом посте.
  • WP_Query — класс, позволяющий получать посты из базы данных с необходимыми параметрами.
  • Темплейт — шаблон вывода постов.
  • Фильтрация — изменение вывода постов с заданными параметрами. Можно фильтровать посты по наличию или значению произвольных полей, числа даты, и др.
  • Метаполе — произвольное поле записи.

Пример цикла на основе WP_Query:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php 
    $related_posts = new WP_Query( array(
        'post_type' => 'post', //Тип записи
    ) );
    if ( $related_posts->have_posts() ) {
        while ( $related_posts->have_posts() ) {
            $related_posts->the_post();
                get_template_part( 'templates/related-posts', get_post_format() ); //Темплейт вывода постов. Лежит в папке templates активной темы.
            }
    } else {
        echo '<p>Записей не найдено.</p>'; //На случай, если записей нет.
    }
    wp_reset_postdata(); //Сбрасываем цикл.
?>

Таким способом мы можем получить все записи за все время, и, если их будет очень много, скорее всего уроним сайт. Поэтому мы должны ограничить количество постов для вывода, либо отфильтровать их по заданным параметрам. А для вывода постов, будем использовать темплейт related-posts, который будет лежать в папке templates активной темы.

Параметры фильтрации постов:

  • order — направление сортировки по параметру orderby. Бывает: ASC — по порядку, DESC — в обратном порядке.
  • orderby — сортировка по: none — без сортировки, ID — по ID (номеру поста), author — по id автора (номера автора), title — по загловку, name — по названию поста, date — дате публикации, modified — дате изменения, type — по типу контента, rand — случайный порядок, comment_count — количеству комментариев, meta_value — значению произвольного поля, meta_value_num — значению числового произвольного поля.
  • posts_per_page — количество записей на страницу.
  • meta_query — массив параметров метаполей постов.

Теперь изменим наш цикл, и попробуем вывести 8 последних постов, отсортированных по дате.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php 
    $related_posts = new WP_Query( array(
        'post_type'      => 'post', //Тип записи.
        'posts_per_page' => 8, //Выведем первые 8 записей. 
        'orderby'        => date, //Сортировка по дате.
    ) );
    if ( $related_posts->have_posts() ) {
        while ( $related_posts->have_posts() ) {
            $related_posts->the_post();
                get_template_part( 'templates/related-posts', get_post_format() ); //Темплейт вывода постов. Лежит в папке templates активной темы.
            }
    } else {
        echo '<p>Записей не найдено.</p>'; //На случай, если записей нет.
    }
    wp_reset_postdata(); //Сбрасываем цикл.
?>

Усложним задачу: будем фильтровать посты по наличию поля meta_featured, с выводом 8 постов на страницу. Например: с помощью CMB2 можно создать метаполе типа чекбокс, и выводить на главную только заданные посты.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php 
    $related_posts = new WP_Query( array(
        'post_type'      => 'post', //Тип записи.
        'posts_per_page' => 8, //Выведем первые 8 записей. 
        'meta_query' => array( //Выберем посты, в которых есть произвольное поле meta_featured.
            array(
                'key' => 'meta_featured',
                'compare' => 'IN'
            )
        )
    ) );
    if ( $related_posts->have_posts() ) {
        while ( $related_posts->have_posts() ) {
            $related_posts->the_post();
                get_template_part( 'templates/related-posts', get_post_format() ); //Темплейт вывода постов. Лежит в папке templates активной темы.
            }
    } else {
        echo '<p>Записей не найдено.</p>'; //На случай, если записей нет.
    }
    wp_reset_postdata(); //Сбрасываем цикл.
?>

Более сложный пример: будем фильтровать посты по числовому метаполю meta_votes, с выводом 8 постов на страницу.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php 
    $related_posts = new WP_Query( array(
        'post_type'      => 'post', //Тип записи.
        'posts_per_page' => 8, //Выведем первые 8 записей. 
        'order'          => 'DESC', //В сторону уменьшения.
        'orderby'        => 'meta_value_num', //Числовое метаполе.
        'meta_key'       => 'meta_votes' //Имя метаполя.
    ) );
    if ( $related_posts->have_posts() ) {
        while ( $related_posts->have_posts() ) {
            $related_posts->the_post();
                get_template_part( 'templates/related-posts', get_post_format() ); //Темплейт вывода постов. Лежит в папке templates активной темы.
            }
    } else {
        echo '<p>Записей не найдено.</p>'; //На случай, если записей нет.
    }
    wp_reset_postdata(); //Сбрасываем цикл.
?>

Итоги

Понимание и принципы работы фильтрации постов, дает неограниченный простор к кастомизации вордпресса.

03 апреля
Теги: , ,

Как мы узнали ранее, замечательный плагин CMB2 позволяет создавать произвольные поля различных типов.

Скачать плагин CMB2

Основные понятия статьи:

  • Типы контента — WordPress использует несколько типов контента: post — записи, page — страницы, custom post types — пользовательские типы записей. И несколько других, в рамках этой статьи невостребованных.
  • Произвольные поля — дополнительные данные записей или станиц, можно указывать любые типы, от чисел и текста, до файлов и галерей изображений. В статье будем их называть метаполями. Просто потому что мне так захотелось.
  • CMB2 — плагин, для создания любых метаполей.
  • Темплейт single.php — шаблон вывода записей (post).

Давайте подробнее разберем его работу на базовых примерах, создадим дополнительные поля для записей (post).

Инициализируем наши поля в файле functions.php активной темы:

1
2
3
4
5
6
7
8
9
10
11
12
add_action( 'cmb2_admin_init', 'cmb2_metaboxes' );
function cmb2_metaboxes() {
    $post_prefix = 'postmeta_'; //Префикс, на случай если мы будет использовать разные метаполя для разных типов постов.
    $cmb_post = new_cmb2_box( array(
        'id'            => 'metaboxes',
        'title'         => __( 'Дополнительные поля' ),
        'object_types'  => array( 'post', ), //Выводим метаполя для записей (post). Или page для страниц.
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Показывать название полей слева.
    ) );
}

Теперь прикрутим новое метаполе типа текст.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
add_action( 'cmb2_admin_init', 'cmb2_metaboxes' );
function cmb2_metaboxes() {
    $post_prefix = 'postmeta_'; //Префикс, на случай если мы будет использовать разные метаполя для разных типов постов.
    $cmb_post = new_cmb2_box( array(
        'id'            => 'metaboxes',
        'title'         => __( 'Дополнительные поля' ),
        'object_types'  => array( 'post', ), //Выводим метаполя для записей (post). Или page для страниц.
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Показывать название полей слева.
    ) );
    //Поле типа текст.
    $cmb_post->add_field( array(
        'name' => esc_html__( 'Год выхода:' ), //Название поля в админке.
        'desc' => esc_html__( 'Например: 1995.' ), //Описание поля в админке.
        'id'   => $post_prefix . 'year', //Используем наш префикс и добавляем уникальное название year.
        'type' => 'text_small', //Поле типа текст.
    ) );
}

Результат в админке:

CMB2 - Поле типа текст.

Получение этого поля возможно в теплейте single.php, или в прямо в цикле довольно простым кодом:

1
2
$year = get_post_meta($post->ID, 'postmeta_year', true);
echo $year;

Усложним задачу, добавим еще одно поле типа переключатели (radio button).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
add_action( 'cmb2_admin_init', 'cmb2_metaboxes' );
function cmb2_metaboxes() {
    $post_prefix = 'postmeta_'; //Префикс, на случай если мы будет использовать разные метаполя для разных типов постов.
    $cmb_post = new_cmb2_box( array(
        'id'            => 'metaboxes',
        'title'         => __( 'Дополнительные поля' ),
        'object_types'  => array( 'post', ), //Выводим метаполя для записей (post). Или page для страниц.
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Показывать название полей слева.
    ) );
    //Поле типа текст.
    $cmb_post->add_field( array(
        'name' => esc_html__( 'Год выхода:' ), //Название поля в админке.
        'desc' => esc_html__( 'Например: 1995.' ), //Описание поля в админке.
        'id'   => $post_prefix . 'year', //Используем наш префикс и добавляем уникальное название year.
        'type' => 'text_small', //Поле типа текст.
    ) );
    //Поле типа переключатели.
    $cmb_post->add_field( array(
        'name'             => esc_html__( 'Выберите жанр:' ), //Название поля в админке.
        'desc'             => esc_html__( 'Можно выбрать только один жанр.' ), //Описание поля в админке.
        'id'               => $post_prefix . 'genre',
        'type'             => 'radio_inline', //Поле типа переключатели. Может быть двух типов: radio и radio_inline.
        'show_option_none' => 'Не указано', //Показывать пустое значение. 
        'options'          => array(
            'Драма' => esc_html__( 'Драма' ),
            'Триллер' => esc_html__( 'Триллер' ),
            'Ужасы' => esc_html__( 'Ужасы' ),
        ),
    ) );
}

Может быть двух типов: radio (вертикальный вывод) и radio_inline (вывод в строку). Получаем их так же как и в случае с полем типа текст:

1
2
$genre = get_post_meta($post->ID, 'postmeta_genre', true);
echo $genre;

Результат в админке:

CMB2 - Поле типа переключатели.

Сделаем еще одно поле, добавим возможность прикреплять файл (file).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
add_action( 'cmb2_admin_init', 'cmb2_metaboxes' );
function cmb2_metaboxes() {
    $post_prefix = 'postmeta_'; //Префикс, на случай если мы будет использовать разные метаполя для разных типов постов.
    $cmb_post = new_cmb2_box( array(
        'id'            => 'metaboxes',
        'title'         => __( 'Дополнительные поля' ),
        'object_types'  => array( 'post', ), //Выводим метаполя для записей (post). Или page для страниц.
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Показывать название полей слева.
    ) );
    //Поле типа текст.
    $cmb_post->add_field( array(
        'name' => esc_html__( 'Год выхода:' ), //Название поля в админке.
        'desc' => esc_html__( 'Например: 1995.' ), //Описание поля в админке.
        'id'   => $post_prefix . 'year', //Используем наш префикс и добавляем уникальное название year.
        'type' => 'text_small', //Поле типа текст.
    ) );
    //Поле типа переключатели.
    $cmb_post->add_field( array(
        'name'             => esc_html__( 'Выберите жанр:' ), //Название поля в админке.
        'desc'             => esc_html__( 'Можно выбрать только один жанр.' ), //Описание поля в админке.
        'id'               => $post_prefix . 'genre',
        'type'             => 'radio_inline', //Поле типа переключатели. Может быть двух типов: radio и radio_inline.
        'show_option_none' => 'Не указано', //Показывать пустое значение. 
        'options'          => array(
            'Драма' => esc_html__( 'Драма' ),
            'Триллер' => esc_html__( 'Триллер' ),
            'Ужасы' => esc_html__( 'Ужасы' ),
        ),
    ) );
    //Поле типа файл.
    $cmb_post->add_field( array(
        'name'    => 'Файл:', //Название поля в админке.
        'desc'    => 'Загрузите новый Файл.', //Описание поля в админке.
        'id'      => $post_prefix . 'file',
        'type'    => 'file', //Поле типа файл.
        'options' => array(
            'url' => true, //Показывает url файла, можеть быть true - показывать и false - скрыть.
        ),
        'text'    => array(
            'add_upload_file_text' => 'Добавить файл' //Текст кнопки.
        ),
	'query_args' => array( //Мы можем сами выбирать форматы файла, наример: 'type' => 'application/pdf', разрешит добавлять только файлы в формате pdf.
            'type' => array(
                'image/gif',
                'image/jpeg',
                'image/png',
            ),
	),
        'preview_size' => 'large', //Размер превью. Возможно несколько значений: small, medium, large. Либо свой размер: array( 100, 100 ).
    ) );
}

Результат в админке:

CMB2 - Поле типа файл.

Сделаем возможность скачать этот файл в темплейте single.php:

1
2
$file = get_post_meta($post->ID, 'postmeta_file', true);
echo '<a href="'. $file .'">Скачать файл</a>';

Сделаем дополнительное поле типа чекбокс. Например, можно использовать его в цикле вордпресса для вывода featured постов на главной странице.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
add_action( 'cmb2_admin_init', 'cmb2_metaboxes' );
function cmb2_metaboxes() {
    $post_prefix = 'postmeta_'; //Префикс, на случай если мы будет использовать разные метаполя для разных типов постов.
    $cmb_post = new_cmb2_box( array(
        'id'            => 'metaboxes',
        'title'         => __( 'Дополнительные поля' ),
        'object_types'  => array( 'post', ), //Выводим метаполя для записей (post). Или page для страниц.
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Показывать название полей слева.
    ) );
    //Поле типа чекбокс.
    $cmb_post->add_field( array(
        'name' => esc_html__( 'Показывать на главной' ), //Название поля в админке.
        'desc' => esc_html__( '' ), //Описание поля в админке.
        'id'   => $post_prefix . 'featured', //Используем наш префикс и добавляем уникальное название featured.
        'type' => 'checkbox', //Поле типа чекбокс.
    ) );
    //Поле типа текст.
    $cmb_post->add_field( array(
        'name' => esc_html__( 'Год выхода:' ), //Название поля в админке.
        'desc' => esc_html__( 'Например: 1995.' ), //Описание поля в админке.
        'id'   => $post_prefix . 'year', //Используем наш префикс и добавляем уникальное название year.
        'type' => 'text_small', //Поле типа текст.
    ) );
    //Поле типа переключатели.
    $cmb_post->add_field( array(
        'name'             => esc_html__( 'Выберите жанр:' ), //Название поля в админке.
        'desc'             => esc_html__( 'Можно выбрать только один жанр.' ), //Описание поля в админке.
        'id'               => $post_prefix . 'genre',
        'type'             => 'radio_inline', //Поле типа переключатели. Может быть двух типов: radio и radio_inline.
        'show_option_none' => 'Не указано', //Показывать пустое значение. 
        'options'          => array(
            'Драма' => esc_html__( 'Драма' ),
            'Триллер' => esc_html__( 'Триллер' ),
            'Ужасы' => esc_html__( 'Ужасы' ),
        ),
    ) );
    //Поле типа файл.
    $cmb_post->add_field( array(
        'name'    => 'Файл:', //Название поля в админке.
        'desc'    => 'Загрузите новый Файл.', //Описание поля в админке.
        'id'      => $post_prefix . 'file',
        'type'    => 'file', //Поле типа файл.
        'options' => array(
            'url' => true, //Показывает url файла, можеть быть true - показывать и false - скрыть.
        ),
        'text'    => array(
            'add_upload_file_text' => 'Добавить файл' //Текст кнопки.
        ),
	'query_args' => array(//Мы можем сами выбирать форматы файла, наример: 'type' => 'application/pdf', разрешит добавлять только файлы в формате pdf.
            'type' => array(
                'image/gif',
                'image/jpeg',
                'image/png',
            ),
	),
        'preview_size' => 'large', //Размер превью. Возможно несколько значений: small, medium, large. Либо свой размер: array( 100, 100 ).
    ) );
}

Результат в админке:

CMB2 - Поле типа чекбокс.

Итоги

Скорость, с которой CMB2 позволяет кастомизировать админку, расширяя базовый функционал WordPress’а и его простота, делает плагин CMB2 отличным подспорьем в любом проекте.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
    $args = array(
        'post_type' => 'product',
        'posts_per_page' => 3,
        'tax_query' => array(
                array(
                    'taxonomy' => 'product_visibility',
                    'field'    => 'name',
                    'terms'    => 'featured',
                ),
            ),
        );
    $featured_products = new WP_Query( $args );
    if ( $featured_products->have_posts() ) {
        while ( $featured_products->have_posts() ) : $featured_products->the_post();
            wc_get_template_part( 'content', 'product' ); // Можно заменить на свой шаблон вывода, например: get_template_part( 'template-parts/featured-products', get_post_format() ); 
        endwhile;
    } else {
        echo 'Рекомендуемых товаров нет.';
    }
    wp_reset_postdata();
?>
28 декабря

Замечательный плагин CMB2, который, позволяет быстро и просто создавать нужные произвольные поля, можно использовать и для добавления опционных свойств к профилю пользователя.

Скачать плагин CMB2

Сделаем выбор рубрики пользователя в профиле:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function cmb2_get_term_options( $field ) {
    $args = $field->args( 'get_terms_args' );
    $args = is_array( $args ) ? $args : array();
 
    $args = wp_parse_args( $args, array( 'taxonomy' => 'category' ) );
 
    $taxonomy = $args['taxonomy'];
 
    $terms = (array) cmb2_utils()->wp_at_least( '4.5.0' )
        ? get_terms( $args )
        : get_terms( $taxonomy, $args );
    $term_options = array();
    if ( ! empty( $terms ) ) {
        foreach ( $terms as $term ) {
            $term_options[ $term->term_id ] = $term->name;
        }
    }
    return $term_options;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function cmb2_sample_metaboxes() {
        //USERMETA
	$prefix = 'usermeta_';
	$cmb = new_cmb2_box( array(
            'id'            => 'first_box',
            'title'         => __( 'Мета поля' ),
            'object_types'  => array( 'user', ),
            'context'       => 'normal',
            'priority'      => 'high',
            'show_names'    => true,
	) );
        $cmb->add_field( array(
            'name'       => 'Сайт',
            'desc'           => 'Выберите рубрику пользователя.',
            'id'             => $prefix . 'tax',
            'type'           => 'select',
            'options_cb'     => 'cmb2_get_term_options',
            'get_terms_args' => array(
                'taxonomy'   => 'category',
                'hide_empty' => false,
            ),
        ) );
}

Получаем номер рубрики:

1
$user_tax = get_user_meta($user_ID, 'usermeta_tax', true);
15 декабря

Иногда, с помощью стандартного цикла WordPress, необходимо решать нестандартные задачи. Например, следующий код найдет все записи типа post и сложит их произвольные поля с ключом meta_key.

1
2
3
4
5
6
7
8
9
10
11
12
$summ_args = array(
    'post_type' => 'post'
);
$query = new WP_Query( $summ_args );
$posts = $query->posts;
 
foreach ($posts as $post) {
    $summ += get_post_meta($post->ID, 'meta_key', true);
 
}
echo $summ;
wp_reset_postdata();
Теги: , ,

Давненько я ничего не писал, делюсь сокровенным своим всем. А именно, прекрасным плагином для создания произвольных полей CMB2.

CMB2

Скачать плагин CMB2

Плагин позволяет создавать за считанные секунды такие произвольные поля, как:

  • Поля для ввода — текста, цены, времени, даты;
  • Всевозможные селекты, чекбоксы и радио кнопки;
  • Файлы и изображения.
  • И др.

Установка

Достаточно скачать, положить в папку plugins и активировать плагин. Сам плагин, вплоть до версии 2.2.5.3 своего интерфейса не имеет. Да он и не нужен.

Инициализируем произвольные поля, следующий код нужно вставить в файл functions.php вашей темы.

1
2
3
4
5
6
7
8
9
10
11
12
function cmb2_sample_metaboxes() {
	$prefix = 'my_metaboxes_'; // Уникальный префикс произвольных полей 
	$cmb = new_cmb2_box( array(
		'id'            => 'my_metabox',
		'title'         => __( 'Мои произвольные поля' ),
		'object_types'  => array( 'post', ), // По умолчанию, стоит post, если нужно указать другой тип записи, меняйте на свой.
		'context'       => 'normal',
		'priority'      => 'high',
		'show_names'    => true,
	) );
        // Сюда будем вставлять свои произвольные поля.
}

Важный момент: все примеры можно легко найти в файле example-functions.php, в папке с плагином.

Пример: создадим новое произвольное поле — текст.

Ищем файл example-functions.php, в папке с плагином, открываем и копируем оттуда код (строка 142):

1
2
3
4
5
6
7
8
9
10
11
12
$cmb_demo->add_field( array(
        'name' => esc_html__( 'Test Text Small', 'cmb2' ),
        'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
        'id'   => $prefix . 'textsmall',
        'type' => 'text_small',
        // 'repeatable' => true,
        // 'column' => array(
        // 	'name'     => esc_html__( 'Column Title', 'cmb2' ), // Set the admin column title
        // 	'position' => 2, // Set as the second column.
        // );
        // 'display_cb' => 'yourprefix_display_text_small_column', // Output the display of the column values through a callback.
) );

Вставляем его в functions.php вашей темы.

Теперь, код должен быть таким:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function cmb2_sample_metaboxes() {
	$prefix = 'my_metaboxes_'; // Уникальный префикс произвольных полей
	$cmb = new_cmb2_box( array(
		'id'            => 'my_metabox',
		'title'         => __( 'Мои произвольные поля' ),
		'object_types'  => array( 'post', ), // По умолчанию, стоит post, если нужно указать другой тип записи, меняйте на свой.
		'context'       => 'normal',
		'priority'      => 'high',
		'show_names'    => true,
	) );
        $cmb_demo->add_field( array( //Обязательно изменить переменную на $cmb
		'name' => esc_html__( 'Test Text Small', 'cmb2' ), // Название 
		'desc' => esc_html__( 'field description (optional)', 'cmb2' ), // Подсказка
		'id'   => $prefix . 'textsmall', // Имя произвольного поля
		'type' => 'text_small',
		// 'repeatable' => true,
		// 'column' => array(
		// 	'name'     => esc_html__( 'Column Title', 'cmb2' ), // Set the admin column title
		// 	'position' => 2, // Set as the second column.
		// );
		// 'display_cb' => 'yourprefix_display_text_small_column', // Output the display of the column values through a callback.
	) );
}

Что нужно поправить:

  • Переменную $cmb_demo на $cmb.
  • ‘name’ — Название произвольного поля.
  • ‘desc’ — Подсказка для произвольного поля.
  • ‘id’ — имя произвольного поля в базе.

Результат:

Получим свое произвольное поле.

Получить произвольное поле можно стандартными средствами вордпресса:

1
<?php echo get_post_meta($post->ID, 'my_metaboxes_textsmall', true); ?>

Не запутайтесь: имя произвольного поля формируется из переменной $prefix и id.

26 сентября
12