Лучшая подборка кода для вашего файла 'functions.php'
Как и многие другие, кто сейчас читает этот пост, я изучал различные блоги, форумы и дискуссионные группы, чтобы улучшить свои навыки работы с WordPress. В течение последних 12 месяцев я поставил себе цель заменить использование плагинов добавлением кода непосредственно в файл functions.php
.
Хотя я полностью согласен, что плагины очень полезны во многих ситуациях, мой опыт показал, что в 90% случаев использования, даже если плагин существует, его применение может создать ненужные сложности и проблемы совместимости. Кроме того, во многих случаях такие плагины добавляли меню и другие элементы администрирования, которые мне не нужны.
Чаще всего я обнаруживал, что, анализируя код плагинов, я мог выделить нужный мне фрагмент кода и жестко закодировать его в моем functions.php
. Это обеспечивало мне именно ту функциональность, которая мне нужна, без необходимости включать лишние элементы.
Итак, цель этого поста - попытаться привлечь вас, читателей/администраторов/разработчиков, поделиться со мной и другими любыми полезными фрагментами кода, которые вы добавили в файл functions.php
вашей темы для расширения или улучшения WordPress без использования плагинов.
Когда вы публикуете ответ, пожалуйста, дайте каждому фрагменту кода название, сообщите, с какой версией WordPress он совместим, включите описание, которое наилучшим образом описывает его функцию, и (если применимо) добавьте ссылку на оригинальный плагин или источник, где вы нашли информацию.
Я с нетерпением жду всех ваших ответов и, конечно же, буду постоянно добавлять свои новые находки, когда буду их обнаруживать.
Пожалуйста, голосуйте за вопрос и любые ответы, которые вы считаете полезными, нажимая на стрелку вверх слева от вопроса или ответа.

Предварительное заполнение типов записей
Вот один из примеров для этой коллекции.
////////////////////////////////////////////////////////////////////////////////////
// Этот код автоматически заполняет типы записей и посты.
///////////////////////////////////////////////////////////////////////////////////
add_filter( 'default_content', 'my_editor_content' );
function my_editor_content( $content ) {
global $post_type;
switch( $post_type ) {
case 'your_post_type_here': // автоматическое заполнение
$content = 'Контент, которым вы хотите предварительно заполнить тип записи.';
break;
}
return $content;
}
Это может быть полезно, когда нужно публиковать одну и ту же информацию с небольшими изменениями.

Отличная идея! Мне нравится этот простой вариант. Можешь ли ты расширить его, возможно, показав способы автоматического заполнения пользовательских полей или других критериев/опций, а может даже средства для автоматической вставки медиа?

Я определенно могу подумать о расширении функционала. Пока что я не пробовал развивать эту идею дальше.

Автоматическое подключение кода Google Analytics
Проверено на: WordPress 3.1 RC3
Я использую этот скрипт на всех своих сайтах начиная с WordPress 2.3.0... Он просто добавляет стандартный код отслеживания Google в подвал сайта.
// Добавляем код отслеживания Google Analytics
function add_google_analytics() {
?>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-XXXXXXX-X");
pageTracker._trackPageview();
} catch(err) {}</script>
<?php
}
add_action('wp_footer', 'add_google_analytics');
Не забудьте заменить UA-XXXXXXX-X
на ваш собственный код отслеживания Google...

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

Не уверен насчет добавления переменных отслеживания кампаний, просто потому что у меня пока не было такой необходимости. Но чтобы добавить те же скрипты на страницы админки, вы можете просто использовать add_action('admin_footer', 'add_google_analytics');
для подключения к подвалу административных страниц.

Список всех констант для информации и отладки
Протестировано на: WordPress 3.0.1
Будет отображать информацию только для авторизованных пользователей
if ( is_user_logged_in() ) {
print('<pre>');
print_r( @get_defined_constants() );
print('</pre>');
}
Версия с опциональным фильтром для частичного совпадения имен констант и их значений:
function constants($filter = false) {
$constants = get_defined_constants();
if( $filter ) {
$temp = array();
foreach ( $constants as $key => $constant )
if( false !== stripos( $key, $filter ) || false !== stripos( $constant, $filter ) )
$temp[$key] = $constant;
$constants = $temp;
}
ksort( $constants );
var_dump( $constants );
}

Изменение стандартного слага для автора
Добавьте этот код в functions.php, чтобы изменить стандартный слаг автора на любой другой.
Просто замените "sellers" на желаемый слаг.
// Изменение URL-слага с author на sellers
function new_author_base() {
global $wp_rewrite;
$author_slug = 'sellers';
$wp_rewrite->author_base = $author_slug;
}
add_action('init', 'new_author_base');

Однако вам не захочется запускать этот код при каждой загрузке страницы.

Да, сброс ролей при каждой загрузке спасёт вас от множества продавцов. :) Лучше используйте плагин Edit Author Slug.

Добавление кнопки "Следующая страница" в визуальном редакторе
add_filter('mce_buttons','wysiwyg_editor');
function wysiwyg_editor($mce_buttons) {
$pos = array_search('wp_more',$mce_buttons,true);
if ($pos !== false) {
$tmp_buttons = array_slice($mce_buttons, 0, $pos+1);
$tmp_buttons[] = 'wp_page';
$mce_buttons = array_merge($tmp_buttons, array_slice($mce_buttons, $pos+1));
}
return $mce_buttons;
}

