, CodeTRAX.org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * The NOTICE file contains additional licensing and copyright information. */ /** * Module containing utility functions. */ // Prevent direct access to this file. if ( ! defined( 'ABSPATH' ) ) { header( 'HTTP/1.0 403 Forbidden' ); echo 'This file should not be accessed directly!'; exit; // Exit if accessed directly } // Returns the post object filtered. // In addition see this: https://github.com/Automattic/amp-wp/commit/21180205487d71e595088e2cd1d1acba3f240ea5 function amt_get_queried_object() { // Sometimes, it is possible that a post object (static WP Page), which behaves // like a custom post type archive (eg the WooCommerce main shop page -- slug=shop) // has been set as the static front page. // In such cases the get_queried_object() function may not return a regular // WP_Post object, which is required by this plugin. So, in such cases we // retrieve the WP_Post object manually. if ( amt_is_static_front_page() && is_post_type_archive() ) { $post = get_post( amt_get_front_page_id() ); } else { // Use the normal way to get the $post object. // Get current post object $post = get_queried_object(); } // Allow filtering of the $post object. $post = apply_filters('amt_get_queried_object', $post); return $post; } // Returns the plugin options function amt_get_options() { return get_option("add_meta_tags_opts"); } // Returns a key for the non persistent cache function amt_get_amtcache_key($basename, $post=null) { // Non persistent object cache if ( is_null($post) ) { // other data $amtcache_key = sprintf('%s_data', $basename); } elseif ( is_numeric($post) ) { // id $amtcache_key = sprintf('%s_%d', $basename, $post); } elseif ( isset($post->ID) ) { // post, user $amtcache_key = sprintf('%s_%d', $basename, $post->ID); } elseif ( isset($post->term_id) ) { // term $amtcache_key = sprintf('%s_%d', $basename, $post->term_id); } else { // Use a static key name. Very unlikely for the page to have two non post objects. $amtcache_key = sprintf('%s_other_post', $basename); } //var_dump($post); //var_dump($amtcache_key); return $amtcache_key; } /** * Helper function that returns an array of allowable HTML elements and attributes * for use in wp_kses() function. */ function amt_get_allowed_html_kses() { // Store supported global attributes to an array // As of http://www.w3schools.com/tags/ref_standardattributes.asp $global_attributes = array( 'accesskey' => array(), 'class' => array(), 'contenteditable' => array(), 'contextmenu' => array(), // 'data-*' => array(), 'dir' => array(), 'draggable' => array(), 'dropzone' => array(), 'hidden' => array(), 'id' => array(), 'lang' => array(), 'spellcheck' => array(), 'style' => array(), 'tabindex' => array(), 'title' => array(), 'translate' => array() ); // Construct an array of valid elements and attributes $valid_elements_attributes = array( // As of http://www.w3schools.com/tags/tag_meta.asp // plus 'itemprop' and 'property' 'meta' => array_merge( array( 'charset' => array(), 'content' => array(), 'value' => array(), 'http-equiv' => array(), 'name' => array(), 'scheme' => array(), 'itemprop' => array(), // schema.org 'property' => array() // opengraph and others ), $global_attributes ), // As of http://www.w3schools.com/tags/tag_link.asp 'link' => array_merge( array( 'charset' => array(), 'href' => array(), 'hreflang' => array(), 'media' => array(), 'rel' => array(), 'rev' => array(), 'sizes' => array(), 'target' => array(), 'type' => array() ), $global_attributes ) ); // Allow filtering of $valid_elements_attributes $valid_elements_attributes = apply_filters( 'amt_valid_full_metatag_html', $valid_elements_attributes ); return $valid_elements_attributes; } /** * Sanitizes text for use in the description and similar metatags. * * Currently: * - removes shortcodes * - removes double quotes * - convert single quotes to space */ function amt_sanitize_description($desc) { // Remove shortcode // Needs to be before cleaning double quotes as it may contain quoted settings. // $pattern = get_shortcode_regex(); //var_dump($pattern); // TODO: Possibly this is not needed since shortcodes are stripped in amt_get_the_excerpt(). // $desc = preg_replace('#' . $pattern . '#s', '', $desc); // Clean double quotes $desc = str_replace('"', '', $desc); // $desc = str_replace('"', '', $desc); // Convert single quotes to space //$desc = str_replace("'", ' ', $desc); //$desc = str_replace(''', ' ', $desc); //$desc = str_replace("'", ' ', $desc); //$desc = str_replace("‘", ' ', $desc); //$desc = str_replace("’", ' ', $desc); // Finally, convert double space to single space. //$desc = str_replace(' ', ' ', $desc); // Allow further filtering of description $desc = apply_filters( 'amt_sanitize_description_extra', $desc ); return $desc; } /** * Sanitizes text for use in the 'keywords' or similar metatags. * * Currently: * - converts to lowercase * - removes double quotes * - convert single quotes to space */ function amt_sanitize_keywords( $text ) { // Convert to lowercase if (function_exists('mb_strtolower')) { $text = mb_strtolower($text, get_bloginfo('charset')); } else { $text = strtolower($text); } // Clean double quotes $text = str_replace('"', '', $text); $text = str_replace('"', '', $text); // Convert single quotes to space $text = str_replace("'", ' ', $text); $text = str_replace(''', ' ', $text); $text = str_replace("'", ' ', $text); // Allow further filtering of keywords $text = apply_filters( 'amt_sanitize_keywords_extra', $text ); return $text; } /** * Helper function that converts the placeholders used by Add-Meta-Tags * to a form, in which they remain unaffected by the sanitization functions. * * Currently the problem is the '%ca' part of '%cats%' which is removed * by sanitize_text_field(). */ function amt_convert_placeholders( $data ) { $data = str_replace('%cats%', '#cats#', $data); $data = str_replace('%tags%', '#tags#', $data); $data = str_replace('%terms%', '#terms#', $data); $data = str_replace('%contentkw%', '#contentkw#', $data); $data = str_replace('%title%', '#title#', $data); return $data; } /** * Helper function that reverts the placeholders used by Add-Meta-Tags * back to their original form. This action should be performed after * after the sanitization functions have processed the data. */ function amt_revert_placeholders( $data ) { $data = str_replace('#cats#', '%cats%', $data); $data = str_replace('#tags#', '%tags%', $data); $data = str_replace('#terms#', '%terms%', $data); $data = str_replace('#contentkw#', '%contentkw%', $data); $data = str_replace('#title#', '%title%', $data); return $data; } /** * This function is meant to be used in order to append information about the * current page to the description or the title of the content. * * Works on both: * 1. paged archives or main blog page * 2. multipage content */ function amt_process_paged( $data ) { if ( !empty( $data ) ) { $data_to_append = ' | Page '; //TODO: Check if it should be translatable //$data_to_append = ' | ' . __('Page', 'add-meta-tags') . ' '; // Allowing filtering of the $data_to_append $data_to_append = apply_filters( 'amt_paged_append_data', $data_to_append ); // For paginated archives or paginated main page with latest posts. if ( is_paged() ) { $paged = get_query_var( 'paged' ); // paged if ( $paged && $paged >= 2 ) { return $data . $data_to_append . $paged; } // For a Post or PAGE Page that has been divided into pages using the QuickTag } else { $paged = get_query_var( 'page' ); // page if ( $paged && $paged >= 2 ) { return $data . $data_to_append . $paged; } } } return $data; } // Escapes the contents of a field that can accept an attachment ID (integer) and a URL // Mainly used for 'Global Image Override' fields and 'Default_image_URL' field. function amt_esc_id_or_url_notation( $data ) { if ( empty($data) || is_numeric($data) ) { return $data; } // Treat as URL. Split into pieaces (URL,WIDTHxHEIGHT), escape each and // then reconstruct the data. $parts = explode(',', $data); if ( count($parts) == 1 ) { // We have just the URL return esc_url($data); } else { $url = $parts[0]; $dimensions = explode('x', $parts[1]); if ( count($dimensions) != 2 ) { return esc_url($url); } elseif ( ! is_numeric($dimensions[0]) || ! is_numeric($dimensions[1]) ) { return esc_url($url); } } return sprintf('%s,%dx%d', esc_url($url), absint($dimensions[0]), absint($dimensions[1])); } // Function that cleans the content of the post // Removes HTML markup, expands or removes short codes etc. function amt_get_clean_post_content( $options, $post ) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_clean_post_content', $post); $plain_text_processed = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $plain_text_processed !== false ) { return $plain_text_processed; } // Early filter that lets dev define the post. This makes it possible to // exclude specific parts of the post for the rest of the algorithm. // NOTE: qtranslate-X needs to pass through __() at this point. $initial_content = apply_filters( 'amt_get_the_excerpt_initial_content', $post->post_content, $post ); // First expand the shortcodes if the relevant setting is enabled. if ( $options['expand_shortcodes'] == '1' ) { $initial_content = do_shortcode( $initial_content ); // Filter the initial content again after expanding the shortcodes. $initial_content = apply_filters( 'amt_get_the_excerpt_initial_content_expanded_shortcodes', $initial_content, $post ); } // Second strip all HTML tags //$plain_text = wp_kses( $initial_content, array() ); // Use wp_strip_all_tags() instead of wp_kses(). The latter leave the contents // of script/style HTML tags. $plain_text = wp_strip_all_tags( $initial_content, true ); // Strip properly registered shortcodes $plain_text = strip_shortcodes( $plain_text ); // Also strip any shortcodes (For example, required for the removal of Visual Composer shortcodes) $plain_text = preg_replace('#\[[^\]]+\]#', '', $plain_text); // Late preprocessing filter. Content has no HTML tags and no properly registered shortcodes. Other shortcodes might still exist. $plain_text_processed = apply_filters( 'amt_get_the_excerpt_plain_text', $plain_text, $post ); // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $plain_text_processed, $group='add-meta-tags' ); return $plain_text_processed; } /** * Returns the post's excerpt. * This function was written in order to get the excerpt *outside* the loop * because the get_the_excerpt() function does not work there any more. * This function makes the retrieval of the excerpt independent from the * WordPress function in order not to break compatibility with older WP versions. * * Also, this is even better as the algorithm tries to get text of average * length 250 characters, which is more SEO friendly. The algorithm is not * perfect, but will do for now. * * MUST return sanitized text. */ function amt_get_the_excerpt( $post, $excerpt_max_len=300, $desc_avg_length=250, $desc_min_length=150 ) { $options = amt_get_options(); // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_the_excerpt', $post); $amt_excerpt = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $amt_excerpt !== false ) { return $amt_excerpt; } if ( empty($post->post_excerpt) || get_post_type( $post ) == 'attachment' ) { // In attachments we always use $post->post_content to get a description // Here we generate an excerpt from $post->post_content // Get clean content data $plain_text_processed = amt_get_clean_post_content( $options, $post ); // Get the initial text. // We use $excerpt_max_len characters of the text for the description. $amt_excerpt = sanitize_text_field( amt_sanitize_description( substr($plain_text_processed, 0, $excerpt_max_len) ) ); // Remove any URLs that may exist exactly at the beginning of the description. // This may happen if for example you put a youtube video url first thing in // the post body. $amt_excerpt = preg_replace( '#^https?:[^\t\r\n\s]+#i', '', $amt_excerpt ); $amt_excerpt = ltrim( $amt_excerpt ); // If this was not enough, try to get some more clean data for the description (nasty hack) if ( strlen($amt_excerpt) < $desc_avg_length ) { $amt_excerpt = sanitize_text_field( amt_sanitize_description( substr($plain_text_processed, 0, (int) ($excerpt_max_len * 1.5)) ) ); if ( strlen($amt_excerpt) < $desc_avg_length ) { $amt_excerpt = sanitize_text_field( amt_sanitize_description( substr($plain_text_processed, 0, (int) ($excerpt_max_len * 2)) ) ); } } /** ORIGINAL ALGO // Get the initial data for the excerpt $amt_excerpt = strip_tags(substr($post->post_content, 0, $excerpt_max_len)); // If this was not enough, try to get some more clean data for the description (nasty hack) if ( strlen($amt_excerpt) < $desc_avg_length ) { $amt_excerpt = strip_tags(substr($post->post_content, 0, (int) ($excerpt_max_len * 1.5))); if ( strlen($amt_excerpt) < $desc_avg_length ) { $amt_excerpt = strip_tags(substr($post->post_content, 0, (int) ($excerpt_max_len * 2))); } } */ $end_of_excerpt = strrpos($amt_excerpt, "."); if ($end_of_excerpt) { // if there are sentences, end the description at the end of a sentence. $amt_excerpt_test = substr($amt_excerpt, 0, $end_of_excerpt + 1); if ( strlen($amt_excerpt_test) < $desc_min_length ) { // don't end at the end of the sentence because the description would be too small $amt_excerpt .= "..."; } else { // If after ending at the end of a sentence the description has an acceptable length, use this $amt_excerpt = $amt_excerpt_test; } } else { // otherwise (no end-of-sentence in the excerpt) add this stuff at the end of the description. $amt_excerpt .= "..."; } } else { // When the post excerpt has been set explicitly, then it has priority. $amt_excerpt = sanitize_text_field( amt_sanitize_description( $post->post_excerpt ) ); // NOTE ABOUT ATTACHMENTS: In attachments $post->post_excerpt is the caption. // It is usual that attachments have both the post_excerpt and post_content set. // Attachments should never enter here, but be processed above, so that // post->post_content is always used as the source of the excerpt. } /** * In some cases, the algorithm might not work, depending on the content. * In those cases, $amt_excerpt might only contain ``...``. Here we perform * a check for this and return an empty $amt_excerpt. */ if ( trim($amt_excerpt) == "..." ) { $amt_excerpt = ""; } /** * Allow filtering of the generated excerpt. * * Filter with: * * function customize_amt_excerpt( $amt_excerpt, $post ) { * $amt_excerpt = ... * return $amt_excerpt; * } * add_filter( 'amt_get_the_excerpt', 'customize_amt_excerpt', 10, 2 ); */ $amt_excerpt = apply_filters( 'amt_get_the_excerpt', $amt_excerpt, $post ); // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $amt_excerpt, $group='add-meta-tags' ); return $amt_excerpt; } /** * Returns a comma-delimited list of a post's terms that belong to custom taxonomies. */ function amt_get_keywords_from_custom_taxonomies( $post ) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_keywords_from_custom_taxonomies', $post); $custom_tax_keywords = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $custom_tax_keywords !== false ) { return $custom_tax_keywords; } $custom_tax_keywords = ''; // Array to hold all terms of custom taxonomies. $keywords_arr = array(); // Get the custom taxonomy names. // Arguments in order to retrieve all public custom taxonomies // (excluding the builtin categories, tags and post formats.) $args = array( 'public' => true, '_builtin' => false ); $output = 'names'; // or objects $operator = 'and'; // 'and' or 'or' $taxonomies = get_taxonomies( $args, $output, $operator ); // Get the terms of each taxonomy and append to $keywords_arr foreach ( $taxonomies as $taxonomy ) { $terms = get_the_terms( $post->ID, $taxonomy ); if ( $terms && is_array($terms) ) { foreach ( $terms as $term ) { $keywords_arr[] = $term->name; } } } if ( ! empty( $keywords_arr ) ) { $custom_tax_keywords = implode(', ', $keywords_arr); } else { $custom_tax_keywords = ''; } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $custom_tax_keywords, $group='add-meta-tags' ); return $custom_tax_keywords; } /** * Returns a comma-delimited list of a post's categories. */ function amt_get_keywords_from_post_cats( $post ) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_keywords_from_post_cats', $post); $postcats = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $postcats !== false ) { return $postcats; } $postcats = ''; foreach((get_the_category($post->ID)) as $cat) { if ( $cat->slug != 'uncategorized' ) { $postcats .= $cat->cat_name . ', '; } } // strip final comma $postcats = substr($postcats, 0, -2); // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $postcats, $group='add-meta-tags' ); return $postcats; } /** * Helper function. Returns the first category the post belongs to. */ function amt_get_first_category( $post ) { $cats = amt_get_keywords_from_post_cats( $post ); $bits = explode(',', $cats); if (!empty($bits)) { return $bits[0]; } return ''; } /** * Retrieves the post's user-defined tags. * * This will only work in WordPress 2.3 or newer. On older versions it will * return an empty string. */ function amt_get_post_tags( $post ) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_post_tags', $post); $posttags = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $posttags !== false ) { return $posttags; } $posttags = ''; if ( version_compare( get_bloginfo('version'), '2.3', '>=' ) ) { $tags = get_the_tags($post->ID); if ( ! empty( $tags ) ) { foreach ( $tags as $tag ) { $posttags .= $tag->name . ', '; } $posttags = rtrim($posttags, " ,"); } } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $posttags, $group='add-meta-tags' ); return $posttags; } /** * Returns a comma-delimited list of all the blog's categories. * The built-in category "Uncategorized" is excluded. */ function amt_get_all_categories($no_uncategorized = TRUE) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_all_categories'); $all_cats = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $all_cats !== false ) { return $all_cats; } $all_cats = ''; global $wpdb; if ( version_compare( get_bloginfo('version'), '2.3', '>=' ) ) { $cat_field = "name"; $sql = "SELECT name FROM $wpdb->terms LEFT OUTER JOIN $wpdb->term_taxonomy ON ($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id) WHERE $wpdb->term_taxonomy.taxonomy = 'category' ORDER BY name ASC"; } else { $cat_field = "cat_name"; $sql = "SELECT cat_name FROM $wpdb->categories ORDER BY cat_name ASC"; } $categories = $wpdb->get_results($sql); if ( ! empty( $categories ) ) { foreach ( $categories as $cat ) { if ($no_uncategorized && $cat->$cat_field != "Uncategorized") { $all_cats .= $cat->$cat_field . ', '; } } $all_cats = rtrim($all_cats, " ,"); } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $all_cats, $group='add-meta-tags' ); return $all_cats; } /** * Returns an array of the category names that appear in the posts of the loop. * Category 'Uncategorized' is excluded. * * Accepts the $category_arr, an array containing the initial categories. */ function amt_get_categories_from_loop() { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_categories_from_loop'); $category_arr = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $category_arr !== false ) { return $category_arr; } $category_arr = array(); if (have_posts()) { while ( have_posts() ) { the_post(); // Iterate the post index in The Loop. Retrieves the next post, sets up the post, sets the 'in the loop' property to true. $categories = get_the_category(); if( ! empty($categories) ) { foreach( $categories as $category ) { if ( ! in_array( $category->name, $category_arr ) && $category->slug != 'uncategorized' ) { $category_arr[] = $category->name; } } } } } rewind_posts(); // Not sure if this is needed. // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $category_arr, $group='add-meta-tags' ); return $category_arr; } /** * Returns an array of the tag names that appear in the posts of the loop. * * Accepts the $tag_arr, an array containing the initial tags. */ function amt_get_tags_from_loop() { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_tags_from_loop'); $tag_arr = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $tag_arr !== false ) { return $tag_arr; } $tag_arr = array(); if (have_posts()) { while ( have_posts() ) { the_post(); // Iterate the post index in The Loop. Retrieves the next post, sets up the post, sets the 'in the loop' property to true. $tags = get_the_tags(); if( ! empty($tags) ) { foreach( $tags as $tag ) { if ( ! in_array( $tag->name, $tag_arr ) ) { $tag_arr[] = $tag->name; } } } } } rewind_posts(); // Not sure if this is needed. // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $tag_arr, $group='add-meta-tags' ); return $tag_arr; } /** * Returns an array of URLS of referenced items in the post. * * Accepts a post object. */ function amt_get_referenced_items( $post ) { if ( is_singular() ) { // TODO: check if this check is needed at all! $referenced_list_content = amt_get_post_meta_referenced_list( $post->ID ); if ( ! empty( $referenced_list_content ) ) { // Each line contains a single URL. Split the string and convert each line to an array item. $referenced_list_content = str_replace("\r", '', $referenced_list_content); // Do not change the double quotes. return explode("\n", $referenced_list_content); // Do not change the double quotes. } } return array(); } /** * This is a helper function that returns the post's or page's description. * * Important: MUST return sanitized data, unless this plugin has sanitized the data before storing to db. * */ function amt_get_content_description( $post, $auto=true ) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_content_description', $post); $content_description = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $content_description !== false ) { return $content_description; } // By default, if a custom description has not been entered by the user in the // metabox, a description is autogenerated. To stop this automatic generation // of a description and return only the description that has been entered manually, // set $auto to false via the following filter. $auto = apply_filters( 'amt_generate_description_if_no_manual_data', $auto ); $content_description = ''; if ( is_singular() || amt_is_static_front_page() || amt_is_static_home() ) { // TODO: check if this check is needed at all! $desc_fld_content = amt_get_post_meta_description( $post->ID ); if ( !empty($desc_fld_content) ) { // If there is a custom field, use it $content_description = $desc_fld_content; } else { // Else, use the post's excerpt. Valid for Pages too. if ($auto) { // The generated excerpt should already be sanitized. $content_description = amt_get_the_excerpt( $post ); } } } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $content_description, $group='add-meta-tags' ); // Allow filtering of the final description // NOTE: qtranslate-X needs to pass through __() at this point. $content_description = apply_filters( 'amt_get_content_description', $content_description, $post ); return $content_description; } /** * This is a helper function that returns the post's or page's keywords. * * Important: MUST return sanitized data, unless this plugin has sanitized the data before storing to db. * */ function amt_get_content_keywords($post, $auto=true, $exclude_categories=false) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_content_keywords', $post); $content_keywords = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $content_keywords !== false ) { return $content_keywords; } // By default, if custom keywords have not been entered by the user in the // metabox, keywords are autogenerated. To stop this automatic generation // of keywords and return only the keywords that have been entered manually, // set $auto to false via the following filter. $auto = apply_filters( 'amt_generate_keywords_if_no_manual_data', $auto ); $content_keywords = ''; /* * Custom post field "keywords" overrides post's categories, tags (tags exist in WordPress 2.3 or newer) * and custom taxonomy terms (custom taxonomies exist since WP version 2.8). * %cats% is replaced by the post's categories. * %tags% is replaced by the post's tags. * %terms% is replaced by the post's custom taxonomy terms. */ if ( is_singular() || amt_is_static_front_page() || amt_is_static_home() ) { $keyw_fld_content = amt_get_post_meta_keywords( $post->ID ); // If there is a custom field, use it if ( ! empty($keyw_fld_content) ) { // On single posts, expand the %cats%, %tags% and %terms% placeholders. // This should not take place in pages (no categories, no tags by default) // or custom post types, the support of which for categories and tags is unknown. if ( is_single() ) { // Here we sanitize the provided keywords for safety $keywords_from_post_cats = sanitize_text_field( amt_sanitize_keywords( amt_get_keywords_from_post_cats($post) ) ); if ( ! empty($keywords_from_post_cats) ) { $keyw_fld_content = str_replace("%cats%", $keywords_from_post_cats, $keyw_fld_content); } // Also, the %tags% placeholder is replaced by the post's tags (WordPress 2.3 or newer) if ( version_compare( get_bloginfo('version'), '2.3', '>=' ) ) { // Here we sanitize the provided keywords for safety $keywords_from_post_tags = sanitize_text_field( amt_sanitize_keywords( amt_get_post_tags($post) ) ); if ( ! empty($keywords_from_post_tags) ) { $keyw_fld_content = str_replace("%tags%", $keywords_from_post_tags, $keyw_fld_content); } } // Also, the %terms% placeholder is replaced by the post's custom taxonomy terms (WordPress 2.8 or newer) if ( version_compare( get_bloginfo('version'), '2.8', '>=' ) ) { // Here we sanitize the provided keywords for safety $keywords_from_post_terms = sanitize_text_field( amt_sanitize_keywords( amt_get_keywords_from_custom_taxonomies($post) ) ); if ( ! empty($keywords_from_post_terms) ) { $keyw_fld_content = str_replace("%terms%", $keywords_from_post_terms, $keyw_fld_content); } } } $content_keywords .= $keyw_fld_content; // Otherwise, generate the keywords from categories, tags and custom taxonomy terms. // Note: // Here we use is_singular(), so that pages are also checked for categories and tags. // By default, pages do not support categories and tags, but enabling such // functionality is trivial. See #1206 for more details. } elseif ( $auto && is_singular() ) { /* * Add keywords automatically. * Keywords consist of the post's categories, the post's tags (tags exist in WordPress 2.3 or newer) * and the terms of the custom taxonomies to which the post belongs (since WordPress 2.8). */ // Categories - Here we sanitize the provided keywords for safety if ( $exclude_categories === false ) { $keywords_from_post_cats = sanitize_text_field( amt_sanitize_keywords( amt_get_keywords_from_post_cats($post) ) ); if (!empty($keywords_from_post_cats)) { $content_keywords .= $keywords_from_post_cats; } } // Tags - Here we sanitize the provided keywords for safety $keywords_from_post_tags = sanitize_text_field( amt_sanitize_keywords( amt_get_post_tags($post) ) ); if (!empty($keywords_from_post_tags)) { if ( ! empty($content_keywords) ) { $content_keywords .= ", "; } $content_keywords .= $keywords_from_post_tags; } // Custom taxonomy terms - Here we sanitize the provided keywords for safety $keywords_from_post_custom_taxonomies = sanitize_text_field( amt_sanitize_keywords( amt_get_keywords_from_custom_taxonomies($post) ) ); if (!empty($keywords_from_post_custom_taxonomies)) { if ( ! empty($content_keywords) ) { $content_keywords .= ", "; } $content_keywords .= $keywords_from_post_custom_taxonomies; } } } // Add post format to the list of keywords if ( $auto && is_singular() && get_post_format($post->ID) !== false ) { if ( empty($content_keywords) ) { $content_keywords .= get_post_format($post->ID); } else { $content_keywords .= ', ' . get_post_format($post->ID); } } /** * Finally, add the global keywords, if they are set in the administration panel. */ //if ( !empty($content_keywords) && ( is_singular() || amt_is_static_front_page() || amt_is_static_home() ) ) { if ( $auto && ( is_singular() || amt_is_static_front_page() || amt_is_static_home() ) ) { $options = get_option("add_meta_tags_opts"); $global_keywords = amt_get_site_global_keywords($options); if ( ! empty($global_keywords) ) { // If we have $content_keywords so far if ( ! empty($content_keywords) ) { if ( strpos($global_keywords, '%contentkw%') === false ) { // The placeholder ``%contentkw%`` has not been used. Append the content keywords to the global keywords. $content_keywords = $global_keywords . ', ' . $content_keywords; } else { // The user has used the placeholder ``%contentkw%``. Replace it with the content keywords. $content_keywords = str_replace('%contentkw%', $content_keywords, $global_keywords); } // If $content_keywords have not been found. } else { if ( strpos($global_keywords, '%contentkw%') === false ) { // The placeholder ``%contentkw%`` has not been used. Just use the global keywords as is. $content_keywords = $global_keywords; } else { // The user has used the placeholder ``%contentkw%``, but we do not have generated any content keywords => Delete the %contentkw% placeholder. $global_keywords_new = array(); foreach ( explode(',', $global_keywords) as $g_keyword ) { $g_keyword = trim($g_keyword); if ( $g_keyword != '%contentkw%' ) { $global_keywords_new[] = $g_keyword; } } if ( ! empty($global_keywords_new) ) { $content_keywords = implode(', ', $global_keywords_new); } } } } } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $content_keywords, $group='add-meta-tags' ); return $content_keywords; } /** * Helper function that returns an array containing the post types that are * supported by Add-Meta-Tags. These include: * * - post * - page * - attachment * * And also to ALL public custom post types which have a UI. * */ function amt_get_supported_post_types() { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_supported_post_types'); $supported_types = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $supported_types !== false ) { return $supported_types; } $supported_builtin_types = array('post', 'page', 'attachment'); $public_custom_types = get_post_types( array('public'=>true, '_builtin'=>false, 'show_ui'=>true) ); $supported_types = array_merge($supported_builtin_types, $public_custom_types); // Allow filtering of the supported content types. $supported_types = apply_filters( 'amt_supported_post_types', $supported_types ); // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $supported_types, $group='add-meta-tags' ); return $supported_types; } /** * Helper function that returns an array containing permissions for the * Metadata metabox. */ function amt_get_metadata_metabox_permissions() { // // Default Metadata metabox permission settings. // Regardless of these settings the `edit_posts` capability is _always_ // checked when reading/writing metabox data, so the `edit_posts` capability // should be considered as the least restrictive capability that can be used. // The available Capabilities vs Roles table can be found here: // http://codex.wordpress.org/Roles_and_Capabilities // To disable a box, simply add a very restrictive capability like `create_users`. // $metabox_permissions = array( // Minimum capability for the metabox to appear in the editing // screen of the supported post types. 'global_metabox_capability' => 'edit_posts', // The following permissions have an effect only if they are stricter // than the permission of the `global_metabox_capability` setting. // Edit these, only if you want to further restrict access to // specific boxes, for example the `full metatags` box. 'description_box_capability' => 'edit_posts', 'keywords_box_capability' => 'edit_posts', 'title_box_capability' => 'edit_posts', 'news_keywords_box_capability' => 'edit_posts', 'full_metatags_box_capability' => 'edit_posts', 'image_url_box_capability' => 'edit_posts', 'content_locale_box_capability' => 'edit_posts', 'express_review_box_capability' => 'edit_posts', 'referenced_list_box_capability' => 'edit_posts', // Term meta 'term_full_metatags_box_capability' => 'edit_published_posts', 'term_image_url_box_capability' => 'edit_published_posts', // User meta 'user_full_metatags_box_capability' => 'edit_published_posts', 'user_image_url_box_capability' => 'edit_published_posts', ); // Allow filtering of the metabox permissions $metabox_permissions = apply_filters( 'amt_metadata_metabox_permissions', $metabox_permissions ); return $metabox_permissions; } /** * Helper function that returns an array of the supported custom fields. */ function amt_get_post_custom_field_names() { return array( '_amt_description', '_amt_keywords', '_amt_title', '_amt_news_keywords', '_amt_full_metatags', '_amt_image_url', '_amt_content_locale', '_amt_express_review', '_amt_referenced_list', ); } /** * Helper function that returns an array of the supported term meta */ function amt_get_term_custom_field_names() { return array( '_amt_term_full_metatags', '_amt_term_image_url', ); } /** * Helper function that returns an array of the supported user meta fields. */ function amt_get_user_custom_field_names() { return array( // Contact methods 'amt_facebook_author_profile_url', 'amt_facebook_publisher_profile_url', 'amt_googleplus_author_profile_url', 'amt_googleplus_publisher_profile_url', 'amt_twitter_author_username', 'amt_twitter_publisher_username', // User Meta '_amt_user_full_metatags', '_amt_user_image_url', ); } /** * Helper function that returns an array containing the post types * on which the Metadata metabox should be added. * * - post * - page * * And also to ALL public custom post types which have a UI. * * NOTE ABOUT attachments: * The 'attachment' post type does not support saving custom fields like other post types. * See: http://www.codetrax.org/issues/875 */ function amt_get_post_types_for_metabox() { // Get the post types supported by Add-Meta-Tags $supported_builtin_types = amt_get_supported_post_types(); // The 'attachment' post type does not support saving custom fields like // other post types. See: http://www.codetrax.org/issues/875 // So, the 'attachment' type is removed (if exists) so as not to add a metabox there. $attachment_post_type_key = array_search( 'attachment', $supported_builtin_types ); if ( $attachment_post_type_key !== false ) { // Remove this type from the array unset( $supported_builtin_types[ $attachment_post_type_key ] ); } // Get public post types $public_custom_types = get_post_types( array('public'=>true, '_builtin'=>false, 'show_ui'=>true) ); $supported_types = array_merge($supported_builtin_types, $public_custom_types); // Allow filtering of the supported content types. $supported_types = apply_filters( 'amt_metabox_post_types', $supported_types ); // Leave this filter out of the documentation for now. return $supported_types; } /** * Helper function that returns the value of the custom field that contains * the content description. * The default field name for the description has changed to ``_amt_description``. * For easy migration this function supports reading the description from the * old ``description`` custom field and also from the custom field of other plugins. */ function amt_get_post_meta_description( $post_id ) { $options = get_option('add_meta_tags_opts'); if ( ! is_array($options) ) { return ''; } elseif ( ! array_key_exists( 'metabox_enable_description', $options) ) { return ''; } elseif ( $options['metabox_enable_description'] == '0' ) { return ''; } // Internal fields - order matters $supported_custom_fields = array( '_amt_description', 'description' ); // External fields - Allow filtering $external_fields = array(); $external_fields = apply_filters( 'amt_external_description_fields', $external_fields, $post_id ); // Merge external fields to our supported custom fields $supported_custom_fields = array_merge( $supported_custom_fields, $external_fields ); // Get an array of all custom fields names of the post $custom_fields = get_post_custom_keys( $post_id ); if ( empty( $custom_fields ) ) { // Just return an empty string if no custom fields have been associated with this content. return ''; } // Try our fields foreach( $supported_custom_fields as $sup_field ) { // If such a field exists in the db, return its content as the description. if ( in_array( $sup_field, $custom_fields ) ) { return get_post_meta( $post_id, $sup_field, true ); } } //Return empty string if all fail return ''; } /** * Helper function that returns the value of the custom field that contains * the content keywords. * The default field name for the keywords has changed to ``_amt_keywords``. * For easy migration this function supports reading the keywords from the * old ``keywords`` custom field and also from the custom field of other plugins. */ function amt_get_post_meta_keywords($post_id) { $options = get_option('add_meta_tags_opts'); if ( ! is_array($options) ) { return ''; } elseif ( ! array_key_exists( 'metabox_enable_keywords', $options) ) { return ''; } elseif ( $options['metabox_enable_keywords'] == '0' ) { return ''; } // Internal fields - order matters $supported_custom_fields = array( '_amt_keywords', 'keywords' ); // External fields - Allow filtering $external_fields = array(); $external_fields = apply_filters( 'amt_external_keywords_fields', $external_fields, $post_id ); // Merge external fields to our supported custom fields $supported_custom_fields = array_merge( $supported_custom_fields, $external_fields ); // Get an array of all custom fields names of the post $custom_fields = get_post_custom_keys( $post_id ); if ( empty( $custom_fields ) ) { // Just return an empty string if no custom fields have been associated with this content. return ''; } // Try our fields foreach( $supported_custom_fields as $sup_field ) { // If such a field exists in the db, return its content as the keywords. if ( in_array( $sup_field, $custom_fields ) ) { return get_post_meta( $post_id, $sup_field, true ); } } //Return empty string if all fail return ''; } /** * Helper function that returns the value of the custom field that contains * the custom content title. * The default field name for the title is ``_amt_title``. * No need to migrate from older field name. */ function amt_get_post_meta_title($post_id) { $options = get_option('add_meta_tags_opts'); if ( ! is_array($options) ) { return ''; } elseif ( ! array_key_exists( 'metabox_enable_title', $options) ) { return ''; } elseif ( $options['metabox_enable_title'] == '0' ) { return ''; } // Internal fields - order matters $supported_custom_fields = array( '_amt_title' ); // External fields - Allow filtering $external_fields = array(); $external_fields = apply_filters( 'amt_external_title_fields', $external_fields, $post_id ); // Merge external fields to our supported custom fields $supported_custom_fields = array_merge( $supported_custom_fields, $external_fields ); // Get an array of all custom fields names of the post $custom_fields = get_post_custom_keys( $post_id ); if ( empty( $custom_fields ) ) { // Just return an empty string if no custom fields have been associated with this content. return ''; } // Try our fields foreach( $supported_custom_fields as $sup_field ) { // If such a field exists in the db, return its content as the custom title. if ( in_array( $sup_field, $custom_fields ) ) { return get_post_meta( $post_id, $sup_field, true ); } } //Return empty string if all fail return ''; } /** * Helper function that returns the value of the custom field that contains * the 'news_keywords' value. * The default field name for the 'news_keywords' is ``_amt_news_keywords``. * No need to migrate from older field name. */ function amt_get_post_meta_newskeywords($post_id) { $options = get_option('add_meta_tags_opts'); if ( ! is_array($options) ) { return ''; } elseif ( ! array_key_exists( 'metabox_enable_news_keywords', $options) ) { return ''; } elseif ( $options['metabox_enable_news_keywords'] == '0' ) { return ''; } // Internal fields - order matters $supported_custom_fields = array( '_amt_news_keywords' ); // External fields - Allow filtering $external_fields = array(); $external_fields = apply_filters( 'amt_external_news_keywords_fields', $external_fields, $post_id ); // Merge external fields to our supported custom fields $supported_custom_fields = array_merge( $supported_custom_fields, $external_fields ); // Get an array of all custom fields names of the post $custom_fields = get_post_custom_keys( $post_id ); if ( empty( $custom_fields ) ) { // Just return an empty string if no custom fields have been associated with this content. return ''; } // Try our fields foreach( $supported_custom_fields as $sup_field ) { // If such a field exists in the db, return its content as the news keywords. if ( in_array( $sup_field, $custom_fields ) ) { return get_post_meta( $post_id, $sup_field, true ); } } //Return empty string if all fail return ''; } // // Helper function that returns the value of the custom field that contains // the per-post full metatags. // The default field name is ``_amt_full_metatags``. // No need to migrate from older field name. // function amt_get_post_meta_full_metatags($post_id) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_post_meta_full_metatags', $post_id); $field_value = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $field_value !== false ) { return $field_value; } $field_value = ''; $options = get_option('add_meta_tags_opts'); if ( ! is_array($options) ) { $field_value = ''; } elseif ( ! array_key_exists( 'metabox_enable_full_metatags', $options) ) { $field_value = ''; } elseif ( $options['metabox_enable_full_metatags'] == '0' ) { $field_value = ''; } else { // Internal fields - order matters $supported_custom_fields = array( '_amt_full_metatags' ); // External fields - Allow filtering $external_fields = array(); $external_fields = apply_filters( 'amt_external_full_metatags_fields', $external_fields, $post_id ); // Merge external fields to our supported custom fields $supported_custom_fields = array_merge( $supported_custom_fields, $external_fields ); // Get an array of all custom fields names of the post $custom_fields = get_post_custom_keys( $post_id ); if ( empty( $custom_fields ) ) { // Just return an empty string if no custom fields have been associated with this content. $field_value = ''; } else { // Try our fields foreach( $supported_custom_fields as $sup_field ) { // If such a field exists in the db, return its content as the news keywords. if ( in_array( $sup_field, $custom_fields ) ) { $field_value = get_post_meta( $post_id, $sup_field, true ); break; } } } } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $field_value, $group='add-meta-tags' ); return $field_value; } // // Helper function that returns the value of the custom field that contains // a global image override URL. // The default field name for the 'global image override URL' is ``_amt_image_url``. // No need to migrate from older field name. // function amt_get_post_meta_image_url($post_id) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_post_meta_image_url', $post_id); $image_url = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $image_url !== false ) { return $image_url; } $image_url = ''; $options = get_option('add_meta_tags_opts'); if ( ! is_array($options) ) { $image_url = ''; } elseif ( ! array_key_exists( 'metabox_enable_image_url', $options) ) { $image_url = ''; } elseif ( $options['metabox_enable_image_url'] == '0' ) { $image_url = ''; } else { // Internal fields - order matters $supported_custom_fields = array( '_amt_image_url' ); // External fields - Allow filtering $external_fields = array(); $external_fields = apply_filters( 'amt_external_image_url_fields', $external_fields, $post_id ); // Merge external fields to our supported custom fields $supported_custom_fields = array_merge( $supported_custom_fields, $external_fields ); // Get an array of all custom fields names of the post $custom_fields = get_post_custom_keys( $post_id ); if ( empty( $custom_fields ) ) { // Just return an empty string if no custom fields have been associated with this content. $image_url = ''; } else { // Try our fields foreach( $supported_custom_fields as $sup_field ) { // If such a field exists in the db, return its content as the news keywords. if ( in_array( $sup_field, $custom_fields ) ) { $image_url = get_post_meta( $post_id, $sup_field, true ); break; } } } } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $image_url, $group='add-meta-tags' ); return $image_url; } /** * Helper function that returns the value of the custom field that contains * a locale override for the content. * The default field name for the 'content locale override' is ``_amt_content_locale``. * No need to migrate from older field name. */ function amt_get_post_meta_content_locale($post_id) { $options = get_option('add_meta_tags_opts'); if ( ! is_array($options) ) { return ''; } elseif ( ! array_key_exists( 'metabox_enable_content_locale', $options) ) { return ''; } elseif ( $options['metabox_enable_content_locale'] == '0' ) { return ''; } // Internal fields - order matters $supported_custom_fields = array( '_amt_content_locale' ); // External fields - Allow filtering $external_fields = array(); $external_fields = apply_filters( 'amt_external_content_locale_fields', $external_fields, $post_id ); // Merge external fields to our supported custom fields $supported_custom_fields = array_merge( $supported_custom_fields, $external_fields ); // Get an array of all custom fields names of the post $custom_fields = get_post_custom_keys( $post_id ); if ( empty( $custom_fields ) ) { // Just return an empty string if no custom fields have been associated with this content. return ''; } // Try our fields foreach( $supported_custom_fields as $sup_field ) { // If such a field exists in the db, return its content as the news keywords. if ( in_array( $sup_field, $custom_fields ) ) { return get_post_meta( $post_id, $sup_field, true ); } } //Return empty string if all fail return ''; } /** * Helper function that returns the value of the custom field that contains * express review related information. * The default field name for the 'express review' is ``_amt_express_review``. * No need to migrate from older field name. */ function amt_get_post_meta_express_review($post_id) { $options = get_option('add_meta_tags_opts'); if ( ! is_array($options) ) { return ''; } elseif ( ! array_key_exists( 'metabox_enable_express_review', $options) ) { return ''; } elseif ( $options['metabox_enable_express_review'] == '0' ) { return ''; } // Internal fields - order matters $supported_custom_fields = array( '_amt_express_review' ); // External fields - Allow filtering $external_fields = array(); $external_fields = apply_filters( 'amt_external_express_review_fields', $external_fields, $post_id ); // Merge external fields to our supported custom fields $supported_custom_fields = array_merge( $supported_custom_fields, $external_fields ); // Get an array of all custom fields names of the post $custom_fields = get_post_custom_keys( $post_id ); if ( empty( $custom_fields ) ) { // Just return an empty string if no custom fields have been associated with this content. return ''; } // Try our fields foreach( $supported_custom_fields as $sup_field ) { // If such a field exists in the db, return its content as the news keywords. if ( in_array( $sup_field, $custom_fields ) ) { return get_post_meta( $post_id, $sup_field, true ); } } //Return empty string if all fail return ''; } /** * Helper function that returns the value of the custom field that contains * the list of URLs of items referenced in the post. * The default field name is ``_amt_referenced_list``. * No need to migrate from older field name. */ function amt_get_post_meta_referenced_list($post_id) { $options = get_option('add_meta_tags_opts'); if ( ! is_array($options) ) { return ''; } elseif ( ! array_key_exists( 'metabox_enable_referenced_list', $options) ) { return ''; } elseif ( $options['metabox_enable_referenced_list'] == '0' ) { return ''; } // Internal fields - order matters $supported_custom_fields = array( '_amt_referenced_list' ); // External fields - Allow filtering $external_fields = array(); $external_fields = apply_filters( 'amt_external_referenced_list_fields', $external_fields, $post_id ); // Merge external fields to our supported custom fields $supported_custom_fields = array_merge( $supported_custom_fields, $external_fields ); // Get an array of all custom fields names of the post $custom_fields = get_post_custom_keys( $post_id ); if ( empty( $custom_fields ) ) { // Just return an empty string if no custom fields have been associated with this content. return ''; } // Try our fields foreach( $supported_custom_fields as $sup_field ) { // If such a field exists in the db, return its content as the URL list of referenced items (text). if ( in_array( $sup_field, $custom_fields ) ) { return get_post_meta( $post_id, $sup_field, true ); } } //Return empty string if all fail return ''; } // // Helper functions for the retrieval of term meta // // Helper function that returns the value of the custom field that contains // the per-term full metatags. // The default field name is ``_amt_term_full_metatags``. // No need to migrate from older field name. function amt_get_term_meta_full_metatags($term_id) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_term_meta_full_metatags', $term_id); $field_value = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $field_value !== false ) { return $field_value; } $options = amt_get_options(); $field_name = '_amt_term_full_metatags'; $field_value = ''; if ( $options['metabox_term_enable_full_metatags'] == '1' ) { $field_value = get_term_meta( $term_id, $field_name, true ); } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $field_value, $group='add-meta-tags' ); return $field_value; } // // Helper function that returns the value of the custom field that contains // a global image override URL. // The default field name for the 'global image override URL' is ``_amt_term_image_url``. // No need to migrate from older field name. // function amt_get_term_meta_image_url($term_id) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_term_meta_image_url', $term_id); $field_value = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $field_value !== false ) { return $field_value; } $options = amt_get_options(); $field_name = '_amt_term_image_url'; $field_value = ''; if ( $options['metabox_term_enable_image_url'] == '1' ) { $field_value = get_term_meta( $term_id, $field_name, true ); } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $field_value, $group='add-meta-tags' ); return $field_value; } // // Helper functions for the retrieval of user meta // // Helper function that returns the value of the custom field that contains // the per-user full metatags. // The default field name is ``_amt_user_full_metatags``. // No need to migrate from older field name. function amt_get_user_meta_full_metatags($user_id) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_user_meta_full_metatags', $user_id); $field_value = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $field_value !== false ) { return $field_value; } $options = amt_get_options(); $field_name = '_amt_user_full_metatags'; $field_value = ''; if ( $options['metabox_user_enable_full_metatags'] == '1' ) { $field_value = get_user_meta( $user_id, $field_name, true ); } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $field_value, $group='add-meta-tags' ); return $field_value; } // // Helper function that returns the value of the custom field that contains // a global image override URL. // The default field name for the 'global image override URL' is ``_amt_user_image_url``. // No need to migrate from older field name. // function amt_get_user_meta_image_url($user_id) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_user_meta_image_url', $user_id); $field_value = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $field_value !== false ) { return $field_value; } $options = amt_get_options(); $field_name = '_amt_user_image_url'; $field_value = ''; if ( $options['metabox_user_enable_image_url'] == '1' ) { $field_value = get_user_meta( $user_id, $field_name, true ); } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $field_value, $group='add-meta-tags' ); return $field_value; } /** * Helper function that returns an array of objects attached to the provided * $post object. */ function amt_get_ordered_attachments( $post ) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_ordered_attachments', $post); $ordered_attachments = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $ordered_attachments !== false ) { return $ordered_attachments; } // to return IDs: // $attachments = array_values( get_children( array( 'post_parent' => $post->post_parent, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID' ) ) ); $ordered_attachments = get_children( array( 'numberposts' => -1, 'post_parent' => $post->ID, 'post_type' => 'attachment', 'post_status' => 'inherit', //'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID' ) ); // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $ordered_attachments, $group='add-meta-tags' ); return $ordered_attachments; } /** * Helper function that returns the permalink of the provided $post object, * taking into account multipage content. * * ONLY for content. * DO NOT use with: * - paged archives * - static page as front page * - static page as posts index page * * Uses logic from default WordPress function: _wp_link_page * - http://core.trac.wordpress.org/browser/trunk/src/wp-includes/post-template.php#L705 * Also see: wp-includes/canonical.php line: 227 (Post Paging) * */ function amt_get_permalink_for_multipage( $post ) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_permalink_for_multipage', $post); $permalink = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $permalink !== false ) { return $permalink; } $permalink = ''; $pagenum = get_query_var( 'page' ); // Content is multipage if ( $pagenum && $pagenum > 1 ) { // Not using clean URLs -> Add query argument to the URL (eg: ?page=2) if ( '' == get_option('permalink_structure') || in_array( $post->post_status, array('draft', 'pending')) ) { $permalink = esc_url( add_query_arg( 'page', $pagenum, get_permalink($post->ID) ) ); // Using clean URLs } else { $permalink = trailingslashit( get_permalink($post->ID) ) . user_trailingslashit( $pagenum, 'single_paged'); } // Content is not paged } else { $permalink = get_permalink($post->ID); } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $permalink, $group='add-meta-tags' ); return $permalink; } /** * Helper function that returns true if a static page is used as the homepage * instead of the default posts index page. */ function amt_has_page_on_front() { $front_type = get_option('show_on_front', 'posts'); if ( $front_type == 'page' ) { return true; } return false; } /** * Helper function that returns true, if the currently displayed page is a * page that has been set as the 'posts' page in the 'Reading Settings'. * See: http://codex.wordpress.org/Conditional_Tags#The_Main_Page * * This function was written because is_page() is not true for the page that is * used as the 'posts' page. */ function amt_is_static_home() { if ( amt_has_page_on_front() && is_home() ) { return true; } return false; } /** * Helper function that returns true, if the currently displayed page is a * page that has been set as the 'front' page in the 'Reading Settings'. * See: http://codex.wordpress.org/Conditional_Tags#The_Main_Page * * This function was written because is_front_page() returns true if a static * page is used as the front page and also if the latest posts are displayed * on the front page. */ function amt_is_static_front_page() { if ( amt_has_page_on_front() && is_front_page() ) { return true; } return false; } /** * Helper function that returns true, if the currently displayed page is the * main index page of the site that displays the latest posts. * * This function was written because is_front_page() returns true if a static * page is used as the front page and also if the latest posts are displayed * on the front page. */ function amt_is_default_front_page() { if ( !amt_has_page_on_front() && is_front_page() ) { return true; } return false; } /** * Helper function that returns the ID of the page that is used as the 'front' * page. If a static page has not been set as the 'front' page in the * 'Reading Settings' or if the latest posts are displayed in the front page, * then 0 is returned. */ function amt_get_front_page_id() { return intval(get_option('page_on_front', 0)); } /** * Helper function that returns the ID of the page that is used as the 'posts' * page. If a static page has not been set as the 'posts' page in the * 'Reading Settings' or if the latest posts are displayed in the front page, * then 0 is returned. */ function amt_get_posts_page_id() { return intval(get_option('page_for_posts', 0)); } // //function amt_store_oembed_response( $return, $data, $url ) { // /** // * Filter the returned oEmbed HTML. // * // * Use this filter to add support for custom data types, or to filter the result. // * // * @since 2.9.0 // * // * @param string $return The returned oEmbed HTML. // * @param object $data A data object result from an oEmbed provider. // * @param string $url The URL of the content to be embedded. // */ //return apply_filters( 'oembed_dataparse', $return, $data, $url ); //} //add_filter('oembed_dataparse', 'amt_store_oembed_response', 9999, 3); // // SEE: // * http://wordpress.stackexchange.com/questions/70752/featured-image-of-video-from-oembed // * http://wordpress.stackexchange.com/questions/19500/oembed-thumbnails-and-wordpress?lq=1 // * http://wordpress.stackexchange.com/questions/114656/detecting-embed-urls-within-post-content // * http://wordpress.stackexchange.com/a/74026 // * http://wordpress.stackexchange.com/a/180169 // * http://wordpress.stackexchange.com/questions/78140/video-playing-from-featured-image?lq=1 // * http://wordpress.stackexchange.com/questions/73996/how-to-replace-youtube-videos-with-a-click-to-play-thumbnail?lq=1 // GOOD FOR OWN IMPLEMENTATION: // * http://wordpress.stackexchange.com/questions/78140/video-playing-from-featured-image?lq=1 // * http://wordpress.stackexchange.com/questions/25808/setting-a-posts-featured-image-from-an-embedded-youtube-video?rq=1 // * http://wordpress.stackexchange.com/questions/70752/featured-image-of-video-from-oembed // // // Returns an array with URLs to players for some embedded media. // function amt_get_embedded_media( $post ) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_embedded_media', $post); $embedded_media_urls = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $embedded_media_urls !== false ) { return $embedded_media_urls; } // Post content pre-processing // At this point we give devs the opportunity to inject raw URLs of // supported embeddable media, so that they can be picked up by // the algorithms below. // Array of URLs of supported embeddable media. $external_media_urls = apply_filters( 'amt_embedded_media_external', array(), $post ); // Store post body $post_body = $post->post_content; // Attach the external media URLs to the post content. //$post_body .= sprintf( '\n%s\n', implode('\n', $external_media_urls) ); $post_body .= PHP_EOL . implode(PHP_EOL, $external_media_urls) . PHP_EOL; // Format of the array // Embeds are grouped by type images/videos/sounds // Embedded media are added to any group as an associative array. $embedded_media_urls = array( 'images' => array(), 'videos' => array(), 'sounds' => array() ); // Find Videos // // Keys: // page - URL to a HTML page that contains the object. // player - URL to the player that can be used in an iframe. // thumbnail - URL to a preview image // Youtube // Supported: // - http://www.youtube.com/watch?v=VIDEO_ID //$pattern = '#youtube.com/watch\?v=([-|~_0-9A-Za-z]+)#'; //$pattern = '#http:\/\/(?:www.)?youtube.com\/.*v=(\w*)#i'; $pattern = '#https?:\/\/(?:www.)?youtube.com\/.*v=([a-zA-Z0-9_-]+)#i'; preg_match_all( $pattern, $post_body, $matches ); //var_dump($matches); if ($matches) { // $matches[0] contains a list of YT video URLS // $matches[1] contains a list of YT video IDs // Add matches to $embedded_media_urls foreach( $matches[0] as $youtube_video_url ) { // First we verify that this is an embedded Youtube video and not // one that is just linked. We confirm this by checking if the // relevant oembed custom field has been created. // Get cached HTML data for embedded youtube videos. // Do it like WordPress. // See source code: // - class-wp-embed.php: line 177 [[ $cachekey = '_oembed_' . md5( $url . serialize( $attr ) ); ]] // - media.php: line 1332 [[ function wp_embed_defaults ]] // If no attributes have been used in the [embed] shortcode, $attr is an empty string. $attr = ''; $attr = wp_parse_args( $attr, wp_embed_defaults() ); $cachekey = '_oembed_' . md5( $youtube_video_url . serialize( $attr ) ); $cache = get_post_meta( $post->ID, $cachekey, true ); //var_dump($cache); if ( empty($cache) ) { continue; } // Get video ID from the video URL preg_match( '#.*v=([a-zA-Z0-9_-]+)#', $youtube_video_url, $video_url_info ); //var_dump($video_url_info); $youtube_video_id = $video_url_info[1]; // Get data from the cached HTML //var_dump($cache); preg_match( '#.* (?:width="([\d]+)") (?:height="([\d]+)") .*#', $cache, $media_info ); //var_dump($media_info); $player_width = '640'; if ( isset($media_info[1]) ) { $player_width = $media_info[1]; } $player_height = '480'; if ( isset($media_info[2]) ) { $player_height = $media_info[2]; } $item = array( 'type' => 'youtube', 'page' => 'https://www.youtube.com/watch?v=' . $youtube_video_id, 'player' => 'https://youtube.com/v/' . $youtube_video_id, //'player' => 'https://www.youtube.com/embed/' . $youtube_video_id, // Since we can construct the video thumbnail from the ID, we add it 'thumbnail' => apply_filters( 'amt_oembed_youtube_image_preview', 'https://img.youtube.com/vi/' . $youtube_video_id . '/sddefault.jpg', $youtube_video_id ), //'thumbnail' => apply_filters( 'amt_oembed_youtube_image_preview', '', $youtube_video_id ), // TODO: check http://i1.ytimg.com/vi/FTnqYIkjSjQ/maxresdefault.jpg MAXRES // http://img.youtube.com/vi/rr6H-MJCNw0/hqdefault.jpg 480x360 (same as 0.jpg) // http://img.youtube.com/vi/rr6H-MJCNw0/sddefault.jpg 640x480 // See more here: http://stackoverflow.com/a/2068371 'width' => $player_width, 'height' => $player_height, ); //array_unshift( $embedded_media_urls['videos'], $item ); array_push( $embedded_media_urls['videos'], $item ); } } // Vimeo // Supported: // - http://vimeo.com/VIDEO_ID // Check output of: http://vimeo.com/api/v2/video/VIDEO_ID.xml // INVALID METHOD: 'thumbnail' => 'https://i.vimeocdn.com/video/' . $vimeo_video_id . '_640.jpg' //$pattern = '#vimeo.com/([-|~_0-9A-Za-z]+)#'; $pattern = '#https?:\/\/(?:www.)?vimeo.com\/(\d+)#i'; preg_match_all( $pattern, $post_body, $matches ); //var_dump($matches); if ($matches) { // $matches[0] contains a list of Vimeo video URLS // $matches[1] contains a list of Vimeo video IDs // Add matches to $embedded_media_urls foreach( $matches[0] as $vimeo_video_url ) { // First we verify that this is an embedded Vimeo video and not // one that is just linked. We confirm this by checking if the // relevant oembed custom field has been created. // Get cached HTML data for embedded Vimeo videos. // Do it like WordPress. // See source code: // - class-wp-embed.php: line 177 [[ $cachekey = '_oembed_' . md5( $url . serialize( $attr ) ); ]] // - media.php: line 1332 [[ function wp_embed_defaults ]] // If no attributes have been used in the [embed] shortcode, $attr is an empty string. $attr = ''; $attr = wp_parse_args( $attr, wp_embed_defaults() ); $cachekey = '_oembed_' . md5( $vimeo_video_url . serialize( $attr ) ); $cache = get_post_meta( $post->ID, $cachekey, true ); //var_dump($cache); if ( empty($cache) ) { continue; } // Get video ID from the URL preg_match( '#.*vimeo.com\/(\d+)#', $vimeo_video_url, $video_url_info ); //var_dump($video_url_info); $vimeo_video_id = $video_url_info[1]; // Get data from the cached HTML //var_dump($cache); preg_match( '#.* (?:width="([\d]+)") (?:height="([\d]+)") .*#', $cache, $media_info ); //var_dump($media_info); $player_width = '640'; if ( isset($media_info[1]) ) { $player_width = $media_info[1]; } $player_height = '480'; if ( isset($media_info[2]) ) { $player_height = $media_info[2]; } $item = array( 'type' => 'vimeo', 'page' => 'https://vimeo.com/' . $vimeo_video_id, 'player' => 'https://player.vimeo.com/video/' . $vimeo_video_id, 'thumbnail' => apply_filters( 'amt_oembed_vimeo_image_preview', '', $vimeo_video_id ), 'width' => $player_width, 'height' => $player_height, ); array_push( $embedded_media_urls['videos'], $item ); } } // Vine // Supported: // - https://vine.co/v/VIDEO_ID // Also check output of: https://vine.co/v/bwBYItOUKrw/card $pattern = '#https?:\/\/(?:www.)?vine.co\/v\/([a-zA-Z0-9_-]+)#i'; preg_match_all( $pattern, $post_body, $matches ); //var_dump($matches); if ($matches) { // $matches[0] contains a list of Vimeo video URLS // $matches[1] contains a list of Vimeo video IDs // Add matches to $embedded_media_urls foreach( $matches[0] as $vine_video_url ) { // First we verify that this is an embedded Vine video and not // one that is just linked. We confirm this by checking if the // relevant oembed custom field has been created. // Get cached HTML data for embedded Vine videos. // Do it like WordPress. // See source code: // - class-wp-embed.php: line 177 [[ $cachekey = '_oembed_' . md5( $url . serialize( $attr ) ); ]] // - media.php: line 1332 [[ function wp_embed_defaults ]] // If no attributes have been used in the [embed] shortcode, $attr is an empty string. $attr = ''; $attr = wp_parse_args( $attr, wp_embed_defaults() ); $cachekey = '_oembed_' . md5( $vine_video_url . serialize( $attr ) ); $cache = get_post_meta( $post->ID, $cachekey, true ); //var_dump($cache); if ( empty($cache) ) { continue; } // Get id info from the URL preg_match( '#.*vine.co\/v\/([a-zA-Z0-9_-]+)#', $vine_video_url, $video_url_info ); //var_dump($video_url_info); $vine_video_id = $video_url_info[1]; // Get data from the cached HTML //var_dump($cache); preg_match( '#.* (?:width="([\d]+)") (?:height="([\d]+)") .*#', $cache, $media_info ); //var_dump($media_info); $player_width = '600'; if ( isset($media_info[1]) ) { $player_width = $media_info[1]; } $player_height = '600'; if ( isset($media_info[2]) ) { $player_height = $media_info[2]; } $item = array( 'type' => 'vine', 'page' => 'https://vine.co/v/' . $vine_video_id, 'player' => 'https://vine.co/v/' . $vine_video_id . '/embed/simple', 'thumbnail' => apply_filters( 'amt_oembed_vine_image_preview', '', $vine_video_id ), 'width' => $player_width, 'height' => $player_height, ); array_push( $embedded_media_urls['videos'], $item ); } } // Find Sounds // // Keys: // page - URL to a HTML page that contains the object. // player - URL to the player that can be used in an iframe. // thumbnail - URL to a preview image -= ALWAYS EMPTY, but needed for the player twitter card. // Soundcloud // Supported: // - https://soundcloud.com/USER_ID/TRACK_ID // player: // https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/117455833 // // ALSO SEE: https://developers.soundcloud.com/docs/api/reference#tracks // $pattern = '#https?:\/\/(?:www.)?soundcloud.com\/[^/]+\/[a-zA-Z0-9_-]+#i'; preg_match_all( $pattern, $post_body, $matches ); //var_dump($matches); if ($matches) { // $matches[0] contains a list of Soundcloud URLS // Add matches to $embedded_media_urls foreach( $matches[0] as $soundcloud_url ) { // First we verify that this is an embedded Soundcloud audio and not // one that is just linked. We confirm this by checking if the // relevant oembed custom field has been created. // Get cached HTML data for embedded Soundcloud audios. // Do it like WordPress. // See source code: // - class-wp-embed.php: line 177 [[ $cachekey = '_oembed_' . md5( $url . serialize( $attr ) ); ]] // - media.php: line 1332 [[ function wp_embed_defaults ]] // If no attributes have been used in the [embed] shortcode, $attr is an empty string. $attr = ''; $attr = wp_parse_args( $attr, wp_embed_defaults() ); $cachekey = '_oembed_' . md5( $soundcloud_url . serialize( $attr ) ); $cache = get_post_meta( $post->ID, $cachekey, true ); //var_dump($cache); if ( empty($cache) ) { continue; } // Get data from the cached HTML preg_match( '#.* (?:width="([\d]+)") (?:height="([\d]+)") .*#', $cache, $soundcloud_clip_info ); //var_dump($soundcloud_clip_info); $player_width = '640'; if ( isset($soundcloud_clip_info[1]) ) { $player_width = $soundcloud_clip_info[1]; } $player_height = '320'; if ( isset($soundcloud_clip_info[2]) ) { $player_height = $soundcloud_clip_info[2]; } $item = array( 'type' => 'soundcloud', 'page' => $soundcloud_url, 'player' => 'https://w.soundcloud.com/player/?url=' . $soundcloud_url, 'thumbnail' => apply_filters( 'amt_oembed_soundcloud_image_preview', '', $soundcloud_url ), 'width' => $player_width, 'height' => $player_height, ); array_push( $embedded_media_urls['sounds'], $item ); } } // Find Images // // Keys: // page - URL to a HTML page that contains the object. // player - URL to the player that can be used in an iframe. // thumbnail - URL to thumbnail // image - URL to image // alt - alt text // width - image width // height - image height // Flickr // // Supported: // Embedded URLs MUST be of Format: http://www.flickr.com/photos/USER_ID/IMAGE_ID/ // // Sizes: // t - Thumbnail (100x) // q - Square 150 (150x150) // s - Small 240 (140x) // n - Small 320 (320x) // m - Medium 500 (500x) // z - Medium 640 (640x) // c - Large 800 (800x) // b - Large 900 (900x) // l - Large 1024 (1024x) DOES NOT WORK // h - High 1600 (1600x) DOES NOT WORK // $pattern = '#https?:\/\/(?:www.)?flickr.com\/photos\/[^\/]+\/[^\/]+\/#i'; //$pattern = '#https?://(?:www.)?flickr.com/photos/[^/]+/[^/]+/#i'; preg_match_all( $pattern, $post_body, $matches ); //var_dump($matches); if ($matches) { // $matches[0] contains a list of Flickr image page URLS // Add matches to $embedded_media_urls foreach( $matches[0] as $flick_page_url ) { // Get cached HTML data for embedded images. // Do it like WordPress. // See source code: // - class-wp-embed.php: line 177 [[ $cachekey = '_oembed_' . md5( $url . serialize( $attr ) ); ]] // - media.php: line 1332 [[ function wp_embed_defaults ]] // If no attributes have been used in the [embed] shortcode, $attr is an empty string. $attr = ''; $attr = wp_parse_args( $attr, wp_embed_defaults() ); $cachekey = '_oembed_' . md5( $flick_page_url . serialize( $attr ) ); $cache = get_post_meta( $post->ID, $cachekey, true ); //var_dump($cache); if ( empty($cache) ) { continue; } // Get image info from the cached HTML preg_match( '#([^#i', $cache, $img_info ); //var_dump($img_info); if ( ! empty( $img_info ) ) { $item = array( 'type' => 'flickr', 'page' => $flick_page_url, 'player' => $flick_page_url . 'lightbox/', 'thumbnail' => str_replace( 'z.jpg', 'q.jpg', $img_info[1] ), // size q BEFORE CHANGING this check if the 150x150 is hardcoded into any metadata generator. It is in Twitter cards. 'image' => $img_info[1], // size z 'alt' => $img_info[2], 'width' => $img_info[3], 'height' => $img_info[4] ); array_push( $embedded_media_urls['images'], $item ); } } } /** // Instagram // // Supported: // Embedded URLs MUST be of Format: https://instagram.com/p/IMAGE_ID/ // $pattern = '#https?:\/\/(?:www.)?instagram.com\/p\/[^\/]+\/#i'; preg_match_all( $pattern, $post_body, $matches ); //var_dump($matches); if ($matches) { // $matches[0] contains a list of Flickr image page URLS // Add matches to $embedded_media_urls foreach( $matches[0] as $instagram_page_url ) { // Get cached HTML data for embedded images. // Do it like WordPress. // See source code: // - class-wp-embed.php: line 177 [[ $cachekey = '_oembed_' . md5( $url . serialize( $attr ) ); ]] // - media.php: line 1332 [[ function wp_embed_defaults ]] // If no attributes have been used in the [embed] shortcode, $attr is an empty string. $attr = ''; $attr = wp_parse_args( $attr, wp_embed_defaults() ); $cachekey = '_oembed_' . md5( $instagram_page_url . serialize( $attr ) ); $cache = get_post_meta( $post->ID, $cachekey, true ); var_dump($cache); // Get image info from the cached HTML preg_match( '#target="_top">(.*)<\/a>#i', $cache, $img_info ); //var_dump($img_info); if ( ! empty( $img_info ) ) { $item = array( 'page' => $instagram_page_url, 'player' => $instagram_page_url . 'lightbox/', 'thumbnail' => str_replace( 'z.jpg', 'q.jpg', $img_info[1] ), // size q BEFORE CHANGING this check if the 150x150 is hardcoded into any metadata generator. It is in Twitter cards. 'image' => $img_info[1], // size z 'alt' => $img_info[1], 'width' => '640', 'height' => '640', ); array_unshift( $embedded_media_urls['images'], $item ); } } } */ // Allow filtering of the embedded media array $embedded_media_urls = apply_filters( 'amt_embedded_media', $embedded_media_urls, $post->ID ); // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $embedded_media_urls, $group='add-meta-tags' ); //var_dump($embedded_media_urls); return $embedded_media_urls; } /** * Dublin Core helper functions */ function amt_get_dublin_core_author_notation($post) { $last_name = get_the_author_meta('last_name', $post->post_author); $first_name = get_the_author_meta('first_name', $post->post_author); if ( empty($last_name) && empty($first_name) ) { return get_the_author_meta('display_name', $post->post_author); } return $last_name . ', ' . $first_name; } /** * Taken from WordPress (http://core.trac.wordpress.org/browser/tags/3.6.1/wp-includes/general-template.php#L1397) * Modified to accept a mysqltime object. */ function amt_iso8601_date( $mysqldate ) { return mysql2date('c', $mysqldate); } // Helper function that determines whether code that has to do with the // Metadata Review mode should be enabled. function amt_check_run_metadata_review_code($options) { if ( $options["review_mode"] == "1" && current_user_can('create_users') ) { return true; } return false; } /** * Custom meta tag highlighter. * * Expects string. */ function amt_metatag_highlighter( $metatags ) { // Convert special chars, but leave quotes. // Required for pre box. $metatags = htmlspecialchars($metatags, ENT_NOQUOTES); if ( ! apply_filters('amt_metadata_review_mode_enable_highlighter', true) ) { return $metatags; } // Find all property/value pairs preg_match_all('#([^\s]+="[^"]+?)"#i', $metatags, $matches); if ( ! $matches ) { return $metatags; } // Highlight properties and values. //var_dump($matches[0]); foreach ($matches[0] as $match) { $highlighted = preg_replace('#^([^=]+)="(.+)"$#i', '$1="$2"', $match); //var_dump($highlighted); $metatags = str_replace($match, $highlighted, $metatags); } // Highlight 'itemscope' $metatags = str_replace('itemscope', 'itemscope', $metatags); // Highlight Schema.org object //$metatags = preg_replace('#: ([a-zA-Z0-9]+) -->#', ': $1 -->', $metatags); // Highlight HTML comments $metatags = str_replace('<!--', '<!--', $metatags); $metatags = str_replace('-->', '-->', $metatags); // Do some conversions $metatags = wp_pre_kses_less_than( $metatags ); // Done by wp_pre_kses_less_than() //$metatags = str_replace('', '/>', $metatags); //$metatags = str_replace('
', '___', $metatags); //$metatags = str_replace('___', '
', $metatags); return $metatags; } // Accepts a URL and converts the protocol to https. Returns the processed URL. function amt_make_https( $url ) { return preg_replace( '#^http://#' , 'https://', $url ); } function amt_return_true() { return true; } function amt_return_false() { return false; } // Returns site locale function amt_get_language_site($options) { $language = get_bloginfo('language'); // If set, the 'global_locale' setting overrides WordPress. if ( ! empty( $options["global_locale"] ) ) { $language = $options["global_locale"]; } // Allow filtering of the site language $language = apply_filters( 'amt_language_site', $language ); return $language; } // Returns content locale // NOTE: SHOULD NOT BE USED ON ARCHIVES function amt_get_language_content($options, $post) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_language_content', $post); $language = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $language !== false ) { return $language; } $language = get_bloginfo('language'); // If set, the 'global_locale' setting overrides WordPress. if ( ! empty( $options["global_locale"] ) ) { $language = $options["global_locale"]; } // If set, the locale setting from the Metabox overrides all other local settings. $metabox_locale = amt_get_post_meta_content_locale($post->ID); if ( ! empty( $metabox_locale ) ) { $language = $metabox_locale; } // Allow filtering of the content language $language = apply_filters( 'amt_language_content', $language, $post ); // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $language, $group='add-meta-tags' ); return $language; } // Returns the hreflang attribute's value function amt_get_the_hreflang($locale, $options) { $output = ''; // Convert underscore to dash $locale = str_replace('_', '-', $locale); // Return locale if no further processing is needed if ( $options['hreflang_strip_region'] == '0' ) { $output = $locale; } else { // Strip region code $locale_parts = explode('-', $locale); if ( count($locale_parts) == 1 ) { $output = $locale; } elseif ( count($locale_parts) > 2 ) { $output = $locale_parts[0] . '-' . $locale_parts[1]; } elseif ( count($locale_parts) == 2 ) { // In this case we need to understand whether locale is // language_TERRITORY or language_Script_TERRITORY // If the last part is a two letter string, we assume it's the region and strip it if ( strlen($locale_parts[1]) == 2 ) { // We assume this is a region code and strip it $output = $locale_parts[0]; } else { // We assume that the locale consist only of language_Script $output = $locale_parts[0] . '-' . $locale_parts[1]; } } } // Allow filtering $output = apply_filters( 'amt_get_the_hreflang', $output ); return $output; } // // Returns array with attributes // or NULL function amt_get_image_attributes_array( $notation ) { // Special notation about the default image: // URL[,WIDTHxHEIGHT] if ( empty( $notation ) ) { return; } $data = array( 'id' => null, // This function always returns a null attachment id. // Filled from special notation 'url' => null, 'width' => null, 'height' => null, 'type' => null, ); $parts = explode(',', $notation); $parts_count = count($parts); // URL if ( $parts_count == 1 ) { // Retrieve URL if ( preg_match('#^(https?://.+)$#', $parts[0], $matches) ) { //var_dump($matches); $data['url'] = $matches[1]; // Also try to determine the image type $extension = substr( $data['url'], strrpos($data['url'], '.') + 1); if ( $extension == 'jpg' ) { $extension = 'jpeg'; } if ( in_array( $extension, array('jpeg', 'png', 'gif', 'bmp') ) ) { $data['type'] = 'image/' . $extension; } } // URL,WIDTHxHEIGHT } elseif ( $parts_count == 2 ) { // Retrieve URL if ( preg_match('#^(https?://.+)$#', $parts[0], $matches) ) { //var_dump($matches); $data['url'] = $matches[1]; // Also try to determine the image type $extension = substr( $data['url'], strrpos($data['url'], '.') + 1); if ( $extension == 'jpg' ) { $extension = 'jpeg'; } if ( in_array( $extension, array('jpeg', 'png', 'gif', 'bmp') ) ) { $data['type'] = 'image/' . $extension; } // Retrieve width and height if ( preg_match('#^([\d]+)x([\d]+)$#', $parts[1], $matches) ) { //var_dump($matches); $data['width'] = $matches[1]; $data['height'] = $matches[2]; } } } return $data; } // Function that returns an array with data about the default image. // Returns false if no image could be found. function amt_get_default_image_data() { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_default_image_data'); $data = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $data !== false ) { return $data; } // The default_image_url option accepts: // 1. An attachment ID // 2. Special notation about the default image: // URL[,WIDTHxHEIGHT] $data = array( 'id' => null, // post ID of attachment // The ID should be enough information to retrieve all attachment information // Alternatively, if the ID is not set, at least the 'url' should be set. 'url' => null, 'width' => null, 'height' => null, 'type' => null, ); $options = amt_get_options(); $value = $options["default_image_url"]; if ( ! empty($value) ) { // First check if we have an ID if ( is_numeric($value) ) { $data['id'] = absint($value); // Alternatively, check for special notation } else { $data = amt_get_image_attributes_array( $value ); } } // Allow filtering $data = apply_filters('amt_default_image_data', $data); // Check if we have an image if ( is_null($data['id']) && is_null($data['url']) ) { $data = false; } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $data, $group='add-meta-tags' ); return $data; } // Function that returns an array with data about the image. // Returns false if no image could be found. function amt_get_image_data( $value ) { // Non persistent object cache $amtcache_key = amt_get_amtcache_key('amt_cache_get_image_data_' . md5($value) ); $data = wp_cache_get( $amtcache_key, $group='add-meta-tags' ); if ( $data !== false ) { return $data; } // The special notation option accepts: // 1. An attachment ID // 2. Special notation about the default image: // URL[,WIDTHxHEIGHT] $data = array( 'id' => null, // post ID of attachment // The ID should be enough information to retrieve all attachment information // Alternatively, if the ID is not set, at least the 'url' should be set. 'url' => null, 'width' => null, 'height' => null, 'type' => null, ); if ( ! empty($value) ) { // First check if we have an ID if ( is_numeric($value) ) { $data['id'] = absint($value); // Alternatively, check for special notation } else { $data = amt_get_image_attributes_array( $value ); } } // Allow filtering //$data = apply_filters('amt_get_image_data', $data); // Check if we have an image if ( is_null($data['id']) && is_null($data['url']) ) { $data = false; } // Non persistent object cache // Cache even empty wp_cache_add( $amtcache_key, $data, $group='add-meta-tags' ); return $data; } // Returns the default Twitter Card type function amt_get_default_twitter_card_type($options) { $default = 'summary'; if ( $options["tc_enforce_summary_large_image"] == "1" ) { $default = 'summary_large_image'; } // Allow filtering of the default card type $default = apply_filters( 'amt_twitter_cards_default_card_type', $default ); return $default; } // Function that returns the content of the Site Description setting of the // general Add-Meta-Tags settings. // This function allows filtering of the description, so that it can be set // programmatically, for instance in multilingual web sites. function amt_get_site_description($options) { $output = ''; if ( is_array($options) && array_key_exists('site_description', $options) ) { $output = $options['site_description']; } // Allow filtering $output = apply_filters( 'amt_settings_site_description', $output ); return $output; } // Function that returns the content of the Site Keywords setting of the // general Add-Meta-Tags settings. // This function allows filtering of the keywords, so that it can be set // programmatically, for instance in multilingual web sites. function amt_get_site_keywords($options) { $output = ''; if ( is_array($options) && array_key_exists('site_keywords', $options) ) { $output = $options['site_keywords']; } // Allow filtering $output = apply_filters( 'amt_settings_site_keywords', $output ); return $output; } // Function that returns the content of the Global Keywords setting of the // general Add-Meta-Tags settings. // This function allows filtering of the 'global keywords', so that it can be set // programmatically, for instance in multilingual web sites. function amt_get_site_global_keywords($options) { $output = ''; if ( is_array($options) && array_key_exists('global_keywords', $options) ) { $output = $options['global_keywords']; } // Allow filtering $output = apply_filters( 'amt_settings_global_keywords', $output ); return $output; } // Function that returns the content of the Copyright URL setting of the // general Add-Meta-Tags settings. // This function allows filtering of the 'copyright URL', so that it can be set // programmatically, for instance in multilingual web sites. function amt_get_site_copyright_url($options) { $output = ''; if ( is_array($options) && array_key_exists('copyright_url', $options) ) { $output = $options['copyright_url']; } // Allow filtering $output = apply_filters( 'amt_settings_copyright_url', $output ); return $output; } // Function that returns an itemref attribute, ready to be placed in the HTML element. function amt_get_schemaorg_itemref( $object_type ) { // Construct filter name, eg 'amt_schemaorg_itemref_organization' $filter_name = 'amt_schemaorg_itemref_' . $object_type; // Construct itemref attribute. Should contain a comma delimited list of IDs. $itemref = apply_filters( $filter_name, '' ); if ( ! empty($itemref) ) { $itemref_attrib = ' itemref="' . $itemref . '"'; } else { $itemref_attrib = ''; } return $itemref_attrib; } // Returns a string suitable for a Schema.org ID // Absolute or relative URLs are fine function amt_get_schemaorg_entity_id( $object_type ) { return sprintf('#amt-%s', $object_type); } // Returns a string suitable for as a full 'itemid attribute together with itemscope. // Absolute or relative URLs are fine function amt_get_schemaorg_entity_id_as_itemid( $object_type ) { return sprintf(' itemid="%s"', amt_get_schemaorg_entity_id( $object_type )); } // Returns the URL of the page of the local author profile function amt_get_local_author_profile_url( $author_id, $options ) { $url = ''; if ( empty($author_id) ) { return $url; } if ( $options['author_profile_source'] == 'default' ) { $url = get_author_posts_url( $author_id ); } elseif ( $options['author_profile_source'] == 'frontpage' ) { $url = get_bloginfo( 'url' ); } elseif ( $options['author_profile_source'] == 'buddypress' ) { //return get_bloginfo( 'url' ); if ( function_exists('bp_core_get_user_domain') ) { //return bp_core_get_user_domain($author_id); $url = trailingslashit( bp_core_get_user_domain($author_id) . amt_bp_get_profile_slug() ); } } elseif ( $options['author_profile_source'] == 'url' ) { $custom_url = get_the_author_meta('url', $author_id); if ( ! empty($custom_url) ) { $url = $custom_url; } } $url = apply_filters( 'amt_get_local_author_profile_url', $url ); if ( empty($url) ) { // Return the default if all else fails. return get_author_posts_url( $author_id ); } else { return $url; } } // Determines if custom content has been requested. function amt_is_custom($post, $options) { return apply_filters( 'amt_is_custom', false, $post, $options ); } // Determines if a Product page has been requested. function amt_is_product() { return apply_filters( 'amt_is_product', false ); } // Determines if a Product Group page has been requested. function amt_is_product_group() { // Normally a product group should fall into the is_tax() validation. // Product groups other than WordPress custom taxonomies are not suported. // However, we use this function in order to distinguish a non product // related taxonomy from a product related one (aka product group). // This is useful in case we need to set the metadata object type to a // group type, like it happens with Opengraph og:type=product.group. return apply_filters( 'amt_is_product_group', false ); } // Media Limits function amt_metadata_get_default_media_limit($options) { $limit = 16; if ( is_array($options) && array_key_exists('force_media_limit', $options) && $options['force_media_limit'] == '1' ) { $limit = 1; } return $limit; } function amt_metadata_get_image_limit($options) { $limit = amt_metadata_get_default_media_limit($options); $limit = apply_filters( 'amt_metadata_image_limit', $limit ); return absint($limit); } function amt_metadata_get_video_limit($options) { $limit = amt_metadata_get_default_media_limit($options); $limit = apply_filters( 'amt_metadata_video_limit', $limit ); return absint($limit); } function amt_metadata_get_audio_limit($options) { $limit = amt_metadata_get_default_media_limit($options); $limit = apply_filters( 'amt_metadata_audio_limit', $limit ); return absint($limit); } // Reviews // Returns an array containing review related data, only when the provided data is valid. function amt_get_review_data( $post ) { // Get review information from custom field $data = amt_get_post_meta_express_review( $post->ID ); // // REVIEW_AMPERSAND_NOTE // // Note about conversion of ampersand: // Data is returned with & converted to & by amt_get_post_meta_express_review(). // This character mainly exists in sameAs URLs (TODO: Find better replacement using preg_replace to spacifically target sameAs attributes) // The problem is that ';' is interpretted as a comment in the INI specification, // so parse_ini_string() strips part of the URL, which is wrong. // Here we convert & to & and leave it as is in the generated review data. // To convert it back to & after parse_ini_string() add something like: // $value = str_replace('&', '&', $value); // inside the foreach loop below. // //var_dump($data); $data = str_replace('&', '&', $data); //var_dump($data); if ( empty($data) ) { return; } // Parse as INI $review_data_raw = parse_ini_string( $data, true, INI_SCANNER_RAW ); //var_dump($review_data_raw); // Check for mandatory properties if ( ! array_key_exists('ratingValue', $review_data_raw) ) { return; } elseif ( ! array_key_exists('object', $review_data_raw) ) { return; } elseif ( ! array_key_exists('name', $review_data_raw) ) { return; } elseif ( ! array_key_exists('sameAs', $review_data_raw) ) { return; } // Construct final review data array. // Extra properties are collected into ['extraprop'] sub array. $review_data = array(); $review_data['extra'] = array(); $mandatory_arr = array( 'ratingValue', 'object', 'name', 'sameAs' ); // Add extra properties foreach ( $review_data_raw as $key => $value ) { // Reverse the ampersand replacement. (see note above) $key = str_replace('&', '&', $key); $value = str_replace('&', '&', $value); if ( in_array( $key, $mandatory_arr ) ) { $review_data[$key] = $value; } else { $review_data['extra'][$key] = $value; } } //var_dump($review_data); return $review_data; } // Return the information text that should be attached to the post content. function amt_get_review_info_box( $review_data ) { // Variables: #ratingValue#, #bestrating#, #object#, #name#, #sameAs#, #extra# // #extra# contains meta elements containing the extra properties of the reviewed item. $template = '

