<?php include_once( dirname(__FILE__) . '/interface-syndication-client.php' ); class Syndication_WP_XML_Client implements Syndication_Client { private $site_ID; private $default_post_type; private $default_post_status; private $default_comment_status; private $default_ping_status; private $nodes_to_post; private $id_field; private $enc_field; private $enc_is_photo; private $feed_url; function __construct( $site_ID ) { $this->site_ID = $site_ID; $this->set_feed_url( get_post_meta( $site_ID, 'syn_feed_url', true ) ); $this->default_post_type= get_post_meta( $site_ID, 'syn_default_post_type', true ); $this->default_post_status = get_post_meta( $site_ID, 'syn_default_post_status', true ); $this->default_comment_status = get_post_meta( $site_ID, 'syn_default_comment_status', true ); $this->default_ping_status = get_post_meta( $site_ID, 'syn_default_ping_status', true ); $this->nodes_to_post = get_post_meta( $site_ID, 'syn_node_config', false); $this->id_field = get_post_meta( $site_ID, 'syn_id_field', true); $this->enc_field = get_post_meta( $site_ID, 'syn_enc_field', true ); $this->enc_is_photo = get_post_meta( $site_ID, 'syn_enc_is_photo', true); add_action( 'syn_post_pull_new_post', array( __CLASS__, 'save_meta' ), 10, 5 ); add_action( 'syn_post_pull_new_post', array( __CLASS__, 'save_tax' ), 10, 5 ); add_action( 'syn_post_pull_edit_post', array( __CLASS__, 'update_meta' ), 10, 5 ); add_action( 'syn_post_pull_edit_post', array( __CLASS__, 'update_tax' ), 10, 5 ); add_action ( 'syn_post_pull_new_post', array(__CLASS__ , 'publish_pulled_post' ), 10, 5 ); // Debugging add_action ( 'syn_post_pull_new_post', array(__CLASS__, 'log_new' ), 10, 5 ); add_action ( 'syn_post_pull_edit_post', array(__CLASS__, 'log_update' ), 10, 5 ); } /** * Return Client Data * @return array array( 'id' => (string) $transport_name, 'modes' => array( 'push', 'pull' ), 'name' => (string) $name ); */ private function set_feed_url($url) { $url = apply_filters( 'syn_feed_url', $url ); if ( parse_url( $url ) ) { $this->feed_url = $url; } else { $this->error_message = sprintf( __( 'Feed url not set for this feed: %s', 'push-syndication' ), $site_ID ); } } public static function get_client_data() { return array( 'id' => 'WP_XML', 'modes' => array( 'pull' ), 'name' => 'XML' ); } public function new_post( $post_ID ) { return false; // Not supported } public function edit_post( $post_ID, $ext_ID ) { return false; // Not supported } public function delete_post( $ext_ID ) { return false; // Not supported } public function get_post( $ext_ID ) { return false; // Not supported } /** * Retrieves a list of posts from a slave site. * * @param array $args Arguments when retrieving posts. * * @return boolean true on success false on failure. */ public function get_posts( $args = array()) { // create $post with values from $this::node_to_post // create $post_meta with values from $this::node_to_meta //TODO: required fields for post //TODO: handle categories // clear last log in feed's data delete_post_meta($this->site_ID, 'syn_log'); $abs_nodes = array(); $item_nodes = array(); $enc_nodes = array(); $tax_nodes = array(); $abs_post_fields = array(); $abs_meta_data = array(); $abs_tax_data = array(); $posts = array(); $nodes = $this->nodes_to_post[0]; $post_root = $nodes['post_root']; unset($nodes['post_root']); $namespace = isset($nodes['namespace']) ? $nodes['namespace'] : null; unset($nodes['namespace']); $enc_parent = $nodes['enc_parent']; unset($nodes['enc_parent']); $enc_field = isset( $this->enc_field ) ? $this->enc_field : null; $categories = (array) $nodes['categories']; unset($nodes['categories']); $enclosures_as_strings = isset($nodes['enclosures_as_strings']) ? true : false; unset($nodes['enclosures_as_strings']); //TODO: add checkbox on feed config to allow enclosures to be saved as strings as SI does //TODO: add tags here and in feed set up UI foreach( $nodes['nodes'] as $key => $storage_locations) { foreach ($storage_locations as $storage_location) { $storage_location['xpath'] = $key; if ($storage_location['is_item']) { $item_nodes[] = $storage_location; } else if ($storage_location['is_photo']) { $enc_nodes[] = $storage_location; } else if ( $storage_location['is_tax'] && $storage_location['is_item'] ) { $tax_nodes[] = $storage_location; } else { $abs_nodes[] = $storage_location; } } } $feed = $this->fetch_feed(); // Catch attempts to pull content from a file which doesn't exist. // TODO: kill feed client if too many failures if ( is_wp_error( $feed ) ) { self::log_post( 'n/a', null, get_post($this->site_ID), sprintf( __( 'Could not reach feed at: %s | Error: %s', 'push-syndication' ), $this->feed_url, $feed->get_error_message() ) ); return array(); } $xml = simplexml_load_string( $feed, null, 0, $namespace, false ); if ( false === $xml ) { self::log_post( 'n/a', null, get_post( $this->site_ID ), sprintf( __( 'Failed to parse feed at: %s', 'push-syndication' ), $this->feed_url ) ); return array(); } $abs_post_fields['enclosures_as_strings'] = $enclosures_as_strings; // TODO: handle constant strings in XML foreach( $abs_nodes as $abs_node) { $value_array = array(); try { if ('string(' == substr( $abs_node['xpath'], 0, 7 ) ) { $value_array[0] = substr( $abs_node['xpath'], 7, strlen($abs_node['xpath'])-8 ); } else { $value_array = $xml->xpath(stripslashes($abs_node['xpath'])); } if ($abs_node['is_meta']) { $abs_meta_data[$abs_node['field']] = (string)$value_array[0]; } else if ( $abs_node['is_tax'] ) { $abs_tax_data[$abs_node['field']] = (string)$value_array[0]; } else { $abs_post_fields[$abs_node['field']] = (string)$value_array[0]; } } catch (Exception $e) { //TODO: catch value not found here and alert for error //TODO: catch multiple values returned here and alert for error return array(); } } $post_position = 0; $items = $xml->xpath( $post_root ); if ( empty( $items ) ) { self::log_post( 'n/a', null, get_post($this->site_ID), sprintf( __( 'No post nodes found using XPath "%s" in feed', 'push-syndication' ), $post_root ) ); return array(); } foreach ( $items as $item ) { $item_fields = array(); $enclosures = array(); $meta_data = array(); $meta_data['is_update'] = current_time('mysql'); $tax_data = array(); $value_array = array(); $item_fields['post_type'] = $this->default_post_type; //save photos as enclosures in meta if ((isset($enc_parent) && strlen($enc_parent)) && ! empty( $enc_nodes )) : $meta_data['enclosures'] = $this->get_encs($item->xpath($enc_parent), $enc_nodes); endif; foreach ($item_nodes as $save_location ) { try { if ('string(' == substr( $save_location['xpath'], 0, 7 ) ) { $value_array[0] = substr( $save_location['xpath'], 7, strlen($save_location['xpath'])-8 ); } else { $value_array = $item->xpath( stripslashes( $save_location['xpath'] ) ); } if (isset($save_location['is_meta']) && $save_location['is_meta']) { //SimpleXMLElement::xpath returns either an array or false if an element isn't returned //checking $value_array first avoids the warning we get if the field isn't found if( $value_array && ( count( $value_array ) > 1 ) ) { $value_array = array_map( 'strval', $value_array ); $meta_data[$save_location['field']] = $value_array; } else if ( $value_array ) { //return a string if $value_array contains only a single element $meta_data[$save_location['field']] = (string) $value_array[0]; } } else if ( isset($save_location['is_tax']) && $save_location['is_tax'] ) { //for some taxonomies, multiple values may be supplied in the field foreach ( $value_array as $value ) { $tax_data[$save_location['field']] = ( string ) $value; } } else { $item_fields[$save_location['field']] = (string)$value_array[0]; } } catch (Exception $e) { // TODO: catch value not found here and alert for error // TODO: catch multiple values returned here and alert for error return array(); } } $meta_data = array_merge($meta_data, $abs_meta_data); $tax_data = array_merge($tax_data, $abs_tax_data); if ( !empty( $enc_field ) ) { $meta_data['enc_field'] = $enc_field; } if ( !isset( $meta_data['position'] ) ) { $meta_data['position'] = $post_position; } $item_fields['postmeta'] = $meta_data; if ( !empty( $tax_data ) ) { $item_fields['tax'] = $tax_data; } $item_fields['post_category'] = $categories; if ( ! empty( $meta_data[$this->id_field] ) ) { $item_fields['post_guid'] = $meta_data[$this->id_field]; } $posts[] = $item_fields; $post_position++; } return $posts; } /** * @param array $enclosures * @return array */ private function get_encs($feed_enclosures = array(), $enc_nodes = array()) { $enclosures = array(); foreach($feed_enclosures as $count => $enc) { if ( isset( $this->enc_is_photo ) && 1 == $this->enc_is_photo ) { $enc_array = array('caption'=>'', 'credit' => '', 'description' => '', 'url' => '', 'width' => '', 'height' => '', 'position' => ''); } else { $enc_array = array(); } $enc_value = array(); foreach ($enc_nodes as $post_value) { try { if ('string(' == substr( $post_value['xpath'], 0, 7 ) ) { $enc_value[0] = substr( $post_value['xpath'], 7, strlen($post_value['xpath'])-8 ); } else { $enc_value = $enc->xpath(stripslashes($post_value['xpath'])); } $enc_array[$post_value['field']] = esc_attr((string)$enc_value[0]); } catch (Exception $e) { //TODO: catch value not found here and alert for error or not return true; } } // if position is not provided in the feed, use the order in which they appear in the feed if ( empty( $enc_array['position'] ) ) { $enc_array['position'] = $count; } $enclosures[] = $enc_array; } return $enclosures; } /** * Test the connection with the slave site. * * @return boolean true on success false on failure. */ public function test_connection() { return ! is_wp_error( $this->fetch_feed() ); } /** * Checks whether the given post exists in the slave site. * * @param int $ext_ID Slave post ID to check. * * @return boolean true on success false on failure. */ public function is_post_exists( $ext_ID ) { return false; // Not supported } /** * Display the client settings for the slave site. * * @param object $site The site object to display settings. */ public static function display_settings( $site ) { //TODO: JS if is_meta show text box, if is_photo show photo select with numbers as values, else show select of post fields //TODO: JS Validation //TODO: deal with ability to select, i.e. media:group/media:thumbnail[@width="75"]/@url (can't be unserialized as is with quotes around 75) $feed_url = get_post_meta( $site->ID, 'syn_feed_url', true ); $default_post_type = get_post_meta( $site->ID, 'syn_default_post_type', true ); $default_post_status = get_post_meta( $site->ID, 'syn_default_post_status', true ); $default_comment_status = get_post_meta( $site->ID, 'syn_default_comment_status', true ); $default_ping_status = get_post_meta( $site->ID, 'syn_default_ping_status', true ); $node_config = get_post_meta( $site->ID, 'syn_node_config', true ); $id_field = get_post_meta( $site->ID, 'syn_id_field', true ); $enc_field = get_post_meta( $site->ID, 'syn_enc_field', true ); $enc_is_photo = get_post_meta( $site->ID, 'syn_enc_is_photo', true); $last_update_time = get_post_meta( $site->ID, 'syn_last_pull_time', true); if ( isset( $node_config['namespace'] )) { $namespace = $node_config['namespace']; } //unset is outside of isset() test to remove the item from the array if the key is there with no value unset( $node_config['namespace'] ); if ( isset( $node_config['post_root'] )) { $post_root = $node_config['post_root']; } unset( $node_config['post_root'] ); if ( isset( $node_config['enc_parent'] )) { $enc_parent = $node_config['enc_parent']; } unset( $node_config['enc_parent'] ); if ( isset( $node_config['categories'] ) && !empty( $node_config['categories'] ) ) { $categories = (array) $node_config['categories']; } unset( $node_config['categories'] ); $custom_nodes = $node_config['nodes']; ?> <p> <label for="feed_url"><?php esc_html_e( 'Enter feed URL', 'push-syndication' ); ?></label> </p> <p> <input type="text" name="feed_url" id="feed_url" size="100" value="<?php echo esc_attr( $feed_url ); ?>" /> </p> <p> <label for="default_post_type"><?php esc_html_e( 'Select post type', 'push-syndication' ); ?></label> </p> <p> <select name="default_post_type" id="default_post_type" /> <?php $post_types = get_post_types(); foreach( $post_types as $post_type ) { echo '<option value="' . esc_attr( $post_type ) . '"' . selected( $post_type, $default_post_type ) . '>' . esc_html( $post_type ) . '</option>'; } ?> </select> </p> <p> <label for="default_post_status"><?php esc_html_e( 'Select post status', 'push-syndication' ); ?></label> </p> <p> <select name="default_post_status" id="default_post_status" /> <?php $post_statuses = get_post_statuses(); foreach( $post_statuses as $key => $value ) { echo '<option value="' . esc_attr( $key ) . '"' . selected( $key, $default_post_status ) . '>' . esc_html( $key ) . '</option>'; } ?> </select> </p> <p> <label for="default_comment_status"><?php esc_html_e( 'Select comment status', 'push-syndication' ); ?></label> </p> <p> <select name="default_comment_status" id="default_comment_status" /> <option value="open" <?php selected( 'open', $default_comment_status ) ?>><?php _e( 'open', 'push-syndication' ); ?></option> <option value="closed" <?php selected( 'closed', $default_comment_status ) ?>><?php _e( 'closed', 'push-syndication' ); ?></option> </select> </p> <p> <label for="default_ping_status"><?php esc_html_e( 'Select ping status', 'push-syndication' ); ?></label> </p> <p> <select name="default_ping_status" id="default_ping_status" /> <option value="open" <?php selected( 'open', $default_ping_status ) ?> ><?php _e( 'open', 'push-syndication' ); ?></option> <option value="closed" <?php selected( 'closed', $default_ping_status ) ?> ><?php _e( 'closed', 'push-syndication' ); ?></option> </select> </p> <p> <label for="namespace"><?php esc_html_e( 'Enter XML namespace', 'push-syndication' ); ?></label> </p> <p> <input type="text" size=75 name="namespace" id="namespace" value="<?php echo esc_attr($namespace);?>" /> </p> <p> <label for="post_root"><?php esc_html_e( 'Enter xpath to post root', 'push-syndication' ); ?></label> </p> <p> <input type="text" name="post_root" id="post_root" value="<?php echo esc_attr($post_root); ?>" /> </p> <p> <label for="id_node"><?php esc_html_e( 'Enter postmeta key for unique post identifier', 'push-syndication' ); ?></label> </p> <p> <input type="text" name="id_field" id="id_field" value="<?php echo esc_attr($id_field); ?>" /> </p> <p> <label for="enc_parent"><?php esc_html_e( 'Enter parent element for enclosures', 'push-syndication' ); ?></label> </p> <p> <input type="text" name="enc_parent" id="enc_parent" value="<?php echo esc_attr($enc_parent); ?>" /> </p> <p> <label for="enc_field"><?php esc_html_e( 'Enter meta name for enclosures', 'push-syndication' ); ?></label> </p> <p> <input type="text" name="enc_field" id="enc_field" value="<?php echo esc_attr($enc_field); ?>" /> </p> <p> <label for="enc_is_photo"> <input type="checkbox" name="enc_is_photo" id="enc_is_photo" value="1" <?php checked( $enc_is_photo ); ?> /> <?php esc_html_e( 'Enclosure is an image file', 'push-syndication' ); ?> </label> </p> <p> <label for="categories"><?php esc_html_e( 'Select category/categories', 'push-syndication' ); ?></label> </p> <p> <select name="categories" multiple="multiple"> <?php $site_categories = get_categories( array( 'hide_empty' => 0 ) ); foreach ($site_categories as $category) { if ( isset( $categories ) ) { $selected = in_array( $category->cat_ID, $categories ) ? 'selected="selected"' : null; } $option = '<option value="'.$category->cat_ID.'" ' . $selected . '>'; $option .= $category->category_nicename; $option .= '</option>'; echo $option; } ?> </select> </p> <h2><?php _e( 'XPath-to-Data Mapping', 'push-syndication' ); ?></h2> <p><?php printf( __( '<strong>PLEASE NOTE:</strong> %s are required. If you want a link to another site, %s required. To include a static string, enclose the string as "%s(your_string_here)" -- no quotes.', 'push-syndication' ), 'post_title, post_guid, guid', 'is_permalink', 'string' ); ?></p> <ul class='syn-xml-client-xpath-head syn-xml-client-list-head'> <li class="text"> <label for="xpath"><?php esc_html_e( 'Xpath Expression', 'push-syndication' )?></label> </li> <li> <label for="item_node"><?php esc_html_e( 'Item', 'push-syndication' )?></label> </li> <li> <label for="photo_node"><?php esc_html_e( 'Enc.', 'push-syndication' )?></label> </li> <li> <label for="meta_node"><?php esc_html_e( 'Meta', 'push-syndication' )?></label> </li> <li> <label for="tax_node"><?php esc_html_e( 'Tax', 'push-syndication' )?></label> </li> <li class="text"> <label for="item_field"><?php esc_html_e( 'Field in post', 'push-syndication' )?></label> </li> </ul> <?php $rowcount = 0; if ( !empty( $custom_nodes ) ) : foreach ($custom_nodes as $key => $storage_locations) : foreach ($storage_locations as $storage_location) : ?> <ul class='syn-xml-client-xpath-form syn-xml-client-xpath-list syn-xml-client-list' data-row-count="<?php echo esc_attr( $rowcount ); ?>"> <li class="text"> <input type="text" name="node[<?php echo $rowcount; ?>][xpath]" id="node-<?php echo $rowcount; ?>-xpath" value="<?php echo htmlspecialchars(stripslashes($key)) ; ?>" /> </li> <li> <input type="checkbox" name="node[<?php echo $rowcount; ?>][is_item]" id="node-<?php echo $rowcount; ?>-is_item" <?php checked( $storage_location['is_item'] ); ?> value="true" /> </li> <li> <input type="checkbox" name="node[<?php echo $rowcount; ?>][is_photo]" id="node-<?php echo $rowcount; ?>-is_photo" <?php checked( $storage_location['is_photo'] ); ?> value="true" /> </li> <li> <input type="checkbox" name="node[<?php echo $rowcount; ?>][is_meta]" id="node-<?php echo $rowcount; ?>-is_meta" <?php checked( $storage_location['is_meta'] ); ?> value="true" /> </li> <li> <input type="checkbox" name="node[<?php echo $rowcount; ?>][is_tax]" id="node-<?php echo $rowcount; ?>-is_tax" <?php checked( $storage_location['is_tax'] ); ?> value="true" /> </li> <li class="text"> <input type="text" name="node[<?php echo $rowcount; ?>][field]" id="node-<?php echo $rowcount; ?>-field" value="<?php echo stripcslashes( $storage_location['field'] ); ?>" /> </li> <a href="#" class="syn-delete syn-pull-xpath-delete"><?php _e( 'Delete', 'push-syndication' ); ?></a> <?php endforeach; ?> </ul> <?php ++$rowcount; endforeach; endif; ?> <ul class='syn-xml-client-xpath-form syn-xml-xpath-list syn-xml-client-list' data-row-count="<?php echo esc_attr( $rowcount ); ?>"> <li class="text"> <input type="text" name="node[<?php echo $rowcount; ?>][xpath]" id="node-<?php echo $rowcount; ?>-xpath" /> </li> <li> <input type="checkbox" name="node[<?php echo $rowcount; ?>][is_item]" id="node-<?php echo $rowcount; ?>-is_item" /> </li> <li> <input type="checkbox" name="node[<?php echo $rowcount; ?>][is_photo]" id="node-<?php echo $rowcount; ?>-is_photo" /> </li> <li> <input type="checkbox" name="node[<?php echo $rowcount; ?>][is_meta]" id="node-<?php echo $rowcount; ?>-is_meta" /> </li> <li> <input type="checkbox" name="node[<?php echo $rowcount; ?>][is_tax]" id="node-<?php echo $rowcount; ?>-is_tax" /> </li> <li class="text"> <input type="text" name="node[<?php echo $rowcount; ?>][field]" id="node-<?php echo $rowcount; ?>-field" /> </li> <a href="#" class="syn-delete syn-pull-xpath-delete"><?php _e( 'Delete', 'push-syndication' ); ?></a> </ul> <a href="#" class="syn-pull-xpath-add-new button"><?php _e( 'Add new', 'push-syndication' ); ?></a> <script> jQuery( document ).ready( function( $ ) { $( '.syn-pull-xpath-delete' ).on( 'click', function( e ) { e.preventDefault(); $( this ).closest( '.syn-xml-client-xpath-form' ).remove(); } ); $( '.syn-pull-xpath-add-new' ).on( 'click', function( e ) { e.preventDefault(); var $last_form = $( '.syn-xml-client-xpath-form:last' ), $new_form = $last_form.clone(), original_row_count = parseInt( $last_form.attr( 'data-row-count' ) ); new_row_count = original_row_count + 1; $new_form.attr( 'data-row-count', new_row_count ); $new_form.find( 'input' ).each( function() { var $this = $( this ), name = $this.attr( 'name' ), type = $this.attr( 'type' ); if ( type == 'radio' || type == 'checkbox' ) $this.attr( 'checked', false ); else if ( type == 'select' ) $this.attr( 'selected', false ); else $this.val( '' ); name = name.replace( '[' + ( original_row_count ) + ']', '[' + new_row_count + ']' ); $this.attr( 'name', name ); // hack hack hack!!! } ); $new_form.insertAfter( $last_form ); } ); } ); </script> <h2><?php _e( 'Log', 'push-syndication' ); ?></h2> <p class="syn-xml-client-last-update"><em><?php printf( __( 'Last Update: %s', 'push-syndication' ), ( $last_update_time ? date( 'c', $last_update_time ) : __( 'n/a', 'push-syndication' ) ) ); ?></em></p> <?php $syn_log = get_post_meta($site->ID, 'syn_log', true); if ( ! empty( $syn_log ) ) : ?> <ul class='syn-xml-client-xpath-log-head syn-xml-client-list-head'> <li> <label for="post_id"><?php esc_html_e( 'Post ID', 'push-syndication' )?></label> </li> <li> <label for="status"><?php esc_html_e( 'Status', 'push-syndication' )?></label> </li> <li class="wide"> <label for="date_time"><?php esc_html_e( 'Date/Time', 'push-syndication' )?></label> </li> <li> <label for="view"><?php esc_html_e( 'VIEW', 'push-syndication' )?></label> </li> </ul> <?php foreach($syn_log as $log_row) : $view_link = get_permalink($log_row['post_id']); ?> <ul class='syn-xml-client-log syn-xml-client-list'> <li> <?php if ( gettype($log_row['post_id']) == 'integer' ) { edit_post_link( $log_row['post_id'], null, null, $log_row['post_id'] ); } else { echo "ERROR"; } ?> </li> <li> <?php echo esc_html( $log_row['status'] ); ?> </li> <li class="wide"> <?php echo esc_html( $log_row['time'] ); ?> </li> <li> <a href="<?php echo esc_url( $view_link ); ?>"><?php _e( 'View', 'push-syndication' ); ?></a> </li> </ul> <?php endforeach; endif; } /** * Save the client settings for the slave site. * * @param int $site_ID The site ID to save settings. * * @return boolean true on success false on failure. */ public static function save_settings( $site_ID ) { // TODO: adjust to save all settings required by XML feed // TODO: validate saved values (e.g. valid post_type? valid status?) update_post_meta( $site_ID, 'syn_feed_url', esc_url_raw( $_POST['feed_url'] ) ); update_post_meta( $site_ID, 'syn_default_post_type', sanitize_text_field( $_POST['default_post_type'] ) ); update_post_meta( $site_ID, 'syn_default_post_status', sanitize_text_field( $_POST['default_post_status'] ) ); update_post_meta( $site_ID, 'syn_default_comment_status', sanitize_text_field( $_POST['default_comment_status'] ) ); update_post_meta( $site_ID, 'syn_default_ping_status', sanitize_text_field( $_POST['default_ping_status'] ) ); update_post_meta( $site_ID, 'syn_id_field', sanitize_text_field( $_POST['id_field'] ) ); update_post_meta( $site_ID, 'syn_enc_field', sanitize_text_field( $_POST['enc_field'] ) ); update_post_meta( $site_ID, 'syn_enc_is_photo', isset( $_POST['enc_is_photo'] ) ? sanitize_text_field( $_POST['enc_is_photo'] ) : null ); $node_changes = $_POST['node']; $node_config = array(); $custom_nodes = array(); if (isset($node_changes)) { foreach($node_changes as $row) { $row_data = array(); //if no new has been added to the empty row at the end, ignore it if ( ! empty( $row['xpath'] ) ) { foreach ( array( 'is_item', 'is_meta', 'is_tax', 'is_photo' ) as $field ) { $row_data[$field] = isset( $row[$field] ) && in_array( $row[$field], array( 'true', 'on' ) ) ? 1 : 0; } $xpath = html_entity_decode( $row['xpath'] ); unset($row['xpath']); $row_data['field'] = sanitize_text_field( $row['field'] ); if ( ! isset( $custom_nodes[$xpath] ) ) $custom_nodes[$xpath] = array(); $custom_nodes[$xpath][] = $row_data; } } } $node_config['namespace'] = sanitize_text_field( $_POST['namespace'] ); $node_config['post_root'] = sanitize_text_field( $_POST['post_root'] ); $node_config['enc_parent'] = sanitize_text_field( $_POST['enc_parent'] ); $node_config['categories'] = sanitize_text_field( $_POST['categories'] ); $node_config['nodes'] = $custom_nodes; update_post_meta( $site_ID, 'syn_node_config', $node_config); return true; } public static function publish_pulled_post($result, $post, $site, $transport_type, $client) { wp_publish_post( $result ); } public static function log_new( $result, $post, $site, $transport_type, $client ) { self::log_post( $result, $post, $site, __( 'new', 'push-syndication' ) ); } public static function log_update( $result, $post, $site, $transport_type, $client ) { self::log_post( $result, $post, $site, __( 'update', 'push-syndication' ) ); } private static function log_post( $post_id, $post, $site, $status ) { // TODO: need to limit how many log entries can be added $log_entry = array(); $log_entry['post_id'] = $post_id; $log_entry['status'] = $status; if ( !empty( $post ) ) { $log_entry['time'] = $post['postmeta']['is_update']; } else { $log_entry['time'] = current_time('mysql'); } $log = get_post_meta( $site->ID, 'syn_log', true ); if ( empty( $log ) ) { $log[0] = $log_entry; } else { $log[] = $log_entry; } update_post_meta( $site->ID, 'syn_log', $log ); } public static function save_meta ($result, $post, $site, $transport_type, $client) { if ( ! $result || is_wp_error( $result ) || ! isset( $post['postmeta'] ) ) { return false; } $categories = $post['post_category']; wp_set_post_terms($result, $categories, 'category', true); $metas = $post['postmeta']; //handle enclosures separately first $enc_field = isset( $metas['enc_field'] ) ? $metas['enc_field'] : null; $enclosures = isset( $metas['enclosures'] ) ? $metas['enclosures'] : null; if ( isset( $enclosures ) && isset ( $enc_field ) ) { // first remove all enclosures for the post (for updates) if any delete_post_meta( $result, $enc_field); foreach( $enclosures as $enclosure ) { if (defined('ENCLOSURES_AS_STRINGS') && constant('ENCLOSURES_AS_STRINGS')) { $enclosure = implode("\n", $enclosure); } add_post_meta($result, $enc_field, $enclosure, false); } // now remove them from the rest of the metadata before saving the rest unset($metas['enclosures']); } foreach ($metas as $meta_key => $meta_value) { add_post_meta($result, $meta_key, $meta_value, true); } } public static function update_meta ($result, $post, $site, $transport_type, $client) { if ( ! $result || is_wp_error( $result ) || ! isset( $post['postmeta'] ) ) { return false; } $categories = $post['post_category']; wp_set_post_terms($result, $categories, 'category', true); $metas = $post['postmeta']; // handle enclosures separately first $enc_field = isset( $metas['enc_field'] ) ? $metas['enc_field'] : null; $enclosures = isset( $metas['enclosures'] ) ? $metas['enclosures'] : null; if ( isset( $enclosures ) && isset( $enc_field ) ) { // first remove all enclosures for the post (for updates) delete_post_meta( $result, $enc_field); foreach( $enclosures as $enclosure ) { if (defined('ENCLOSURES_AS_STRINGS') && constant('ENCLOSURES_AS_STRINGS')) { $enclosure = implode("\n", $enclosure); } add_post_meta($result, $enc_field, $enclosure, false); } // now remove them from the rest of the metadata before saving the rest unset($metas['enclosures']); } foreach ($metas as $meta_key => $meta_value) { update_post_meta($result, $meta_key, $meta_value); } } public static function save_tax ($result, $post, $site, $transport_type, $client) { if ( ! $result || is_wp_error( $result ) || ! isset( $post['tax'] ) ) { return false; } $taxonomies = $post['tax']; foreach ( $taxonomies as $tax_name => $tax_value ) { // post cannot be used to create new taxonomy if ( ! taxonomy_exists( $tax_name ) ) { continue; } wp_set_object_terms($result, (string)$tax_value, $tax_name, true); } } public static function update_tax ($result, $post, $site, $transport_type, $client) { if ( ! $result || is_wp_error( $result ) || ! isset( $post['tax'] ) ) { return false; } $taxonomies = $post['tax']; $replace_tax_list = array(); foreach ( $taxonomies as $tax_name => $tax_value ) { //post cannot be used to create new taxonomy if ( ! taxonomy_exists( $tax_name ) ) { continue; } if ( !in_array($tax_name, $replace_tax_list ) ) { //if we haven't processed this taxonomy before, replace any terms on the post with the first new one wp_set_object_terms($result, (string)$tax_value, $tax_name ); $replace_tax_list[] = $tax_name; } else { //if we've already added one term for this taxonomy, append any others wp_set_object_terms($result, (string)$tax_value, $tax_name, true); } } } public function fetch_feed() { $request = wp_remote_get( $this->feed_url ); if ( is_wp_error( $request ) ) { return $request; } elseif ( 200 != wp_remote_retrieve_response_code( $request ) ) { return new WP_Error( 'syndication-fetch-failure', 'Failed to fetch XML Feed; HTTP code: ' . wp_remote_retrieve_response_code( $request ) ); } return wp_remote_retrieve_body( $request ); } }