Список постов с меткой "deprecated" (неактуальные статьи, кандидаты на удаление)

Добавляем кнопки «Мне нравится» от Facebook, ВКонтакте, Twitter

Сегодня я расскажу, как добавить кнопки социальных сетей в свой WordPress блог так, чтобы они не тормозили загрузку и отрисовку страницы. Заранее хочу предупредить, что не являюсь специалистом ни в HTML, ни в JavaScript, ни в Php. Все решения собраны по крупицам на просторах интернета.

Чтобы оказывать меньше влияния на скорость загрузки блога, все скрипты социальных сетей и служебные HTML-элементы вынесены в конец страницы сразу после вызова wp_footer().

Для того, чтобы скрипты не влияли на отображение страницы, вся работа с ними происходит только после полной загрузки блога, для этого используется библиотека jQuery, которая присутствует в каждой поставке WordPress, и событие document.onload.

Таким образом, все скрипты живут в footer.php после вызова wp_footer() в таком обрамлении:

<script type="text/javascript">
jQuery(window).load(function() {
  /*
   * Сюда мы будем добавлять скрипты социальных сетей
   */
}
</script>

Все социальные кнопки у меня используются только в постах, поэтому их HTML-элементы добавлены в single.php сразу после вызова функции the_content().

ВКонтакте

Идем на страницу виджета, где выбираем внешний вид кнопки. У меня получился вот такой код:

<!-- Put this script tag to the <head> of your page -->
<script type="text/javascript" src="//vk.com/js/api/openapi.js?115"></script>

<script type="text/javascript">
  VK.init({apiId: 3904727, onlyWidgets: true});
</script>

<!-- Put this div tag to the place, where the Like block will be -->
<div id="vk_like_example"></div>
<script type="text/javascript">
VK.Widgets.Like("vk_like_example", {type: "button", height: 20});
</script>

Забираем отсюда div, который выглядит так:

<div id="vk_like_example"></div>

И добавляем в single.php.

Для корректной работы кнопки «Мне нравится», необходимо добавить div элемент в footer.php (перед вызовом jQuery(document).load):

<div id="vk_api_transport"></div>

Код загрузки кнопки в footer.php:

 jQuery.getScript(
      '//vk.com/js/api/openapi.js?115',
      function() {
        VK.init({apiId: 3904727, onlyWidgets: true});
        VK.Widgets.Like("vk_like_example", {type: "button", height: 20});
    });

Как вы могли заметить — все данные я взял из предоставленного кода практически без изменений. Все, теперь можно настроить размер кнопки и его отступы в вашем стиле.

Facebook

Получаем код виджета тут:

<div id="fb-root"></div>
<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/ru_RU/sdk.js#xfbml=1&appId=545514278883012&version=v2.0";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

И вот такой div:

<div class="fb-like" data-href="https://developers.facebook.com/docs/plugins/" data-layout="button_count" data-action="like" data-show-faces="true" data-share="false"></div>

Добавляем div в single.php:

<div class="fb-like" data-href="https://developers.facebook.com/docs/plugins/" data-layout="button_count" data-action="like" data-show-faces="true" data-share="false"></div>

Затем специальный div в footer.php (перед вызовом jQuery(document).load) для правильной работы кнопки от Facebook:

<div id="fb-root"></div>

После этого смотрим свой appId и добавляем следующий код в footer.php:

    jQuery.ajaxSetup({ cache: true });

    window.fbAsyncInit = function() {
      FB.init({
        appId      : '545514278883012',
        status     : true,
        cookie     : true,
        oauth      : true,
        xfbml      : true,
      });      
    };

    jQuery.getScript('//connect.facebook.net/ru_RU/all.js');

С этим кодом я промучился больше всего.

Twitter

За кнопкой идем сюда:

<a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>

Забираем отсюда к себе в single.php:

<a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>

И в footer.php:

jQuery.getScript('//platform.twitter.com/widgets.js');

Самый элементарный код. Один минус — если сайт твиттера недоступен, отображает уродскую ссылку.

Заключение

Все вышеописанные кнопки в single.php:

<div id="like_buttons">
  <div id="vk_like_example"></div>
  <div class="fb-like" data-layout="button_count" data-action="like" data-show-faces="true" data-share="false"></div>
  <div id="tweet">
    <a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>
  </div>
</div>

Загрузка всех плагинов в footer.php:

<?php if(is_single()) { ?>
<div id="fb-root"></div>
<div id="vk_api_transport"></div>
<script type="text/javascript">
jQuery(window).load(function() {
    jQuery.ajaxSetup({ cache: true });

    window.fbAsyncInit = function() {
      FB.init({
        appId      : '545514278883012',
        status     : true,
        cookie     : true,
        oauth      : true,
        xfbml      : true,
      });      
    };

    jQuery.getScript('//connect.facebook.net/ru_RU/all.js');
    jQuery.getScript('//platform.twitter.com/widgets.js');
    
    jQuery.getScript(
      '//vk.com/js/api/openapi.js',
      function() {
        VK.init({apiId: 3904727, onlyWidgets: true});
        VK.Widgets.Like("vk_like_example", {type: "button", verb: 1, height: 20, width: 165});
    });

    window.___gcfg = {lang: 'ru'};
});
</script><?php } ?>

Весь код, приведенный выше добавляет кнопки только в блого-записи. Возможно, вам понадобятся кнопки на всех страницах, для этого нужно исключить проверку is_single() и добавлять HTML-элементы социальных кнопок не только лишь в single.php.

И еще один момент: если вы скопируете код отсюда один в один (без замены appId в Facebook и ВКонтакте), то все лайки будут сыпаться в мою копилку. Мне-то не жалко, но вам от этого никакого толку. (:

P.S. Если вам пригодилась информация из данного поста — пожалуйста, нажмите одну из социальных кнопок ниже.

UPD: Пришел к выводу, что загрузка кода с сайтов социальных сетей неоптимальна. На эту тему мой новый пост: «Добавляем Social Likes на сайт с WordPress».

Вопросы программисту C/C++ на собеседовании с ответами

Заметил, что на собеседовании часто задают одни и те же вопросы по программированию. Если бы брали на работу водителя, то некоторые вопросы звучат примерно так:

  • В какую сторону надо крутить руль, чтоб повернуть направо?
  • За что отвечает педаль сцепления/тормоза/газа?

Такое конечно случается далеко не всегда, но первые пару вопросов обычно такого рода («А какую надо давить педаль, чтоб автомобиль остановился?»). Публикую свои ответы на некоторые вопросы для программистов. Вдруг кому пригодится.. Возможно, здесь много ошибок и помарок — при составлении этого списка я не пользовался интернетом. Старался выдать, что знаю сам.

Как можно оптимизировать данный цикл?

void func(int *array, int len)
{
    for (int i = 0; i < len; i++)
    {
        array[i] = array[i] * array[i];
    }
}

Вот таким образом:

void func(int *array, int len)
{
    const int *end = array + len;

    while (array != end)
    {
        const int value = *array;
        *array++ = value * value;
    }
}

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

В чем отличие std::list<T> от std::vector<T>?

std::vector<T> — это обертка над обычным С/C++ массивом. Соответственно:

  • если std::vector<T> заполнен, то при добавлении нового элемента, массив удаляется целиком и создается заново с бОльшим размером
  • любой элемент массива можно получить моментально, потому что позиция элемента вычисляется банальным прибавлением индекса к первому элементу (array[i] = array + i)
  • удаление любого элемента из массива, кроме последнего, приведет к перемещению всех элементов справа от удаляемого на одну позицию влево (при соблюдении некоторых условий, можно воспользоваться хаком)
  • занимает неразрывный блок памяти

std::list<T> — это список элементов, которые связаны между собой указателями prev (предыдущий элемент) и next (следующий элемент). Внутри себя std::list<T> хранит указатель на первый элемент и последний (зависит от реализации). Исходя из этого:

  • чтобы удалить любой элемент, необходимо просто переставить указатели
  • для того, чтобы обратиться к произвольному элементу, необходимо пробежаться от начала или конца (в зависимости от реализации) к искомому
  • каждому элементу выделяется память индивидуально

В языке Java различия между ArrayList и LinkedList практически такие же.

Почему в C++ нужно использовать new вместо теплого лампового malloc()?

Потому что malloc() тупо выделяет блок памяти и возвращает этот блок программисту. А new выделяет память и вызывает конструктор объекта. Тоже самое относится к delete и free(). delete вызывает деструктор и освобождает память. free() просто освобождает память. Также есть размещающий new, который создает объект в уже выделенной вами памяти.

Кстати, изначально конструкторы и деструкторы классов в C++ назывались new и delete и выглядели вот так:

class SomeClass
{
    // Конструктор
    void new();

    // Деструктор
    void delete()
};

В чем отличие между new/delete и new[]/delete[]?

new выделяет память для одного элемента и вызывает конструктор для него, в то время как new[] выделяет память для массива элементов и вызывает конструктор для каждого из них. delete должен вызываться для объекта выделенного с помощью new, а delete[] для массива, выделенного с помощью new[]. От проблем соответствия new/delete вас могут избавить классы std::auto_ptr<T> (для одного элемента) и std::tr1::scoped_array<T> (для массива элементов). Которые сами вызывают правильный delete в деструкторе.

Для чего нужен тип std::auto_ptr<T>?

В стародавние времена вы должны были сами следить за тем, чтоб после каждого new был вызван свой delete. Это было жутко неудобно (программисты Си выкручиваются из этой ситуации вставляя goto):

bool func()
{
    Stream *stream = new Stream;

    if (0 != stream->open("some stream"))
    {
        delete stream;
        return false;
    }

    if (0 != stream->load())
    {
        delete stream;
        return false;
    }

    // Выполняем полезную работу
    // Закончили полезную работу
    delete stream;
    return true;
}

После появление std::auto_ptr<T> стало возможным переписать функцию таким образом:

bool func()
{
    std::auto_ptr<Stream> stream(new Stream);

    if (0 != stream->open("some stream"))
    {
        // Здесь "delete stream" вызывается автоматически
        return false;
    }

    if (0 != stream->load())
    {
        // Здесь "delete stream" вызывается автоматически
        return false;
    }

    // Выполняем полезную работу
    // Закончили полезную работу

    // Здесь "delete stream" вызывается автоматически
    return true;
}

И еще очень важный момент: std::auto_ptr<T> владеет объектом единолично. Вы не сможете шарить объект между двумя std::auto_ptr<T> (используйте в таких случаях std::shared_ptr<T>):

void func() 
{
    Object *object = new Object;

    std::auto_ptr<Object> ptr1(object); // object теперь живет внутри ptr1
    std::auto_ptr<Object> ptr2(ptr1); // ptr1 опустел, object внутри ptr2

    // здесь деструктор ptr2 удалит object
    // а здесь вызовется деструктор ptr1 впустую
}

И помните: std::auto_ptr<T> не подходит для массивов выделенных с помощью new[]. Для этих целей используйте std::tr1::scoped_array<T> или boost::scoped_array<T>.

Что такое RAII?

Это переводится как «Получение ресурса есть инициализация». Идея вкратце такая: в конструкторе открываем/блокируем ресурс, в деструкторе закрываем/освобождаем ресурс. Вот пример:

class FILEWrap
{
public:
    FILEWrap( const char *fileName )
        : f_(fopen(fileName, "rb"))
    {
    }

    ~FILEWrap()
    {
        if (f_)
        {
            fclose(f_);
        }
    }

private:
    FILE *f_;
};

Или более каноничный пример (блокирование мьютекса или критической секции):

class MutexLock
{
public:
    MutexLock(Mutex &mutex)
        : mutex_(mutex)
    {
        mutex.lock();
    }

    ~MutexLock()
    {
        mutex.unlock();
    }

private:
    Mutex &mutex_;
};

Зачем нужен виртуальный деструктор?

Попробуем обойтись без него:

#include <stdio.h>

class A
{
public:
    A() 
    { 
        printf("construct A\n"); 
    }

    ~A() 
    { 
        printf("destruct A\n"); 
    }
};


class B : public A
{
public:
    B() 
    { 
        printf("construct B\n"); 
    }

    ~B() 
    { 
        printf("destruct B\n"); 
    }
};


int main()
{
    B *b = new B;
    A *a = b;
    delete a;
}

Вывод:

construct A
construct B
destruct A

Как можно заметить деструктор B не вызвался. Сделаем деструктор класса A виртуальным и посмотрим что получится:

#include <stdio.h>

class A
{
public:
    A() 
    { 
        printf("construct A\n"); 
    }

    virtual ~A() 
    { 
        printf("destruct A\n"); 
    }
};


class B : public A
{
public:
    B() 
    { 
        printf("construct B\n"); 
    }

    ~B() 
    { 
        printf("destruct B\n"); 
    }
};


int main()
{
    B *b = new B;
    A *a = b;
    delete a;
}

Теперь все отлично:

construct A
construct B
destruct B
destruct A

В каком порядке инициализируются члены класса?

Члены класса создаются в порядке их объявления в классе. Уничтожаются они в обратном порядке. Давайте проверим:

#include <stdio.h>
 
class Printer
{
public:
    Printer( const char *n ) 
        : n_(n)
    {
        printf("+%s ", n_);
    }
 
    ~Printer() 
    {
        printf("-%s ", n_);
    }
 
private:
    const char *n_;
};


class A : public Printer
{   
public:
    A() 
        : Printer("A") 
    {
    }
};


class B : public Printer
{
public:
    B() 
        : Printer("B") 
    {
    }
};


class C : public Printer
{
public:
    C() 
        : Printer("C") 
    {
    }
};
 
 
class Test
{
private:
    A A_;
    B B_;
    C C_;
};
 
 
int main()
{
    Test test;
}

Запустим:

+A +B +C -C -B -A

Все правильно.

Порядок объявления очень важен, если один член класса во время инициализации использует данные другого члена. Кстати, компилятор gcc выдает warning (с флагом -Wall), если вы описали инициализацию членов класса в другом порядке. И это еще одна причина в пользу использования настройки компилятора «считать предупреждения ошибками» (в gcc это флаг -Werror).

Настройка защищенного доступа к блогу

Наконец-то разобрался с правильной настройкой протокола HTTPS для блога. Итак, по пунктам:

Доступность протокола HTTPS

Проверяем, что ваш сайт доступен по адресу https://example.com. Если недоступен, тогда эта инструкция вам не подходит.

Поисковые роботы

Создаем файл robots-https.txt в корне сайта с таким содержимым:

User-agent: *
Disallow: /

Добавляем правило в .htaccess (сразу после «RewriteEngine On»):

RewriteCond %{HTTPS} on
RewriteRule ^robots\.txt$ robots-https.txt

Это запретит поисковым роботам индексировать содержимое сайт по https. По адресу https://example.com/robots.txt должно выдаваться содержимое robots-https.txt.

Доступ к админке и странице логина

Добавляем в wp-config.php:

define('FORCE_SSL_ADMIN', true);
define('FORCE_SSL_LOGIN', true);

Это хоть немного убережет вас от кражи паролей с помощью перехвата трафика.

Запрет HTTPS на остальных страницах блога

Добавляем правило в .htaccess (сразу после robots-https):

RewriteCond %{SERVER_PORT} ^443$
RewriteCond %{REQUEST_URI} !^/(wp-admin/|wp-login|wp-includes/)
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1 [R=301,L]

Это позволит автоматически перекидывать ваших пользователей со страниц вида https://example.com на http://example.com, если они вдруг придут с поисковика на эту страницу. При этом не портится защищенный доступ к админке и странице логина.

Какие я использую плагины для WordPress

Всем привет! Вот решил рассказать какие плагины я использую в WordPress и зачем. Поехали!

Akismet

Классика защиты от спама в комментариях. Проверяет новые комментарии по своей базе и отсеивает всякий мусор. Категорически рекомендуется к установке. Для затравки цитата из моей админки: «Akismet защитил ваш сайт от 3 522 спам-комментариев».

Executable PHP widget

Позволяет добавлять виджеты в тему с исполняемым PHP кодом. Установил специально для YoWindow.

Google Analytics for WordPress

Поддержка службы «Google Analytics». Благодаря ему можно смотреть подробную статистику посещений блога.

Google XML Sitemaps

Генерация файлика sitemap.xml, включая запакованную версию. Этот файл идет в нагрузку к robots.txt и используется поисковиками для более подробной индексации сайта. Рекомендую!

LiveJournal Crossposter

Автоматически создает копию поста в моем блоге в ЖЖ. В последнее время почему-то глючит и создает дубли при кросспостинге. Кандидат на удаление.

Mail From

Задает имя для робота, который шлет отчеты на почту. Согласитесь, что noreply@blog2k.ru намного лучше какого-нибудь ip141.32.31@blog2k.ru. Чисто декоративный плагин.

Pagination Rel Links

Задает значения аттрибута rel — «next|prev» для лучшего индексирования страниц. Подробности можно узнать в этой статье на хабре.

StatPress Reloaded

Статистика посещений моего блога в дополнение к службам «Google Analytics» и «Яндекс.Метрика». Чисто позырить — кто ходит по блогу и зачем.

Use Google Libraries

Загрузка стандартных библиотек (типа jQuery) с хостинга Google. Теоретически из-за этого блог грузится быстрее, потому что загрузка скриптов происходит с разных IP адресов. Честно говоря, не проверял. Поверил на слово.

WordPress Popular Posts

Список популярных постов, который вы видите справа. Можно выводить список популярных постов за сутки, неделю, месяц или за все время наблюдения. В плагине StatPress Reloaded есть похожий функционал, но он как-то совсем криво работает и сделан, видимо, для галочки.

WP-Syntax

Подсветка синтаксиса исходников. Поддержка C/C++/Python/Java/sh и еще куча других. Его работу можно увидеть воочию в разделе «Программирование».

WP LaTeX

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

WP Super Cache

Кеширует страницы блога, избавляя сервер от лишней работы по разбору PHP скриптов. Реально ускоряет блог.

WP Ya.Share

Добавляет кнопку «Поделиться» от «Яндекса» для множества социальных сетей к каждому посту.

Яндекс.Метрика

Интеграция сервиса «Яндекс.Метрика». Учитывая, что «Яндекс.Метрика» «залипает» во время загрузки графиков — кандидат на удаление.

UPD: написал обновленную версию этого поста, часть вторую. Ознакомится можно по ссылке: «Какие я использую плагины для WordPress — 2».

Тестовые задания для программистов. Издание исправленное и дополненное

Я просто оставлю это здесь.

[user@domain ~]# cc -Wall -Werror -pedantic Binary.c
BinaryPrint.c:6:5: error: C++ style comments are not allowed in ISO C90
BinaryPrint.c:6:5: error: (this will be reported only once per input file)
cc1: warnings being treated as errors
BinaryPrint.c: In function 'BinaryPrint':
BinaryPrint.c:13: warning: ISO C90 forbids mixed declarations and code

diff -r afee20b80dff BinaryPrint.c
--- a/BinaryPrint.c     Tue Feb 22 09:11:12 2011 +0300
+++ b/BinaryPrint.c     Tue Nov 15 18:51:10 2011 +0300
@@ -3,31 +3,31 @@

 void BinaryPrint( long n )
 {
-    // Частный случай - n равно нулю
+    unsigned long mask = 1 << (sizeof(n) * 8 - 1);
+
+    /* Пропускаем бесполезные нули слева */
+    int skipZero = 1;
+
+    /* Частный случай - n равно нулю */
     if (n == 0)
     {
         printf("0\n");
         return;
     }

-    unsigned long mask = 1 << (sizeof(n) * 8 - 1);
-
-    // Пропускаем бесполезные нули слева
-    int skipZero = 1;
-
     while (mask)
     {
-        // Определим текущий бит
+        /* Определим текущий бит */
         unsigned char c = (n & mask) ? 1 : 0;

-        // Отключим пропуск нулей в дальнейшем
+        /* Отключим пропуск нулей в дальнейшем */
         if (skipZero && c)
             skipZero = 0;

         if (!skipZero)
             printf("%d", c);

-        // Сдвинем маску на один бит вправо
+        /* Сдвинем маску на один бит вправо */
         mask >>= 1;
     }
     printf("\n");
[user@domain ~]# cc -Wall -Werror -pedantic RemoveDups.c
RemoveDups.c:8:5: error: C++ style comments are not allowed in ISO C90
RemoveDups.c:8:5: error: (this will be reported only once per input file)
cc1: warnings being treated as errors
RemoveDups.c: In function 'RemoveDups':
RemoveDups.c:16: warning: value computed is not used
RemoveDups.c:22: warning: value computed is not used
RemoveDups.c:24: warning: value computed is not used
diff -r afee20b80dff RemoveDups.c
--- a/RemoveDups.c      Tue Feb 22 09:11:12 2011 +0300
+++ b/RemoveDups.c      Tue Nov 15 18:56:00 2011 +0300
@@ -5,25 +5,25 @@
     const char * src = pStr;
     char * dst = pStr;

-    // Пока не дойдем до конца строки
+    /* Пока не дойдем до конца строки */
     while (*src)
     {
-        // Записываем в pStr текущий символ, если указатели разные
+        /* Записываем в pStr текущий символ, если указатели разные */
         if (dst != src)
             *dst = *src;

-        // Сдвигаем dst вправо
-        *dst++;
+        /* Сдвигаем dst вправо */
+        dst++;

-        // Пока не конец строки и следующий символ такой же
+        /* Пока не конец строки и следующий символ такой же */
         while ((*src + 1) && *(src + 1) == *src)
         {
-            // Сдвигаем указатель src вправо
-            *src++;
+            /* Сдвигаем указатель src вправо */
+            src++;
         }
-        *src++;
+        src++;
     }
-    // Запишем ноль в конец строки
+    /* Запишем ноль в конец строки */
     *dst = 0;
 }

Читайте также: «Вопросы программисту на собеседовании с ответами».

Личный блог Евгения Жирнова