Добавление пользовательских стилей в редактор TinyMCE
Иногда пользователи и клиенты путаются из-за различий в отображении контента в редакторе и на фронтенде. Копирование нескольких соответствующих строк из вашей основной таблицы стилей в новый файл tinymce.css может значительно помочь:
function custom_mce_css($wp) {
return $wp .= ',' . get_bloginfo('stylesheet_directory') . '/css/tinymce.css';
}
add_filter( 'mce_css', 'custom_mce_css' );

Отлично. Я только что обнаружил, что есть решение от Seamus Leahy, которое расширяет всё это на шаг дальше, добавляя класс body к tinymce. http://www.digwp.com/2010/11/actual-wysiwyg

Я предпочитаю создавать таблицу стилей и для фронтенда, и для TinyMCE одновременно. Затем я использую базовый функционал функции add_editor_style() для подключения таблицы стилей и обеспечения её загрузки при загрузке TinyMCE. Статья в Codex: http://codex.wordpress.org/Function_Reference/add_editor_style

Изменение размера больших изображений при загрузке
Изображение будет изменено в соответствии с максимальным размером в настройках медиафайлов.
/**изменение размера при загрузке до максимального размера в настройках медиа */
function replace_uploaded_image($image_data) {
// если нет большого изображения: возвращаем
if (!isset($image_data['sizes']['large'])) return $image_data;
// пути к загруженному изображению и большому изображению
$upload_dir = wp_upload_dir();
$uploaded_image_location = $upload_dir['basedir'] . '/' .$image_data['file'];
$large_image_location = $upload_dir['path'] . '/'.$image_data['sizes']['large']['file'];
// удаляем загруженное изображение
unlink($uploaded_image_location);
// переименовываем большое изображение
rename($large_image_location,$uploaded_image_location);
// обновляем метаданные изображения и возвращаем их
$image_data['width'] = $image_data['sizes']['large']['width'];
$image_data['height'] = $image_data['sizes']['large']['height'];
unset($image_data['sizes']['large']);
return $image_data;
}
add_filter('wp_generate_attachment_metadata','replace_uploaded_image');

Это означает, что исходный загруженный большой файл фактически заменяется? Мой PHP не очень хорош, но похоже, что ответ - да?

@davemac Я понимаю, что это уже очень старый вопрос, но насколько я понимаю код, исходное изображение изменяется до размеров 'большого' размера изображения, установленного в настройках WordPress. Это хорошо, но в итоге вы получаете 2 изображения одинакового размера. Я бы предложил вручную установить значения так, чтобы исходное изображение было только такого размера, какой вам действительно понадобится на сайте. Тогда у вас останется почти оригинальное изображение для работы в будущем.