This is a review of #name# #extra# , which has been rated with #ratingValue#/#bestrating# stars!

'; // Allow filtering of the template $template = apply_filters( 'amt_schemaorg_review_info_template', $template ); // Set variables $bestrating = apply_filters( 'amt_schemaorg_review_bestrating', '5' ); // Replace placeholders $output = $template; $output = str_replace('#ratingValue#', esc_attr($review_data['ratingValue']), $output); $output = str_replace('#bestrating#', esc_attr($bestrating), $output); $output = str_replace('#object#', esc_attr($review_data['object']), $output); $output = str_replace('#name#', esc_attr($review_data['name']), $output); $output = str_replace('#sameAs#', esc_url_raw($review_data['sameAs']), $output); // Extra properties $extra_arr = array(); foreach ( $review_data['extra'] as $key => $value ) { if ( is_array($value) ) { // Add sub entity // If it is an array, the 'object' property is mandatory if ( ! array_key_exists( 'object', $value ) ) { continue; } $extra_arr[] = ''; foreach ( $value as $subkey => $subvalue ) { if ( $subkey != 'object' ) { if ( in_array( $subkey, array('url', 'sameAs') ) ) { $extra_arr[] = ''; } else { $extra_arr[] = ''; } } } $extra_arr[] = ''; } else { // Add simple meta element $extra_arr[] = ''; } } $output = str_replace('#extra#', implode(PHP_EOL, $extra_arr), $output); // Allow filtering of the output $output = apply_filters( 'amt_schemaorg_review_info_output', $output ); return $output; } // Sample review sets function amt_get_sample_review_sets() { // Default review sets $review_sets = array( 'Book' => array( '; Review rating (required)', 'ratingValue = 4.2', '; Mandatory reviewed item properties (required)', 'object = Book', 'name = On the Origin of Species', 'sameAs = http://en.wikipedia.org/wiki/On_the_Origin_of_Species', '; Extra reviewed item properties (optional)', 'isbn = 123456', '[author]', 'object = Person', 'name = Charles Darwin', 'sameAs = https://en.wikipedia.org/wiki/Charles_Darwin', ), 'Movie' => array( '; Review rating (required)', 'ratingValue = 4.2', '; Mandatory reviewed item properties (required)', 'object = Movie', 'name = Reservoir Dogs', 'sameAs = http://www.imdb.com/title/tt0105236/', '; Extra reviewed item properties (optional)', ';datePublished = 1992-01-21T00:00', '[director]', 'object = Person', 'name = Quentin Tarantino', 'sameAs = https://en.wikipedia.org/wiki/Quentin_Tarantino', '[actor]', 'object = Person', 'name = Harvey Keitel', 'sameAs = https://en.wikipedia.org/wiki/Harvey_Keitel', ), 'Article' => array( '; Review rating (required)', 'ratingValue = 4.2', '; Mandatory reviewed item properties (required)', 'object = Article', 'name = Structured Data', 'sameAs = https://developers.google.com/structured-data/', '; Extra reviewed item properties (optional)', 'datePublished = 2015-07-21T00:00', 'headline = Promote Your Content with Structured Data Markup', 'image = https://developers.google.com/structured-data/images/reviews-mobile.png', ), ); // Check if we have any meta tag sets. $review_sets = apply_filters( 'amt_sample_review_sets', $review_sets ); if ( empty($review_sets) ) { return; } $html = PHP_EOL . '' . PHP_EOL; $html .=' '; return '
' . __('Use sample review data:', 'add-meta-tags') . $html . '
'; } // Breadcrumbs // Generates a semantic (Schema.org) breadcrumb trail. // Accepts array function amt_get_breadcrumbs( $user_options ) { // Get plugin options $plugin_options = get_option("add_meta_tags_opts"); // Get post object $post = amt_get_queried_object(); // Default Options $default_options = array( // ID of list element. 'list_id' => 'breadcrumbs', // Show breadcrumb item for the home page. 'show_home' => true, // Text for the home link (requires show_home=true). 'home_link_text' => 'Home', // Show breadcrumb item for the last page. 'show_last' => true, // Show last breadcrumb as link (requires show_last=true). 'show_last_as_link' => true, // Separator. Set to empty string for no separator. 'separator' => '>' ); // Final options. $options = array_merge( $default_options, $user_options ); $bc_arr = array(); $bc_arr[] = ''; $bc_arr[] = ''; $bc_arr[] = '