<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SimpleCoding.org &#187; Web разработка</title>
	<atom:link href="http://www.simplecoding.org/category/web-razrabotka/feed" rel="self" type="application/rss+xml" />
	<link>http://www.simplecoding.org</link>
	<description>Блог о программировании</description>
	<lastBuildDate>Fri, 27 Jan 2012 18:27:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Yii фреймворк: создание XML-RPC сервера</title>
		<link>http://www.simplecoding.org/yii-frejmvork-sozdanie-xml-rpc-servera.html</link>
		<comments>http://www.simplecoding.org/yii-frejmvork-sozdanie-xml-rpc-servera.html#comments</comments>
		<pubDate>Sat, 24 Dec 2011 20:15:06 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1247</guid>
		<description><![CDATA[На мой взгляд, XML-RPC протокол является одним из наиболее удобных способов передачи данных между Интернет-ресурсами. Можно, конечно, поспорить, но на изучение XML-RPC требуется минимальное количество времени, есть множество готовых библиотек, да и используется он очень широко. Поэтому я никогда не понимал, почему разработчики отличного фреймворка Yii решили не включать библиотеку для работы с XML-RPC в [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1021" class="wp-caption alignnone" style="width: 272px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/03/yii_xml_rpc.png" alt="yii xml rpc" title="yii xml rpc" width="262" height="189" style="float:left" class="size-full wp-image-1021" /><p class="wp-caption-text"> </p></div>
<p>На мой взгляд, <strong>XML-RPC протокол</strong> является одним из наиболее удобных способов передачи данных между Интернет-ресурсами. Можно, конечно, поспорить, но на изучение XML-RPC требуется минимальное количество времени, есть множество готовых библиотек, да и используется он очень широко. Поэтому я никогда не понимал, почему разработчики отличного <a href="http://www.yiiframework.com">фреймворка Yii</a> решили не включать библиотеку для работы с XML-RPC в дистрибутив. Хотя, возможно, это вопрос времени <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Тем не менее, работать нужно уже сейчас, и в этой статье мы разберём, как решить проблему с помощью сторонних библиотек.</p>
<p><em>Примечание</em>. Если вас интересует создание XML-RPC клиента, почитайте статью <a href="http://www.simplecoding.org/xml-rpc-i-yii-frejmvork.html">XML-RPC и Yii фреймворк</a>.</p>
<h2>Немного теории.</h2>
<p>Мы можем использовать два основных подхода при создании <strong>XML-RPC сервера</strong>.</p>
<p><strong>1) Отдельный скрипт.</strong> В этом случае создаём файл с именем вроде xmlrpc.php и помещаем его в корень сайта. В нём будет находиться код обработки XML-RPC запросов. Такой подход используется, например, в WordPress. Достоинство в том, что вам не нужно вносить никаких изменений в код вашего проекта, т.е. XML-RPC интерфейс получается независимым. С другой стороны, независимость приводит к тому, что вам будет гораздо сложнее работать со встроенными библиотеками фреймворка.</p>
<p><strong>2) Использование действий контроллера.</strong> Этот вариант гораздо интереснее. Во-первых, вы автоматически получаете доступ ко всем возможностям Yii. Во-вторых, в этом случае XML-RPC методы можно разделить по модулям. Т.е. подключение / отключение модуля будет автоматически подключать / отключать соответствующие XML-RPC методы.<br />
<span id="more-1247"></span><br />
Т.к. реализация первого подхода никакой сложности не представляет (фактически вы можете использовать примеры из документации к вашей библиотеке для работы с XML-RPC), мы рассмотрим второй вариант.</p>
<h2>Какие библиотеки можно использовать?</h2>
<p>По большому счёту – любые, т.к. подключение сторонних библиотек к Yii выполняется без особых проблем. Я обычно использую библиотеку <a href="http://scripts.incutio.com/xmlrpc/manual.php">Incutio XML-RPC Library</a>. Она достаточно простая, работает без проблем и, кроме того, используется в WordPress, а эта CMS используется очень часто.</p>
<p>Переходим к практике.</p>
<h2>Шаг 1. Подключаем библиотеку.</h2>
<p>Для этого скачиваем библиотеку и сохраняем файл <code>IXR_Library.php</code> в папку <code>protected/vendors</code>. Теперь подключить библиотеку можно так:</p>
<pre class="brush: php">Yii::import('application.vendors.*');
require_once ('IXR_Library.php');</pre>
<p>Этот код можно добавить в любое действие (<code>action</code>) контроллера.</p>
<h2>Шаг 2. Создаём точку входа.</h2>
<p>Как я уже говорил, в качестве точки входа мы используем действие контроллера. Код будет выглядеть примерно так:</p>
<pre class="brush: php">class MyController extends Controller {
	...
	public function actionXmlrpc() {
		Yii::import('application.vendors.*');
		require_once ('IXR_Library.php');

		$server = new IXR_Server(array(
			'my.hello' =&gt; array($this,'hello'),
		));
	}
	...
}</pre>
<p>В этом методе мы просто создаём объект типа <code>IXR_Server</code>, конструктору которого нужно передать массив с названиями XML-RPC методов. В данном случае в массиве только один элемент. Ключ этого элемента является названием XML-RPC метода, а значение – именем функции, которую нужно вызвать.</p>
<p><code>array($this,'hello')</code> означает, что будет вызван метод <code>hello</code> данного контроллера.</p>
<p>Тут нужно помнить об одном нюансе. Обычно в XML-RPC запросах не передаются данные сессий. Логин и пароль отправляются в каждом запросе в качестве параметров. Поэтому необходимо, обеспечить доступ к методу <code>actionXmlrpc()</code> без авторизации. Для этого немного изменим метод <code>accessRules</code></p>
<pre class="brush: php">public function accessRules() {
	return array(
		array('allow',  // allow all users to perform 'index' and 'view' actions
			'actions'=&gt;array('index','view','xmlrpc'),
			'users'=&gt;array('*'),
		),
		…,
	);
}</pre>
<h2>Шаг 3. Добавляем методы.</h2>
<p>Теоретически, можно ограничиться просто добавлением метода <code>hello</code>, который просто вернет «Hello, world!».</p>
<pre class="brush: php">public function hello($args) {
	return 'Hello, world!';
}</pre>
<p>Но в 99% нужно аутентифицировать пользователя. Добавим метод</p>
<pre class="brush: php">protected function xmlrpcLogin($username, $password) {
	$identity = new UserIdentity($username, $password);
	$identity-&gt;authenticate();
	if ($identity-&gt;errorCode === UserIdentity::ERROR_NONE) {
		Yii::app()-&gt;user-&gt;login($identity, 0);
		return true;
	}
	else {
		return false;
	}
}</pre>
<p>Здесь мы используем класс <code>UserIdentity</code>, который автоматически создаётся фреймворком Yii при создании приложения. В параметрах этого метода нужно передать логин и пароль. В случае успешной аутентификации метод вернёт TRUE, в противном случае – FALSE. Кроме того, данные пользователя будут доступны через Yii::app()-&gt;user, т.е. точно также как и при обычной работе с фреймворком.</p>
<p>Теперь перепишем код метода hello.</p>
<pre class="brush: php">public function hello($args) {
	if (!$this-&gt;xmlrpcLogin($args[0], $args[1])) {
		return new IXR_Error(-1, 'You did not provide the correct password');
	}
return 'Hello, world!';
}</pre>
<p>Здесь предполагается, что логин и пароль будут переданы в первом и втором параметрах XML-RPC запроса.</p>
<h2>Шаг 4. Проверяем работу.</h2>
<p>Для проверки достаточно создать обычный PHP скрипт со следующим кодом.</p>
<pre class="brush: php">require_once ('IXR_Library.php');

$client = new IXR_Client('http://my_site.domen/my/xmlrpc');
$client-&gt;debug = true;

$args = array();
$args[0] = 'login';
$args[1] = 'password';

if (!$client-&gt;query('my.hello', $args)) {
    die('Something went wrong - '.$client-&gt;getErrorCode().' : '.$client-&gt;getErrorMessage());
}
echo $client-&gt;getResponse();</pre>
<p>Как видите, создание XML-RPC сервера особой сложности не представляет. Конечно, самая сложная работа – это написание самих методов. Но не забывайте, что если у вас уже готов web интерфейс и логика по максимуму вынесена в модели, то вы сможете спокойно использовать её и в XML-RPC методах.</p>
<p><strong>Успехов!</strong></p>
<p><em>Полезная информация</em></p>
<p>Новогодний подарок от Inferno Solutions &#8211; всем новым клиентам панель ISP бесплатно и 30$ в подарок при заказе <a href="https://cp.inferno.name/cart.php">VPS в Германии</a>, Украине или Голландии! Укажите при заказе в примечании ISP+30.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/yii-frejmvork-sozdanie-xml-rpc-servera.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress: публикация постов с помощью XML-RPC с поддержкой таксономий</title>
		<link>http://www.simplecoding.org/wordpress-publikaciya-postov-s-pomoshhyu-xml-rpc-s-podderzhkoj-taksonomij.html</link>
		<comments>http://www.simplecoding.org/wordpress-publikaciya-postov-s-pomoshhyu-xml-rpc-s-podderzhkoj-taksonomij.html#comments</comments>
		<pubDate>Tue, 11 Oct 2011 08:02:30 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1229</guid>
		<description><![CDATA[WordPress на сегодняшний день является одой из самых популярных CMS и последнее время активно развивается. Но, к сожалению, это развитие не всегда получается гармоничным. Одной из возможностей, которая почему-то по возможностям постоянно отстаёт от остальной части движка, является XML-RPC. На сегодняшний день этот протокол является основным средством удалённой публикации постов. И, при этом, он фактически [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1230" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/10/wordpress-xml-rpc-publish.png" alt="wordpress xml-rpc publish" title="wordpress xml-rpc publish" width="300" height="239" class="size-full wp-image-1230" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>WordPress</strong> на сегодняшний день является одой из самых популярных CMS и последнее время активно развивается. Но, к сожалению, это развитие не всегда получается гармоничным.</p>
<p>Одной из возможностей, которая почему-то по возможностям постоянно отстаёт от остальной части движка, является <strong>XML-RPC</strong>. На сегодняшний день этот протокол является основным средством удалённой публикации постов. И, при этом, он фактически бесполезен если вы используете произвольные типы записей (custom post types) и таксономии (custom taxonomies). Ни один XML-RPC метод публикации постов в WP 3.2.1 их не поддерживает.</p>
<p>Конечно, можно надеятся, что в будущих версиях ситуация изменится в лучшую сторону, но ничто не мешает добавить нужные методы прямо сейчас.</p>
<p>Рассмотрим небольшой пример.<br />
<span id="more-1229"></span><br />
Допустим, нам нужно <strong>публиковать посты произвольного типа через XML-RPC и связывать их с таксономиями</strong>. При этом, таксономии могут быть как иерархическими, так и плоскими.</p>
<p><em>Примечание</em>. Подробнее о типах постов и таксономиях рассказано в статьях: <a href="http://www.simplecoding.org/wordpress-vyvod-zapisej-proizvolnyx-tipov-custom-post-types.html">WordPress: вывод записей произвольных типов (Custom Post Types)</a> и <a href="http://www.simplecoding.org/upravlenie-kontentom-v-wordpress-cms-situaciya-na-segodnya-i-blizhajshaya-perspektiva.html">Управление контентом в WordPress CMS: ситуация на сегодня и ближайшая перспектива</a>.</p>
<h2>Немного теории</h2>
<p>В WordPress предусмотрен фильтр (<code>xmlrpc_methods</code>), позволяющий добавлять новые методы во встроенный XML-RPC сервер. Делается это следующим образом:</p>
<pre class="brush: php">add_filter('xmlrpc_methods', 'add_xml_rpc_methods');</pre>
<p>Во втором параметре фильтра указываем имя функции, которая создаст запись в глобальном массиве XML-RPC методов.</p>
<pre class="brush: php">function add_xml_rpc_methods($methods) {
	$methods['my.my_method_name'] = 'my_method_name';
	return $methods;
}

function my_method_name($args) {
//обработка XML-RPC запроса и отправка ответа
}</pre>
<p>Чтобы создать XML-RPC метод нужно добавить новый элемент в массив <code>$methods</code>. Ключ этого элемента является именем метода, а значение – именем функции, которая выполняет обработку XML-RPC запроса и формирует ответ.</p>
<h2>Реализация: XML-RPC клиент</h2>
<p>Начнём с кода, который отправляет XML-RPC запрос. В данном случае будем использовать библиотеку <a href="http://scripts.incutio.com/xmlrpc/">The Incutio XML-RPC Library</a> (она же используется и в WordPress).</p>
<pre class="brush: php">require_once ('IXR_Library.php');

$client = new IXR_Client('http://my_blog.com/xmlrpc.php');
$client-&gt;timeout = 60000;

$requestData[0] = 0; //id блога
$requestData[1] = 'admin'; //имя пользователя
$requestData[2] = 'pass'; //пароль

$post = array();

$post['post_title'] = 'New Post';
$post['post_excerpt'] = 'Short description';
$post['post_content'] = 'This story about ...';
$post['post_status'] = 'draft';
$post['post_type'] = 'my_custom_post_type'; //тип поста
$post['post_date'] = date('Y-m-d H:i:s');
$post['post_modified'] = date('Y-m-d H:i:s');

//формируем массив с терминами таксономий
$terms = array();
$terms['taxonomy_1'][] = (int)$term['term_id_1'];
$terms['taxonomy_1'][] = (int)$term['term_id_2'];
$terms['taxonomy_2'][] = (int)$term['term_id_3'];
$terms['taxonomy_3'][] = (int)$term['term_id_4'];

$post['tax_input'] = $terms;

$requestData[3] = $post;

if (!$client-&gt;query('my.publish_post', $requestData)) {
	echo 'Publish Post error: '.$client-&gt;getErrorMessage();
	return;
}

$publishedPost = $client-&gt;getResponse();</pre>
<p>Прежде всего, создаём объект <code>IXR_Client</code>, конструктору которого передаём адрес скрипт, который выполняет обработку XML-RPC запросов (xmlrpc.php).</p>
<p>Затем формируем массив с данными для публикации поста. В первых трёх элементах указываем: <code>id</code> блога (на данный момент не используется), логин и пароль. В четвертом элементе – массив с данными нового поста.</p>
<p>Чтобы сократить количество кода на стороне XML-RPC сервера, названия полей этого массива должны совпадать с полями массива, который передаётся функции <a href="http://codex.wordpress.org/Function_Reference/wp_insert_post">wp_insert_post</a>. Кстати, большинство ключей элементов этого массива совпадает с именами полей таблицы posts базы данных.</p>
<p>Обратите внимание на параметр</p>
<pre class="brush: php">$post['post_type'] = 'my_custom_post_type'; //тип поста</pre>
<p>В нём указан тип поста, который мы хотим создать. Естественно, этот тип должен быть <a href="http://codex.wordpress.org/Function_Reference/register_post_type">заранее создан</a>.</p>
<p><strong>Отдельно остановимся на таксономиях.</strong></p>
<p>WordPress поддерживает таксономии 2-х типов: иерархические и плоские. Чтобы связать пост с терминами таксономий нужно перечислить их в элементе tax_input массива, который передаётся функции <code>wp_insert_post</code>. Например, так:</p>
<pre class="brush: php">'tax_input' =&gt; array('taxonomy_1' =&gt; array('term', 'term2', 'term3'), 'taxonomy_2' =&gt; array('term1', 'term2'))</pre>
<p>Здесь <code>taxonomy_1</code>, <code>taxonomy_2</code> – имена таксономий, а <code>term</code>, <code>term1</code> и т.д. – имена терминов.</p>
<p>Но здесь есть нюансы. Если публикуется «плоская» таксономия, то можно указать, либо имя термина, либо его <code>id</code>. При этом, <code>id</code> должен иметь тип <code>int</code>, если <code>id</code> сохранён в виде строки, то WordPress просто создаст новый термин. Для иерархических таксономий можно использовать только <code>id</code> термина (при этом нет ограничения на тип значения, оно будет автоматически приведено к типу <code>int</code>).</p>
<p>Т.е. универсальный вариант установки таксономий выглядит так:</p>
<pre class="brush: php">$terms['taxonomy_1'][] = (int)$term['term_id_1'];
$terms['taxonomy_1'][] = (int)$term['term_id_2'];
$terms['taxonomy_2'][] = (int)$term['term_id_3'];
$terms['taxonomy_3'][] = (int)$term['term_id_4'];</pre>
<p>Отправка запроса выполняется с помощью метода query, а прочитать результат можно используя <code>getResponse</code>.</p>
<h2>XML-RPC сервер</h2>
<p>На серверной стороне нужно зарегистрировать новый XML-RPC метод и написать функцию, которая будет обрабатывать запрос, и возвращать результат.</p>
<p><em>Примечание</em>. Следующий код можно добавить в плагин или в файл functions.php темы.</p>
<pre class="brush: php">add_filter('xmlrpc_methods', 'add_xml_rpc_methods' );

function add_xml_rpc_methods($methods) {
	$methods['my.publish_post'] = 'my_publish_post';
	return $methods;
}

function my_publish_post($args) {
	$blog_id = (int) $args[0];
	$username = $args[1];
	$password = $args[2];
	$post_data  = $args[3];

	if ( !get_option( 'enable_xmlrpc' ) ) {
		return new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.  An admin user can enable them at %s'),  admin_url('options-writing.php') ) );
	}

	$user = wp_authenticate($username, $password);

	if (is_wp_error($user)) {
		return new IXR_Error(403, __('Bad login/pass combination.'));
	}

	wp_set_current_user( $user-&gt;ID );

	if ( !current_user_can( 'edit_private_posts' ) ) {
		return new IXR_Error( 401, __( 'Sorry, you cannot edit private posts.' ) );
	}

	if (!is_array($post_data)) {
		return new IXR_Error( 401, __( 'Sorry, no post data not found.' ) );
	}

	$id = wp_insert_post( $post_data );

	if ($id === 0) {
		return new IXR_Error( 401, __( 'Post save error.' ) );
	}

	$post = array();
	$post['id'] = $id;
	$post['permalink'] = get_permalink($id);

	return $post;
}</pre>
<p>Здесь мы регистрируем XML-RPC метод <code>my.publish_post</code> и указываем, что при обращении к нему WordPress должен вызвать функцию <code>my_publish_post</code>.</p>
<p>Большая часть кода в этой функции совпадает с большинством обработчиков стандартных XML-RPC методов WP. Собственно он оттуда и скопирован <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  . Этот код проверяет, разрешен ли XML-RPC для данного блога (строки 14-16, кстати, не забудьте его включить в админке на странице Settings -&gt; Writing), аутентифицирует пользователя и проверяет, достаточно ли у него прав для публикации поста.</p>
<p>Сама публикация выполняется с помощью всего одной функции <code>wp_insert_post</code> (строка 34).</p>
<p>Клиенту возвращаем <code>id</code> созданного поста и постоянную ссылку на него (формируем с помощью функции get_permalink).</p>
<h2>Заключение</h2>
<p>Как видите, принцип достаточно простой. Любую встроенную функцию WP можно вызвать через XML-RPC протокол и использовать все возможности движка при удалённой публикации постов.</p>
<p>Если есть вопросы или замечания, пишите, постараюсь ответить.</p>
<p><strong>Успехов!</strong></p>
<p>Интересные ссылки</p>
<p>Закажите <a href="http://printfotobook.ru">печать фотокниг</a> тремя способами: онлайн, в офисе или вип</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/wordpress-publikaciya-postov-s-pomoshhyu-xml-rpc-s-podderzhkoj-taksonomij.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>jQuery: обработка параметров URL</title>
		<link>http://www.simplecoding.org/jquery-obrabotka-parametrov-url.html</link>
		<comments>http://www.simplecoding.org/jquery-obrabotka-parametrov-url.html#comments</comments>
		<pubDate>Fri, 19 Aug 2011 07:45:55 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1225</guid>
		<description><![CDATA[Приветствую всех! Сегодня хочу показать небольшой пример использования библиотеки jQuery для работы с параметрами ссылок. Предположим на нашей странице есть ссылка, клик по которой отправляет запрос на выполнение некоторой операции. Пускай это будет удаление какого-нибудь объекта. HTML разметка такой ссылки может выглядеть следующим образом. &#60;a class="delete" href="http://www.simplecoding.org/script.php?action=delete_object&#38;object_id=1"&#62;Удалить&#60;/a&#62; Как видите, ссылка содержит два параметра (action и [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1226" class="wp-caption alignnone" style="width: 299px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/08/jquery_parsequery.png" alt="jquery parsequery" title="jquery parsequery" width="289" height="152" class="size-full wp-image-1226" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех!</strong></p>
<p>Сегодня хочу показать небольшой пример использования библиотеки <strong>jQuery</strong> для работы с параметрами ссылок.</p>
<p>Предположим на нашей странице есть ссылка, клик по которой отправляет запрос на выполнение некоторой операции. Пускай это будет удаление какого-нибудь объекта.</p>
<p><strong>HTML разметка</strong> такой ссылки может выглядеть следующим образом.</p>
<pre class="brush: html">&lt;a class="delete" href="http://www.simplecoding.org/script.php?action=delete_object&amp;object_id=1"&gt;Удалить&lt;/a&gt;</pre>
<p>Как видите, ссылка содержит два параметра (<code>action</code> и <code>object_id</code>), значения которых PHP скрипт сможет получить из массива <code>$_GET</code>.</p>
<p>Теперь, мы хотим выполнить удаление объекта с помощью <strong>AJAX запроса</strong>. Изменять ради него ссылку нет никакой необходимости. Просто назначаем обработчик для события <code>click</code>.<br />
<span id="more-1225"></span></p>
<pre class="brush: javascript">$('a.delete').click(function() {
  return false;
});</pre>
<p>Этот код блокирует отправку обычного запроса при клике по ссылке. Нам нужно <strong>получить параметры и отправить AJAX запрос</strong>.</p>
<p>В обработчике события <strong>click</strong> получить значение атрибута <strong>href</strong> ссылки можно следующим образом.</p>
<pre class="brush: javascript">$(this).attr('href')</pre>
<p>Затем нужно найти в этой строке параметры. Тут есть <strong>два варианта</strong>.</p>
<p>1) Если вам достаточно параметров, указанных в атрибуте <strong>href</strong> и вы не хотите их изменять, то просто передать методам <code>$.ajax</code> (или <code>$.post</code>, или <code>$.get</code>) строку с параметрами запроса.</p>
<p>Т.е. код будет выглядеть примерно так</p>
<pre class="brush: javascript">var params = $(this).attr('href').split('?');
$.post('ajax_delete.php', params[1], function(response) {
    console.log(response);
} );</pre>
<p>Здесь мы с помощью метода <code>split</code> разбили запрос на две части (по знаку вопроса), и передали методу <code>$.post</code> второй элемент массива <code>params</code>. Для данного примера он выглядит так<br />
<code>action=delete_object&amp;object_id=1</code></p>
<p>2) Если перед отправкой AJAX запроса нужно изменить/удалить/добавить какие-то параметры, то удобнее всего преобразовать строку с параметрами в хеш.</p>
<p>Для этих целей существует специальный плагин – <a href="http://plugins.jquery.com/project/parseQuery">parseQuery</a></p>
<p>Использовать его можно так.</p>
<pre class="brush: javascript">var params = $.parseQuery($( this ).attr( 'href' ).split('?'));</pre>
<p>В результате вы получите хеш</p>
<pre class="brush: javascript">{
	action: delete_object,
	object_id: 1
}</pre>
<p>Код отправки AJAX запроса при этом не изменяется. Точно также передаёте переменную <code>params</code> во втором параметре метода <code>$.post</code>.</p>
<p>В заключение посмотрите код обработчика целиком.</p>
<pre class="brush: javascript">$(document).ready(function() {
	$('a.delete').click( function() {
		var params = $(this).attr('href').split('?');
		$.post('ajax_delete.php', params[1], function(response) {
			console.log(response);
		});
		return false;
	});
});</pre>
<p>Как видите, задача решается с помощью минимального количества кода. И если у посетителя будет отключен JavaScript, то ничего особенного не произойдет. При кликах по ссылкам будут отправляться обычные запросы.</p>
<p>Если есть вопросы или замечания, пишите.</p>
<p><strong>Успехов!</strong></p>
<p><em>Интересно почитать</em></p>
<p>Платежный модуль <a href="http://www.rugento.ru/robokassa-payment-module.html" target="_blank">Robokassa для Magento</a> с поддержкой.</p>
<p>Нужна фотокнига? В наличие <a href="http://printfotobook.ru/primery_fotoknig">фотокниги образцы</a>, множество видов дизайна и верстки</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/jquery-obrabotka-parametrov-url.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>HTML5: загрузка файлов с помощью Drag &amp; Drop</title>
		<link>http://www.simplecoding.org/html5-zagruzka-fajlov-s-pomoshhyu-drag-drop.html</link>
		<comments>http://www.simplecoding.org/html5-zagruzka-fajlov-s-pomoshhyu-drag-drop.html#comments</comments>
		<pubDate>Thu, 21 Jul 2011 13:13:41 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1222</guid>
		<description><![CDATA[Приветствую всех! В этой статье хочу рассказать о нескольких своих экспериментах с HTML5. Начну издалека. Всем нам периодически приходится работать с различными web интерфейсами и часто возникает ощущение, что эта работа могла бы быть организована более эффективно. Возможно, в каких-то случаях виноваты разработчики сервиса, но часто проблема заключается в ограничениях, которые накладывают браузеры. Рассмотрим загрузку [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1223" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/07/html5_drag_drop_upload.png" alt="html5 drag&amp;drop upload" title="html5 drag&amp;drop upload" width="300" height="186" class="size-full wp-image-1223" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех!</strong></p>
<p>В этой статье хочу рассказать о нескольких своих экспериментах с HTML5. Начну издалека. Всем нам периодически приходится работать с различными web интерфейсами и часто возникает ощущение, что эта работа могла бы быть организована более эффективно.</p>
<p>Возможно, в каких-то случаях виноваты разработчики сервиса, но часто проблема заключается в ограничениях, которые накладывают браузеры. Рассмотрим загрузку файлов на сервер. В большинстве случаев вам предложат стандартное поле с кнопкой выбора файла с вашего компьютера и/или поле, в котором можно указать URL файла, размещенного где-нибудь в Сети.</p>
<p>Загрузку файлов с локального компьютера трогать пока не будем, я планирую опубликовать отдельный пост на эту тему, разберем загрузку с удалённого сервера.</p>
<p>Проблемы начинаются с первого же шага. Даже если вы четко понимаете, где искать URL и хорошо умеете пользоваться инструментами вроде <strong>firebug</strong>, то всё равно потребуется несколько кликов мышкой чтобы получить нужный адрес. Было бы гораздо удобнее просто перетянуть нужную картинку из одного окна браузера в другое.<br />
<span id="more-1222"></span><br />
Пример реализации такого интерфейса я покажу в этой статье. Если хотите, можете посмотреть, как он работает на демонстрационной страничке или скачать архив с исходниками.</p>
<p><a href="http://demosites.simplecoding.org/images-upload/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a><a href='http://www.simplecoding.org/wp-content/uploads/2011/07/images-upload.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p><strong>Обратите внимание!</strong> Данный пример работает только в браузере <strong>Google Chrome</strong>. По-идее, поддержка всех необходимых технологий есть в <strong>Firefox</strong> и <strong>Safari</strong>, но с ними я пока не разбирался.<br />
В качестве объектов для «перетягивания» я брал в основном картинки с википедии. Было замечено несколько проблем связанных с не латинскими символами в URL картинок, но чтобы не перегружать пример проверками и преобразованиями я их оставил как есть.</p>
<h2>Принцип работы</h2>
<p>Стандарт HTML5 предусматривает поддержку «перетягивания» объектов страницы (Drag and Drop). Кстати, пример простейшей реализации D&#038;D я уже показывал – <a href="http://www.simplecoding.org/drag-drop-s-ispolzovaniem-html5.html">Drag &#038; Drop с использованием HTML5</a>. И, кроме того, есть довольно много JavaScript библиотек, реализующих поддержку D&#038;D.</p>
<p>Но тут важно понимать, что если необходимо «перетягивать» картинки со сторонних ресурсов, то использовать библиотеки не получится. Т.к. вы не сможете добавить свой JS код на чужую страницу. А для того, чтобы загрузить картинку, нам нужно получить её URL, т.е. браузер должен вместе с перетягиваемым объектом передавать и его параметры (например, атрибут src картинки или весь тег img).</p>
<p>В этом случае мы можем создать на своей странице «приёмник» картинок. Это будет обычный <code>div</code> которому назначен обработчик события <code>drop</code>. Если пользователь «сбросит» картинку над этим div&#039;ом, то будет вызван обработчик и в первом параметре он получит объект, содержащий информацию о перетягиваемой картинке.</p>
<p>Дальше всё достаточно просто. Если мы получили нужный URL, то можно отправить AJAX-запрос серверному скрипту, который выполнит загрузку файла.</p>
<h2>Реализация</h2>
<p>Начнём со страницы нашего приложения.</p>
<pre class="brush: html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
        &lt;title&gt;Images Upload&lt;/title&gt;
		&lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt;
    &lt;/head&gt;
    &lt;body&gt;
		&lt;div id="images"&gt;&lt;/div&gt;
		&lt;div id="img_target"&gt;&lt;/div&gt;
		&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"&gt;&lt;/script&gt;
		&lt;script src="main.js"&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre>
<p>На ней размещены два блока: <code>images</code> – здесь будем показывать загруженные изображения и <code>img_target</code> – на этот блок нужно перетягивать картинки.</p>
<p>Внизу страницы подключаем библиотеку jQuery и скрипт main.js, который будет отправлять информацию о перетянутых изображениях на сервер.</p>
<p><strong>Рассмотрим main.js</strong></p>
<pre class="brush: javascript">$(function() {
    $('#img_target')
        .bind('dragenter', function(event) {
            $(this).addClass('drop_here');
            return false;
        })
        .bind('dragleave', function(event) {
            $(this).removeClass('drop_here');
            return false;
        })
        .bind('dragover', function(event) {
            return false;
        })
        .bind('drop', function(event) {
            $(this).removeClass('drop_here');
			var srcRegex = /src=\"([^\s]+)\"/ig;
            var data = event.originalEvent.dataTransfer.getData('text/html');
			var img_data = srcRegex.exec(data);
			$.post('upload.php', {'file_url':img_data[1]}, function(res) {
				var response = eval('(' + res + ')');
				$('#images').append($('&lt;img src="' + response.file_url + '" /&gt;'));
			});
            return true;
        });
});</pre>
<p>Здесь мы назначаем обработчики событиям <code>dragenter</code>, <code>dragleave</code> и <code>dragover</code>. Все они должны просто возвращать false и, чтобы как-то проинформировать пользователя о том, что можно «сбрасывать» картинку, в обработчике <code>dragenter</code> устанавливаем CSS класс <code>drop_here</code> для блока-приёмника.</p>
<p>Основная часть работы выполняется в обработчике события <code>drop</code>. При возникновении этого события мы читаем информацию о «сброшенном» объекте и «вырезаем» значение атрибута <code>src</code>, т.е. URL картинки (строки 16-18). Информация передается в объекте event.originalEvent.dataTransfer (строка 17).</p>
<p>Затем <strong>формируем обычный AJAX запрос</strong> и в качестве параметра передаём ему найденный URL.</p>
<p>Серверный скрипт (upload.php) получит URL изображения на удалённом сервере и загрузит его. А в ответе на AJAX запрос он отправит новый URL загруженной картинки.</p>
<p>В свою очередь, обработчик AJAX-запроса создаст тег <code>img</code> и вставит его в блок <code>images</code>. Таким образом, загруженные картинки будут появляться над полем загрузки.</p>
<p><strong>Рассмотрим upload.php</strong></p>
<pre class="brush: php">&lt;?php

define('BASE_URL', 'http://localhost/tests/images-upload/');

function upload_from_url($file_url) {
	$url_segments = explode('/', $file_url);
	$file_name = urldecode(end($url_segments));
	if (false !== $file_name) {
		$file_name_parts = explode('.', $file_name);
		if (in_array(strtolower(end($file_name_parts)), array('jpeg','jpg','png','gif'))) {
			$destination=fopen("upload/".$file_name,"w");
			$source=fopen($file_url,"r");
			$maxsize=300*1024;
			$length=0;
			while (($a=fread($source,1024))&#038;&#038;($length&lt;$maxsize)) {
				$length=$length+1024;
				fwrite($destination,$a);
			}
			fclose($source);
			fclose($destination);
		}
	}
	$new_file_url = BASE_URL.'upload/'.$file_name;
	return $new_file_url;
}

$res = array('err' =&gt; 'Не указан URL файла');

if (isset($_POST['file_url'])) {
	$new_url = upload_from_url($_POST['file_url']);
	$res = array('file_url' =&gt; $new_url);
}

echo json_encode($res);</pre>
<p>Принцип работы следующий. Читаем URL картинки и пытаемся её загрузить (строки 29-32).</p>
<p>Если картинка загружена, сохраняем её в папку <code>upload</code>. Получение картинки с удалённого сервера осуществляется с помощью функций <code>fread</code>. Файл читаем блоками по 1кБ (строки 15-18). Такой подход позволяет прервать загрузку файла, если его размер превышает заданный предел (в данном случае 300кБ).</p>
<p>После загрузки файла формируем для него URL и отправляем браузеру в формате <strong>JSON</strong>.</p>
<p>Как видите, реализовать такой загрузчик несложно. И пользоваться им достаточно удобно. Естественно, основным недостатком является поддержка HTML5 браузерами, точнее её отсутствие <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Тем не менее, если вы создаёте интерфейс для сотрудников какой-нибудь компании, и можете оговорить тип браузера, то HTML5 вполне можно использовать.</p>
<p><strong>Успехов!</strong></p>
<p><em>Интересно почитать.</em></p>
<p>Фотокнига — фантастический <a href="http://imagebook.ru/sjurpriz_ljubimomu_muzhchine">сюрприз для любимого мужчины</a>. Попробуйте сами!</p>
<p>Правильно подготовим <a href="http://online-nalogi.ru/3_ndfl_pokupka_kvartiry">3-ндфл при покупке квартиры за 2011 год</a>, дадим инструкции для получения вычета</p>
<p>Нужно распарсить сайт? Интересный пример как написан <a href="http://www.sergunik.name/?p=140" title="php parser">парсер на php</a>. Можно даже скачать скрипт парсера.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/html5-zagruzka-fajlov-s-pomoshhyu-drag-drop.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Как показать на Google Maps объекты, находящиеся в заданной области</title>
		<link>http://www.simplecoding.org/kak-pokazat-na-google-maps-obekty-naxodyashhiesya-v-zadannoj-oblasti.html</link>
		<comments>http://www.simplecoding.org/kak-pokazat-na-google-maps-obekty-naxodyashhiesya-v-zadannoj-oblasti.html#comments</comments>
		<pubDate>Tue, 28 Jun 2011 09:48:03 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1214</guid>
		<description><![CDATA[Показать пример решения такой задачи меня попросили в комментариях к одной из предыдущих статей о Google Maps. С выполнением этой просьбы я довольно сильно затянул, но, надеюсь, эта статья кому-нибудь пригодится Начнём с постановки задачи Предположим, у нас есть данные о группе объектов (их названия и координаты). Необходимо отметить их на карте с помощью маркеров. [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1215" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/06/google_maps.png" alt="google maps" title="google maps" width="300" height="197" style="float:left" class="size-full wp-image-1215" /><p class="wp-caption-text"> </p></div>
<p>Показать пример решения такой задачи меня попросили в комментариях к одной из предыдущих статей о <strong>Google Maps</strong>. С выполнением этой просьбы я довольно сильно затянул, но, надеюсь, эта статья кому-нибудь пригодится <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Начнём с постановки задачи</strong></p>
<p>Предположим, у нас есть данные о группе объектов (их названия и координаты). Необходимо отметить их на карте с помощью маркеров. При этом, показать нужно не все объекты, а только те, которые находятся внутри заданной области.</p>
<p>Будем считать, что заданная область представляет собой окружность, т.е. мы знаем координаты её центра и радиус. А координаты объектов находятся в KML файле (это XML формат, разработанный для описания объектов на Google maps).<br />
<span id="more-1214"></span><br />
Таким образом, <strong>алгоритм расстановки объектов</strong> получается довольно простым.</p>
<p>1) Читаем координаты объекта из KML файла.<br />
2) Рассчитываем расстоянием между центром окружности и текущим объектом.<br />
3) Если это расстояние меньше радиуса окружности, ставим маркер, если больше – пропускаем объект.</p>
<p>Переходим к решению.</p>
<p>Посмотреть, как работает этот пример, можно на демонстрационной страничке или установив скрипты на своем сервере.</p>
<p><a href="http://demosites.simplecoding.org/google-maps/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a> <a href='http://www.simplecoding.org/wp-content/uploads/2011/06/google_maps.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<h2>Серверная часть</h2>
<p>Начнем с серверного скрипта, который формирует страницу с картой (index.php).</p>
<pre class="brush: php">&lt;?php
$organizations = simplexml_load_file('doc.kml');

$organizations_data = array();

foreach ($organizations-&gt;Folder-&gt;Placemark as $organisation) {
    $organizations_data[] = array(
        'name' =&gt; (string)$organisation-&gt;name,
        'coordinates' =&gt; (string)$organisation-&gt;Point-&gt;coordinates,
    );
}
?&gt;

&lt;!DOCTYPE html&gt;

&lt;html&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;title&gt;Объекты на Google Maps&lt;/title&gt;
    &lt;script&gt;
&lt;?php
    echo 'var organizations = '.json_encode($organizations_data).';';
?&gt;
    &lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;

&lt;h1&gt;Google Maps: отображение объектов, которые находятся в заданной области&lt;/h1&gt;

&lt;div id="my_map" style="width:600px;height:400px"&gt;&lt;/div&gt;

&lt;script src="main.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Прежде всего, загружаем данные из KML файла (строка 2). Т.к. это обычный XML файл, то мы можем использовать любую библиотеку для работы с этим форматом. В данном случае – <a href="http://php.net/manual/en/book.simplexml.php">SimpleXML</a>.</p>
<p>Затем, необходимо обеспечить доступ к этим данным на клиентской стороне, т.к. настройка Google Maps выполняется с помощью <strong>JavaScript</strong>.</p>
<p>Для этого мы формируем массив с необходимыми данными (строки 6-11), преобразовываем его в <strong>JSON</strong> формат (строка 22) и присваиваем переменной <code>organizations</code> (строка 22) в теге <code>script</code>. Таким образом, мы получаем <strong>JavaScript массив</strong> с координатами всех объектов из KML файла.</p>
<p>Тут я хочу сделать небольшое отступление. В принципе, работать с KML файлом можно и на стороне браузера, это несложно. Но в общем случае, этот файл не обязательно будет находиться на вашем сервере, а кросс-доменные (XSS) запросы запрещены политикой безопасности браузеров. Т.е. придётся искать какой-нибудь обходной путь. Подробнее на эту тему можно почитать <a href="http://www.simplecoding.org/kak-obojti-zapret-na-xss.html">здесь</a>, <a href="http://www.simplecoding.org/xss-i-same-origin-policy.html">здесь</a>, <a href="http://www.simplecoding.org/xss-s-ispolzovaniem-jsonp-i-jquery.html">здесь</a> и <a href="http://www.simplecoding.org/javascript-xss-poluchenie-dannyx-ot-facebook-i-vkontakte.html">здесь</a>.</p>
<p>Подробно разбирать работу с <strong>SimpleXML</strong>, думаю, смысла не имеет. Для данного примера достаточно понимать, что после загрузки файла вы получите объект, имеющий такую же структуру как и xml-документ.</p>
<p>Т.е. вызов <code>$organizations-&gt;Folder-&gt;Placemark</code> вернет вам содержимое тега <code>&lt;Placemark&gt;</code> в документе с такой структурой</p>
<pre class="brush: xml">&lt;kml xmlns="…" xmlns:kml="…" xmlns:atom="…"&gt;
&lt;Folder&gt;
	&lt;Placemark&gt;
	…
	&lt;/Placemark&gt;
&lt;/Folder&gt;
&lt;/kml&gt;</pre>
<p><em>Обратите внимание!</em> Библиотека чувствительна к регистру тегов в xml-файле.</p>
<p>На самой странице мы создаём блок для карты (<code>my_map</code>).</p>
<p>И подключаем файл main.js, который и будет выполнять настройку карты.</p>
<h2>Клиентская часть</h2>
<p>Сразу посмотрим на весь скрипт целиком.</p>
<pre class="brush: javascript">var map, circle, circleOptions, setCenter, marker, organizations_markers;

function initialize() {
    var centerPoint = new google.maps.LatLng(48.67, 44.47); //Волгоград
    var myOptions = {
        zoom: 12,
        center: centerPoint,
        mapTypeId: google.maps.MapTypeId.HYBRID
    }
    map = new google.maps.Map(document.getElementById("my_map"), myOptions);

    //радиус окружности - 5 км
    var radius = 5;

    circleOptions = {
        center: centerPoint,
        fillColor: "#00AAFF",
        fillOpacity: 0.5,
        strokeColor: "#FFAA00",
        strokeOpacity: 0.8,
        strokeWeight: 2,
        clickable: false,
        radius: radius*1000
    }

    //рисуем окружность
    circle = new google.maps.Circle(circleOptions);
    circle.setMap(map);

    //устанавливаем маркеры организаций
    organizations_markers = [];
    for (var i = 0; i &lt; organizations.length; i++) {
        var ll = organizations[i].coordinates.split(',');
        var latlng = new google.maps.LatLng(ll[1], ll[0]);
        if (distHaversine(latlng, centerPoint) &lt; radius) {
            organizations_markers[i] = new google.maps.Marker({
                    position:latlng,
                    clickable:true
                });
            organizations_markers[i].setMap(map);
        }
    }
}

function loadScript() {
    var script = document.createElement("script");
    script.src = "http://maps.google.com/maps/api/js?sensor=false&#038;callback=initialize";
    document.body.appendChild(script);
}

rad = function(x) {return x*Math.PI/180;}

//эта функция используются для определения расстояния между точками на
//поверхности Земли, заданных с помощью географических координат
//результат возвращается в км
distHaversine = function(p1, p2) {
    var R = 6371; // earth's mean radius in km
    var dLat  = rad(p2.lat() - p1.lat());
    var dLong = rad(p2.lng() - p1.lng());

    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d = R * c;

    return d.toFixed(3);
}

window.onload = loadScript;</pre>
<p>В первую очередь мы создаём карту и устанавливаем её основные параметры (координаты центра, приближение). Для этого, назначаем обработчик событию <code>window.onload</code> (строка 69). Этот обработчик добавляет на страницу тег <code>script</code> в параметре <code>src</code> которого передается адрес имя метода, который будет вызван после загрузки Google Maps (в данном случае &#8211; <code>initialize</code>). Таким образом, все наши настройки выполняются в этом методе.</p>
<p>Выполняем установку параметров карты (строки 4-10). Мы указали: центральную точку (<code>centerPoint</code>), приближение (<code>zoom</code>) и тип карты (<code>mapTypeId</code>).</p>
<p>Теперь рисуем окружность (строки 13-28). Её центр совпадает с центром карты, а радиус равен 5 км. В настройках окружности указываем толщину и цвет линии, цвет и прозрачность фона и другие параметры.</p>
<p>После этого <strong>расставляем маркеры объектов</strong>.</p>
<p>Напомню, что координаты этих объектов находятся в массиве organizations, который был сформирован серверным скриптом.</p>
<p>Т.е. нам нужно пройтись по всем элементам этого массива и рассчитать расстояние от центра окружности до текущего объекта (строки 31-42).</p>
<p>Расчет расстояний для точек на поверхности Земли выполняется с помощью функции гаверсинусов (<code>distHaversine</code>). Её реализацию на JavaScript я взял <a href="http://stackoverflow.com/questions/1502590/calculate-distance-between-two-points-in-google-maps-v3">здесь</a>.</p>
<p>Если это расстояние меньше заданного, создаём маркер и показываем его на карте (строки 36-40). В противном случае – переходим к следующему объекту.</p>
<p>Как видите, алгоритм достаточно простой. Если немного усовершенствовать скрипт, можно сделать окружность перемещаемой и с переменным радиусом. Таким образом, имея хорошую базу объектов для какого-нибудь города, можно получить довольно удобный инструмент определения ближайших к заданной точке объектов.</p>
<p>Если есть вопросы или замечания, пишите, постараюсь ответить в комментариях <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Успехов!</strong></p>
<p><em>Интересно почитать</em></p>
<p>Хотите создать свой сайт? <a href="http://template-cms.ru/">Template CMS &#8211; быстрая и маленькая CMS!</a> Поможет решить эту задачу с минимальными затратами времени и ресурсов.</p>
<p>В раздумьях, <a href="http://imagebook.ru/podarok_k_svadbe">что подарить на свадьбу друзьям</a>? Попробуйте свадебную фотокнигу.</p>
<p>Заполним <a href="http://online-nalogi.ru"> 3-ндфл за 2011</a> год за 1 день, от 500 рублей!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/kak-pokazat-na-google-maps-obekty-naxodyashhiesya-v-zadannoj-oblasti.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>JavaScript XSS: получение данных от facebook и вконтакте</title>
		<link>http://www.simplecoding.org/javascript-xss-poluchenie-dannyx-ot-facebook-i-vkontakte.html</link>
		<comments>http://www.simplecoding.org/javascript-xss-poluchenie-dannyx-ot-facebook-i-vkontakte.html#comments</comments>
		<pubDate>Sun, 22 May 2011 11:02:21 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1211</guid>
		<description><![CDATA[О виджетах популярных социальных сетей знают практически все web мастера. Использовать их достаточно просто. В большинстве случаев нужно вставить блок с JavaScript кодом в шаблон страницы. Но что мы получаем в результате? Стандартную кнопку, позволяющую посетителю быстро опубликовать ссылку на текущую страницу в социальной сети и обычно счетчик таких публикаций. При этом, внешний вид такого [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1212" class="wp-caption alignnone" style="width: 221px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/05/facebook_vkontakte.png" alt="facebook vkontakte" title="facebook vkontakte" width="211" height="141" class="size-full wp-image-1212" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>О <strong>виджетах популярных социальных сетей</strong> знают практически все web мастера. Использовать их достаточно просто. В большинстве случаев нужно вставить блок с <strong>JavaScript</strong> кодом в шаблон страницы.</p>
<p>Но что мы получаем в результате? Стандартную кнопку, позволяющую посетителю быстро опубликовать ссылку на текущую страницу в социальной сети и обычно счетчик таких публикаций.</p>
<p>При этом, внешний вид такого виджета полностью определяется разработчиком и изменить его довольно проблематично, т.к. он находится внутри <code>iframe</code>, который загружен с другого домена. То есть ваши стили не будут применяться к этому iframe&#039;у.</p>
<p>Безусловно, такие виджеты выглядят очень не плохо и, самое главное, они узнаваемы. Большинство посетителей прекрасно понимает как ими пользоваться безо всяких дополнительных подсказок.</p>
<p>Тем не менее, бывают ситуации когда нужно изменить внешний вид виджета, да и грузить JavaScript код социальных сетей не очень хочется.</p>
<p>В этом случае придется <strong>создать свой виджет</strong> и обеспечить правильную его работу с социальными сетями.</p>
<p>Именно о таком решении я хочу рассказать в этой статье. В качестве примера возьмем <strong>facebook</strong> и <strong>вконтакте</strong>. Выбор этот сделан не случайно, разница между API этих сервисов довольно ощутимая. Чуть ниже вы поймете почему.<br />
<span id="more-1211"></span><br />
Условно, виджет можно разбить на две части.</p>
<p>1) Кнопка публикации.<br />
2) Счетчик публикаций.</p>
<p>Рассмотрим их подробнее.</p>
<h2>Кнопка публикаций</h2>
<p>Здесь все предельно просто. В обоих случаях информация передаётся в параметрах GET запроса. Т.е. достаточно сформировать ссылки следующего вида.</p>
<p>Для facebook:</p>
<pre class="brush: html">&lt;a href="http://www.facebook.com/sharer.php?u=url&#038;t=text" target="_blank"&gt;facebook&lt;/a&gt;</pre>
<p>Для вконтакте:</p>
<pre class="brush: html">&lt;a href="http://vkontakte.ru/share.php?url=url" target="_blank"&gt;вконтакте&lt;/a&gt;';</pre>
<p>Вместо <code>url</code> и <code>text</code> нужно подставить адрес и описание страницы, соответственно.</p>
<h2>Счетчик публикаций</h2>
<p>Здесь код будет немного сложнее. В обоих случаях для получения значений счетчика нужно отправить запрос серверу социальной сети. И тут начинаются варианты.</p>
<p>В большинстве источников, которые я видел в Сети, предлагают отправлять такой запрос со своего сервера (с помощью PHP) и затем кэшировать результат. Мне этот подход не нравится по нескольким причинам.</p>
<p>1) Любой запрос занимает какое-то время, которое прибавляется к общему времени формирования страницы. Кэширование в какой-то степени решает эту проблему (запросы будут отправляться не при каждом просмотре страницы), но не полностью.</p>
<p>2) При большом количестве запросов, социальная сеть может заблокировать ваш IP (зависит от политики социальной сети).</p>
<p>3) Создаётся дополнительная нагрузка на ваш сервер.</p>
<p>Второй вариант – <strong>отправлять запросы со стороны клиента, с помощью JavaScript</strong>.</p>
<p>В этом случае запрос уйдет из браузера посетителя и, по крайней мере, IP адреса таких запросов будут отличаться. Кроме того, запрос можно отправить после полной загрузки страницы и работа вашего сайта ни коим образом не будет зависеть от доступности социальной сети.</p>
<p>Но, при реализации такого подхода, возникают две <strong>проблемы</strong>.</p>
<p><strong>1) Встроенная защита браузеров от кросс-доменных запросов.</strong></p>
<p>Т.е. вы не можете отправить AJAX запрос на другой домен, но можно вставить в страницу тег <code>script</code> и в его атрибуте <code>src</code> указать адрес нужного скрипта на другом домене. В результате браузер загрузит нужный вам скрипт и выполнит код, находящийся в нём.</p>
<p>При использовании jQuery задача решается с минимумом усилий. Например, так:</p>
<pre class="brush: javascript">$.getJSON('http://vkontakte.ru/share.php?act=count&#038;index=1&#038;url=page_url&#038;callback=?', function(response) {
	…
});</pre>
<p>Обратите внимание на параметр <code>callback=?</code>. Если он указан, то jQuery вставит тег <code>script</code> внутрь страницы. Вообще параметр <code>callback</code> разработан для поддержки <strong>JSONP</strong> и указывает серверу, что ответ в JSON формате нужно передать в качестве параметра указанной функции. Имя этой функции jQuery формирует автоматически и подставляет вместо знака вопроса.</p>
<p>Естественно, JSONP должен поддерживаться на стороне сервера. И сейчас мы разберем какие ответы мы получим от социальных сетей на практике.</p>
<p><strong>2) Формат ответа социальной сети.</strong></p>
<p>С facebook всё отлично. Эта социальная сеть поддерживает JSONP и если мы отправим запрос вида.</p>
<pre class="brush: javascript">$.getJSON('http://graph.facebook.com/' + encodeURI(page_url)
		+ '&#038;callback=?', function(response) {
	if (response.shares !== undefined) {
		fb_counter = response.shares;
	}
	$('#facebook_count').html(response.shares);
});
<pre>

То получим следующий ответ.
<pre class="brush: javascript">jQuery16105957901661749929_1306057803097({
   "id": "http://www.smashingmagazine.com/",
   "shares": 5454
});</pre>
<p><code>jQuery16105957901661749929_1306057803097</code> – имя функции, которое сгенерировала jQuery.<br />
В первом параметре этой функции передаётся строка в JSON формате с адресом страницы и количеством публикаций.<br />
В результате, в обработчик запроса будет передан JS объект с нужными данными. В этом примере он называется <code>response</code>, т.е. получить количество публикаций ссылки можно с помощью вызова <code>response.shares</code>.</p>
<p>В случае с вконтаке всё сложнее. Эта социальная сеть JSONP не поддерживает и на запрос</p>
<pre class="brush: javascript">$.getJSON('http://vkontakte.ru/share.php?act=count&#038;index=1&#038;url='
	+ encodeURI(page_url) + '&#038;callback=?', function(response) {});</pre>
<p>отвечает следующей строкой:</p>
<pre class="brush: javascript">VK.Share.count(1, 9);</pre>
<p>Естественно, это приводит к возникновению ошибки</p>
<p><code>VK is not defined</code></p>
<p>Вообще ответ сервера вконтакте – это обычный вызов метода count, присвоенного параметру <code>Share</code> объекта <code>VK</code>. Откуда берется этот объект? Его создаёт скрипт, который нужно подключить при использовании стандартного виджета. Но этот скрипт нам не нужен, т.к. виджет мы не используем, а количество публикаций ссылки нужно вставить в заранее подготовленный блок о котором стандартный скрипт ничего не знает.</p>
<p>Т.е. нам нужен собственный объект VK с соответствующими параметрами. Создать его совсем не сложно.</p>
<pre class="brush: javascript">var VK = {
    Share: {
        count: function(value, count) {
            $('#vkontakte_count').html(count);
        }
    }
}</pre>
<p>Теперь, после получения ответа от сервера вконтакте, будет вызвана анонимная функция, установленная для параметра <code>count</code>. Во втором параметре она получит количество публикаций страницы.</p>
<p>Обратите внимание – этот код должен находится в глобальной области видимости.</p>
<p>Привожу весь код целиком.</p>
<p>Страницы со счетчиками</p>
<pre class="brush: html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Счетчики&lt;/title&gt;
    &lt;meta charset="utf-8" /&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div&gt;Facebook &lt;span id="facebook_count"&gt;&lt;/span&gt;&lt;/div&gt;
    &lt;div&gt;ВКонтакте &lt;span id="vkontakte_count"&gt;&lt;/span&gt;&lt;/div&gt;

    &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"&gt;&lt;/script&gt;
    &lt;script src="social_counters.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Скрипт social_counters.js</p>
<pre class="brush: javascript">jQuery(document).ready(function($) {
    var fb_counter = 0;
    var vk_counter = 0;
    var page_url = 'http://www.smashingmagazine.com/';

	$.getJSON('http://vkontakte.ru/share.php?act=count&#038;index=1&#038;url='
		+ encodeURI(page_url) + '&#038;callback=?', function(response) {});

	$.getJSON('http://graph.facebook.com/' + encodeURI(page_url)
			+ '&#038;callback=?', function(response) {
		if (response.shares !== undefined) {
			fb_counter = response.shares;
		}
		$('#facebook_count').html(response.shares);
	});
});

var VK = {
    Share: {
        count: function(value, count) {
            $('#vkontakte_count').html(count);
        }
    }
}</pre>
<h2>В заключение пара замечаний</h2>
<p>1) Поддержка JSONP значительно упрощает жизнь разработчикам и в конечном итоге способствует популяризации социальной сети или сервиса.</p>
<p>2) Отсутствие этой поддержки не означает, что вы не сможете интегрировать ваш сайт с данной социальной сетью. Главное, чтобы была возможность получить нужные данные в какой-нибудь форме. Естественно, при этом придётся написать какое-то количество дополнительного кода.</p>
<p>Если вы заметили ошибку или знаете более удачное решение данной проблемы, пишите, будет интересно обсудить.<br />
<strong>Успехов!</strong></p>
<p><strong>Интересно почитать</strong></p>
<p>Не знаете, <a href="http://imagebook.ru/chto_podarit_podruge">что подарить подруге на день рождения</a>? Фотоальбом с ее лучшими снимками!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/javascript-xss-poluchenie-dannyx-ot-facebook-i-vkontakte.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Сортировка в MySQL: несколько редко используемых возможностей</title>
		<link>http://www.simplecoding.org/sortirovka-v-mysql-neskolko-redko-ispolzuemyx-vozmozhnostej.html</link>
		<comments>http://www.simplecoding.org/sortirovka-v-mysql-neskolko-redko-ispolzuemyx-vozmozhnostej.html#comments</comments>
		<pubDate>Mon, 25 Apr 2011 08:17:43 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1204</guid>
		<description><![CDATA[О сортировке данных с помощью SQL запросов, думаю, знают все web разработчики. Достаточно указать в запросе предложение ORDER BY с нужными параметрами и вы получите желаемый результат. Параметры задавать тоже несложно. Просто перечисляете через запятую столбцы по которым нужно выполнить сортировку и указываете её направление (по возрастанию (ASC) или по убыванию (DESC)). Т.е. запрос, выполняющий [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1205" class="wp-caption alignnone" style="width: 272px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/04/mysql_order_by.png" alt="mysql order by" title="mysql order by" width="262" height="177" style="float:left" class="size-full wp-image-1205" /><p class="wp-caption-text"> </p></div>
<p>О <a href="http://dev.mysql.com/doc/refman/5.6/en/sorting-rows.html">сортировке данных с помощью SQL</a> запросов, думаю, знают все web разработчики.</p>
<p>Достаточно указать в запросе предложение <code>ORDER BY</code> с нужными параметрами и вы получите желаемый результат.</p>
<p>Параметры задавать тоже несложно. Просто перечисляете через запятую столбцы по которым нужно выполнить сортировку и указываете её направление (по возрастанию (<code>ASC</code>) или по убыванию (<code>DESC</code>)).</p>
<p>Т.е. запрос, выполняющий сортировку может выглядеть примерно следующим образом.</p>
<pre class="brush: sql">SELECT * FROM articles ORDER BY a_title ASC, a_date DESC</pre>
<p>В этом случае записи из таблицы <code>articles</code> будут отсортированы в возрастающем порядке по полю <code>a_title</code>, а для записей у которых совпадают значения в поле <code>a_title</code> – по полю <code>a_date</code> в убывающем порядке.</p>
<p>Именно в такой форме используются возможности сортировки в большинстве случаев. Но встречаются ситуации, в которых нужно использовать более сложные правила.<br />
<span id="more-1204"></span></p>
<h2>Сортировка с учетом типа данных</h2>
<p>Представьте, что у вас есть две таблицы. Первая содержит какие-нибудь <strong>записи</strong> (статьи, новости, товары и т.п.), а вторая – <strong>метаданные</strong> для этих записей. Метаданные могут содержать какую угодно информацию, например, рейтинг новости или цвет товара.</p>
<p>При этом таблицы будут иметь приблизительно следующую структуру.</p>
<div id="attachment_1206" class="wp-caption alignnone" style="width: 354px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/04/db_structure.png" alt="db_structure" title="db_structure" width="344" height="144" class="size-full wp-image-1206" /><p class="wp-caption-text"> </p></div>
<p>Подобные решения используются во многих <strong>CMS</strong>, т.к. авторы не знают какие именно метаданные будет использовать разработчик сайта и предоставляют ему возможность создавать их в неограниченном количестве.</p>
<p>Но что произойдет если мы попытаемся выполнить сортировку по метаданным?</p>
<p>Такую сортировку можно выполнить с помощью следующего запроса</p>
<pre class="brush: sql">SELECT * FROM articles AS a LEFT JOIN metadata AS m ON a.a_id=m.m_article_id WHERE m.m_name="color"</pre>
<p>Этот запрос выведет все записи из таблицы <code>articles</code> для которых создано мета-поле <code>color</code>.</p>
<p>Очевидно, что тип поля <code>m_value</code> должен быть текстовым, т.к. заранее неизвестно что будет храниться в метаданных.</p>
<p>При этом числовые данные будут отсортированы не правильно. Дело в том, что <code>ORDER BY</code> сравнивает значения с учетом типа поля и, например, при сортировке по возрастанию вы получите следующий ряд значений: «1», «10», «2», «3» и т.д.</p>
<p>Т.е. при выполнении такого запроса нужно указать, что поле <code>m_value</code> необходимо считать числовым. Делается это следующим образом.</p>
<pre class="brush: sql">SELECT * FROM metadata ORDER BY (m_value+0)</pre>
<p>Обратная операция (сортировка числового поля по правилам текстового) записывается немного сложнее.</p>
<pre class="brush: sql">SELECT left(a_id, 20) AS id_str FROM articles ORDER BY id_str</pre>
<p>Функция <code>left</code> возвращает строку, содержащую первые <code>N</code> символов из строки, указанной в первом параметре. Количество символов (N) задается во втором параметре. В данном случае будут выбраны первые 20 символов (достаточно чтобы преобразовать 8-байтное целое число в строку). Т.е. движок <strong>MySQL</strong> выполнит сортировку по строке, полученной из значения числового поля.</p>
<p>Хочу предупредить, что несмотря на то, что данные методы могут быть удобны в ряде ситуаций, их использование приводит к <strong>снижению скорости выполнения SQL запросов</strong>. Поэтому злоупотреблять ими не стоит. С другой стороны, сортировка с помощью PHP (или любого другого языка) также займет какое-то время.</p>
<h2>Сортировка текста с учетом регистра</h2>
<p>Для текстовых полей сортировка выполняется без учета регистра. В большинстве случаев это правильно, т.к. в таблице символов прописная «А» идет после строчной «я». Т.е. отсортированные с учетом регистра строки будут расположены в следующем порядке.</p>
<p>1. «Язык запросов»<br />
2. «Язык программирования»<br />
3. «Язык Запросов»</p>
<p>Но если всё-таки сортировку нужно выполнить с учетом регистра, просто добавьте оператор <code>BINARY</code> перед именем поля.</p>
<pre class="brush: sql">SELECT * FROM articles ORDER BY BINARY a_title</pre>
<h2>Сортировка по фрагменту строки</h2>
<p>Если вам приходится использовать этот прием, то, скорее всего, ваша база данных не соответствует перовой нормальной форме. Поэтому, подумайте, может лучше пересмотреть её структуру?</p>
<p>Но, в любом случае, вы можете использовать функцию <a href="http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_substring-index">SUBSTRING_INDEX</a> для выбора подстроки и последующей сортировки. Например,</p>
<pre class="brush: sql">SELECT SUBSTRING_INDEX(a_title, ' ', -1) AS at FROM wp_5_posts ORDER BY at</pre>
<h2>Сортировка записей по заданному списку значений</h2>
<p>Представьте, что у вас есть записи, которые каким-то образом связаны с временем года. И вы храните эту информацию в одном из столбцов таблицы.</p>
<p>Очевидно, что, используя стандартный вариант сортировки (по алфавиту), расположить сезоны порядке «весна», «лето», «осень», «зима» не получится. Естественно, можно каждому времени года присвоить свой код, но есть и другой вариант решения – использовать функцию <a href="http://dev.mysql.com/doc/refman/5.6/en/string-functions.html#function_field">FIELD</a>.</p>
<pre class="brush: sql">SELECT * FROM articles ORDER BY FIELD(a_season, "весна","лето","осень","зима")</pre>
<p>Эта функция ищет значение, указанное в первом параметре, среди значений, перечисленных в остальных параметрах, и возвращает его порядковый номер. При выполнении запроса в первый параметр функции <code>FIELD</code> будут передаваться значения из поля <code>a_season</code> и, таким образом, записи будут отсортированы в заданном нами порядке.</p>
<h2>Сортировка строк по их длине</h2>
<p>Эта возможность используется довольно редко, т.к. обычно длина строки смысловой нагрузки не несет. Тем не менее, в некоторых случаях может пригодиться.</p>
<pre class="brush: sql">SELECT * FROM articles ORDER BY CHAR_LENGTH(a_title)</pre>
<p>Как видите, «фокус» заключается в использовании функции <code>CHAR_LENGTH</code>, которая определяет количество символов в строке.</p>
<h2>Заключение</h2>
<p>Думаю, глядя на последние несколько рецептов, вы понимаете, что подобным образом можно использовать практически все функции MySQL. Мне будет интересно, если вы поделитесь примерами из своей практики <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Интересное в Интернете</strong></p>
<p>Заказ <a href="http://imagebook.ru/wedding">свадебных фотоальбомов</a> с доставкой по РФ и СНГ</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/sortirovka-v-mysql-neskolko-redko-ispolzuemyx-vozmozhnostej.html/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>JavaScript виджет: бесконечная загрузка твитов</title>
		<link>http://www.simplecoding.org/javascript-vidzhet-beskonechnaya-zagruzka-tvitov.html</link>
		<comments>http://www.simplecoding.org/javascript-vidzhet-beskonechnaya-zagruzka-tvitov.html#comments</comments>
		<pubDate>Tue, 05 Apr 2011 18:59:36 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1200</guid>
		<description><![CDATA[В последнее время я часто замечаю на различных сайтах виджеты, которые подгружают контент при определённых действиях посетителя. Такой подход позволяет с одной стороны, сократить количество данных на странице, а с другой – при необходимости показывать практически неограниченный объем информации. Рассмотрим небольшой практический пример. Допустим, мы хотим показать в сайдбаре виджет с твитами из какой-нибудь ленты [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1201" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/04/load_on_scroll.png" alt="load on scroll" title="load on scroll" width="300" height="243" style="float:left" class="size-full wp-image-1201" /><p class="wp-caption-text"> </p></div>
<p>В последнее время я часто замечаю на различных сайтах виджеты, которые подгружают контент при определённых действиях посетителя. Такой подход позволяет с одной стороны, сократить количество данных на странице, а с другой – при необходимости показывать практически неограниченный объем информации.</p>
<p>Рассмотрим небольшой практический пример.</p>
<p>Допустим, мы хотим показать в сайдбаре <em>виджет с твитами</em> из какой-нибудь ленты (естественно, существует множество готовых решений, но сейчас не о них речь, кроме того, данное решение можно использовать для загрузки любого контента).</p>
<p>На первый взгляд всё предельно просто, twitter предоставляет <a href="http://dev.twitter.com/doc/get/statuses/user_timeline">API</a>, с помощью которого можно получить твиты любого пользователя (если они открыты). Вставить их сайдбар тоже не проблема.</p>
<p>Но на практике возникает <strong>несколько интересных моментов</strong>.<br />
<span id="more-1200"></span><br />
1) Информация от <strong>twitter</strong> не является основным контентом сайта и не должна влиять на скорость загрузки страницы. Кроме того, доступность сервиса также не должна влиять на работу сайта.</p>
<p>2) Твиты могут появляться довольно быстро, поэтому чтобы информация в виджете была всегда актуальной от кеширования придётся отказаться.</p>
<p>3) Т.к. твиты не являются основным содержимым страницы, то посетитель скорее всего не заметит если они появятся через некоторое время после загрузки основной части страницы.</p>
<p>4) Не ясно, сколько именно твитов нужно выводить. Части посетителей эта информация будет не интересна вообще, но пользователи этого сервиса, возможно, захотят прочитать несколько десятков сообщений.</p>
<p>5) Количество места, выделенного под виджет, обычно ограничено. И необходимо чтобы загрузка новых твитов не «ломала» дизайн.</p>
<p>Таким образом, нам нужно загружать твиты после загрузки страницы и желательно, чтобы от посетителя требовался минимум действий для загрузки новых твитов.</p>
<p><strong>Теперь рассмотрим сам виджет.</strong></p>
<p>Начнём с алгоритма.</p>
<p>1) Создаём на странице область с фиксированной высотой и вертикальным полосой прокрутки.</p>
<p>2) После загрузки страницы подгружаем в эту область твиты с помощью JavaScript.</p>
<p>3) Если пользователь переместит ползунок скролла в крайнее нижнее положение – загружаем следующую «порцию» твитов.</p>
<p>Посмотреть как работает такой виджет можно на демонстрационной страничке. И сразу же даю ссылку на архив с этим примером.</p>
<p><a href="http://demosites.simplecoding.org/infinite-scroll/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a> <a href='http://www.simplecoding.org/wp-content/uploads/2011/04/infinite_scroll.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p>Разметка виджета с твитами может выглядеть следующим образом.</p>
<pre class="brush: html">&lt;div id="tweets"&gt;
    &lt;div class="loader hidden"&gt;&lt;/div&gt;