Использование figure и figcaption для подписей
Проверено на: WordPress 3.1.3
(Автор: WP Engineer: http://wpengineer.com/917/filter-caption-shortcode-in-wordpress/)
function mytheme_caption( $attr, $content = null ) {
$output = apply_filters( 'img_caption_shortcode', '', $attr, $content );
if ( $output != '' )
return $output;
extract( shortcode_atts ( array(
'id' => '',
'align' => 'alignnone',
'width'=> '',
'caption' => ''
), $attr ) );
if ( 1 > (int) $width || empty( $caption ) )
return $content;
if ( $id ) $id = 'id="' . $id . '" ';
return '<figure ' . $id . 'class="wp-caption ' . $align . '" style="width: ' . $width . 'px">'
. do_shortcode( $content ) . '<figcaption class="wp-caption-text">' . $caption . '</figcaption></figure>';
}
add_shortcode( 'wp_caption', 'mytheme_caption' );
add_shortcode( 'caption', 'mytheme_caption' );

Вот несколько полезных шорткодов для вас:
1. Простой шорткод для добавления кнопок "Поделиться" в Twitter и Facebook
function shreplz() {
return '
<div class="sharebox">
<div class="twittme"><a href="https://twitter.com/share" class="twitter-share-button" data-count="horizontal">Твитнуть</a><script type="text/javascript" src="//platform.twitter.com/widgets.js"></script></div>
<div class="shareface"><a name="fb_share"></a> <script src="http://static.ak.fbcdn.net/connect.php/js/FB.Share" type="text/javascript"></script></div>
<br style="clear: left;" />
</div>
';
}
add_shortcode('sharethis', 'shreplz');
// Как использовать: [sharethis]
2. Простой шорткод для создания снимка удаленного сайта с использованием WordPress API
function wpr_snap($atts, $content = null) {
extract(shortcode_atts(array(
"snap" => 'http://s.wordpress.com/mshots/v1/',
"url" => 'http://www.sagive.co.il',
"alt" => 'Мое изображение',
"w" => '400', // ширина
"h" => '300' // высота
), $atts));
$img = '<img src="' . $snap . '' . urlencode($url) . '?w=' . $w . '&h=' . $h . '" alt="' . $alt . '"/>';
return $img;
}
add_shortcode("snap", "wpr_snap");
// Как использовать: [snap url="http://www.example.com" alt="Крутой сайт!" w="300px" h="200px"]
3. Простой шорткод для вставки iFrame
function GenerateIframe( $atts ) {
extract( shortcode_atts( array(
'href' => 'http://the-url',
'height' => '550px',
'width' => '600px',
), $atts ) );
return '<iframe src="'.$href.'" width="'.$width.'" height="'.$height.'"> <p>Ваш браузер не поддерживает iframes.</p></iframe>';
}
add_shortcode('iframe', 'GenerateIframe');
// Как использовать: [iframe href="http://www.exmaple.com" height="480" width="640"]
4. Простой шорткод для включения удаленного файла или документа
function getfile_content( $atts ) {
extract( shortcode_atts( array(
'fileurl' => ''
), $atts ) );
if ($fileurl!='')
return @file_get_contents($fileurl);
}
add_shortcode( 'getfile', 'getfile_content' );
// Как использовать: [getfile fileurl="http://www.exmaple.com/somepage.html"]
. Вот несколько сниппетов, связанных с комментариями:
1. Отключение возможности комментирования глобально
function closeCommentsGlobaly($data) { return false; }
add_filter('comments_number', 'closeCommentsGlobaly');
add_filter('comments_open', 'closeCommentsGlobaly');
2. Добавление специального CSS-класса для комментариев администратора
if (1 == $comment->user_id)
echo 'siteadmin'; // Укажите ваш класс здесь
3. Крутой список комментариев с данными — отлично подходит для пользовательских закрытых страниц
$comments = get_comments( array(
'number' => 10, // Количество комментариев
'status' => 'approve' // Тип комментариев
) );
foreach($comments as $eachComment){
// Сбор и присвоение данных
$commentID = comment_ID;
$commentAuthorEmail = $eachComment->comment_author_email;
$commentPostId = $eachComment->comment_post_ID;
$commentPostTitle = get_the_title( $commentPostId );
$commentPostUrl = get_permalink( $commentPostId );
$comment_sidebarnumber = get_comments_number( $commentPostId );
global $wpdb;
$userCommentCount = $wpdb->get_var('SELECT COUNT('.$commentID.') FROM ' . $wpdb->comments. ' WHERE comment_author_email = "' . $commentAuthorEmail . '"');
echo '<div style="border: 1px solid #ccc; padding: 10px;">';
echo '<ul style="margin: 0px;">';
echo '<li>Имя: '. $eachComment->comment_author .'</li>';
echo '<li>Комментировал(а): <a href="'.$commentPostUrl.'">'. $commentPostTitle .'</a></li>';
echo '<li>Дата комментария: '. $eachComment->comment_date .'</li>';
echo '<li>Сайт комментатора: '. $eachComment->comment_author_email .'</</li>';
echo '<li>Email комментатора: '. $eachComment->comment_author_email .'</</li>';
echo '<li>Этот комментатор '. $eachComment->comment_author .' оставил(а) '. $userCommentCount .' комментариев на вашем сайте</</li>';
echo '</ul>';
echo '<p style="padding: 10px;"><strong>'. $eachComment->comment_author .' написал(а)</strong>: '. $eachComment->comment_content .'</p>';
echo '</div>';
}

Условная проверка на потомка в иерархии
Условная функция для проверки, является ли текущая страница потомком указанного ID. Полезна для определения, является ли страница дочерней, внучатой или находящейся еще ниже в иерархическом дереве.
function is_tree($pid) { // $pid = ID страницы, чьих потомков мы ищем
global $post; // загружаем данные о текущей странице
$anc = get_post_ancestors( $post->ID );
foreach($anc as $ancestor) {
if(is_page() && $ancestor == $pid) {
return true;
}
}
if(is_page()&&(is_page($pid)))
return true; // мы на самой странице или её подстранице
else
return false; // мы где-то ещё
};

Я искал это довольно долго. Спасибо, что собрали всё воедино! Могу я попросить немного разъяснений по варианту использования. В идеале я хотел бы использовать это в моих списках меню, чтобы, если у меня есть родительское меню верхнего уровня вверху сайта, оно показывало только элементы 1-го поколения. Когда я нахожусь на элементе 2-3 поколения, элемент 1-го поколения может быть выделен с помощью CSS-атрибута "current-parent". Возможно ли это?

Создание условного тега для пользовательских таксономий
В этом примере 'student' был пользовательским типом записи, а 'stud_cat' - пользовательской таксономией. Используйте has_student(null)
для условия
function has_student( $student, $_post = null ) {
if ( !empty( $student ) )
return false;
if ( $_post )
$_post = get_post( $_post );
else
$_post =& $GLOBALS['post'];
if ( !$_post )
return false;
$r = is_object_in_term( $_post->ID, 'studcat', $student );
if ( is_wp_error( $r ) )
return false;
return $r;
}

Думаю, теперь это заменяется на has_term()
, так как версия 3.1 уже выпущена?

Простые решения для безопасности WordPress
Здесь речь идет о безопасности через скрытие. Эти функции выполняют три разные задачи.
- Удаление строки версии из кода. Нет смысла сообщать, какую версию мы используем.
- Удаление сообщений об ошибках (Неверный пароль, Пользователь не найден и т.д.) со страницы входа в админку.
Когда администратор оставляет комментарий, добавляется CSS-класс. Этот код удаляет имя администратора в классах комментариев.
// УДАЛЕНИЕ СТРОКИ ВЕРСИИ ИЗ ЗАГОЛОВКА remove_action('wp_head', 'wp_generator'); // СКРЫТИЕ СООБЩЕНИЙ ОБ ОШИБКАХ ВХОДА (Неверный пароль, Пользователь не найден и т.д.) add_filter('login_errors',create_function('$a', "return null;")); // Удаление класса с именем администратора в комментариях // Источник: http://www.wprecipes.com/wordpress-hack-remove-admin-name-in-comments-class function remove_comment_author_class( $classes ) { foreach( $classes as $key => $class ) { if(strstr($class, "comment-author-")) { unset( $classes[$key] ); } } return $classes; } add_filter( 'comment_class' , 'remove_comment_author_class' );

Удаление номера версии WordPress — это плохая практика. Гораздо безопаснее всегда поддерживать WordPress в актуальном состоянии с последними исправлениями безопасности. Дополнительный бонус: начинающие хакеры переключатся на более старые версии.

Замена стандартного Gravatar на пользовательское изображение
Вам нужно будет только указать путь к вашему изображению по умолчанию.
function custom_gravatar($avatar_defaults) {
$logo = get_bloginfo('template_directory') . '/images/icons/gravatar_logo.jpg'; //Измените на любой желаемый путь.
$avatar_defaults[$logo] = get_bloginfo('name');
return $avatar_defaults;
}//КОНЕЦ ФУНКЦИИ
add_filter( 'avatar_defaults', 'custom_gravatar' );

Автоматическое создание новой страницы при активации темы
if (isset($_GET['activated']) && is_admin()){
$new_page_title = 'Это заголовок страницы';
$new_page_content = 'Это содержимое страницы';
$new_page_template = ''; //например: template-custom.php. Оставьте пустым, если не нужен пользовательский шаблон страницы.
//не редактируйте ниже этой строки
$page_check = get_page_by_title($new_page_title);
$new_page = array(
'post_type' => 'page',
'post_title' => $new_page_title,
'post_content' => $new_page_content,
'post_status' => 'publish',
'post_author' => 1,
);
if(!isset($page_check->ID)){
$new_page_id = wp_insert_post($new_page);
if(!empty($new_page_template)){
update_post_meta($new_page_id,'_wp_page_template', $new_page_template);
}
}

Список всех подкатегорий
Протестировано на: Wordpress 3.0.1
$echo = '<ul>' . "\n";
$childcats = get_categories('child_of=' . $cat . '&hide_empty=1');
foreach ($childcats as $childcat) {
if (1 == $childcat->category_parent) {
$echo .= "\t" . '<li><a href="' . get_category_link($childcat->cat_ID).'" title="' . $childcat->category_description . '">';
$echo .= $childcat->cat_name . '</a>';
$echo .= '</li>' . "\n";
}
}
$echo .= '</ul>' . "\n";
echo $echo;
Также здесь больше информации и функций в статье http://wpengineer.com/2025/list-all-subcategories/

Зачем делать так, когда есть специальная функция для вывода списка категорий..Смотрите: http://codex.wordpress.org/Template_Tags/wp_list_categories#Only_Show_Children_of_a_Category

Автоматическая очистка SEO-ссылок без потери функциональности
Проверено на: WordPress 3.0.1
Добавив этот код в файл functions.php, WordPress будет автоматически очищать URL-адрес от всех ненужных слов. Я также расширил возможности, добавив дополнительные настройки, которые скрывают опцию изменения слага в настройках экрана, а также метабокс. Включив приведенный ниже код, любая новая запись будет автоматически получать сокращенный URL, и у вас по-прежнему будет возможность вручную редактировать слаг, нажав на URL под заголовком записи и сохранив запись.
// АВТОМАТИЧЕСКАЯ ОЧИСТКА SEO-СЛАГОВ ОТ КОРОТКИХ СЛОВ
add_filter('name_save_pre', 'seo_slugs', 0);
function seo_slugs($slug) {
// Не изменяем существующий слаг
if ($slug) return $slug;
global $wpdb;
$seo_slug = strtolower(stripslashes($_POST['post_title']));
$seo_slug = preg_replace('/&.+?;/', '', $seo_slug); // удаляем HTML-сущности
// удаляем все, что не является буквой, цифрой, пробелом или апострофом
$seo_slug = preg_replace ("/[^a-zA-Z0-9 \']/", "", $seo_slug);
// Преобразуем в массив и удаляем стоп-слова, сравнивая с массивом c.w.
$seo_slug_array = array_diff (split(" ", $seo_slug), seo_slugs_stop_words());
// Преобразуем очищенный массив в строку
$seo_slug = join("-", $seo_slug_array);
return $seo_slug;
}
function seo_slugs_stop_words () {
return array ("a", "able", "about", "above", "abroad", "according", "accordingly", "across", "actually", "adj", "after", "afterwards", "again", "against", "ago", "ahead", "ain't", "all", "allow", "allows", "almost", "alone", "along", "alongside", "already", "also", "although", "always", "am", "amid", "amidst", "among", "amongst", "an", "and", "another", "any", "anybody", "anyhow", "anyone", "anything", "anyway", "anyways", "anywhere", "apart", "appear", "appreciate", "appropriate", "are", "aren't", "around", "as", "a's", "aside", "ask", "asking", "associated", "at", "available", "away", "awfully", "b", "back", "backward", "backwards", "be", "became", "because", "become", "becomes", "becoming", "been", "before", "beforehand", "begin", "behind", "being", "believe", "below", "beside", "besides", "best", "better", "between", "beyond", "both", "brief", "but", "by", "c", "came", "can", "cannot", "cant", "can't", "caption", "cause", "causes", "certain", "certainly", "changes", "clearly", "c'mon", "co", "co.", "com", "come", "comes", "concerning", "consequently", "consider", "considering", "contain", "containing", "contains", "corresponding", "could", "couldn't", "course", "c's", "currently", "d", "dare", "daren't", "definitely", "described", "despite", "did", "didn't", "different", "directly", "do", "does", "doesn't", "doing", "done", "don't", "down", "downwards", "during", "e", "each", "edu", "eg", "eight", "eighty", "either", "else", "elsewhere", "end", "ending", "enough", "entirely", "especially", "et", "etc", "even", "ever", "evermore", "every", "everybody", "everyone", "everything", "everywhere", "ex", "exactly", "example", "except", "f", "fairly", "far", "farther", "few", "fewer", "fifth", "first", "five", "followed", "following", "follows", "for", "forever", "former", "formerly", "forth", "forward", "found", "four", "from", "further", "furthermore", "g", "get", "gets", "getting", "given", "gives", "go", "goes", "going", "gone", "got", "gotten", "greetings", "h", "had", "hadn't", "half", "happens", "hardly", "has", "hasn't", "have", "haven't", "having", "he", "he'd", "he'll", "hello", "help", "hence", "her", "here", "hereafter", "hereby", "herein", "here's", "hereupon", "hers", "herself", "he's", "hi", "him", "himself", "his", "hither", "hopefully", "how", "howbeit", "however", "hundred", "i", "i'd", "ie", "if", "ignored", "i'll", "i'm", "immediate", "in", "inasmuch", "inc", "inc.", "indeed", "indicate", "indicated", "indicates", "inner", "inside", "insofar", "instead", "into", "inward", "is", "isn't", "it", "it'd", "it'll", "its", "it's", "itself", "i've", "j", "just", "k", "keep", "keeps", "kept", "know", "known", "knows", "l", "last", "lately", "later", "latter", "latterly", "least", "less", "lest", "let", "let's", "like", "liked", "likely", "likewise", "little", "look", "looking", "looks", "low", "lower", "ltd", "m", "made", "mainly", "make", "makes", "many", "may", "maybe", "mayn't", "me", "mean", "meantime", "meanwhile", "merely", "might", "mightn't", "mine", "minus", "miss", "more", "moreover", "most", "mostly", "mr", "mrs", "much", "must", "mustn't", "my", "myself", "n", "name", "namely", "nd", "near", "nearly", "necessary", "need", "needn't", "needs", "neither", "never", "neverf", "neverless", "nevertheless", "new", "next", "nine", "ninety", "no", "nobody", "non", "none", "nonetheless", "noone", "no-one", "nor", "normally", "not", "nothing", "notwithstanding", "novel", "now", "nowhere", "o", "obviously", "of", "off", "often", "oh", "ok", "okay", "old", "on", "once", "one", "ones", "one's", "only", "onto", "opposite", "or", "other", "others", "otherwise", "ought", "oughtn't", "our", "ours", "ourselves", "out", "outside", "over", "overall", "own", "p", "particular", "particularly", "past", "per", "perhaps", "placed", "please", "plus", "possible", "presumably", "probably", "provided", "provides", "q", "que", "quite", "qv", "r", "rather", "rd", "re", "really", "reasonably", "recent", "recently", "regarding", "regardless", "regards", "relatively", "respectively", "right", "round", "s", "said", "same", "saw", "say", "saying", "says", "second", "secondly", "see", "seeing", "seem", "seemed", "seeming", "seems", "seen", "self", "selves", "sensible", "sent", "serious", "seriously", "seven", "several", "shall", "shan't", "she", "she'd", "she'll", "she's", "should", "shouldn't", "since", "six", "so", "some", "somebody", "someday", "somehow", "someone", "something", "sometime", "sometimes", "somewhat", "somewhere", "soon", "sorry", "specified", "specify", "specifying", "still", "sub", "such", "sup", "sure", "t", "take", "taken", "taking", "tell", "tends", "th", "than", "thank", "thanks", "thanx", "that", "that'll", "thats", "that's", "that've", "the", "their", "theirs", "them", "themselves", "then", "thence", "there", "thereafter", "thereby", "there'd", "therefore", "therein", "there'll", "there're", "theres", "there's", "thereupon", "there've", "these", "they", "they'd", "they'll", "they're", "they've", "thing", "things", "think", "third", "thirty", "this", "thorough", "thoroughly", "those", "though", "three", "through", "throughout", "thru", "thus", "till", "to", "together", "too", "took", "toward", "towards", "tried", "tries", "truly", "try", "trying", "t's", "twice", "two", "u", "un", "under", "underneath", "undoing", "unfortunately", "unless", "unlike", "unlikely", "until", "unto", "up", "upon", "upwards", "us", "use", "used", "useful", "uses", "using", "usually", "v", "value", "various", "versus", "very", "via", "viz", "vs", "w", "want", "wants", "was", "wasn't", "way", "we", "we'd", "welcome", "well", "we'll", "went", "were", "we're", "weren't", "we've", "what", "whatever", "what'll", "what's", "what've", "when", "whence", "whenever", "where", "whereafter", "whereas", "whereby", "wherein", "where's", "whereupon", "wherever", "whether", "which", "whichever", "while", "whilst", "whither", "who", "who'd", "whoever", "whole", "who'll", "whom", "whomever", "who's", "whose", "why", "will", "willing", "wish", "with", "within", "without", "wonder", "won't", "would", "wouldn't", "x", "y", "yes", "yet", "you", "you'd", "you'll", "your", "you're", "yours", "yourself", "yourselves", "you've", "z", "zero");
}
Добавив приведенный ниже дополнительный код в файл functions.php, вы удалите/скроете опцию изменения слага в выпадающем меню настроек экрана, а также метабокс.
// СКРЫТИЕ МЕТАБОКСА СЛАГА И ОПЦИЙ ЭКРАНА
function hide_slug_options() {
global $post;
global $pagenow;
$hide_slugs = "<style type=\"text/css\">#slugdiv, #edit-slug-box, [for=\"slugdiv-hide\"] { display: none; }</style>\n";
if (is_admin() && $pagenow=='post-new.php' OR $pagenow=='post.php') print($hide_slugs);
}
add_action( 'admin_head', 'hide_slug_options' );

Исключение дочерних категорий из определенной категории.
Довольно просто, но я не смог найти решение, которое делало бы именно то, что мне нужно. Также код будет показывать пост, если выбрана родительская категория, за исключением случаев, когда у поста выбрана дочерняя категория этой родительской.
/* этот код исключает все дочерние категории (ID категории = 20) постов
на главной странице, но разрешает показывать родительскую категорию (ID категории = 20). */
function exclude_category_children($query) {
$child_cats = (array) get_term_children('20', 'category');
if ( $query->is_home ) {
$query->set('category__not_in', $child_cats);
return $query;
}
}
add_filter('pre_get_posts', 'exclude_category_children');

Разрешить использование iFrames в редакторе WordPress
// разрешаем iframes в TinyMCE add_filter('tiny_mce_before_init', create_function( '$a', '$a["extended_valid_elements"] = "iframe[id|class|title|style|align|frameborder|height|longdesc|marginheight|marginwidth|name|scrolling|src|width]"; return $a;') );

Удаление меню в админ-панели для всех пользователей, кроме пользователя #1 (обычно это первый администратор)
/*-----------------------------------------------------------------------------------*/
/* Ограничение доступа
/*-----------------------------------------------------------------------------------*/
function remove_menus () {
global $menu;
$user = wp_get_current_user();
if ($user->ID!=1) { // Если не администратор,
$restricted = array(__('Консоль'), __('Записи'), __('Медиафайлы'), __('Ссылки'), __('Страницы'), __('Внешний вид'), __('Инструменты'), __('Пользователи'), __('Настройки'), __('Комментарии'), __('Плагины'));
end ($menu);
while (prev($menu)){
$value = explode(' ',$menu[key($menu)][0]);
if(in_array($value[0] != NULL?$value[0]:"" , $restricted)){unset($menu[key($menu)]);}
}
}
}
add_action('admin_menu', 'remove_menus');

Пользователь 1 может быть первым администратором. Но после добавления новых администраторов первый может стать обычным пользователем. Проверяйте возможности, а не номера. Кроме того, этот код должен быть в плагине, а не в functions.php. Он никак не связан с темой.

Таким образом вы можете разрешить всем администраторам работать как обычно, но при этом скрыть первого администратора и оставить его для системного администратора / службы поддержки. Я не согласен, что этот код должен быть в плагине. Functions.php — это и есть плагин. Этот файл по сути ведет себя как плагин
Разработка_Тем#Файл_Functions

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

Да. Но давайте рассмотрим следующее: вы разрабатываете сайт для клиента. Этот сайт всегда будет использовать только одну тему, созданную дизайнером. Тема и есть сайт. Вы добавляете пользовательские типы записей, метабоксы, подгружаете дополнительные функции и т.д. Теперь вы хотите дать некоторым пользователям права администратора, но при этом скрыть некоторые разделы сайта, которые ваш клиент никогда не будет использовать или которые могут его запутать (Ссылки, Инструменты, Комментарии — лучшие примеры), а также предоставить команде поддержки что-то вроде "СуперАдмина", чтобы они могли видеть всю административную область.

Я вижу, что вы не согласны с использованием, но функция работает и полезна, поэтому я не понимаю, зачем ставить -1.

Это не должно находиться в functions.php — как, к сожалению, многие ответы здесь — и это обязательно сломается рано или поздно. Кроме того, это нарушает стандарты кодирования WordPress. Пожалуйста, не принимайте это на свой счет. Мой голос — это рекомендация для читателя.

Конечно, ничего личного, tosco. Мы все стараемся помогать и учиться. Мы не согласны, такое бывает :)

@Daniel Sachs Посмотрите этот gist и замените user_login
на role
(?).

@kaiser Это отлично, если бы я хотел использовать это как плагин или убирать меню для всех админов. Как я уже говорил, это позволяет убрать меню только для одного конкретного пользователя с ID1

Отключение предупреждения о необходимости обновления браузера в WordPress 3.2
//Отключение предупреждения о необходимости обновления браузера в WordPress 3.2
function disable_browser_upgrade_warning() {
remove_meta_box( 'dashboard_browser_nag', 'dashboard', 'normal' );
}
add_action( 'wp_dashboard_setup', 'disable_browser_upgrade_warning' );

Отображение используемых файлов шаблонов
Показывает встроенные комментарии с указанием основного файла шаблона (Template File) и файлов, подключаемых через get_template_part, при отображении страниц. Полезно для отладки составных шаблонов.
add_action('all','template_snoop');
function template_snoop(){
$args = func_get_args();
if( !is_admin() and $args[0] ){
if( $args[0] == 'template_include' ) {
echo "<!-- Основной шаблон: {$args[1]} -->\n";
} elseif( strpos($args[0],'get_template_part_') === 0 ) {
global $last_template_snoop;
if( $last_template_snoop )
echo "\n\n<!-- Конец части шаблона: {$last_template_snoop} -->";
$tpl = rtrim(join('-', array_slice($args,1)),'-').'.php';
echo "\n<!-- Часть шаблона: {$tpl} -->\n\n";
$last_template_snoop = $tpl;
}
}
}

Функция условной проверки is_tree()
/* Адаптировано из csstricks с добавлением
проверки предков .... использование = if(is_tree($id)) { // выполняем действия } ...
Возвращает true, если страница = $id ИЛИ любой из её дочерних элементов ИЛИ потомков */
function is_tree($pid) { // $pid = ID страницы, для которой ищем дочерние страницы
global $post; // загружаем данные о текущей странице
$ancestors = get_post_ancestors($post);
if(is_page()&&($post->post_parent==$pid||is_page($pid)||(in_array($pid,$ancestors))))
return true; // мы находимся на странице или её подстранице
else
return false; // мы находимся в другом месте
};

Отображение пользователей, оставивших наибольшее количество комментариев без использования плагина
function top_comment_authors($amount = 5) {
global $wpdb;
$results = $wpdb->get_results('
SELECT
COUNT(comment_author_email) AS comments_count, comment_author_email, comment_author, comment_author_url
FROM '.$wpdb->comments.'
WHERE comment_author_email != "" AND comment_type = "" AND comment_approved = 1
GROUP BY comment_author_email
ORDER BY comments_count DESC, comment_author ASC
LIMIT '.$amount
);
$output = "<ul>";
foreach($results as $result) {
$output .= "<li>".$result->comment_author."</li>";
}
$output .= "</ul>";
echo $output;
}
Другие параметры, которые можно использовать: $result->comment_author_email $result->comments_count $result->comment_author_url

Получение реального IP-адреса пользователя, когда это возможно
Протестировано на: Wordpress 3.0.1
Если вы используете прокси или балансировщик нагрузки, добавьте этот код в файл wp-config.php или functions.php
// Получаем реальный IP-адрес пользователя
$_SERVER['REMOTE_ADDR'] = getRealIpAddress();
function getRealIpAddress( $validate = true ) {
if ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) ) {
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$ip = trim($ips[count($ips) - 1]);
} elseif ( isset($_SERVER['HTTP_X_REAL_IP']) && !empty($_SERVER['HTTP_X_REAL_IP']) ) {
$ip = $_SERVER['HTTP_X_REAL_IP'];
} elseif ( isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP']) ) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
if ( $validate && function_exists('filter_var') && filter_var($ip, FILTER_VALIDATE_IP, array('flags' => FILTER_FLAG_IPV4, FILTER_FLAG_NO_PRIV_RANGE, FILTER_FLAG_NO_RES_RANGE)) )
return $ip;
elseif ( $validate )
return long2ip(ip2long($ip));
return $ip;
}

