Version Description
WORDPRESS COMPATIBILITY: Tested with new versions of WordPress up to 4.5.
FILTERS AND ADD-ONS: Allow filters and add-ons to filter terms and taxonomy (categories, tags, custom taxonomies, etc.) more thoroughly and more fine-grainedly using syndicated_post_terms_match, syndicated_post_terms_match_{taxonomy}, syndicated_post_terms_unfamiliar, syndicated_post_terms_mapping, syndicated_item_feed_terms, and syndicated_item_preset_terms filters.
FILTERS AND ADD-ONS: Globals $fwp_channel and $fwp_feedmeta REMOVED. These global variables, originally introduced to allow filters access to information about the source feed in
syndicated_item
filters were deprecated 6+ years ago. If you have any filters or add-ons which still depend on these global variables, you've been using obsolete techniques and you should see about fixing them to access data about the source feed using the SyndicatedPost::link element instead. For documentation, see the FeedWordPress documentation wiki at http://feedwordpress.radgeek.com/wiki/syndicatedpost and http://feedwordpress.radgeek.com/wiki/syndicatedlink.BUGFIX: Syndication > Diagnostics HTTP diagnostic test widget was broken due to a dumb error on my part. Now fixed.
SMALL CODING CHANGES: Lots of small changes to code organization, incorporation of some PHP 5.x coding conventions, etc.
Release Info
Developer | radgeek |
Plugin | FeedWordPress |
Version | 2016.0420 |
Comparing to | |
See all releases |
Code changes from version 2015.0514 to 2016.0420
- diagnostics-page.php +17 -3
- feedwordpress-elements.js +1 -1
- feedwordpress.php +3 -3
- readme.txt +30 -3
- syndicatedpost.class.php +246 -296
- syndicatedpostterm.class.php +4 -1
- syndicatedpostxpathquery.class.php +462 -0
@@ -356,23 +356,36 @@ function clone_http_test_args_keyvalue_prototype () {
|
|
356 |
<td><a href="#http-test-args" onclick="return clone_http_test_args_keyvalue_prototype();">+ Add</a></td>
|
357 |
</tr>
|
358 |
</table>
|
|
|
|
|
359 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
360 |
<?php if (isset($page->test_html['http_test'])) : ?>
|
|
|
|
|
|
|
|
|
361 |
<div style="position: relative">
|
362 |
<div style="width: 100%; overflow: scroll; background-color: #eed">
|
363 |
<pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -o-pre-wrap;"><?php print $page->test_html['http_test']; ?></pre>
|
364 |
</div>
|
365 |
</div>
|
366 |
-
<?php endif; ?>
|
367 |
</td>
|
368 |
</tr>
|
|
|
369 |
</table>
|
370 |
|
371 |
<?php
|
372 |
} /* FeedWordPressDiagnosticsPage::tests_box () */
|
373 |
|
374 |
-
|
375 |
-
|
376 |
if (isset($post['http_test_url']) and isset($post['http_test_method'])) :
|
377 |
$url = $post['http_test_url'];
|
378 |
|
@@ -410,6 +423,7 @@ function clone_http_test_args_keyvalue_prototype () {
|
|
410 |
break;
|
411 |
endswitch;
|
412 |
|
|
|
413 |
$this->test_html['http_test'] = esc_html(MyPHP::val($out));
|
414 |
endif;
|
415 |
} /* FeedWordPressDiagnosticsPage::do_http_test () */
|
356 |
<td><a href="#http-test-args" onclick="return clone_http_test_args_keyvalue_prototype();">+ Add</a></td>
|
357 |
</tr>
|
358 |
</table>
|
359 |
+
</td>
|
360 |
+
</tr>
|
361 |
|
362 |
+
<tr>
|
363 |
+
<th>XPath:</th>
|
364 |
+
<td><div><input type="text" name="http_test_xpath" value="" placeholder="xpath-like query" /></div>
|
365 |
+
<div><p>Leave blank to test HTTP, fill in to test a query.</p></div>
|
366 |
+
</td>
|
367 |
+
</tr>
|
368 |
+
|
369 |
<?php if (isset($page->test_html['http_test'])) : ?>
|
370 |
+
<tr>
|
371 |
+
<th scope="row">RESULTS:</th>
|
372 |
+
<td>
|
373 |
+
<div>URL: <code><?php print esc_html($page->test_html['url']); ?></code></div>
|
374 |
<div style="position: relative">
|
375 |
<div style="width: 100%; overflow: scroll; background-color: #eed">
|
376 |
<pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -o-pre-wrap;"><?php print $page->test_html['http_test']; ?></pre>
|
377 |
</div>
|
378 |
</div>
|
|
|
379 |
</td>
|
380 |
</tr>
|
381 |
+
<?php endif; ?>
|
382 |
</table>
|
383 |
|
384 |
<?php
|
385 |
} /* FeedWordPressDiagnosticsPage::tests_box () */
|
386 |
|
387 |
+
private $test_html;
|
388 |
+
public function do_http_test ($post) {
|
389 |
if (isset($post['http_test_url']) and isset($post['http_test_method'])) :
|
390 |
$url = $post['http_test_url'];
|
391 |
|
423 |
break;
|
424 |
endswitch;
|
425 |
|
426 |
+
$this->test_html['url'] = $url;
|
427 |
$this->test_html['http_test'] = esc_html(MyPHP::val($out));
|
428 |
endif;
|
429 |
} /* FeedWordPressDiagnosticsPage::do_http_test () */
|
@@ -629,7 +629,7 @@ function fwp_xpathtest_ok (response, result_id, destination) {
|
|
629 |
|
630 |
if (response.results instanceof Array) {
|
631 |
for (var i = 0; i < response.results.length; i++) {
|
632 |
-
resultsHtml += '<li>result['+i.toString()+'] = <code>'+response.results[i]+'</code></li>';
|
633 |
}
|
634 |
} else {
|
635 |
resultsHtml += '<li>result = <code>' + response.results + '</code></li>';
|
629 |
|
630 |
if (response.results instanceof Array) {
|
631 |
for (var i = 0; i < response.results.length; i++) {
|
632 |
+
resultsHtml += '<li>result['+(i+1).toString()+'] = <code>'+response.results[i]+'</code></li>';
|
633 |
}
|
634 |
} else {
|
635 |
resultsHtml += '<li>result = <code>' + response.results + '</code></li>';
|
@@ -3,7 +3,7 @@
|
|
3 |
Plugin Name: FeedWordPress
|
4 |
Plugin URI: http://feedwordpress.radgeek.com/
|
5 |
Description: simple and flexible Atom/RSS syndication for WordPress
|
6 |
-
Version:
|
7 |
Author: Charles Johnson
|
8 |
Author URI: http://radgeek.com/
|
9 |
License: GPL
|
@@ -11,7 +11,7 @@ License: GPL
|
|
11 |
|
12 |
/**
|
13 |
* @package FeedWordPress
|
14 |
-
* @version
|
15 |
*/
|
16 |
|
17 |
# This uses code derived from:
|
@@ -32,7 +32,7 @@ License: GPL
|
|
32 |
|
33 |
# -- Don't change these unless you know what you're doing...
|
34 |
|
35 |
-
define ('FEEDWORDPRESS_VERSION', '
|
36 |
define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
|
37 |
|
38 |
if (!defined('FEEDWORDPRESS_BLEG')) :
|
3 |
Plugin Name: FeedWordPress
|
4 |
Plugin URI: http://feedwordpress.radgeek.com/
|
5 |
Description: simple and flexible Atom/RSS syndication for WordPress
|
6 |
+
Version: 2016.0420
|
7 |
Author: Charles Johnson
|
8 |
Author URI: http://radgeek.com/
|
9 |
License: GPL
|
11 |
|
12 |
/**
|
13 |
* @package FeedWordPress
|
14 |
+
* @version 2016.0420
|
15 |
*/
|
16 |
|
17 |
# This uses code derived from:
|
32 |
|
33 |
# -- Don't change these unless you know what you're doing...
|
34 |
|
35 |
+
define ('FEEDWORDPRESS_VERSION', '2016.0420');
|
36 |
define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
|
37 |
|
38 |
if (!defined('FEEDWORDPRESS_BLEG')) :
|
@@ -3,8 +3,8 @@ Contributors: Charles Johnson
|
|
3 |
Donate link: http://feedwordpress.radgeek.com/
|
4 |
Tags: syndication, aggregation, feed, atom, rss
|
5 |
Requires at least: 3.0
|
6 |
-
Tested up to: 4.
|
7 |
-
Stable tag:
|
8 |
|
9 |
FeedWordPress syndicates content from feeds you choose into your WordPress weblog.
|
10 |
|
@@ -20,7 +20,7 @@ appears as a series of special posts in your WordPress posts database. If you
|
|
20 |
syndicate several feeds then you can use WordPress's posts database and
|
21 |
templating engine as the back-end of an aggregation ("planet") website. It was
|
22 |
developed, originally, because I needed a more flexible replacement for
|
23 |
-
[Planet][] to use at
|
24 |
|
25 |
[Planet]: http://www.planetplanet.org/
|
26 |
[Feminist Blogs]: http://feministblogs.org/
|
@@ -94,6 +94,33 @@ outs, see the documentation at the [FeedWordPress project homepage][].
|
|
94 |
|
95 |
== Changelog ==
|
96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
= 2015.0514 =
|
98 |
|
99 |
* IMPORTANT SECURITY UPDATE: This version includes two important fixes for
|
3 |
Donate link: http://feedwordpress.radgeek.com/
|
4 |
Tags: syndication, aggregation, feed, atom, rss
|
5 |
Requires at least: 3.0
|
6 |
+
Tested up to: 4.5.2
|
7 |
+
Stable tag: 2016.0420
|
8 |
|
9 |
FeedWordPress syndicates content from feeds you choose into your WordPress weblog.
|
10 |
|
20 |
syndicate several feeds then you can use WordPress's posts database and
|
21 |
templating engine as the back-end of an aggregation ("planet") website. It was
|
22 |
developed, originally, because I needed a more flexible replacement for
|
23 |
+
[Planet][] to use at Feminist Blogs, an aggregator site that I used to administer.
|
24 |
|
25 |
[Planet]: http://www.planetplanet.org/
|
26 |
[Feminist Blogs]: http://feministblogs.org/
|
94 |
|
95 |
== Changelog ==
|
96 |
|
97 |
+
= 2016.0420 =
|
98 |
+
|
99 |
+
* WORDPRESS COMPATIBILITY: Tested with new versions of WordPress up to 4.5.
|
100 |
+
|
101 |
+
* FILTERS AND ADD-ONS: Allow filters and add-ons to filter terms and taxonomy
|
102 |
+
(categories, tags, custom taxonomies, etc.) more thoroughly and more
|
103 |
+
fine-grainedly using syndicated_post_terms_match, syndicated_post_terms_match_{taxonomy},
|
104 |
+
syndicated_post_terms_unfamiliar, syndicated_post_terms_mapping,
|
105 |
+
syndicated_item_feed_terms, and syndicated_item_preset_terms filters.
|
106 |
+
|
107 |
+
* FILTERS AND ADD-ONS: Globals $fwp_channel and $fwp_feedmeta REMOVED.
|
108 |
+
These global variables, originally introduced to allow filters access to
|
109 |
+
information about the source feed in `syndicated_item` filters were
|
110 |
+
deprecated 6+ years ago. If you have any filters or add-ons which still
|
111 |
+
depend on these global variables, you've been using obsolete techniques
|
112 |
+
and you should see about fixing them to access data about the source feed
|
113 |
+
using the SyndicatedPost::link element instead. For documentation, see
|
114 |
+
the FeedWordPress documentation wiki at
|
115 |
+
<http://feedwordpress.radgeek.com/wiki/syndicatedpost> and
|
116 |
+
<http://feedwordpress.radgeek.com/wiki/syndicatedlink>.
|
117 |
+
|
118 |
+
* BUGFIX: Syndication > Diagnostics HTTP diagnostic test widget was broken due to
|
119 |
+
a dumb error on my part. Now fixed.
|
120 |
+
|
121 |
+
* SMALL CODING CHANGES: Lots of small changes to code organization, incorporation
|
122 |
+
of some PHP 5.x coding conventions, etc.
|
123 |
+
|
124 |
= 2015.0514 =
|
125 |
|
126 |
* IMPORTANT SECURITY UPDATE: This version includes two important fixes for
|
@@ -1,6 +1,7 @@
|
|
1 |
<?php
|
2 |
require_once(dirname(__FILE__).'/feedtime.class.php');
|
3 |
require_once(dirname(__FILE__).'/syndicatedpostterm.class.php');
|
|
|
4 |
|
5 |
/**
|
6 |
* class SyndicatedPost: FeedWordPress uses to manage the conversion of
|
@@ -42,7 +43,7 @@ class SyndicatedPost {
|
|
42 |
* @param array $item The item syndicated from the feed.
|
43 |
* @param SyndicatedLink $source The feed it was syndicated from.
|
44 |
*/
|
45 |
-
function
|
46 |
global $wpdb;
|
47 |
|
48 |
if ( empty($item) && empty($source) )
|
@@ -86,21 +87,6 @@ class SyndicatedPost {
|
|
86 |
// Fucking SimplePie.
|
87 |
$this->xmlns['reverse']['rss'][] = '';
|
88 |
|
89 |
-
# These globals were originally an ugly kludge around a bug in
|
90 |
-
# apply_filters from WordPress 1.5. The bug was fixed in 1.5.1,
|
91 |
-
# and I sure hope at this point that nobody writing filters for
|
92 |
-
# FeedWordPress is still relying on them.
|
93 |
-
#
|
94 |
-
# Anyway, I hereby declare them DEPRECATED as of 8 February
|
95 |
-
# 2010. I'll probably remove the globals within 1-2 releases in
|
96 |
-
# the interests of code hygiene and memory usage. If you
|
97 |
-
# currently use them in your filters, I advise you switch off to
|
98 |
-
# accessing the public members SyndicatedPost::feed and
|
99 |
-
# SyndicatedPost::feedmeta.
|
100 |
-
|
101 |
-
global $fwp_channel, $fwp_feedmeta;
|
102 |
-
$fwp_channel = $this->feed; $fwp_feedmeta = $this->feedmeta;
|
103 |
-
|
104 |
// Trigger global syndicated_item filter.
|
105 |
$changed = apply_filters('syndicated_item', $this->item, $this);
|
106 |
$this->item = $changed;
|
@@ -265,93 +251,15 @@ class SyndicatedPost {
|
|
265 |
// Store a hash of the post content for checking whether something needs to be updated
|
266 |
$this->post['meta']['syndication_item_hash'] = $this->update_hash();
|
267 |
|
268 |
-
// Categories:
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
if ($fc) :
|
273 |
-
$cats = array_merge($cats, explode("\n", $fc));
|
274 |
-
endif;
|
275 |
-
endif;
|
276 |
-
|
277 |
-
$fc = $this->link->setting('cats', NULL, array());
|
278 |
-
if (is_array($fc)) :
|
279 |
-
$cats = array_merge($cats, $fc);
|
280 |
-
endif;
|
281 |
-
$this->preset_terms['category'] = $cats;
|
282 |
-
|
283 |
-
// Now add categories from the post, if we have 'em
|
284 |
-
$cats = array();
|
285 |
-
$post_cats = $this->entry->get_categories();
|
286 |
-
if (is_array($post_cats)) : foreach ($post_cats as $cat) :
|
287 |
-
$cat_name = $cat->get_term();
|
288 |
-
if (!$cat_name) : $cat_name = $cat->get_label(); endif;
|
289 |
-
|
290 |
-
if ($this->link->setting('cat_split', NULL, NULL)) :
|
291 |
-
$pcre = "\007".$this->feedmeta['cat_split']."\007";
|
292 |
-
$cats = array_merge(
|
293 |
-
$cats,
|
294 |
-
preg_split(
|
295 |
-
$pcre,
|
296 |
-
$cat_name,
|
297 |
-
-1 /*=no limit*/,
|
298 |
-
PREG_SPLIT_NO_EMPTY
|
299 |
-
)
|
300 |
-
);
|
301 |
-
else :
|
302 |
-
$cats[] = $cat_name;
|
303 |
-
endif;
|
304 |
-
endforeach; endif;
|
305 |
-
|
306 |
-
$this->feed_terms['category'] = apply_filters('syndicated_item_categories', $cats, $this);
|
307 |
-
|
308 |
-
// Tags: start with default tags, if any
|
309 |
-
$tags = array();
|
310 |
-
if ('no' != $this->link->setting('add/post_tag', NULL, 'yes')) :
|
311 |
-
$ft = get_option("feedwordpress_syndication_tags", NULL);
|
312 |
-
$tags = (is_null($ft) ? array() : explode(FEEDWORDPRESS_CAT_SEPARATOR, $ft));
|
313 |
-
endif;
|
314 |
-
|
315 |
-
$ft = $this->link->setting('tags', NULL, array());
|
316 |
-
if (is_array($ft)) :
|
317 |
-
$tags = array_merge($tags, $ft);
|
318 |
-
endif;
|
319 |
-
$this->preset_terms['post_tag'] = $tags;
|
320 |
-
|
321 |
-
// Scan post for /a[@rel='tag'] and use as tags if present
|
322 |
-
$tags = $this->inline_tags();
|
323 |
-
$this->feed_terms['post_tag'] = apply_filters('syndicated_item_tags', $tags, $this);
|
324 |
-
|
325 |
-
$taxonomies = $this->link->taxonomies();
|
326 |
-
$feedTerms = $this->link->setting('terms', NULL, array());
|
327 |
-
$globalTerms = get_option('feedwordpress_syndication_terms', array());
|
328 |
-
|
329 |
-
$specials = array('category' => 'cats', 'post_tag' => 'tags');
|
330 |
-
foreach ($taxonomies as $tax) :
|
331 |
-
if (!isset($specials[$tax])) :
|
332 |
-
$terms = array();
|
333 |
-
|
334 |
-
// See if we should get the globals
|
335 |
-
if ('no' != $this->link->setting("add/$tax", NULL, 'yes')) :
|
336 |
-
if (isset($globalTerms[$tax])) :
|
337 |
-
$terms = $globalTerms[$tax];
|
338 |
-
endif;
|
339 |
-
endif;
|
340 |
-
|
341 |
-
// Now merge in the locals
|
342 |
-
if (isset($feedTerms[$tax])) :
|
343 |
-
$terms = array_merge($terms, $feedTerms[$tax]);
|
344 |
-
endif;
|
345 |
-
|
346 |
-
// That's all, folks.
|
347 |
-
$this->preset_terms[$tax] = $terms;
|
348 |
-
endif;
|
349 |
-
endforeach;
|
350 |
|
351 |
$this->post['post_type'] = apply_filters('syndicated_post_type', $this->link->setting('syndicated post type', 'syndicated_post_type', 'post'), $this);
|
352 |
endif;
|
353 |
|
354 |
-
} /* SyndicatedPost::
|
355 |
|
356 |
#####################################
|
357 |
#### EXTRACT DATA FROM FEED ITEM ####
|
@@ -383,97 +291,26 @@ class SyndicatedPost {
|
|
383 |
* elements or attributes
|
384 |
*/
|
385 |
function query ($path) {
|
386 |
-
|
387 |
-
|
388 |
-
// Allow {url} notation for namespaces. URLs will contain : and /, so...
|
389 |
-
preg_match_all('/{([^}]+)}/', $path, $match, PREG_SET_ORDER);
|
390 |
-
foreach ($match as $ref) :
|
391 |
-
$urlHash[md5($ref[1])] = $ref[1];
|
392 |
-
endforeach;
|
393 |
-
|
394 |
-
foreach ($urlHash as $hash => $url) :
|
395 |
-
$path = str_replace('{'.$url.'}', '{#'.$hash.'}', $path);
|
396 |
-
endforeach;
|
397 |
-
|
398 |
-
$path = explode('/', $path);
|
399 |
-
foreach ($path as $index => $node) :
|
400 |
-
if (preg_match('/{#([^}]+)}/', $node, $ref)) :
|
401 |
-
if (isset($urlHash[$ref[1]])) :
|
402 |
-
$path[$index] = str_replace(
|
403 |
-
'{#'.$ref[1].'}',
|
404 |
-
'{'.$urlHash[$ref[1]].'}',
|
405 |
-
$node
|
406 |
-
);
|
407 |
-
endif;
|
408 |
-
endif;
|
409 |
-
endforeach;
|
410 |
-
|
411 |
-
// Start out with a get_item_tags query.
|
412 |
-
$node = '';
|
413 |
-
while (strlen($node)==0 and !is_null($node)) :
|
414 |
-
$node = array_shift($path);
|
415 |
-
endwhile;
|
416 |
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
$data = $this->get_feed_root_element();
|
422 |
-
$data = array_merge($data, $this->get_feed_channel_elements());
|
423 |
-
break;
|
424 |
-
case 'item' :
|
425 |
-
$node = array_shift($path);
|
426 |
-
default :
|
427 |
-
$data = array($this->entry->data);
|
428 |
-
$method = NULL;
|
429 |
-
endswitch;
|
430 |
-
|
431 |
-
while (!is_null($node)) :
|
432 |
-
if (strlen($node) > 0) :
|
433 |
-
$matches = array();
|
434 |
-
|
435 |
-
list($axis, $element) = $this->xpath_name_and_axis($node);
|
436 |
-
|
437 |
-
foreach ($data as $datum) :
|
438 |
-
if (!is_string($datum) and isset($datum[$axis])) :
|
439 |
-
foreach ($datum[$axis] as $ns => $elements) :
|
440 |
-
if (isset($elements[$element])) :
|
441 |
-
// Potential match.
|
442 |
-
// Check namespace.
|
443 |
-
if (is_string($elements[$element])) : // Attribute
|
444 |
-
$addenda = array($elements[$element]);
|
445 |
-
$contexts = array($datum);
|
446 |
-
else : // Element
|
447 |
-
$addenda = $elements[$element];
|
448 |
-
$contexts = $elements[$element];
|
449 |
-
endif;
|
450 |
-
|
451 |
-
foreach ($addenda as $index => $addendum) :
|
452 |
-
$context = $contexts[$index];
|
453 |
-
|
454 |
-
$namespaces = $this->xpath_possible_namespaces($node, $context);
|
455 |
-
if (in_array($ns, $namespaces)) :
|
456 |
-
$matches[] = $addendum;
|
457 |
-
endif;
|
458 |
-
endforeach;
|
459 |
-
endif;
|
460 |
-
endforeach;
|
461 |
-
endif;
|
462 |
-
endforeach;
|
463 |
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
468 |
|
469 |
-
$matches = array();
|
470 |
-
foreach ($data as $datum) :
|
471 |
-
if (is_string($datum)) :
|
472 |
-
$matches[] = $datum;
|
473 |
-
elseif (isset($datum['data'])) :
|
474 |
-
$matches[] = $datum['data'];
|
475 |
-
endif;
|
476 |
-
endforeach;
|
477 |
return $matches;
|
478 |
} /* SyndicatedPost::query() */
|
479 |
|
@@ -505,84 +342,6 @@ class SyndicatedPost {
|
|
505 |
return $matches;
|
506 |
} /* SyndicatedPost::get_feed_channel_elements() */
|
507 |
|
508 |
-
function xpath_default_namespace () {
|
509 |
-
// Get the default namespace.
|
510 |
-
$type = $this->link->simplepie->get_type();
|
511 |
-
if ($type & SIMPLEPIE_TYPE_ATOM_10) :
|
512 |
-
$defaultNS = SIMPLEPIE_NAMESPACE_ATOM_10;
|
513 |
-
elseif ($type & SIMPLEPIE_TYPE_ATOM_03) :
|
514 |
-
$defaultNS = SIMPLEPIE_NAMESPACE_ATOM_03;
|
515 |
-
elseif ($type & SIMPLEPIE_TYPE_RSS_090) :
|
516 |
-
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_090;
|
517 |
-
elseif ($type & SIMPLEPIE_TYPE_RSS_10) :
|
518 |
-
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_10;
|
519 |
-
elseif ($type & SIMPLEPIE_TYPE_RSS_20) :
|
520 |
-
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_20;
|
521 |
-
else :
|
522 |
-
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_20;
|
523 |
-
endif;
|
524 |
-
return $defaultNS;
|
525 |
-
} /* SyndicatedPost::xpath_default_namespace() */
|
526 |
-
|
527 |
-
function xpath_name_and_axis ($node) {
|
528 |
-
$ns = NULL; $element = NULL;
|
529 |
-
|
530 |
-
if (substr($node, 0, 1)=='@') :
|
531 |
-
$axis = 'attribs'; $node = substr($node, 1);
|
532 |
-
else :
|
533 |
-
$axis = 'child';
|
534 |
-
endif;
|
535 |
-
|
536 |
-
if (preg_match('/^{([^}]*)}(.*)$/', $node, $ref)) :
|
537 |
-
$element = $ref[2];
|
538 |
-
elseif (strpos($node, ':') !== FALSE) :
|
539 |
-
list($xmlns, $element) = explode(':', $node, 2);
|
540 |
-
else :
|
541 |
-
$element = $node;
|
542 |
-
endif;
|
543 |
-
return array($axis, $element);
|
544 |
-
} /* SyndicatedPost::xpath_local_name () */
|
545 |
-
|
546 |
-
function xpath_possible_namespaces ($node, $datum = array()) {
|
547 |
-
$ns = NULL; $element = NULL;
|
548 |
-
|
549 |
-
if (substr($node, 0, 1)=='@') :
|
550 |
-
$attr = '@'; $node = substr($node, 1);
|
551 |
-
else :
|
552 |
-
$attr = '';
|
553 |
-
endif;
|
554 |
-
|
555 |
-
if (preg_match('/^{([^}]*)}(.*)$/', $node, $ref)) :
|
556 |
-
$ns = array($ref[1]);
|
557 |
-
elseif (strpos($node, ':') !== FALSE) :
|
558 |
-
list($xmlns, $element) = explode(':', $node, 2);
|
559 |
-
|
560 |
-
if (isset($this->xmlns['reverse'][$xmlns])) :
|
561 |
-
$ns = $this->xmlns['reverse'][$xmlns];
|
562 |
-
else :
|
563 |
-
$ns = array($xmlns);
|
564 |
-
endif;
|
565 |
-
|
566 |
-
// Fucking SimplePie. For attributes in default xmlns.
|
567 |
-
$defaultNS = $this->xpath_default_namespace();
|
568 |
-
if (isset($this->xmlns['forward'][$defaultNS])
|
569 |
-
and ($xmlns==$this->xmlns['forward'][$defaultNS])) :
|
570 |
-
$ns[] = '';
|
571 |
-
endif;
|
572 |
-
|
573 |
-
if (isset($datum['xmlns'])) :
|
574 |
-
if (isset($datum['xmlns'][$xmlns])) :
|
575 |
-
$ns[] = $datum['xmlns'][$xmlns];
|
576 |
-
endif;
|
577 |
-
endif;
|
578 |
-
else :
|
579 |
-
// Often in SimplePie, the default namespace gets stored
|
580 |
-
// as an empty string rather than a URL.
|
581 |
-
$ns = array($this->xpath_default_namespace(), '');
|
582 |
-
endif;
|
583 |
-
return array_unique($ns);
|
584 |
-
} /* SyndicatedPost::xpath_possible_namespaces() */
|
585 |
-
|
586 |
function get_categories ($params = array()) {
|
587 |
return $this->entry->get_categories();
|
588 |
}
|
@@ -976,6 +735,119 @@ class SyndicatedPost {
|
|
976 |
return $author;
|
977 |
} /* SyndicatedPost::author() */
|
978 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
979 |
/**
|
980 |
* SyndicatedPost::inline_tags: Return a list of all the tags embedded
|
981 |
* in post content using the a[@rel="tag"] microformat.
|
@@ -1568,13 +1440,17 @@ class SyndicatedPost {
|
|
1568 |
// We have to check again in case post has been filtered during
|
1569 |
// the author_id lookup
|
1570 |
if ($this->has_fresh_content()) :
|
1571 |
-
$
|
1572 |
-
'category' => array('abbr' => 'cats', 'domain' => array('category', 'post_tag')),
|
1573 |
-
'post_tag' => array('abbr' => 'tags', 'domain' => array('post_tag')),
|
1574 |
-
);
|
1575 |
|
1576 |
$termSet = array(); $valid = null;
|
1577 |
-
foreach ($
|
|
|
|
|
|
|
|
|
1578 |
if (!is_null($this->post)) : // Not filtered out yet
|
1579 |
# -- Look up, or create, numeric ID for categories
|
1580 |
$taxonomies = $this->link->setting("match/".$taxes['abbr'], 'match_'.$taxes['abbr'], $taxes['domain']);
|
@@ -1582,9 +1458,24 @@ class SyndicatedPost {
|
|
1582 |
// Eliminate dummy variables
|
1583 |
$taxonomies = array_filter($taxonomies, 'remove_dummy_zero');
|
1584 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1585 |
$terms = $this->category_ids (
|
1586 |
-
$
|
1587 |
-
$
|
1588 |
/*taxonomies=*/ $taxonomies,
|
1589 |
array(
|
1590 |
'singleton' => false, // I don't like surprises
|
@@ -1727,6 +1618,8 @@ class SyndicatedPost {
|
|
1727 |
|
1728 |
$dbpost = $this->normalize_post(/*new=*/ true);
|
1729 |
|
|
|
|
|
1730 |
if (!is_null($dbpost)) :
|
1731 |
$dbpost['post_pingback'] = false; // Tell WP 2.1 and 2.2 not to process for pingbacks
|
1732 |
|
@@ -1791,28 +1684,34 @@ class SyndicatedPost {
|
|
1791 |
$dbpost['ID'] = $this->_wp_id;
|
1792 |
endif;
|
1793 |
|
1794 |
-
//
|
1795 |
-
//
|
1796 |
-
|
1797 |
-
|
1798 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
1799 |
|
1800 |
-
|
1801 |
|
1802 |
-
|
1803 |
|
1804 |
-
|
1805 |
|
1806 |
-
|
1807 |
-
|
1808 |
-
|
1809 |
-
|
1810 |
-
|
1811 |
-
|
1812 |
-
|
1813 |
-
|
1814 |
-
|
1815 |
-
|
|
|
1816 |
endif;
|
1817 |
endif;
|
1818 |
|
@@ -1837,7 +1736,10 @@ class SyndicatedPost {
|
|
1837 |
endforeach;
|
1838 |
|
1839 |
$this->validate_post_id($dbpost, $update, array(__CLASS__, __FUNCTION__));
|
|
|
|
|
1840 |
endif;
|
|
|
1841 |
} /* function SyndicatedPost::insert_post () */
|
1842 |
|
1843 |
function insert_new () {
|
@@ -1884,11 +1786,46 @@ class SyndicatedPost {
|
|
1884 |
return $out;
|
1885 |
}
|
1886 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1887 |
function db_sanitize_post ($out) {
|
1888 |
-
|
1889 |
-
|
1890 |
-
|
1891 |
-
|
|
|
|
|
|
|
|
|
1892 |
if (!function_exists('wp_slash')) :
|
1893 |
|
1894 |
foreach ($out as $key => $value) :
|
@@ -1898,7 +1835,21 @@ class SyndicatedPost {
|
|
1898 |
$out[$key] = $value;
|
1899 |
endif;
|
1900 |
endforeach;
|
1901 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1902 |
endif;
|
1903 |
|
1904 |
return $out;
|
@@ -2338,4 +2289,3 @@ EOM;
|
|
2338 |
} /* SyndicatedPost::category_ids () */
|
2339 |
|
2340 |
} /* class SyndicatedPost */
|
2341 |
-
|
1 |
<?php
|
2 |
require_once(dirname(__FILE__).'/feedtime.class.php');
|
3 |
require_once(dirname(__FILE__).'/syndicatedpostterm.class.php');
|
4 |
+
require_once(dirname(__FILE__).'/syndicatedpostxpathquery.class.php');
|
5 |
|
6 |
/**
|
7 |
* class SyndicatedPost: FeedWordPress uses to manage the conversion of
|
43 |
* @param array $item The item syndicated from the feed.
|
44 |
* @param SyndicatedLink $source The feed it was syndicated from.
|
45 |
*/
|
46 |
+
function __construct ($item, &$source) {
|
47 |
global $wpdb;
|
48 |
|
49 |
if ( empty($item) && empty($source) )
|
87 |
// Fucking SimplePie.
|
88 |
$this->xmlns['reverse']['rss'][] = '';
|
89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
// Trigger global syndicated_item filter.
|
91 |
$changed = apply_filters('syndicated_item', $this->item, $this);
|
92 |
$this->item = $changed;
|
251 |
// Store a hash of the post content for checking whether something needs to be updated
|
252 |
$this->post['meta']['syndication_item_hash'] = $this->update_hash();
|
253 |
|
254 |
+
// Categories, Tags, and other Terms: from settings assignments (global settings, subscription settings),
|
255 |
+
// and from feed assignments (item metadata, post content)
|
256 |
+
$this->preset_terms = apply_filters('syndicated_item_preset_terms', $this->get_terms_from_settings(), $this);
|
257 |
+
$this->feed_terms = apply_filters('syndicated_item_feed_terms', $this->get_terms_from_feeds(), $this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
258 |
|
259 |
$this->post['post_type'] = apply_filters('syndicated_post_type', $this->link->setting('syndicated post type', 'syndicated_post_type', 'post'), $this);
|
260 |
endif;
|
261 |
|
262 |
+
} /* SyndicatedPost::__construct() */
|
263 |
|
264 |
#####################################
|
265 |
#### EXTRACT DATA FROM FEED ITEM ####
|
291 |
* elements or attributes
|
292 |
*/
|
293 |
function query ($path) {
|
294 |
+
$xq = new SyndicatedPostXPathQuery(array("path" => $path));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
295 |
|
296 |
+
$feedChannel = array_merge(
|
297 |
+
$this->get_feed_root_element(),
|
298 |
+
$this->get_feed_channel_elements()
|
299 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
300 |
|
301 |
+
$matches = $xq->match(array(
|
302 |
+
"type" => $this->link->simplepie->get_type(),
|
303 |
+
"xmlns" => $this->xmlns,
|
304 |
+
"map" => array(
|
305 |
+
"/" => array($this->entry->data),
|
306 |
+
"item" => array($this->entry->data),
|
307 |
+
"feed" => $feedChannel,
|
308 |
+
"channel" => $feedChannel
|
309 |
+
),
|
310 |
+
"context" => $this->entry->data,
|
311 |
+
"parent" => $feedChannel,
|
312 |
+
));
|
313 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
314 |
return $matches;
|
315 |
} /* SyndicatedPost::query() */
|
316 |
|
342 |
return $matches;
|
343 |
} /* SyndicatedPost::get_feed_channel_elements() */
|
344 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
345 |
function get_categories ($params = array()) {
|
346 |
return $this->entry->get_categories();
|
347 |
}
|
735 |
return $author;
|
736 |
} /* SyndicatedPost::author() */
|
737 |
|
738 |
+
/**
|
739 |
+
* SyndicatedPost::get_terms_from_settings(): Return an array of terms to associate with the incoming
|
740 |
+
* post based on the Categories, Tags, and other terms associated with each new post by the user's
|
741 |
+
* settings (global and feed-specific).
|
742 |
+
*
|
743 |
+
* @since 2016.0331
|
744 |
+
* @return array of lists, each element has the taxonomy for a key ('category', 'post_tag', etc.),
|
745 |
+
* and a list of term codes (either alphanumeric names, or ID numbers encoded in a format that
|
746 |
+
* SyndicatedLink::category_ids() can understand) within that taxonomy
|
747 |
+
*
|
748 |
+
*/
|
749 |
+
public function get_terms_from_settings () {
|
750 |
+
// Categories: start with default categories, if any.
|
751 |
+
$cats = array();
|
752 |
+
if ('no' != $this->link->setting('add/category', NULL, 'yes')) :
|
753 |
+
$fc = get_option("feedwordpress_syndication_cats");
|
754 |
+
if ($fc) :
|
755 |
+
$cats = array_merge($cats, explode("\n", $fc));
|
756 |
+
endif;
|
757 |
+
endif;
|
758 |
+
|
759 |
+
$fc = $this->link->setting('cats',NULL, array());
|
760 |
+
if (is_array($fc)) :
|
761 |
+
$cats = array_merge($cats, $fc);
|
762 |
+
endif;
|
763 |
+
$preset_terms['category'] = $cats;
|
764 |
+
|
765 |
+
// Tags: start with default tags, if any
|
766 |
+
$tags = array();
|
767 |
+
if ('no' != $this->link->setting('add/post_tag', NULL, 'yes')) :
|
768 |
+
$ft = get_option("feedwordpress_syndication_tags", NULL);
|
769 |
+
$tags = (is_null($ft) ? array() : explode(FEEDWORDPRESS_CAT_SEPARATOR, $ft));
|
770 |
+
endif;
|
771 |
+
|
772 |
+
$ft = $this->link->setting('tags', NULL, array());
|
773 |
+
if (is_array($ft)) :
|
774 |
+
$tags = array_merge($tags, $ft);
|
775 |
+
endif;
|
776 |
+
$preset_terms['post_tag'] = $tags;
|
777 |
+
|
778 |
+
$taxonomies = $this->link->taxonomies();
|
779 |
+
$feedTerms = $this->link->setting('terms', NULL, array());
|
780 |
+
$globalTerms = get_option('feedwordpress_syndication_terms', array());
|
781 |
+
$specials = array('category' => 'cats', 'post_tag' => 'tags');
|
782 |
+
|
783 |
+
foreach ($taxonomies as $tax) :
|
784 |
+
// category and tag settings have already previously been handled
|
785 |
+
// but if this is from another taxonomy, then...
|
786 |
+
if (!isset($specials[$tax])) :
|
787 |
+
$terms = array();
|
788 |
+
|
789 |
+
// See if we should get the globals
|
790 |
+
if ('no' != $this->link->setting("add/$tax", NULL, 'yes')) :
|
791 |
+
if (isset($globalTerms[$tax])) :
|
792 |
+
$terms = $globalTerms[$tax];
|
793 |
+
endif;
|
794 |
+
endif;
|
795 |
+
|
796 |
+
// Now merge in the locals
|
797 |
+
if (isset($feedTerms[$tax])) :
|
798 |
+
$terms = array_merge($terms, $feedTerms[$tax]);
|
799 |
+
endif;
|
800 |
+
|
801 |
+
// That's all, folks.
|
802 |
+
$preset_terms[$tax] = $terms;
|
803 |
+
endif;
|
804 |
+
endforeach;
|
805 |
+
|
806 |
+
return $preset_terms;
|
807 |
+
} /* SyndicatedPost::get_terms_from_settings () */
|
808 |
+
|
809 |
+
/**
|
810 |
+
* SyndicatedPost::get_terms_from_feeds(): Return an array of terms to associate with the incoming
|
811 |
+
* post based on the contents of the subscribed feed (atom:category and rss:category elements, dc:subject
|
812 |
+
* elements, tags embedded using microformats in the post content, etc.)
|
813 |
+
*
|
814 |
+
* @since 2016.0331
|
815 |
+
* @return array of lists, each element has the taxonomy for a key ('category', 'post_tag', etc.),
|
816 |
+
* and a list of alphanumeric term names
|
817 |
+
*/
|
818 |
+
public function get_terms_from_feeds () {
|
819 |
+
// Now add categories from the post, if we have 'em
|
820 |
+
$cats = array();
|
821 |
+
$post_cats = $this->entry->get_categories();
|
822 |
+
if (is_array($post_cats)) : foreach ($post_cats as $cat) :
|
823 |
+
$cat_name = $cat->get_term();
|
824 |
+
if (!$cat_name) : $cat_name = $cat->get_label(); endif;
|
825 |
+
|
826 |
+
if ($this->link->setting('cat_split', NULL, NULL)) :
|
827 |
+
$pcre = "\007".$this->feedmeta['cat_split']."\007";
|
828 |
+
$cats = array_merge(
|
829 |
+
$cats,
|
830 |
+
preg_split(
|
831 |
+
$pcre,
|
832 |
+
$cat_name,
|
833 |
+
-1 /*=no limit*/,
|
834 |
+
PREG_SPLIT_NO_EMPTY
|
835 |
+
)
|
836 |
+
);
|
837 |
+
else :
|
838 |
+
$cats[] = $cat_name;
|
839 |
+
endif;
|
840 |
+
endforeach; endif;
|
841 |
+
|
842 |
+
$feed_terms['category'] = apply_filters('syndicated_item_categories', $cats, $this);
|
843 |
+
|
844 |
+
// Scan post for /a[@rel='tag'] and use as tags if present
|
845 |
+
$tags = $this->inline_tags();
|
846 |
+
$feed_terms['post_tag'] = apply_filters('syndicated_item_tags', $tags, $this);
|
847 |
+
|
848 |
+
return $feed_terms;
|
849 |
+
} /* SyndicatedPost::get_terms_from_feeds () */
|
850 |
+
|
851 |
/**
|
852 |
* SyndicatedPost::inline_tags: Return a list of all the tags embedded
|
853 |
* in post content using the a[@rel="tag"] microformat.
|
1440 |
// We have to check again in case post has been filtered during
|
1441 |
// the author_id lookup
|
1442 |
if ($this->has_fresh_content()) :
|
1443 |
+
$mapping = apply_filters('syndicated_post_terms_mapping', array(
|
1444 |
+
'category' => array('abbr' => 'cats', 'unfamiliar' => 'category', 'domain' => array('category', 'post_tag')),
|
1445 |
+
'post_tag' => array('abbr' => 'tags', 'unfamiliar' => 'post_tag', 'domain' => array('post_tag')),
|
1446 |
+
), $this);
|
1447 |
|
1448 |
$termSet = array(); $valid = null;
|
1449 |
+
foreach ($this->feed_terms as $what => $anTerms) :
|
1450 |
+
// Default to using the inclusive procedures (for cats) rather than exclusive (for inline tags)
|
1451 |
+
$taxes = (isset($mapping[$what]) ? $mapping[$what] : $mapping['category']);
|
1452 |
+
$unfamiliar = $taxes['unfamiliar'];
|
1453 |
+
|
1454 |
if (!is_null($this->post)) : // Not filtered out yet
|
1455 |
# -- Look up, or create, numeric ID for categories
|
1456 |
$taxonomies = $this->link->setting("match/".$taxes['abbr'], 'match_'.$taxes['abbr'], $taxes['domain']);
|
1458 |
// Eliminate dummy variables
|
1459 |
$taxonomies = array_filter($taxonomies, 'remove_dummy_zero');
|
1460 |
|
1461 |
+
// Allow FWP add-on filters to control the taxonomies we use to search for a term
|
1462 |
+
$taxonomies = apply_filters("syndicated_post_terms_match", $taxonomies, $what, $this);
|
1463 |
+
$taxonomies = apply_filters("syndicated_post_terms_match_${what}", $taxonomies, $this);
|
1464 |
+
|
1465 |
+
// Allow FWP add-on filters to control with greater precision what happens on unmatched
|
1466 |
+
$unmatched = apply_filters("syndicated_post_terms_unfamiliar",
|
1467 |
+
$this->link->setting(
|
1468 |
+
"unfamiliar {$unfamiliar}",
|
1469 |
+
"unfamiliar_{$unfamiliar}",
|
1470 |
+
'create:'.$unfamiliar
|
1471 |
+
),
|
1472 |
+
$what,
|
1473 |
+
$this
|
1474 |
+
);
|
1475 |
+
|
1476 |
$terms = $this->category_ids (
|
1477 |
+
$anTerms,
|
1478 |
+
$unmatched,
|
1479 |
/*taxonomies=*/ $taxonomies,
|
1480 |
array(
|
1481 |
'singleton' => false, // I don't like surprises
|
1618 |
|
1619 |
$dbpost = $this->normalize_post(/*new=*/ true);
|
1620 |
|
1621 |
+
$ret = null;
|
1622 |
+
|
1623 |
if (!is_null($dbpost)) :
|
1624 |
$dbpost['post_pingback'] = false; // Tell WP 2.1 and 2.2 not to process for pingbacks
|
1625 |
|
1684 |
$dbpost['ID'] = $this->_wp_id;
|
1685 |
endif;
|
1686 |
|
1687 |
+
// Sanity check: if the attempt to insert post
|
1688 |
+
// returned an error, then feeding that error
|
1689 |
+
// object in to _wp_put_post_revision() would
|
1690 |
+
// cause a fatal error. Better to break out.
|
1691 |
+
if (!is_wp_error($this->_wp_id)) :
|
1692 |
+
// Now that we've made sure the original exists, insert
|
1693 |
+
// this version here as a revision.
|
1694 |
+
$revision_id = _wp_put_post_revision($dbpost, /*autosave=*/ false);
|
1695 |
+
|
1696 |
+
if (!$this->this_revision_needs_original_post()) :
|
1697 |
|
1698 |
+
if ($this->this_revision_is_current()) :
|
1699 |
|
1700 |
+
wp_restore_post_revision($revision_id);
|
1701 |
|
1702 |
+
else :
|
1703 |
|
1704 |
+
// If we do not activate this revision, then the
|
1705 |
+
// add_rss_meta will not be called, which is
|
1706 |
+
// more or less as it should be, but that means
|
1707 |
+
// we have to actively record this revision's
|
1708 |
+
// update hash from here.
|
1709 |
+
$postId = $this->post['ID'];
|
1710 |
+
$key = 'syndication_item_hash';
|
1711 |
+
$hash = $this->update_hash();
|
1712 |
+
FeedWordPress::diagnostic('syndicated_posts:meta_data', "Adding post meta-datum to post [$postId]: [$key] = ".FeedWordPress::val($hash, /*no newlines=*/ true));
|
1713 |
+
add_post_meta( $postId, $key, $hash, /*unique=*/ false );
|
1714 |
+
endif;
|
1715 |
endif;
|
1716 |
endif;
|
1717 |
|
1736 |
endforeach;
|
1737 |
|
1738 |
$this->validate_post_id($dbpost, $update, array(__CLASS__, __FUNCTION__));
|
1739 |
+
|
1740 |
+
$ret = $this->_wp_id;
|
1741 |
endif;
|
1742 |
+
return $ret;
|
1743 |
} /* function SyndicatedPost::insert_post () */
|
1744 |
|
1745 |
function insert_new () {
|
1786 |
return $out;
|
1787 |
}
|
1788 |
|
1789 |
+
public function db_sanitize_post_check_encoding ($out) {
|
1790 |
+
// Check encoding recursively: every string field needs to be checked
|
1791 |
+
// for character encoding issues. This is a bit problematic because we
|
1792 |
+
// *should* be using DB_CHARSET, but DB_CHARSET sometimes has values
|
1793 |
+
// that work for MySQL but not for PHP mb_check_encoding. So instead
|
1794 |
+
// we must rely on WordPress setting blog_charset and hope that the user
|
1795 |
+
// has got their database encoding set up to roughly match
|
1796 |
+
$charset = get_option('blog_charset', 'utf8');
|
1797 |
+
|
1798 |
+
foreach ($out as $key => $value) :
|
1799 |
+
if (is_string($value)) :
|
1800 |
+
|
1801 |
+
if (!function_exists('mb_check_encoding') or mb_check_encoding($value, $charset)) :
|
1802 |
+
$out[$key] = $value;
|
1803 |
+
else :
|
1804 |
+
$fromCharset = mb_detect_encoding($value, mb_detect_order(), /*strict=*/ true);
|
1805 |
+
$out[$key] = mb_convert_encoding($value, $charset, $fromCharset);
|
1806 |
+
endif;
|
1807 |
+
|
1808 |
+
elseif (is_array($value)) :
|
1809 |
+
$out[$key] = $this->db_sanitize_post_check_encoding($value);
|
1810 |
+
|
1811 |
+
else :
|
1812 |
+
$out[$key] = $value;
|
1813 |
+
endif;
|
1814 |
+
|
1815 |
+
endforeach;
|
1816 |
+
|
1817 |
+
return $out;
|
1818 |
+
} /* SyndicatedPost::db_sanitize_post_check_encoding () */
|
1819 |
+
|
1820 |
function db_sanitize_post ($out) {
|
1821 |
+
global $wp_db_version;
|
1822 |
+
|
1823 |
+
$out = $this->db_sanitize_post_check_encoding($out);
|
1824 |
+
|
1825 |
+
// < 3.6. Core API, including `wp_insert_post()`, expects
|
1826 |
+
// properly slashed data. If `wp_slash()` exists, then
|
1827 |
+
// this is after the big change-over in how data slashing
|
1828 |
+
// was handled.
|
1829 |
if (!function_exists('wp_slash')) :
|
1830 |
|
1831 |
foreach ($out as $key => $value) :
|
1835 |
$out[$key] = $value;
|
1836 |
endif;
|
1837 |
endforeach;
|
1838 |
+
|
1839 |
+
// For revisions [@23416,@23554), core API expects
|
1840 |
+
// unslashed data. Cf. <https://core.trac.wordpress.org/browser/trunk/wp-includes/post.php?rev=23416>
|
1841 |
+
// NOOP for those revisions.
|
1842 |
+
|
1843 |
+
// In revisions @23554 to present, `wp_insert_post()`
|
1844 |
+
// expects slashed data once again.
|
1845 |
+
// Cf. <https://core.trac.wordpress.org/changeset/23554/trunk/wp-includes/post.php?contextall=1>
|
1846 |
+
// But at least now we can use the wp_slash API function to do that.
|
1847 |
+
// Hooray.
|
1848 |
+
|
1849 |
+
elseif ($wp_db_version >= 23524) :
|
1850 |
+
|
1851 |
+
$out = wp_slash($out);
|
1852 |
+
|
1853 |
endif;
|
1854 |
|
1855 |
return $out;
|
2289 |
} /* SyndicatedPost::category_ids () */
|
2290 |
|
2291 |
} /* class SyndicatedPost */
|
|
@@ -59,6 +59,9 @@ class SyndicatedPostTerm {
|
|
59 |
|
60 |
protected function search () {
|
61 |
|
|
|
|
|
|
|
62 |
// Either this is a numbered term code, which supplies the ID
|
63 |
// and the taxonomy explicitly (e.g.: {category#2}; in which
|
64 |
// case we have set $this->tax to a unit array containing only
|
@@ -90,7 +93,7 @@ class SyndicatedPostTerm {
|
|
90 |
'CHECKED familiarity of term '
|
91 |
.json_encode($this->term)
|
92 |
.' across '.json_encode($this->tax)
|
93 |
-
. ' with result: '.json_encode($
|
94 |
);
|
95 |
|
96 |
return $this->exists;
|
59 |
|
60 |
protected function search () {
|
61 |
|
62 |
+
// Initialize
|
63 |
+
$found = null;
|
64 |
+
|
65 |
// Either this is a numbered term code, which supplies the ID
|
66 |
// and the taxonomy explicitly (e.g.: {category#2}; in which
|
67 |
// case we have set $this->tax to a unit array containing only
|
93 |
'CHECKED familiarity of term '
|
94 |
.json_encode($this->term)
|
95 |
.' across '.json_encode($this->tax)
|
96 |
+
. ' with result: '.json_encode($found)
|
97 |
);
|
98 |
|
99 |
return $this->exists;
|
@@ -0,0 +1,462 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* class SyndicatedPostXPathQuery: implements an XPath-like syntax used to query
|
4 |
+
* arbitrary elements within the syndicated item.
|
5 |
+
*
|
6 |
+
*/
|
7 |
+
class SyndicatedPostXPathQuery {
|
8 |
+
private $path;
|
9 |
+
private $parsedPath;
|
10 |
+
private $feed_type;
|
11 |
+
private $xmlns;
|
12 |
+
private $urlHash = array();
|
13 |
+
|
14 |
+
/**
|
15 |
+
* SyndicatedPostXPathQuery::__construct
|
16 |
+
*
|
17 |
+
* @param array $args
|
18 |
+
* @uses wp_parse_args
|
19 |
+
*
|
20 |
+
*/
|
21 |
+
public function __construct ($args = array()) {
|
22 |
+
if (is_string($args)) :
|
23 |
+
$args = array("path" => $args);
|
24 |
+
endif;
|
25 |
+
|
26 |
+
$args = wp_parse_args($args, array(
|
27 |
+
"path" => "",
|
28 |
+
));
|
29 |
+
|
30 |
+
$this->setPath($args['path']);
|
31 |
+
} /* SyndicatedPostXPathQuery::__construct() */
|
32 |
+
|
33 |
+
/**
|
34 |
+
* SyndicatedPostXPathQuery::getPath
|
35 |
+
*
|
36 |
+
* @param array $args
|
37 |
+
* @return mixed
|
38 |
+
*/
|
39 |
+
public function getPath ($args = array()) {
|
40 |
+
$args = wp_parse_args($args, array(
|
41 |
+
"parsed" => false,
|
42 |
+
));
|
43 |
+
|
44 |
+
return ($args['parsed'] ? $this->parsedPath : $this->path);
|
45 |
+
} /* SyndicatedPostXPathQuery::getPath () */
|
46 |
+
|
47 |
+
/**
|
48 |
+
* SyndicatedPostXPathQuery::setPath
|
49 |
+
*
|
50 |
+
* @param string $path
|
51 |
+
*/
|
52 |
+
public function setPath ($path) {
|
53 |
+
$this->urlHash = array();
|
54 |
+
|
55 |
+
$this->path = $path;
|
56 |
+
|
57 |
+
// Allow {url} notation for namespaces. URLs will contain : and /, so...
|
58 |
+
preg_match_all('/{([^}]+)}/', $path, $match, PREG_SET_ORDER);
|
59 |
+
foreach ($match as $ref) :
|
60 |
+
$this->urlHash[md5($ref[1])] = $ref[1];
|
61 |
+
endforeach;
|
62 |
+
|
63 |
+
foreach ($this->urlHash as $hash => $url) :
|
64 |
+
$path = str_replace('{'.$url.'}', '{#'.$hash.'}', $path);
|
65 |
+
endforeach;
|
66 |
+
|
67 |
+
$path = $this->parsePath(/*cur=*/ $path, /*orig=*/ $path);
|
68 |
+
|
69 |
+
$this->parsedPath = $path;
|
70 |
+
|
71 |
+
} /* SyndicatedPostXPathQuery::setPath() */
|
72 |
+
|
73 |
+
/**
|
74 |
+
* SyndicatedPostXPathQuery::snipSlug
|
75 |
+
*
|
76 |
+
* @return string
|
77 |
+
*/
|
78 |
+
protected function snipSlug ($path, $start, $n) {
|
79 |
+
$slug = substr($path, $start, ($n-$start));
|
80 |
+
if (strlen($slug) > 0) :
|
81 |
+
if (preg_match('/{#([^}]+)}/', $slug, $ref)) :
|
82 |
+
if (isset($this->urlHash[$ref[1]])) :
|
83 |
+
$slug = str_replace(
|
84 |
+
'{#'.$ref[1].'}',
|
85 |
+
'{'.$this->urlHash[$ref[1]].'}',
|
86 |
+
$slug
|
87 |
+
);
|
88 |
+
endif;
|
89 |
+
endif;
|
90 |
+
endif;
|
91 |
+
return $slug;
|
92 |
+
} /* SyndicatedPostXPathQuery::snipSlug () */
|
93 |
+
|
94 |
+
/**
|
95 |
+
* SyndicatedPostXPathQuery::parsePath ()
|
96 |
+
*
|
97 |
+
* @param mixed $path
|
98 |
+
* @param mixed $rootPath
|
99 |
+
* @return array|object
|
100 |
+
*/
|
101 |
+
public function parsePath ($path, $rootPath) {
|
102 |
+
if (is_array($path)) :
|
103 |
+
// This looks like it's already been parsed.
|
104 |
+
$pp = $path;
|
105 |
+
else :
|
106 |
+
$pp = array();
|
107 |
+
|
108 |
+
// Okay let's parse this thing.
|
109 |
+
$n = 0; $start = 0; $state = 'slug';
|
110 |
+
while ($state != '$') :
|
111 |
+
switch ($state) :
|
112 |
+
case 'slash' :
|
113 |
+
$slug = $this->snipSlug($path, $start, $n);
|
114 |
+
if (strlen($slug) > 0) :
|
115 |
+
$pp[] = $slug;
|
116 |
+
endif;
|
117 |
+
|
118 |
+
$n++;
|
119 |
+
// don't include the slash in our next slug
|
120 |
+
$start = $n;
|
121 |
+
|
122 |
+
$state = (($n < strlen($path)) ? 'slug' : '$');
|
123 |
+
|
124 |
+
break;
|
125 |
+
case 'brackets' :
|
126 |
+
|
127 |
+
// first, snip off what we've consumed so far
|
128 |
+
$slug = $this->snipSlug($path, $start, $n);
|
129 |
+
if (strlen($slug) > 0) :
|
130 |
+
$pp[] = $slug;
|
131 |
+
endif;
|
132 |
+
|
133 |
+
// now, chase the ]
|
134 |
+
$depth = 1;
|
135 |
+
$n++; $start = $n;
|
136 |
+
|
137 |
+
// find the end of the [square-bracketed] expression
|
138 |
+
while ($depth > 0 and $n != '') :
|
139 |
+
$tok = ((strlen($path) > $n) ? $path[$n] : '');
|
140 |
+
switch ($tok) :
|
141 |
+
case '' :
|
142 |
+
// ERROR STATE: syntax error
|
143 |
+
$depth = -1;
|
144 |
+
$state = 'syntax-error';
|
145 |
+
break;
|
146 |
+
case '[' :
|
147 |
+
$depth++;
|
148 |
+
break;
|
149 |
+
case ']' :
|
150 |
+
$depth--;
|
151 |
+
break;
|
152 |
+
default :
|
153 |
+
// NOOP
|
154 |
+
endswitch;
|
155 |
+
$n++;
|
156 |
+
endwhile;
|
157 |
+
|
158 |
+
if ($state != 'syntax-error') :
|
159 |
+
$bracketed = substr($path, $start, ($n-$start)-1);
|
160 |
+
|
161 |
+
// recursive parsing
|
162 |
+
$oFilter = new stdClass;
|
163 |
+
$oFilter->verb = 'has';
|
164 |
+
$oFilter->query = $this->parsePath($bracketed, $rootPath);
|
165 |
+
$pp[] = $oFilter;
|
166 |
+
|
167 |
+
$start = $n;
|
168 |
+
|
169 |
+
$state = 'slash-expected';
|
170 |
+
endif;
|
171 |
+
break;
|
172 |
+
|
173 |
+
case 'slash-expected' :
|
174 |
+
$tok = ((strlen($path) > $n) ? $path[$n] : '');
|
175 |
+
if ($tok == '/' or $tok == '') :
|
176 |
+
$state = 'slash';
|
177 |
+
else :
|
178 |
+
$state = 'syntax-error';
|
179 |
+
endif;
|
180 |
+
break;
|
181 |
+
case 'syntax-error' :
|
182 |
+
$pp = new WP_Error('xpath', __("Syntax error", "feedwordpress"));
|
183 |
+
$state = '$';
|
184 |
+
break;
|
185 |
+
case 'slug' :
|
186 |
+
default :
|
187 |
+
$tok = ((strlen($path) > $n) ? $path[$n] : '');
|
188 |
+
switch ($tok) :
|
189 |
+
case '' :
|
190 |
+
case '/' :
|
191 |
+
$state = 'slash';
|
192 |
+
break;
|
193 |
+
case '[' :
|
194 |
+
$state = 'brackets';
|
195 |
+
break;
|
196 |
+
default :
|
197 |
+
$n++;
|
198 |
+
endswitch;
|
199 |
+
endswitch;
|
200 |
+
endwhile;
|
201 |
+
endif;
|
202 |
+
return $pp;
|
203 |
+
} /* SyndicatedPostXPathQuery::parsePath() */
|
204 |
+
|
205 |
+
/**
|
206 |
+
* SyndicatedPostXPathQuery::match
|
207 |
+
*
|
208 |
+
* @param string $path
|
209 |
+
* @return array
|
210 |
+
*/
|
211 |
+
public function match ($r = array()) {
|
212 |
+
$path = $this->parsedPath;
|
213 |
+
|
214 |
+
$r = wp_parse_args($r, array(
|
215 |
+
"type" => SIMPLEPIE_TYPE_ATOM_10,
|
216 |
+
"xmlns" => array(),
|
217 |
+
"map" => array(),
|
218 |
+
"context" => array(),
|
219 |
+
"parent" => array(),
|
220 |
+
"format" => "string",
|
221 |
+
));
|
222 |
+
|
223 |
+
$this->feed_type = $r['type'];
|
224 |
+
$this->xmlns = $r['xmlns'];
|
225 |
+
|
226 |
+
// Start out with a get_item_tags query.
|
227 |
+
$node = '';
|
228 |
+
while (strlen($node)==0 and !is_null($node)) :
|
229 |
+
$node = array_shift($path);
|
230 |
+
endwhile;
|
231 |
+
|
232 |
+
if (is_string($node) and isset($r['map'][$node])) :
|
233 |
+
$data = $r['map'][$node];
|
234 |
+
$node = array_shift($path);
|
235 |
+
else :
|
236 |
+
$data = $r['map']['/'];
|
237 |
+
endif;
|
238 |
+
|
239 |
+
$matches = $data;
|
240 |
+
while (!is_null($node)) :
|
241 |
+
if (is_object($node) OR strlen($node) > 0) :
|
242 |
+
list($axis, $element) = $this->xpath_name_and_axis($node);
|
243 |
+
if ('self'==$axis) :
|
244 |
+
if (is_object($element) and property_exists($element, 'verb')) :
|
245 |
+
|
246 |
+
$subq = new self(array("path" => $element->query));
|
247 |
+
$result = $subq->match(array(
|
248 |
+
"type" => $r['type'],
|
249 |
+
"xmlns" => $r['xmlns'],
|
250 |
+
"map" => array(
|
251 |
+
"/" => $matches,
|
252 |
+
),
|
253 |
+
"context" => $matches,
|
254 |
+
"parent" => $r['parent'],
|
255 |
+
"format" => "object",
|
256 |
+
));
|
257 |
+
|
258 |
+
// when format = 'object' we should get back
|
259 |
+
// a sparse array of arrays, with indices = indices
|
260 |
+
// from the input array, each element = an array of
|
261 |
+
// one or more matching elements
|
262 |
+
|
263 |
+
if ($element->verb = 'has' and is_array($result)) :
|
264 |
+
|
265 |
+
$results = array();
|
266 |
+
foreach (array_keys($result) as $a) :
|
267 |
+
$results[$a] = $matches[$a];
|
268 |
+
endforeach;
|
269 |
+
|
270 |
+
$matches = $results;
|
271 |
+
$data = $matches;
|
272 |
+
endif;
|
273 |
+
|
274 |
+
elseif (is_numeric($node)) :
|
275 |
+
|
276 |
+
// according to W3C, sequence starts at position 1, not 0
|
277 |
+
// so subtract 1 to line up with PHP array starting at 0
|
278 |
+
$idx = intval($element) - 1;
|
279 |
+
if (isset($matches[$idx])) :
|
280 |
+
$data = array($idx => $matches[$idx]);
|
281 |
+
else :
|
282 |
+
$data = array();
|
283 |
+
endif;
|
284 |
+
|
285 |
+
$matches = array($idx => $data);
|
286 |
+
endif;
|
287 |
+
|
288 |
+
else :
|
289 |
+
$matches = array();
|
290 |
+
|
291 |
+
foreach ($data as $idx => $datum) :
|
292 |
+
if (!is_string($datum) and isset($datum[$axis])) :
|
293 |
+
foreach ($datum[$axis] as $ns => $elements) :
|
294 |
+
if (isset($elements[$element])) :
|
295 |
+
// Potential match.
|
296 |
+
// Check namespace.
|
297 |
+
if (is_string($elements[$element])) : // Attribute
|
298 |
+
$addenda = array($elements[$element]);
|
299 |
+
$contexts = array($datum);
|
300 |
+
|
301 |
+
// Element
|
302 |
+
else :
|
303 |
+
$addenda = $elements[$element];
|
304 |
+
$contexts = $elements[$element];
|
305 |
+
endif;
|
306 |
+
|
307 |
+
foreach ($addenda as $index => $addendum) :
|
308 |
+
$context = $contexts[$index];
|
309 |
+
|
310 |
+
$namespaces = $this->xpath_possible_namespaces($node, $context);
|
311 |
+
if (in_array($ns, $namespaces)) :
|
312 |
+
$matches[] = $addendum;
|
313 |
+
endif;
|
314 |
+
endforeach;
|
315 |
+
endif;
|
316 |
+
endforeach;
|
317 |
+
endif;
|
318 |
+
endforeach;
|
319 |
+
|
320 |
+
$data = $matches;
|
321 |
+
endif;
|
322 |
+
endif;
|
323 |
+
$node = array_shift($path);
|
324 |
+
endwhile;
|
325 |
+
|
326 |
+
$matches = array();
|
327 |
+
foreach ($data as $idx => $datum) :
|
328 |
+
if ($r['format'] == 'string') :
|
329 |
+
if (is_string($datum)) :
|
330 |
+
$matches[] = $datum;
|
331 |
+
elseif (isset($datum['data'])) :
|
332 |
+
$matches[] = $datum['data'];
|
333 |
+
endif;
|
334 |
+
else :
|
335 |
+
$matches[$idx] = $datum;
|
336 |
+
endif;
|
337 |
+
endforeach;
|
338 |
+
|
339 |
+
return $matches;
|
340 |
+
} /* SyndicatedPostXPathQuery::match() */
|
341 |
+
|
342 |
+
public function xpath_default_namespace () {
|
343 |
+
// Get the default namespace.
|
344 |
+
$type = $this->feed_type;
|
345 |
+
if ($type & SIMPLEPIE_TYPE_ATOM_10) :
|
346 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_ATOM_10;
|
347 |
+
elseif ($type & SIMPLEPIE_TYPE_ATOM_03) :
|
348 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_ATOM_03;
|
349 |
+
elseif ($type & SIMPLEPIE_TYPE_RSS_090) :
|
350 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_090;
|
351 |
+
elseif ($type & SIMPLEPIE_TYPE_RSS_10) :
|
352 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_10;
|
353 |
+
elseif ($type & SIMPLEPIE_TYPE_RSS_20) :
|
354 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_20;
|
355 |
+
else :
|
356 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_20;
|
357 |
+
endif;
|
358 |
+
return $defaultNS;
|
359 |
+
} /* SyndicatedPostXPathQuery::xpath_default_namespace() */
|
360 |
+
|
361 |
+
public function xpath_name_and_axis ($node) {
|
362 |
+
$ns = NULL; $element = NULL;
|
363 |
+
|
364 |
+
$axis = 'child'; // "In effect, `child` is the default axis."
|
365 |
+
if (is_object($node) and property_exists($node, 'verb')):
|
366 |
+
if ('has'==$node->verb) :
|
367 |
+
$axis = 'self';
|
368 |
+
endif;
|
369 |
+
elseif (strpos($node, '::') !== false) :
|
370 |
+
list($axis, $node) = explode("::", $node, 2);
|
371 |
+
if ($axis=='attribute') :
|
372 |
+
$axis = 'attribs'; // map from W3C to SimplePie's idiosyncratic notation
|
373 |
+
endif;
|
374 |
+
elseif (substr($node, 0, 1)=='@') :
|
375 |
+
$axis = 'attribs'; $node = substr($node, 1);
|
376 |
+
elseif (is_numeric($node)) :
|
377 |
+
$axis = 'self';
|
378 |
+
elseif (substr($node, 0, 1)=='/') :
|
379 |
+
// FIXME: properly, we should check for // and if we have it,
|
380 |
+
// treat that as short for /descendent-or-self::node()/
|
381 |
+
$axis = 'child'; $node = substr($node, 1);
|
382 |
+
else :
|
383 |
+
// NOOP
|
384 |
+
endif;
|
385 |
+
|
386 |
+
if (is_string($node) and preg_match('/^{([^}]*)}(.*)$/', $node, $ref)) :
|
387 |
+
$element = $ref[2];
|
388 |
+
elseif (is_string($node) and strpos($node, ':') !== FALSE) :
|
389 |
+
list($xmlns, $element) = explode(':', $node, 2);
|
390 |
+
else :
|
391 |
+
$element = $node;
|
392 |
+
endif;
|
393 |
+
return array($axis, $element);
|
394 |
+
} /* SyndicatedPostXPathQuery::xpath_name_and_axis () */
|
395 |
+
|
396 |
+
public function xpath_possible_namespaces ($node, $datum = array()) {
|
397 |
+
$ns = NULL; $element = NULL;
|
398 |
+
|
399 |
+
if (substr($node, 0, 1)=='@') :
|
400 |
+
$attr = '@'; $node = substr($node, 1);
|
401 |
+
else :
|
402 |
+
$attr = '';
|
403 |
+
endif;
|
404 |
+
|
405 |
+
if (preg_match('/^{([^}]*)}(.*)$/', $node, $ref)) :
|
406 |
+
$ns = array($ref[1]);
|
407 |
+
elseif (strpos($node, ':') !== FALSE) :
|
408 |
+
list($xmlns, $element) = explode(':', $node, 2);
|
409 |
+
|
410 |
+
if (isset($this->xmlns['reverse'][$xmlns])) :
|
411 |
+
$ns = $this->xmlns['reverse'][$xmlns];
|
412 |
+
else :
|
413 |
+
$ns = array($xmlns);
|
414 |
+
endif;
|
415 |
+
|
416 |
+
// Fucking SimplePie. For attributes in default xmlns.
|
417 |
+
$defaultNS = $this->xpath_default_namespace();
|
418 |
+
if (isset($this->xmlns['forward'][$defaultNS])
|
419 |
+
and ($xmlns==$this->xmlns['forward'][$defaultNS])) :
|
420 |
+
$ns[] = '';
|
421 |
+
endif;
|
422 |
+
|
423 |
+
if (isset($datum['xmlns'])) :
|
424 |
+
if (isset($datum['xmlns'][$xmlns])) :
|
425 |
+
$ns[] = $datum['xmlns'][$xmlns];
|
426 |
+
endif;
|
427 |
+
endif;
|
428 |
+
else :
|
429 |
+
// Often in SimplePie, the default namespace gets stored
|
430 |
+
// as an empty string rather than a URL.
|
431 |
+
$ns = array($this->xpath_default_namespace(), '');
|
432 |
+
endif;
|
433 |
+
return array_unique($ns);
|
434 |
+
} /* SyndicatedPostXPathQuery::xpath_possible_namespaces() */
|
435 |
+
|
436 |
+
} /* class SyndicatedPostXPathQuery */
|
437 |
+
|
438 |
+
// When called directly, run through and perform some tests.
|
439 |
+
if (basename($_SERVER['SCRIPT_FILENAME'])==basename(__FILE__)) :
|
440 |
+
# some day when I am a grown-up developer I might include
|
441 |
+
# some test cases in this here section
|
442 |
+
# we need to implement wp_parse_args(), __(), and class WP_Error ...
|
443 |
+
#function wp_parse_args ($r, $defaults) {
|
444 |
+
# return array_merge($defaults, $r);
|
445 |
+
#}
|
446 |
+
#function __($text, $domain) {
|
447 |
+
# return $text;
|
448 |
+
#}
|
449 |
+
#class WP_Error {
|
450 |
+
# public function __construct ( $slug, $message ) {
|
451 |
+
# /*DBG*/ echo $slug;
|
452 |
+
# /*DBG*/ echo ": ";
|
453 |
+
# /*DBG*/ echo $message;
|
454 |
+
# }
|
455 |
+
#}
|
456 |
+
#
|
457 |
+
#header("Content-type: text/plain");
|
458 |
+
#
|
459 |
+
#$spxq = new SyndicatedPostXPathQuery(array("path" => $_REQUEST['p']));
|
460 |
+
#
|
461 |
+
#var_dump($spxq);
|
462 |
+
endif;
|