&lt;/div&gt;</pre>
<p>Как видите, после первоначальной загрузки внутри виджета будет находится только один элемент – картинка с изображением загрузчика. Стили для неё мы установим таким образом, чтобы она всегда находилась в центре виджета.</p>
<pre class="brush: css">.loader {
    background-image: url('ajax-loader.gif');
    width: 400px;
    height: 300px;
    background-repeat: no-repeat;
    background-position: center center;
    position: fixed;
}</pre>
<p>Значения <code>width</code> и <code>height</code> должны совпадать с соответствующими значениями, установленными для виджета (div#tweets).</p>
<pre class="brush: css">#tweets {
    height: 300px;
    width: 400px;
    overflow: auto;
    position: relative;
    border: solid 1px #999;
    margin: 3em auto 0 auto;
}</pre>
<p><strong>Переходим к загрузке твитов</strong></p>
<p>Основная сложность заключается в том, что нам нужно с помощью JavaScript выполнить кросс-доменный запрос к серверу twitter’а. Такие запросы запрещены политикой безопасности браузеров, поэтому использовать обычный AJAX запрос не получится.</p>
<p>Тем не менее, благодаря тому, что <strong>Twitter API</strong> поддерживает <strong>JSONP</strong> задача решается достаточно просто.</p>
<pre class="brush: javascript">$(function() {
    //параметры для получения твитов
    var user_id = '24147920';
    var tweets_url = 'http://api.twitter.com/1/statuses/user_timeline.json';
    var page = 1;
    var tweets_num = 10;

    //список твитов и картинка загрузчика
    var container = $('#tweets');
    var loader = $('.loader');

    //шаблон для поиска ссылок в твитах (упрощенный)
    var pattern = /(http\S+)/gi;

    //загружаем первую страницу твитов
    get_tweets(page);

    //обработчик события scroll
    container.scroll(function() {
        //это условие выполняется когда ползунок находится в крайнем нижнем положении
        if  (container[0].scrollTop == container[0].scrollHeight - container[0].clientHeight){
            //показываем загрузчик
            loader.removeClass('hidden');
            //загружаем очередную страницу твитов
            page = page + 1;
            get_tweets(page);
        }
    });

    //эта функция загружает твиты, ищет ссылки и ставит для них
    //соответствующий тег &lt;a href="..."&gt;, вставляет твиты в список
    function get_tweets(page) {
        $.getJSON(
            //формируем запрос на получение твитов (используется JSONP)
            tweets_url + '?user_id=' + user_id + '&#038;page=' + page + '&#038;count=' + tweets_num + '&#038;callback=?',
            function(data) {
                $(data).each(function(i, tweet) {
                    //формируем ссылки
                    var text = tweet.text.replace(pattern, '&lt;a href="$1" target="_blank"&gt;$1&lt;/a&gt;');
                    //вставляем твит в список
                    container.append('&lt;div class="tweet"&gt;' + text + '&lt;/div&gt;');
                });
                //прячем загрузчик
                loader.addClass('hidden');
            }
        );
    }
});</pre>
<p>Прежде всего, мы подготавливаем данные, которые нужны для работы с Twitter API (строки 3-6). Для данного примера я использовал свою собственную ленту твитов, но вы можете вывести любую другую. Также не принципиально сколько твитов загружать за раз, главное, чтобы после первоначальной загрузки появилась полоса прокрутки.</p>
<p>Для получения твитов используем метод <code>getJSON</code> (строки 33-46, библиотека jQuery).</p>
<p>В первом её параметре передаём запрос на получение твитов. В него мы включаем:<br />
- id пользователя (<code>'?user_id=' + user_id</code>);<br />
- номер страницы (<code>'&#038;page=' + page</code>);<br />
- количество твитов на странице (<code>'&#038;count=' + tweets_num</code>);<br />
- имя функции, которая будет вызвана после получения данных (<code>'&#038;callback=?'</code>) – его jQuery формирует автоматически и подставляет вместо знака вопроса.</p>
<p>После получения твитов нам остается только добавить их в список (строки 36-42). При этом, мы ищем ссылки в тексте твитов и обрамляем их тегом <code>&lt;a&gt;</code>.</p>
<p>Завершающий этап – установка обработчика для события <code>scroll</code> (строки 19-28).</p>
<p>Здесь нужно только проверить достигнут конец списка или нет. Если достигнут, показываем загрузчик (убираем класс <code>hidden</code>) и вызываем функцию <code>get_tweets</code>, которой передаём номер нужно страницы. В противном случае, не делаем ничего.</p>
<p>Всё. Можно считать, что виджет в рабочем состоянии. Конечно, перед размещением на рабочем сайте нужно будет его немного доработать, например, добавить вывод сообщение об ошибке при отсутствии доступа к twitter&#039;у. Но, думаю, с этой задачей вы легко справитесь сами <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Успехов!</strong></p>
<p><em>Интересное</em></p>
<p>Глянцевая и матовая <a href="http://imagebook.ru/">печать фотокниг</a> и свадебных фотоальбомов</p>
<p>Любителям страйкбола будет интересно почитать про <a href="http://battleteam.ru/viewtopic.php?t=74">камуфляж Горка</a> его расцветки и разновидности.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/javascript-vidzhet-beskonechnaya-zagruzka-tvitov.html/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Небольшой эксперимент с использованием data: URL</title>
		<link>http://www.simplecoding.org/nebolshoj-eksperiment-s-ispolzovaniem-data-url.html</link>
		<comments>http://www.simplecoding.org/nebolshoj-eksperiment-s-ispolzovaniem-data-url.html#comments</comments>
		<pubDate>Mon, 21 Mar 2011 08:52:15 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1196</guid>
		<description><![CDATA[В последнее время всё больше внимания уделяется клиентской оптимизации сайтов. Я не могу сказать, что раньше ею никто не занимался, скорее, наоборот, с появлением широкополосного доступа к Internet часть проблем решилась сама собой. Но появление новых технологий, предоставляет новые возможности, которыми имеет смысл пользоваться. К сожалению, не всегда есть возможность проигнорировать устаревшие браузеры (главным образом [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1197" class="wp-caption alignnone" style="width: 300px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/03/data_uri.png" alt="data uri" title="data uri" width="290" height="255" class="size-full wp-image-1197" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>В последнее время всё больше внимания уделяется <strong>клиентской оптимизации сайтов</strong>. Я не могу сказать, что раньше ею никто не занимался, скорее, наоборот, с появлением широкополосного доступа к Internet часть проблем решилась сама собой. Но появление новых технологий, предоставляет новые возможности, которыми имеет смысл пользоваться.</p>
<p>К сожалению, не всегда есть возможность проигнорировать устаревшие браузеры (главным образом речь идет о IE6 и 7). И это сильно замедляет использование новых стандартов.</p>
<p>Ситуация довольно сложная. Большинство владельцев ресурсов не согласятся потерять часть аудитории (пусть даже небольшую) только потому, что разработчик решил внедрить новую технологию. Но не все понимают, что использование устаревших технологий делает менее комфортной работу посетителей с нормальными браузерами. В частности, время загрузки страницы для них окажется больше, чем могло бы быть.</p>
<p>Поэтому оптимальным решением было бы автоматическое переключение технологий в зависимости от возможностей браузера.</p>
<p>Об одной из таких технологий и пойдёт речь в этой статье. Называется она <strong>data: URL</strong>.<br />
<span id="more-1196"></span></p>
<p><a href="http://ru.wikipedia.org/wiki/Data:_URL">data:URL</a> представляет собой схему, позволяющую включать произвольные данные непосредственно в строку URL. Т.е. можно разместить небольшие картинки, которые используются для оформления страницы, прямо в файл стилей и, тем самым, уменьшить количество запросов к серверу.</p>
<p>Для себя задачу я ставил достаточно просто. Проверить, насколько сложно будет обеспечить одинаковый вид страницы во всех браузерах, начиная с IE6.</p>
<p>Сразу выкладываю ссылку на архив с примером, который я использовал для экспериментов.</p>
<p><a href='http://www.simplecoding.org/wp-content/uploads/2011/03/data_url.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<h2>Рассмотрим тестовую страницу</h2>
<pre class="brush: html">&lt;!DOCTYPE html&gt;

&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;CSS clip&lt;/title&gt;
    &lt;meta charset="utf-8" /&gt;
&lt;/head&gt;

&lt;body&gt;

&lt;div id="social_icons"&gt;
    &lt;a href="#" class="twitter icon"&gt;&lt;/a&gt;
    &lt;a href="#" class="facebook icon"&gt;&lt;/a&gt;
    &lt;a href="#" class="bobrdobr icon"&gt;&lt;/a&gt;
    &lt;a href="#" class="memori icon"&gt;&lt;/a&gt;
    &lt;a href="#" class="delicious icon"&gt;&lt;/a&gt;
    &lt;a href="#" class="stumbleupon icon"&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Она содержит шесть ссылок, которые нужно показать в виде иконок на социальные сервисы.</p>
<p>Делается это достаточно просто. Для каждой ссылки задаётся ширина, высота и фоновое изображение (иконка).</p>
<p>При этом браузер загрузит каждый файл, который будет указан в свойстве <code>background-image</code>. Т.е. если у нас шесть иконок, то будет отправлено шесть запросов серверу. Учитывая, что размеры иконок редко превышают несколько кБ, загружать их по одной не выгодно.</p>
<p>Наиболее распространённым методом оптимизации в таких случаях является использование <strong>CSS спрайтов</strong>. При этом все картинки объединяются в одну, а нужный фрагмент показывают с помощью свойства <code>background-position</code>.</p>
<p>Именно этот вариант я решил использовать для браузеров IE6 и 7, а для новых – передать иконки с помощью <code>data: URL</code>.</p>
<h2>Подготовка данных для использования в data: URL</h2>
<p>Тут всё достаточно просто. Нужно закодировать содержимое файла с картинкой с помощью base64 и вставить полученную строку в CSS файл.</p>
<p>В моем случае, исходное изображение выглядит следующим образом.</p>
<div id="attachment_1198" class="wp-caption alignnone" style="width: 74px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/03/icons_sprites.png" alt="icons sprites" title="icons sprites" width="64" height="384" class="size-full wp-image-1198" /><p class="wp-caption-text"> </p></div>
<p><em>Примечание</em>. Я использовал коллекцию бесплатных иконок от <a href="http://www.wpzoom.com/wpzoom/500-free-icons-wpzoom-social-networking-icon-set/">wpzoom</a>.</p>
<p>На практике можно воспользоваться одним из сервисов, выполняющих эту операцию. Например, <a href="http://duris.ru/">duris.ru</a> или <a href="http://www.dopiaza.org/tools/datauri/">dopiaza.org</a>.</p>
<p>В результате у меня получилась такая таблица стилей.</p>
<pre class="brush: css">@charset 'utf-8';

.icon {
	width: 64px;
	height: 64px;
	display: block;
	float: left;
	margin: 10px;
}

div#social_icons a {
	background-image: url("data:image/png;base64,iVBORw......");
	background-repeat:no-repeat;
}
.twitter {
	background-position: 0 0;
}
.facebook {
	background-position: 0 -64px;
}
.bobrdobr {
	background-position: 0 -128px;
}
.memori {
	background-position: 0 -192px;
}
.delicious {
	background-position: 0 -256px;
}
.stumbleupon {
	background-position: 0 -322px;
}</pre>
<p><em>Обратите внимание</em>. Здесь не важно кодируете вы один файл со всеми иконками или каждую отдельно. Все данные будут переданы внутри CSS файла.</p>
<p><em>Рассмотрим стили подробнее</em>.</p>
<p>Для каждой ссылки мы указываем высоту (<code>width</code>) и ширину (<code>height</code>). При этом, нужно сделать ссылку блоковым элементом (<code>display: block</code>), иначе длина и высота применятся не будут. Чтобы расположить иконки в один ряд, используем обтекание (<code>float: left</code>).</p>
<p>Далее каждой ссылке устанавливаем фоновое изображение (<code>background-image</code>). В качестве значения <code>url</code> вставляем результат преобразования картинки. Я его сократил, т.к. он занимает около 19 кБ.</p>
<p>Затем с помощью <code>background-position</code> показываем нужный фрагмент картинки. В данном случае все иконки имеют размер 64х64 px и расположены вертикально, поэтому просто изменяем вертикальную координату на 64 px.</p>
<p>Остаётся подключить файл стилей к странице.</p>
<pre class="brush: html">&lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt;</pre>
<p>Всё. В современных браузерах иконки отображаются правильно.</p>
<p>Для формирования страницы браузер выполняет <strong>два</strong> запроса к серверу. Первый – получение самой страницы, второй – получения файла стилей. При этом, файл стилей занимает 19,1 кБ (если его сжать, получится 14,4 кБ).</p>
<h2>Поддержка IE6 и 7</h2>
<p>Есть несколько вариантов решения этой задачи. Подробно они рассмотрены в статье <a href="http://webo.in/articles/habrahabr/46-cross-browser-data-url/">Кроссбраузерное использование data:URL</a>.</p>
<p>Я покажу один из самых простых вариантов, с заменой файла стилей.</p>
<p>Идея предельно простая. С помощью условных комментариев, браузерам IE6 и 7 указываем свой собственный CSS файл.</p>
<p>Выглядит это следующим образом.</p>
<pre class="brush: html">&lt;!--[if lt IE 8]&gt;&lt;link rel="stylesheet" type="text/css" href="ie_6_7_styles.css" /&gt;&lt;![endif]--&gt;
&lt;!--[if gte IE 8]&gt;&lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt;&lt;![endif]--&gt;
&lt;!--[if !IE]&gt;--&gt;&lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt;&lt;!--&lt;![endif]--&gt;</pre>
<p>В результате, современные браузеры загрузят файл <code>styles.css</code>, а шестая и седьмая версии IE – <code>ie_6_7_styles.css</code>.</p>
<p>В этих стилях отличается только свойство <code>background-image</code>. Вместо <code>data:URL</code> указываем файл с иконками.</p>
<pre class="brush: css">div#social_icons a {
    background-image: url("icons/icons_sprites.png");
    background-repeat:no-repeat;
}</pre>
<p>Теперь во всех браузерах иконки отображаются одинаково.</p>
<h2>Результаты</h2>
<p>Должен отметить, что в данном случае, результаты получились не очень впечатляющие.</p>
<p>Безусловно, при использовании <code>data: URL</code> количество запросов уменьшилось (на один), но объём передаваемых данных увеличился практически на 5 кБ (исходный файл <code>icons_sprites.png</code> «весит» 13,9 кБ, а после base64 преобразования он занимает около 19 кБ).</p>
<p>Т.е. получается, что если фоновые изображения хорошо укладываются в CSS спрайты, то эффект от применения <code>data: URL</code> будет минимальным. Точнее, в некоторых случаях можно получить полностью противоположный эффект, т.к. время загрузки файла со стилями увеличится, и посетитель будет какое-то время смотреть на страницу без стилей вообще.</p>
<p>Кроме того, усложняется процесс обновления картинок, т.к. они будут кешироваться вместе с CSS файлом. (Эта проблема решаемая, но выходит за рамки данной статьи).</p>
<p>С другой стороны, в этой статье рассмотрен очень простой пример. Для сложного сайта файлов со спрайтами может получиться довольно много и в этом случае эффект от использования data: URL будет выше за счёт уменьшения количества запросов.</p>
<p>К тому же, если бы не нужна была поддержка IE6, 7, то можно было бы вообще не заниматься созданием файла со спрайтами и установкой <code>background-position</code>, а просто передавать изображения в <code>background-image</code> для соответствующих элементов.</p>
<p>В целом, я не уверен, что в ближайшее время начнется массовое использование <code>data: URL</code>. Тем не менее, технология очень интересная.</p>
<p><strong>Успехов!</strong></p>
<p><strong>Интересно почитать</strong></p>
<p>Хотите сделать карьеру в IT? <a href="http://it-centre.net">Курсы программистов</a> будут хорошей стартовой точкой.</p>
<p>Нужна декларация <a href="http://online-nalogi.ru/3_ndfl_prodazha_kvartiry"> 3-ндфл «продажа квартиры»</a>? Заполним за сутки и вышлем на емейл.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/nebolshoj-eksperiment-s-ispolzovaniem-data-url.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>WordPress: вывод записей произвольных типов (Custom Post Types)</title>
		<link>http://www.simplecoding.org/wordpress-vyvod-zapisej-proizvolnyx-tipov-custom-post-types.html</link>
		<comments>http://www.simplecoding.org/wordpress-vyvod-zapisej-proizvolnyx-tipov-custom-post-types.html#comments</comments>
		<pubDate>Sun, 13 Mar 2011 14:56:48 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1192</guid>
		<description><![CDATA[На сегодняшний день движок WordPress довольно интенсивно развивается. Во всяком случае изменения в версиях с 2.8 по 3.1 добавляют WP возможности полноценных CMS. Большинство из этих возможностей должны быть активированы на уровне темы (или плагина), поэтому сразу после установки WP вы работаете с ним как с обычным блоговым движком. Вроде бы все правильно. Если какие-то [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1193" class="wp-caption alignnone" style="width: 295px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/03/wordpress_custom_queries.png" alt="wordpress custom queries" title="wordpress custom queries" width="285" height="221" class="size-full wp-image-1193" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>На сегодняшний день движок <strong>WordPress</strong> довольно интенсивно развивается. Во всяком случае изменения в версиях с 2.8 по 3.1 добавляют WP возможности полноценных CMS. Большинство из этих возможностей должны быть активированы на уровне темы (или плагина), поэтому сразу после установки WP вы работаете с ним как с обычным блоговым движком.</p>
<p>Вроде бы все правильно. Если какие-то возможности вам не нужны, вы их не используете. Но при этом возникает серьёзная проблема с документацией. Дело в том, большинство примеров и в Кодексе, и в других источниках, ориентированы на самый простой случай – дефолтную инсталляцию WP. Как только вы активируете дополнительные возможности ко многим рекомендациям нужно относится очень аккуратно.</p>
<p>Об одном из таких примеров я хочу рассказать в этой статье.<br />
<span id="more-1192"></span><br />
Предположим, вы решили использовать произвольные типы записей (custom post types). Создать их достаточно просто и на эту тему есть масса статей, поэтому подробно останавливаться на этом моменте не будем.</p>
<p>В большинстве случаев достаточно добавить следующий код в файл functions.php вашей темы.</p>
<pre class="brush: php">register_post_type('gadgets',
	array(
		'labels' =&gt; array(
			'name' =&gt; __('Gadgets'),
			'singular_name' =&gt; __('Gadget'),
			//остальные переводы
		),
		'public' =&gt; true,
		'publicly_queryable' =&gt; true,
		'query_var' =&gt; true,
		'taxonomies' =&gt; array('category','post_tag'),
		'supports' =&gt; array('title','editor','author','thumbnail','excerpt','comments'),
		'rewrite' =&gt; array('slug' =&gt; 'gadgets'),
		//другие настройки
	)
);</pre>
<p>После этого вы сможете создавать записи данного типа в админке и WordPress автоматически сформирует страницу с лентой из этих записей. Адрес у этой страницы будет следующим.</p>
<p><code>http://blog.url/gadgets</code></p>
<p>Теперь обратите внимание, что для этого типа записей мы используем такие же категории, как и для типа <code>Post</code> (строка 11).</p>
<p>Очевидно, что на странице категории мы захотим увидеть записи <strong>всех</strong> типов, но WordPress покажет только тип Post.</p>
<p>Происходит это потому что WP при формировании запроса к базе данных явно указывает тип поста. И по-умолчанию этот тип – <code>post</code>.</p>
<p>К сожалению, в подобных случаях не все авторы тем хотят вникать в нюансы работы движка и просто используют функцию <a href="http://codex.wordpress.org/Function_Reference/query_posts">query_posts</a>. Я понимаю, что примеры её использования приведены в статье <a href="http://codex.wordpress.org/The_Loop">The Loop</a>, но там предполагается, что вам нужно создать дополнительный цикл на странице. Т.е., например, вывести основной список записей и ещё какой-нибудь дополнительный список, с фильтрацией по определённым условиям.</p>
<p>В данном случае нужно изменить основной запрос, т.к. мы можем за один раз получить все необходимые данные. И нет никакого смысла выполнять дополнительный запрос к базе.</p>
<p><strong>Решается задача достаточно просто.</strong></p>
<pre class="brush: php">function prefix_pre_get_posts($query) {
     if ($query-&gt;is_category) {
          $query-&gt;set('post_type', 'any');
     }
     return $query;
}

add_action('pre_get_posts', 'prefix_pre_get_posts');</pre>
<p>Здесь мы назначаем собственный обработчик события (action) <code>pre_get_posts</code>. Как следует из названия, это событие возникает непосредственно перед отправкой запроса к БД. В первом параметре обработчик получает объект типа <a href="http://codex.wordpress.org/Function_Reference/WP_Query">WP_Query</a>, который формирует запрос к базе.</p>
<p>Прежде всего, мы проверяем, что в данный момент создаётся страница категории (строка 2). А затем изменяем атрибут <code>post_type</code>. По-умолчанию он равен <code>post</code>. Не забывайте, что обработчик обязательно должен вернуть изменённый (или неизменённый) объект <code>WP_Query</code>.</p>
<p>Вообще, если вы планируете работать с новыми возможностями WP (произвольными типами записей, таксономиями, форматами записей), то научиться работать с <a href="http://codex.wordpress.org/Function_Reference/WP_Query">WP_Query</a> нужно обязательно. <em>Встроенными функциями движка здесь вы не обойдетесь</em>.</p>
<p>В целом, этого и следовало ожидать, чем больше возможностей у движка, тем больше времени придётся потратить на его изучение <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Успехов!</strong></p>
<p><em>Интересно почитать</em></p>
<p>Если самостоятельно учиться тяжело, то <a href="http://it-centre.net">курсы программирования Киев</a> помогут приобрести необходимые знания.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/wordpress-vyvod-zapisej-proizvolnyx-tipov-custom-post-types.html/feed</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
	</channel>
</rss>