Когда пользователь находится за прокси или балансировщиком нагрузки, любой код, который получает его IP-адрес через суперглобальную переменную $_SERVER['REMOTE_ADDR'], увидит IP-адрес прокси или балансировщика. В свою очередь, прокси/балансировщик помещает оригинальный IP-адрес пользователя в заголовки X-Forwarded-For, X-Real-Ip или Client-Ip (в зависимости от конфигурации прокси/балансировщика). Таким образом, при комментировании (или публикации, но это менее важно) WordPress будет видеть множество пользователей с одного IP-адреса. Этот код исправляет ситуацию, заменяя $_SERVER['REMOTE_ADDR'] на оригинальный IP-адрес.

Исключение категории по умолчанию из публичных страниц
Исключает категорию по умолчанию из публичной части сайта.
Код исключает административную область, иначе у вас не будет возможности управлять записями, назначенными в категорию по умолчанию.
add_filter( 'list_terms_exclusions', 'exclude_default_cat' );
function exclude_default_cat( $exclusions ) {
if( !is_admin() )
$exclusions .= "AND t.term_id != " . get_option( 'default_category' ) . " ";
return $exclusions;
}

Удаление ссылки "Комментарии" из панели администратора, если комментарии закрыты
Вы можете установить статус комментариев по умолчанию как 'closed' (закрыто), но ссылка на комментарии останется. Просто добавьте следующий код в файл functions.php
, чтобы удалить её на основе условия. Предлагается 2 разных подхода.
/**
* Отключает ссылку 'Комментарии', если статус по умолчанию _closed_
*/
function remove_comments()
{
$default_comment_status = get_option( 'default_comment_status' );
if ( $default_comment_status == 'closed' )
{
remove_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 50 );
// альтернативное решение с использованием класса WP_Admin_Bar из /wp-includes/class-wp-admin-bar.php
# global $wp_admin_bar;
# $wp_admin_bar->remove_menu( 'comments' );
}
else
{
return;
}
}

Добавляет пользовательскую выпадающую опцию в WP_NAV_MENUS, где можно выбрать предопределенный CSS-класс для каждого пункта меню
<?php function menu_item_class_select(){
global $pagenow;
if ($pagenow == "nav-menus.php"){
?>
<script>
jQuery(document).ready(function(){
function create_dd(v){
//создаем выпадающий список
var dd = jQuery('<select class="my_class"></select>');
//создаем опции выпадающего списка
//массив с доступными опциями
var classes = ["","class1","class2","class3"];
jQuery.each(classes, function(i,val) {
if (v == val){
dd.append('<option value="'+val+'" selected="selected">'+val+'</option>');
}else{
dd.append('<option value="'+val+'">'+val+'</option>');
}
});
return dd;
}
jQuery(".edit-menu-item-classes").each(function() {
//добавляем выпадающий список
var t = create_dd(jQuery(this).val());
jQuery(this).before(t);
//скрываем все поля ввода
jQuery(this).css("display","none");
});
//обновляем поле ввода при выборе
jQuery(".my_class").bind("change", function() {
var v = jQuery(this).val();
var inp = jQuery(this).next();
inp.attr("value",v);
});
});
</script>
<?php } }
add_action('admin_footer','menu_item_class_select');
?>

Удаление элементов меню админ-панели в WordPress 3.3
function dashboard_tweaks() {
global $wp_admin_bar;
$wp_admin_bar->remove_menu('wp-logo'); // Удаляет логотип WordPress
$wp_admin_bar->remove_menu('about'); // Удаляет пункт "О WordPress"
$wp_admin_bar->remove_menu('wporg'); // Удаляет ссылку на WordPress.org
$wp_admin_bar->remove_menu('documentation'); // Удаляет ссылку на документацию
$wp_admin_bar->remove_menu('support-forums'); // Удаляет ссылку на форумы поддержки
$wp_admin_bar->remove_menu('feedback'); // Удаляет пункт "Обратная связь"
$wp_admin_bar->remove_menu('view-site'); // Удаляет ссылку "Просмотреть сайт"
}
add_action( 'wp_before_admin_bar_render', 'dashboard_tweaks' );
Ссылка на источник: http://pastebin.com/Wrk0JPxw

Запрос тегов между таксономиями
Кэшированный запрос, который выводит HTML-строку, подобную get_tags()
, со всеми тегами для заданной таксономии (по умолчанию - Категория). Вы можете использовать параметры $where_slug
и $where_tax
для фильтрации тегов постов по любой другой таксономии. SQL запрос протестирован для WP 3.1 - WP 3.3.1.
function tags_by_other_taxonomy($where_slug,$where_tax = 'category',$bust_cache = false) {
$cache_key = "{$where_slug}:{$where_tax}";
$cache = get_transient('tags_by_other_taxonomy');
$html = '';
if( true !== $bust_cache and false !== $cache and isset($cache[$cache_key]) and !empty($cache[$cache_key]) ) {
$html = $cache[$cache_key];
} else {
global $wpdb;
$cat_id = $wpdb->get_var("SELECT tt.term_taxonomy_id FROM $wpdb->terms t INNER JOIN $wpdb->term_taxonomy tt ON t.term_id = tt.term_id WHERE t.slug = '{$where_slug}' AND tt.taxonomy = '{$where_tax}' LIMIT 1");
if( !empty($cat_id) ) {
$cat_posts = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships tr inner join $wpdb->posts p ON p.ID = tr.object_id WHERE term_taxonomy_id = {$cat_id} AND p.post_status = 'publish' AND p.post_type = 'post'");
if( count($cat_posts) ) {
$tags = $wpdb->get_results("SELECT DISTINCT t.name,t.slug FROM $wpdb->term_taxonomy tt
INNER JOIN $wpdb->term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
INNER JOIN $wpdb->terms t ON t.term_id = tt.term_id
WHERE tt.taxonomy = 'post_tag' and tr.object_id IN (".implode(',',$cat_posts) .')');
$html = '<ul class="post-tags-'.$where_slug.'">';
if( count($tags) ) {
foreach($tags as $tag)
$html .= '<li><a href="/tag/'.$tag->slug.'/" title="Посты с тегом '.$tag->name.'">'.$tag->name.'</a></li>';
}
$html .= '</ul>';
if( !is_array($cache) )
$cache = array();
$cache[$cache_key] = $html;
set_transient('sc_cross_tax', $cache, 86400);
}
}
}
echo $html;
}
Например, получить все теги для опубликованных записей в категории с ярлыком news:
<?php echo tags_by_other_taxonomy('news'); ?>
