/** * Log debug information * * @since 2.12 * * @param string $message Error message. */ private static function _mla_debug_add($message) { if (self::$mla_debug) { if (class_exists('MLACore')) { MLACore::mla_debug_add($message); } else { error_log($message, 0); } } }
/** * Filters taxonomy updates by language for Bulk Edit during Add New Media * and the Media/Edit Media screen * * @since 2.11 * * @param integer ID of the current post */ public static function edit_attachment($post_id) { static $already_updating = 0; MLACore::mla_debug_add(__LINE__ . " MLA_WPML::edit_attachment( {$post_id} ) _REQUEST = " . var_export($_REQUEST, true), MLACore::MLA_DEBUG_CATEGORY_LANGUAGE); /* * mla_update_single_item may call this action again, and * nothing should happen while updating duplicate items */ if ($already_updating == $post_id || self::$updating_duplicates) { return; } else { $already_updating = $post_id; } /* * Check for Bulk Edit during Add New Media */ if (!empty($_REQUEST['mlaAddNewBulkEditFormString'])) { if (!empty(self::$bulk_edit_request['tax_input'])) { $tax_inputs = self::$bulk_edit_request['tax_input']; if ('checked' == MLACore::mla_get_option('term_assignment', false, false, MLA_WPML::$mla_language_option_definitions)) { self::_build_tax_input($post_id, $tax_inputs, self::$bulk_edit_request['tax_action']); $tax_inputs = self::_apply_tax_input($post_id); } } else { $tax_inputs = NULL; } $updates = MLA::mla_prepare_bulk_edits($post_id, self::$bulk_edit_request, self::$bulk_edit_map); unset($updates['tax_input']); unset($updates['tax_action']); MLAData::mla_update_single_item($post_id, $updates, $tax_inputs); return; } // Upload New Media Bulk Edit /* * For the Bulk Edit action on the Media/Assistant screen, only synchronization is needed */ if (!(isset($_REQUEST['bulk_action']) && 'bulk_edit' == $_REQUEST['bulk_action'])) { /* * This is the Media/Edit Media screen. * The category taxonomy (edit screens) is a special case because * post_categories_meta_box() changes the input name */ if (isset($_REQUEST['tax_input'])) { $tax_inputs = $_REQUEST['tax_input']; } else { $tax_inputs = array(); } if (isset($_REQUEST['post_category'])) { $tax_inputs['category'] = $_REQUEST['post_category']; } if (isset($_REQUEST['tax_action'])) { $tax_actions = $_REQUEST['tax_action']; } else { $tax_actions = NULL; } if (!empty($tax_inputs) && 'checked' == MLACore::mla_get_option('term_assignment', false, false, MLA_WPML::$mla_language_option_definitions)) { self::_build_tax_input($post_id, $tax_inputs, $tax_actions); $tax_inputs = self::_apply_tax_input($post_id); } if (!empty($tax_inputs)) { MLAData::mla_update_single_item($post_id, array(), $tax_inputs); } } // Media/Edit Media screen, NOT Bulk Edit }
/** * Creates new items from the "Bulk Translate" list. * * @since 2.11 * * @param array $item_content NULL, to indicate no handler. * @param string $bulk_action the requested action. * @param integer $post_id the affected attachment. * * @return object updated $item_content. NULL if no handler, otherwise * ( 'message' => error or status message(s), 'body' => '' ) */ public static function mla_list_table_custom_bulk_action($item_content, $bulk_action, $post_id) { global $polylang; MLACore::mla_debug_add(__LINE__ . " MLA_Polylang::mla_list_table_bulk_action_item_request( {$bulk_action}, {$post_id} )", MLACore::MLA_DEBUG_CATEGORY_LANGUAGE); if ('pll-translate' == $bulk_action) { $translations = array(); if (isset($_REQUEST['bulk_tr_languages'])) { $bulk_tr_languages = $_REQUEST['bulk_tr_languages']; // Expand All Languages selection if (isset($bulk_tr_languages['all'])) { foreach ($polylang->model->get_languages_list() as $language) { $bulk_tr_languages[$language->slug] = 'translate'; } unset($bulk_tr_languages['all']); } // Process language selection(s) foreach ($bulk_tr_languages as $language => $action) { $new_id = MLA_Polylang::_get_translation($post_id, $language); $translations[] = $new_id; } } // Clear all the "Filter-by" parameters if (isset($_REQUEST['bulk_tr_options']['clear_filters'])) { MLA::mla_clear_filter_by(); } if (empty($translations)) { $item_content = array('message' => "Item {$post_id}, no translations."); } else { $_REQUEST['heading_suffix'] = __('Bulk Translations', 'media-library-assistant'); MLA_Polylang::$bulk_action_includes = array_merge(MLA_Polylang::$bulk_action_includes, $translations); $translations = implode(',', $translations); $item_content = array('message' => "Item {$post_id}, translation(s): {$translations}."); } } return $item_content; }
/** * Filters all clauses for shortcode queries, post caching plugins * * This is for debug purposes only. * Defined as public because it's a filter. * * @since 1.80 * * @param array query clauses before modification * * @return array query clauses after modification (none) */ public static function mla_query_posts_clauses_request_filter($pieces) { /* translators: 1: DEBUG tag 2: SQL clauses */ MLACore::mla_debug_add(sprintf(_x('%1$s: mla_query_posts_clauses_request_filter = "%2$s".', 'error_log', 'media-library-assistant'), __('DEBUG', 'media-library-assistant'), var_export($pieces, true))); return $pieces; }
/** * Get ALL markup templates from $mla_custom_templates, including 'default' * * @since 2.30 * * @param string Shortcode to which the template(s) apply; default 'gallery' * * @return array|null name => value for all markup templates or null if no templates */ public static function mla_get_markup_templates($shortcode = '') { if (!is_array(MLATemplate_Support::$mla_custom_templates)) { MLACore::mla_debug_add('<strong>mla_debug mla_get_markup_templates()</strong> ' . __('no templates exist', 'media-library-assistant')); return NULL; } if (!empty($shortcode)) { if (array_key_exists($shortcode, MLATemplate_Support::$mla_custom_templates['markup'])) { return MLATemplate_Support::$mla_custom_templates['markup'][$shortcode]; } return NULL; } $templates = array(); foreach (MLATemplate_Support::$mla_custom_templates['markup'] as $shortcode => $value) { $templates = array_merge($templates, $value); } // foreach return $templates; }
/** * Retrieve the terms in one or more taxonomies. * * Alternative to WordPress /wp-includes/taxonomy.php function get_terms() that provides * an accurate count of attachments associated with each term. * * taxonomy - string containing one or more (comma-delimited) taxonomy names * or an array of taxonomy names. Default 'post_tag'. * * post_mime_type - MIME type(s) of the items to include in the term-specific counts. Default 'all'. * * post_type - The post type(s) of the items to include in the term-specific counts. * The default is "attachment". * * post_status - The post status value(s) of the items to include in the term-specific counts. * The default is "inherit". * * ids - A comma-separated list of attachment ID values for an item-specific cloud. * * include - An array, comma- or space-delimited string of term ids to include * in the return array. * * exclude - An array, comma- or space-delimited string of term ids to exclude * from the return array. If 'include' is non-empty, 'exclude' is ignored. * * parent - term_id of the terms' immediate parent; 0 for top-level terms. * * minimum - minimum number of attachments a term must have to be included. Default 0. * * no_count - 'true', 'false' (default) to suppress term-specific attachment-counting process. * * number - maximum number of term objects to return. Terms are ordered by count, * descending and then by term_id before this value is applied. Default 0. * * orderby - 'count', 'id', 'name' (default), 'none', 'random', 'slug' * * order - 'ASC' (default), 'DESC' * * no_orderby - 'true', 'false' (default) to suppress ALL sorting clauses else false. * * preserve_case - 'true', 'false' (default) to make orderby case-sensitive. * * pad_counts - 'true', 'false' (default) to to include the count of all children in their parents' count. * * limit - final number of term objects to return, for pagination. Default 0. * * offset - number of term objects to skip, for pagination. Default 0. * * @since 2.20 * * @param array taxonomies to search and query parameters * * @return array array of term objects, empty if none found */ public static function mla_get_terms($attr) { global $wpdb; /* * Make sure $attr is an array, even if it's empty */ if (empty($attr)) { $attr = array(); } elseif (is_string($attr)) { $attr = shortcode_parse_atts($attr); } /* * Merge input arguments with defaults */ $attr = apply_filters('mla_get_terms_query_attributes', $attr); $arguments = shortcode_atts(self::$mla_get_terms_parameters, $attr); $arguments = apply_filters('mla_get_terms_query_arguments', $arguments); /* * Build an array of individual clauses that can be filtered */ $clauses = array('fields' => '', 'join' => '', 'where' => '', 'order' => '', 'orderby' => '', 'limits' => ''); /* * If we're not counting attachments per term, strip * post fields out of list and adjust the orderby value */ if ($no_count = 'true' == (string) $arguments['no_count']) { $field_array = explode(',', $arguments['fields']); foreach ($field_array as $index => $field) { if (false !== strpos($field, 'p.')) { unset($field_array[$index]); } } $arguments['fields'] = implode(',', $field_array); $arguments['minimum'] = 0; $arguments['post_mime_type'] = 'all'; if ('count' == strtolower($arguments['orderby'])) { $arguments['orderby'] = 'none'; } } $clauses['fields'] = $arguments['fields']; $clause = array('INNER JOIN `' . $wpdb->term_taxonomy . '` AS tt ON t.term_id = tt.term_id'); $clause_parameters = array(); if (!$no_count) { $clause[] = 'LEFT JOIN `' . $wpdb->term_relationships . '` AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id'; $clause[] = 'LEFT JOIN `' . $wpdb->posts . '` AS p ON tr.object_id = p.ID'; /* * Add type and status constraints */ if (is_array($arguments['post_type'])) { $post_types = $arguments['post_type']; } else { $post_types = array($arguments['post_type']); } $placeholders = array(); foreach ($post_types as $post_type) { $placeholders[] = '%s'; $clause_parameters[] = $post_type; } $clause[] = 'AND p.post_type IN (' . join(',', $placeholders) . ')'; if (is_array($arguments['post_status'])) { $post_stati = $arguments['post_status']; } else { $post_stati = array($arguments['post_status']); } $placeholders = array(); foreach ($post_stati as $post_status) { if ('private' != $post_status || is_user_logged_in()) { $placeholders[] = '%s'; $clause_parameters[] = $post_status; } } $clause[] = 'AND p.post_status IN (' . join(',', $placeholders) . ')'; } $clause = join(' ', $clause); $clauses['join'] = $wpdb->prepare($clause, $clause_parameters); /* * Start WHERE clause with a taxonomy constraint */ if (is_array($arguments['taxonomy'])) { $taxonomies = $arguments['taxonomy']; } else { $taxonomies = array($arguments['taxonomy']); } foreach ($taxonomies as $taxonomy) { if (!taxonomy_exists($taxonomy)) { $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy', 'media-library-assistant'), $taxonomy); return $error; } } $clause_parameters = array(); $placeholders = array(); foreach ($taxonomies as $taxonomy) { $placeholders[] = '%s'; $clause_parameters[] = $taxonomy; } $clause = array('tt.taxonomy IN (' . join(',', $placeholders) . ')'); /* * The "ids" parameter can build an item-specific cloud. * Compile a list of all the terms assigned to the items. */ if (!empty($arguments['ids']) && empty($arguments['include'])) { $ids = wp_parse_id_list($arguments['ids']); $placeholders = implode("','", $ids); $clause[] = "AND p.ID IN ( '{$placeholders}' )"; $includes = array(); foreach ($ids as $id) { foreach ($taxonomies as $taxonomy) { $terms = get_the_terms($id, $taxonomy); if (is_array($terms)) { foreach ($terms as $term) { $includes[$term->term_id] = $term->term_id; } // terms } } // taxonomies } // ids /* * If there are no terms we want an empty cloud */ if (empty($includes)) { $arguments['include'] = (string) 0x7fffffff; } else { ksort($includes); $arguments['include'] = implode(',', $includes); } } /* * Add include/exclude and parent constraints to WHERE cluse */ if (!empty($arguments['include'])) { $placeholders = implode("','", wp_parse_id_list($arguments['include'])); $clause[] = "AND t.term_id IN ( '{$placeholders}' )"; } elseif (!empty($arguments['exclude'])) { $placeholders = implode("','", wp_parse_id_list($arguments['exclude'])); $clause[] = "AND t.term_id NOT IN ( '{$placeholders}' )"; } if ('' !== $arguments['parent']) { $parent = (int) $arguments['parent']; $clause[] = "AND tt.parent = '{$parent}'"; } if ('all' !== strtolower($arguments['post_mime_type'])) { $where = str_replace('%', '%%', wp_post_mime_type_where($arguments['post_mime_type'], 'p')); if (0 == absint($arguments['minimum'])) { $clause[] = ' AND ( p.post_mime_type IS NULL OR ' . substr($where, 6); } else { $clause[] = $where; } } $clause = join(' ', $clause); $clauses['where'] = $wpdb->prepare($clause, $clause_parameters); /* * For the inner/initial query, always select the most popular terms */ if ($arguments['no_orderby']) { $arguments['orderby'] = 'count'; $arguments['order'] = 'DESC'; } /* * Add sort order */ $orderby = strtolower($arguments['orderby']); $order = strtoupper($arguments['order']); if ('DESC' != $order) { $order = 'ASC'; } $clauses['order'] = $order; $clauses['orderby'] = "ORDER BY {$orderby}"; /* * Count, Descending, is the default order so no further work * is needed unless a different order is specified */ if ('count' != $orderby || 'DESC' != $order) { if ('true' == strtolower($arguments['preserve_case'])) { $binary_keys = array('name', 'slug'); } else { $binary_keys = array(); } $allowed_keys = array('empty_orderby_default' => 'name', 'count' => 'count', 'id' => 'term_id', 'name' => 'name', 'random' => 'RAND()', 'slug' => 'slug'); $clause = 'ORDER BY ' . self::_validate_sql_orderby($arguments, '', $allowed_keys, $binary_keys); $clauses['orderby'] = substr($clause, 0, strrpos($clause, ' ' . $order)); } // add ORDER BY /* * Add pagination */ $clauses['limits'] = ''; $offset = absint($arguments['offset']); $limit = absint($arguments['limit']); if (0 < $offset && 0 < $limit) { $clauses['limits'] = "LIMIT {$offset}, {$limit}"; } elseif (0 < $limit) { $clauses['limits'] = "LIMIT {$limit}"; } elseif (0 < $offset) { $clause_parameters = 0x7fffffff; $clauses['limits'] = "LIMIT {$offset}, {$clause_parameters}"; } $clauses = apply_filters('mla_get_terms_clauses', $clauses); /* * Build the final query */ $query = array('SELECT'); $query[] = $clauses['fields']; $query[] = 'FROM `' . $wpdb->terms . '` AS t'; $query[] = $clauses['join']; $query[] = 'WHERE ('; $query[] = $clauses['where']; $query[] = ') GROUP BY tt.term_taxonomy_id'; $clause_parameters = absint($arguments['minimum']); if (0 < $clause_parameters) { $query[] = "HAVING count >= {$clause_parameters}"; } /* * If specifically told to omit the ORDER BY clause or the COUNT, * supply a sort order for the initial/inner query only */ if (!($arguments['no_orderby'] || $no_count)) { $query[] = 'ORDER BY count DESC, t.term_id ASC'; } /* * Limit the total number of terms returned */ $terms_limit = absint($arguments['number']); if (0 < $terms_limit) { $query[] = "LIMIT {$terms_limit}"; } /* * $final_clauses, if present, require an SQL subquery */ $final_clauses = array(); if ('count' != $orderby || 'DESC' != $order) { $final_clauses[] = $clauses['orderby']; $final_clauses[] = $clauses['order']; } if ('' !== $clauses['limits']) { $final_clauses[] = $clauses['limits']; } /* * If we're limiting the final results, we need to get an accurate total count first */ if (!$no_count && (0 < $offset || 0 < $limit)) { $count_query = 'SELECT COUNT(*) as count FROM (' . join(' ', $query) . ' ) as subQuery'; $count = $wpdb->get_results($count_query); $found_rows = $count[0]->count; } if (!empty($final_clauses)) { if (!$no_count) { array_unshift($query, 'SELECT * FROM ('); $query[] = ') AS subQuery'; } $query = array_merge($query, $final_clauses); } $query = join(' ', $query); $tags = $wpdb->get_results($query); if (!isset($found_rows)) { $found_rows = $wpdb->num_rows; } if (self::$mla_debug) { MLACore::mla_debug_add('<strong>' . __('mla_debug query arguments', 'media-library-assistant') . '</strong> = ' . var_export($arguments, true)); MLACore::mla_debug_add('<strong>' . __('mla_debug last_query', 'media-library-assistant') . '</strong> = ' . var_export($wpdb->last_query, true)); MLACore::mla_debug_add('<strong>' . __('mla_debug last_error', 'media-library-assistant') . '</strong> = ' . var_export($wpdb->last_error, true)); MLACore::mla_debug_add('<strong>' . __('mla_debug num_rows', 'media-library-assistant') . '</strong> = ' . var_export($wpdb->num_rows, true)); MLACore::mla_debug_add('<strong>' . __('mla_debug found_rows', 'media-library-assistant') . '</strong> = ' . var_export($found_rows, true)); } if ('true' == strtolower(trim($arguments['pad_counts']))) { self::_pad_term_counts($tags, reset($taxonomies), $post_types, $post_stati); } $tags['found_rows'] = $found_rows; $tags = apply_filters('mla_get_terms_query_results', $tags); return $tags; }
/** * Assemble the in-memory representation of the (read-only) Optional Upload MIME Types * * @since 1.40 * * @return boolean Success (true) or failure (false) of the operation */ private static function _get_optional_upload_mime_templates() { if (NULL != self::$mla_optional_upload_mime_templates) { return true; } self::$mla_optional_upload_mime_templates = array(); $template_array = MLACore::mla_load_template('mla-default-mime-types.tpl'); if (isset($template_array['mla-optional-mime-types'])) { $mla_mime_types = preg_split('/[\\r\\n]+/', $template_array['mla-optional-mime-types']); $ID = 0; foreach ($mla_mime_types as $mla_type) { // Ignore blank lines if (empty($mla_type)) { continue; } $array = explode(',', $mla_type); // Bypass damaged entries if (3 > count($array)) { MLACore::mla_debug_add(__LINE__ . " _get_upload_mime_templates mla-default-mime-types.tpl section mla-optional-mime-types( {$ID} '{$mla_type}' ) \$array = " . var_export($array, true), MLACore::MLA_DEBUG_CATEGORY_ANY); continue; } $slug = $array[0]; if ($matched_type = self::mla_get_upload_mime($slug)) { $core_type = $matched_type['core_type']; $mla_type = $matched_type['mla_type']; } else { $core_type = ''; $mla_type = ''; } self::$mla_optional_upload_mime_templates[++$ID] = array('ID' => $ID, 'slug' => $slug, 'mime_type' => $array[1], 'core_type' => $core_type, 'mla_type' => $mla_type, 'description' => $array[2]); } } return true; }
/** * Load option settings templates to $mla_option_templates * * @since 0.80 * * @return void */ private static function _load_option_templates() { MLAOptions::$mla_option_templates = MLACore::mla_load_template('mla-option-templates.tpl'); /* * Load the option settings templates */ if (is_null(MLAOptions::$mla_option_templates)) { MLACore::mla_debug_add('<strong>mla_debug _load_option_templates()</strong> ' . __('error loading tpls/mla-option-templates.tpl', 'media-library-assistant')); return; } elseif (!MLAOptions::$mla_option_templates) { MLACore::mla_debug_add('<strong>mla_debug _load_option_templates()</strong> ' . __('tpls/mla-option-templates.tpl not found', 'media-library-assistant')); MLAOptions::$mla_option_templates = NULL; return; } }
/** * Get ALL markup templates from $mla_templates, including 'default' * * @since 0.80 * * @return array|null name => value for all markup templates or null if no templates */ public static function mla_get_markup_templates() { if (!is_array(MLAShortcode_Support::$mla_custom_templates)) { MLACore::mla_debug_add('<strong>mla_debug mla_get_markup_templates()</strong> ' . __('no templates exist', 'media-library-assistant')); return NULL; } $templates = array(); foreach (MLAShortcode_Support::$mla_custom_templates as $key => $value) { // Note order: -row-open must precede -open! $tail = strrpos($key, '-row-open-markup'); if (!(false === $tail)) { $name = substr($key, 0, $tail); $templates[$name]['row-open'] = $value; continue; } $tail = strrpos($key, '-open-markup'); if (!(false === $tail)) { $name = substr($key, 0, $tail); $templates[$name]['open'] = $value; continue; } $tail = strrpos($key, '-item-markup'); if (!(false === $tail)) { $name = substr($key, 0, $tail); $templates[$name]['item'] = $value; continue; } $tail = strrpos($key, '-row-close-markup'); if (!(false === $tail)) { $name = substr($key, 0, $tail); $templates[$name]['row-close'] = $value; continue; } $tail = strrpos($key, '-close-markup'); if (!(false === $tail)) { $name = substr($key, 0, $tail); $templates[$name]['close'] = $value; } } // foreach return $templates; }
/** * Ajax handler for bulk editing and mapping * * @since 2.00 * * @return void echo json results or error message, then die() */ private static function _bulk_edit_ajax_handler() { MLACore::mla_debug_add('_bulk_edit_ajax_handler $_REQUEST = ' . var_export($_REQUEST, true), MLACore::MLA_DEBUG_CATEGORY_AJAX); /* * The category taxonomy (edit screens) is a special case because * post_categories_meta_box() changes the input name */ if (!isset($_REQUEST['tax_input'])) { $_REQUEST['tax_input'] = array(); } if (isset($_REQUEST['post_category'])) { $_REQUEST['tax_input']['category'] = $_REQUEST['post_category']; unset($_REQUEST['post_category']); } /* * Convert bulk_action to the old button name/value variables */ switch ($_REQUEST['bulk_action']) { case 'bulk_custom_field_map': $_REQUEST['bulk_custom_field_map'] = __('Map Custom Field metadata', 'media-library-assistant'); break; case 'bulk_map': $_REQUEST['bulk_map'] = __('Map IPTC/EXIF metadata', 'media-library-assistant'); break; case 'bulk_edit': $_REQUEST['bulk_edit'] = __('Update', 'media-library-assistant'); } $item_content = (object) self::mla_process_bulk_action('edit'); wp_send_json_success($item_content); }
/** * MLA_List_Table inline edit item values * * Builds the Language dropdown and edit translation links for the * Quick and Bulk Edit forms, adding them to the 'custom_fields' * and 'bulk_custom_fields' substitution parameters. * * @since 2.11 * * @param array $item_values parameter_name => parameter_value pairs * * @return array updated substitution parameter name => value pairs */ public static function mla_list_table_inline_values($item_values) { global $polylang; // Find the first "language" column slug $language_column = ''; foreach ($polylang->filters_columns->model->get_languages_list() as $language) { if (empty($polylang->filters_columns->curlang) || $language->slug != $polylang->filters_columns->curlang->slug) { $language_column = 'language_' . $language->slug; break; } } // do_action is required because the Polylang function uses "current_filter()" to compose its output ob_start(); do_action('quick_edit_custom_box', $language_column, 'attachment'); $value = ob_get_clean(); if (empty($value)) { MLACore::mla_debug_add(__LINE__ . ' MLA_Polylang::mla_list_table_inline_values language_column = ' . var_export($language_column, true), MLACore::MLA_DEBUG_CATEGORY_ANY); MLACore::mla_debug_add(__LINE__ . ' MLA_Polylang::mla_list_table_inline_values $polylang->filters_columns->curlang = ' . var_export($polylang->filters_columns->curlang, true), MLACore::MLA_DEBUG_CATEGORY_ANY); MLACore::mla_debug_add(__LINE__ . ' MLA_Polylang::mla_list_table_inline_values $polylang->filters_columns->model->get_languages_list() = ' . var_export($polylang->filters_columns->model->get_languages_list(), true), MLACore::MLA_DEBUG_CATEGORY_ANY); } // Strip off <fieldset> and <div> tags around the <input> and <label> tags preg_match('/\\<input|\\<label/', $value, $match_start, PREG_OFFSET_CAPTURE); preg_match('/\\<\\/label[^\\>]*\\>/', $value, $match_end, PREG_OFFSET_CAPTURE); $item_values['custom_fields'] .= substr($value, $match_start[0][1], $match_end[0][1] + strlen($match_end[0][0]) - $match_start[0][1]); // Add the Translate links to the Quick Edit values if (array_key_exists('Quick Edit', $item_values)) { $actions = "<input name=\"inline_translations\" type=\"hidden\" value=\"\">\n"; $actions .= "<input name=\"pll_quick_language\" type=\"hidden\" value=\"\">\n"; $actions .= "<input name=\"pll_quick_id\" type=\"hidden\" value=\"\">\n"; $actions .= "<input name=\"lang\" type=\"hidden\" value=\"\">\n"; $actions .= "<label class=\"alignleft\" style=\"clear: both;\">\n<span class=\"title\">Translate</span>\n"; $actions .= "<table class=\"pll-media-action-table\">\n"; foreach ($polylang->model->get_languages_list() as $language) { $actions .= '<tr class = "pll-media-action-row-' . $language->slug . "\">\n"; $actions .= '<td class = "pll-media-language-column"><span class = "pll-translation-flag">' . $language->flag . '</span>' . esc_html($language->name) . "</td>\n"; $actions .= '<td class = "pll-media-action-column pll-media-action-column-' . $language->slug . '">'; $actions .= sprintf('<input type="hidden" name="media_tr_lang[%s]" value="" /><a href="#pll-quick-translate-edit" title="" class=""></a>', esc_attr($language->slug)); $actions .= "</td>\n"; $actions .= "</tr>\n"; } $actions .= "</table>\n</label>\n"; $actions .= "<div class=\"pll-quick-translate-save\"><span class=\"spinner\" style=\"float: left;\"></span></div>\n"; $item_values['custom_fields'] .= $actions; } ob_start(); do_action('bulk_edit_custom_box', $language_column, 'attachment'); $value = ob_get_clean(); // Strip off <fieldset> and <div> tags around the <input> and <label> tags preg_match('/\\<input|\\<label/', $value, $match_start, PREG_OFFSET_CAPTURE); preg_match('/\\<\\/label[^\\>]*\\>/', $value, $match_end, PREG_OFFSET_CAPTURE); $item_values['bulk_custom_fields'] .= substr($value, $match_start[0][1], $match_end[0][1] + strlen($match_end[0][0]) - $match_start[0][1]); return $item_values; }
/** * Ajax handler for IPTC/EXIF tab inline mapping * * @since 2.00 * * @return void echo json response object, then die() */ public static function mla_inline_mapping_iptc_exif_action() { MLACore::mla_debug_add('MLASettings::mla_inline_mapping_iptc_exif_action $_REQUEST = ' . var_export($_REQUEST, true), MLACore::MLA_DEBUG_CATEGORY_AJAX); set_current_screen($_REQUEST['screen']); check_ajax_referer(MLACore::MLA_ADMIN_NONCE_ACTION, MLACore::MLA_ADMIN_NONCE_NAME); /* * Convert the ajax bulk_action back to the older Submit button equivalent */ if (!empty($_REQUEST['bulk_action'])) { switch ($_REQUEST['bulk_action']) { case 'iptc-exif-options-process-standard': $_REQUEST['iptc-exif-options-process-standard'] = __('Map All Attachments, Standard Fields Now', 'media-library-assistant'); break; case 'iptc-exif-options-process-taxonomy': $_REQUEST['iptc-exif-options-process-taxonomy'] = __('Map All Attachments, Taxonomy Terms Now', 'media-library-assistant'); break; case 'iptc-exif-options-process-custom': $_REQUEST['iptc-exif-options-process-custom'] = __('Map All Attachments, Custom Fields Now', 'media-library-assistant'); break; default: $match_count = preg_match('/iptc_exif_mapping\\[custom\\]\\[(.*)\\]\\[(.*)\\]\\[(.*)\\]/', $_REQUEST['bulk_action'], $matches); if ($match_count) { $_REQUEST['iptc_exif_mapping']['custom'][$matches[1]][$matches[2]][$matches[3]] = __('Map All Attachments', 'media-library-assistant'); } } } /* * Check for action or submit buttons. */ if (isset($_REQUEST['iptc_exif_mapping']) && is_array($_REQUEST['iptc_exif_mapping'])) { /* * Find the current chunk */ $offset = isset($_REQUEST['offset']) ? $_REQUEST['offset'] : 0; $length = isset($_REQUEST['length']) ? $_REQUEST['length'] : 0; /* * Check for page-level submit button to map attachments. */ if (!empty($_REQUEST['iptc-exif-options-process-standard'])) { $page_content = self::_process_iptc_exif_standard($offset, $length); } elseif (!empty($_REQUEST['iptc-exif-options-process-taxonomy'])) { $page_content = self::_process_iptc_exif_taxonomy($offset, $length); } elseif (!empty($_REQUEST['iptc-exif-options-process-custom'])) { $page_content = self::_process_iptc_exif_custom(NULL, $offset, $length); } else { $page_content = array('message' => '', 'body' => '', 'processed' => 0, 'unchanged' => 0, 'success' => 0); /* * Check for single-rule action buttons */ foreach ($_REQUEST['iptc_exif_mapping']['custom'] as $key => $value) { $value = stripslashes_deep($value); if (isset($value['action'])) { $settings = array('custom' => array($key => $value)); foreach ($value['action'] as $action => $label) { switch ($action) { case 'map_now': $page_content = self::_process_iptc_exif_custom($settings, $offset, $length); break; case 'add_rule_map': if ('none' == $value['name']) { $page_content['message'] = __('IPTC/EXIF no mapping changes detected.', 'media-library-assistant'); break; } // fallthru // fallthru case 'add_field_map': if ('' == $value['name']) { $page_content['message'] = __('IPTC/EXIF no mapping changes detected.', 'media-library-assistant'); break; } if (0 == $offset) { $page_content = self::_save_iptc_exif_custom_settings($settings); if (false !== strpos($page_content['message'], __('ERROR', 'media-library-assistant'))) { $page_content['processed'] = 0; $page_content['unchanged'] = 0; $page_content['success'] = 0; break; } } $current_values = MLACore::mla_get_option('iptc_exif_mapping'); $settings = array('custom' => array($value['name'] => $current_values['custom'][$value['name']])); $map_content = self::_process_iptc_exif_custom($settings, $offset, $length); $page_content['message'] .= '<br> <br>' . $map_content['message']; $page_content['processed'] = $map_content['processed']; $page_content['unchanged'] = $map_content['unchanged']; $page_content['success'] = $map_content['success']; $page_content['refresh'] = true; break; default: // ignore everything else } //switch action } // foreach action } /// isset action } // foreach rule } } else { $page_content = array('message' => '', 'body' => '', 'processed' => 0, 'unchanged' => 0, 'success' => 0); } $chunk_results = array('message' => $page_content['message'], 'processed' => $page_content['processed'], 'unchanged' => $page_content['unchanged'], 'success' => $page_content['success'], 'refresh' => isset($page_content['refresh']) && true == $page_content['refresh']); MLACore::mla_debug_add('MLASettings::mla_inline_mapping_iptc_exif_action $chunk_results = ' . var_export($chunk_results, true), MLACore::MLA_DEBUG_CATEGORY_AJAX); wp_send_json_success($chunk_results); }
/** * Fetch and filter IPTC and EXIF, XMP or PDF metadata for an image attachment * * @since 0.90 * * @param int post ID of attachment * @param string optional; if $post_id is zero, path to the image file. * * @return array Meta data variables, IPTC and EXIF or PDF */ public static function mla_fetch_attachment_image_metadata($post_id, $path = '') { $results = array('post_id' => $post_id, 'mla_iptc_metadata' => array(), 'mla_exif_metadata' => array(), 'mla_xmp_metadata' => array(), 'mla_pdf_metadata' => array()); if (0 != $post_id) { $path = get_attached_file($post_id); } if (!empty($path)) { if ('pdf' == strtolower(pathinfo($path, PATHINFO_EXTENSION))) { if (!class_exists('MLAPDF')) { require_once MLA_PLUGIN_PATH . 'includes/class-mla-data-pdf.php'; } $pdf_metadata = MLAPDF::mla_extract_pdf_metadata($path); $results['mla_xmp_metadata'] = $pdf_metadata['xmp']; $results['mla_pdf_metadata'] = $pdf_metadata['pdf']; return $results; } $size = getimagesize($path, $info); if (is_callable('iptcparse')) { if (!empty($info['APP13'])) { //set_error_handler( 'MLAData::mla_IPTC_EXIF_error_handler' ); $iptc_values = iptcparse($info['APP13']); //restore_error_handler(); if (!empty(MLAData::$mla_IPTC_EXIF_errors)) { $results['mla_iptc_errors'] = MLAData::$mla_IPTC_EXIF_errors; MLAData::$mla_IPTC_EXIF_errors = array(); MLACore::mla_debug_add(__LINE__ . __('ERROR', 'media-library-assistant') . ': ' . '$results[mla_iptc_errors] = ' . var_export($results['mla_exif_errors'], true), MLACore::MLA_DEBUG_CATEGORY_ANY); } if (!is_array($iptc_values)) { $iptc_values = array(); } foreach ($iptc_values as $key => $value) { if (in_array($key, array('1#000', '1#020', '1#022', '1#120', '1#122', '2#000', '2#200', '2#201'))) { $value = unpack('nbinary', $value[0]); $results['mla_iptc_metadata'][$key] = (string) $value['binary']; } elseif (1 == count($value)) { $results['mla_iptc_metadata'][$key] = $value[0]; } else { $results['mla_iptc_metadata'][$key] = $value; } } // foreach $value } // ! empty } // iptcparse if (is_callable('exif_read_data') && in_array($size[2], array(IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM))) { //set_error_handler( 'MLAData::mla_IPTC_EXIF_error_handler' ); $results['mla_exif_metadata'] = $exif_data = @exif_read_data($path); //restore_error_handler(); if (!empty(MLAData::$mla_IPTC_EXIF_errors)) { $results['mla_exif_errors'] = MLAData::$mla_IPTC_EXIF_errors; MLAData::$mla_IPTC_EXIF_errors = array(); MLACore::mla_debug_add(__LINE__ . __('ERROR', 'media-library-assistant') . ': ' . '$results[mla_exif_errors] = ' . var_export($results['mla_exif_errors'], true), MLACore::MLA_DEBUG_CATEGORY_ANY); } } // exif_read_data $results['mla_xmp_metadata'] = self::mla_parse_xmp_metadata($path, 0); if (NULL == $results['mla_xmp_metadata']) { $results['mla_xmp_metadata'] = array(); } // experimental damage repair for Robert O'Conner (Rufus McDufus) if (isset($exif_data['DateTimeOriginal']) && 8 > strlen($exif_data['DateTimeOriginal'])) { if (isset($results['mla_xmp_metadata']['CreateDate']) && is_numeric(strtotime($results['mla_xmp_metadata']['CreateDate']))) { $exif_data['BadDateTimeOriginal'] = $exif_data['DateTimeOriginal']; $results['mla_exif_metadata']['BadDateTimeOriginal'] = $exif_data['DateTimeOriginal']; $exif_data['DateTimeOriginal'] = $results['mla_xmp_metadata']['CreateDate']; $results['mla_exif_metadata']['DateTimeOriginal'] = $results['mla_xmp_metadata']['CreateDate']; } } // experimental damage repair for Elsie Gilmore (earthnutvt) if (isset($exif_data['Keywords']) && '????' == substr($exif_data['Keywords'], 0, 4)) { if (isset($results['mla_xmp_metadata']['Keywords'])) { $exif_data['Keywords'] = $results['mla_xmp_metadata']['Keywords']; $results['mla_exif_metadata']['Keywords'] = $results['mla_xmp_metadata']['Keywords']; } else { unset($exif_data['Keywords']); unset($results['mla_exif_metadata']['Keywords']); } } } /* * Expand EXIF Camera-related values: * * ExposureBiasValue * ExposureTime * Flash * FNumber * FocalLength * ShutterSpeed from ExposureTime */ $new_data = array(); if (isset($exif_data['FNumber'])) { if (false !== ($value = self::_rational_to_string($exif_data['FNumber'], '%1$d', '%1$d/%2$d', '%1$.1f'))) { $new_data['FNumber'] = $value; } } // FNumber if (isset($exif_data['ExposureBiasValue'])) { $fragments = array_map('intval', explode('/', $exif_data['ExposureBiasValue'])); if (!is_null($fragments[1])) { $numerator = $fragments[0]; $denominator = $fragments[1]; // Clean up some common format issues, e.g. 4/6, 2/4 while (0 == ($numerator & 0x1) && 0 == ($denominator & 0x1)) { $numerator = $numerator >> 1; $denominator = $denominator >> 1; } // Remove excess precision if ($denominator > $numerator && 1000 < $numerator && 1000 < $denominator) { $exif_data['ExposureBiasValue'] = sprintf('%1$+.3f', $numerator / $denominator); } else { $fragments[0] = $numerator; $fragments[1] = $denominator; $exif_data['ExposureBiasValue'] = $numerator . '/' . $denominator; } } if (false !== ($value = self::_rational_to_string($exif_data['ExposureBiasValue'], '%1$+d', '%1$+d/%2$d', '%1$+.2f'))) { $new_data['ExposureBiasValue'] = $value; } } // ExposureBiasValue if (isset($exif_data['Flash'])) { $value = absint($exif_data['Flash']); if ($value & 0x1) { $new_data['Flash'] = __('Yes', 'media-library-assistant'); } else { $new_data['Flash'] = __('No', 'media-library-assistant'); } } // Flash if (isset($exif_data['FocalLength'])) { if (false !== ($value = self::_rational_to_string($exif_data['FocalLength'], '%1$d', '%1$d/%2$d', '%1$.2f'))) { $new_data['FocalLength'] = $value; } } // FocalLength if (isset($exif_data['ExposureTime'])) { if (false !== ($value = self::_rational_to_string($exif_data['ExposureTime'], '%1$d', '%1$d/%2$d', '%1$.2f'))) { $new_data['ExposureTime'] = $value; } } // ExposureTime /* * ShutterSpeed in "1/" format, from ExposureTime * Special logic for "fractional shutter speed" values 1.3, 1.5, 1.6, 2.5 */ if (isset($exif_data['ExposureTime'])) { $fragments = array_map('intval', explode('/', $exif_data['ExposureTime'])); if (!is_null($fragments[1] && $fragments[0])) { if (1 == $fragments[1]) { $new_data['ShutterSpeed'] = $new_data['ExposureTime'] = sprintf('%1$d', $fragments[0]); } elseif (0 != $fragments[1]) { $value = $fragments[0] / $fragments[1]; if (0 < $value && 1 > $value) { // Convert to "1/" value for shutter speed if (1 == $fragments[0]) { $new_data['ShutterSpeed'] = $new_data['ExposureTime']; } else { $test = (double) number_format(1.0 / $value, 1, '.', ''); if (in_array($test, array(1.3, 1.5, 1.6, 2.5))) { $new_data['ShutterSpeed'] = '1/' . number_format(1.0 / $value, 1, '.', ''); } else { $new_data['ShutterSpeed'] = '1/' . number_format(1.0 / $value, 0, '.', ''); } } } else { $new_data['ShutterSpeed'] = $new_data['ExposureTime'] = sprintf('%1$.2f', $value); } } // fractional value } // valid denominator and non-zero numerator } // ShutterSpeed if (isset($exif_data['UndefinedTag:0xA420'])) { $new_data['ImageUniqueID'] = $exif_data['UndefinedTag:0xA420']; } if (isset($exif_data['UndefinedTag:0xA430'])) { $new_data['CameraOwnerName'] = $exif_data['UndefinedTag:0xA430']; } if (isset($exif_data['UndefinedTag:0xA431'])) { $new_data['BodySerialNumber'] = $exif_data['UndefinedTag:0xA431']; } if (isset($exif_data['UndefinedTag:0xA432']) && is_array($exif_data['UndefinedTag:0xA432'])) { $array = $new_data['LensSpecification'] = $exif_data['UndefinedTag:0xA432']; if (isset($array[0])) { if (false !== ($value = self::_rational_to_string($array[0], '%1$d', '%1$d/%2$d', '%1$.2f'))) { $new_data['LensMinFocalLength'] = $value; } } if (isset($array[1])) { if (false !== ($value = self::_rational_to_string($array[1], '%1$d', '%1$d/%2$d', '%1$.2f'))) { $new_data['LensMaxFocalLength'] = $value; } } if (isset($array[2])) { if (false !== ($value = self::_rational_to_string($array[2], '%1$d', '%1$d/%2$d', '%1$.1f'))) { $new_data['LensMinFocalLengthFN'] = $value; } } if (isset($array[3])) { if (false !== ($value = self::_rational_to_string($array[3], '%1$d', '%1$d/%2$d', '%1$.1f'))) { $new_data['LensMaxFocalLengthFN'] = $value; } } } if (isset($exif_data['UndefinedTag:0xA433'])) { $new_data['LensMake'] = $exif_data['UndefinedTag:0xA433']; } if (isset($exif_data['UndefinedTag:0xA434'])) { $new_data['LensModel'] = $exif_data['UndefinedTag:0xA434']; } if (isset($exif_data['UndefinedTag:0xA435'])) { $new_data['LensSerialNumber'] = $exif_data['UndefinedTag:0xA435']; } if (!empty($new_data)) { $results['mla_exif_metadata']['CAMERA'] = $new_data; } /* * Expand EXIF GPS values */ $new_data = array(); if (isset($exif_data['GPSVersion'])) { $new_data['Version'] = sprintf('%1$d.%2$d.%3$d.%4$d', ord($exif_data['GPSVersion'][0]), ord($exif_data['GPSVersion'][1]), ord($exif_data['GPSVersion'][2]), ord($exif_data['GPSVersion'][3])); } if (isset($exif_data['GPSLatitudeRef'])) { $new_data['LatitudeRef'] = $exif_data['GPSLatitudeRef']; $new_data['LatitudeRefS'] = 'N' == $exif_data['GPSLatitudeRef'] ? '' : '-'; $ref = $new_data['LatitudeRef']; $refs = $new_data['LatitudeRefS']; } else { $ref = ''; $refs = ''; } if (isset($exif_data['GPSLatitude'])) { $rational = $exif_data['GPSLatitude']; $new_data['LatitudeD'] = $degrees = self::_rational_to_decimal($rational[0]); $new_data['LatitudeM'] = $minutes = self::_rational_to_decimal($rational[1]); $new_data['LatitudeS'] = sprintf('%1$01.4f', $seconds = self::_rational_to_decimal($rational[2])); $decimal_minutes = $minutes + $seconds / 60; $decimal_degrees = $decimal_minutes / 60; $new_data['Latitude'] = sprintf('%1$dd %2$d\' %3$01.4f" %4$s', $degrees, $minutes, $seconds, $ref); $new_data['LatitudeDM'] = sprintf('%1$d %2$01.4f', $degrees, $decimal_minutes); $new_data['LatitudeDD'] = sprintf('%1$01f', $degrees + $decimal_degrees); $new_data['LatitudeMinDec'] = substr($new_data['LatitudeDM'], strpos($new_data['LatitudeDM'], ' ') + 1); $new_data['LatitudeDegDec'] = substr($new_data['LatitudeDD'], strpos($new_data['LatitudeDD'], '.')); $new_data['LatitudeSDM'] = $refs . $new_data['LatitudeDM']; $new_data['LatitudeSDD'] = $refs . $new_data['LatitudeDD']; $new_data['LatitudeDM'] = $new_data['LatitudeDM'] . $ref; $new_data['LatitudeDD'] = $new_data['LatitudeDD'] . $ref; } if (isset($exif_data['GPSLongitudeRef'])) { $new_data['LongitudeRef'] = $exif_data['GPSLongitudeRef']; $new_data['LongitudeRefS'] = 'E' == $exif_data['GPSLongitudeRef'] ? '' : '-'; $ref = $new_data['LongitudeRef']; $refs = $new_data['LongitudeRefS']; } else { $ref = ''; $refs = ''; } if (isset($exif_data['GPSLongitude'])) { $rational = $exif_data['GPSLongitude']; $new_data['LongitudeD'] = $degrees = self::_rational_to_decimal($rational[0]); $new_data['LongitudeM'] = $minutes = self::_rational_to_decimal($rational[1]); $new_data['LongitudeS'] = sprintf('%1$01.4f', $seconds = self::_rational_to_decimal($rational[2])); $decimal_minutes = $minutes + $seconds / 60; $decimal_degrees = $decimal_minutes / 60; $new_data['Longitude'] = sprintf('%1$dd %2$d\' %3$01.4f" %4$s', $degrees, $minutes, $seconds, $ref); $new_data['LongitudeDM'] = sprintf('%1$d %2$01.4f', $degrees, $decimal_minutes); $new_data['LongitudeDD'] = sprintf('%1$01f', $degrees + $decimal_degrees); $new_data['LongitudeMinDec'] = substr($new_data['LongitudeDM'], strpos($new_data['LongitudeDM'], ' ') + 1); $new_data['LongitudeDegDec'] = substr($new_data['LongitudeDD'], strpos($new_data['LongitudeDD'], '.')); $new_data['LongitudeSDM'] = $refs . $new_data['LongitudeDM']; $new_data['LongitudeSDD'] = $refs . $new_data['LongitudeDD']; $new_data['LongitudeDM'] = $new_data['LongitudeDM'] . $ref; $new_data['LongitudeDD'] = $new_data['LongitudeDD'] . $ref; } if (isset($exif_data['GPSAltitudeRef'])) { $new_data['AltitudeRef'] = sprintf('%1$d', ord($exif_data['GPSAltitudeRef'][0])); $new_data['AltitudeRefS'] = '0' == $new_data['AltitudeRef'] ? '' : '-'; $refs = $new_data['AltitudeRefS']; } else { $refs = ''; } if (isset($exif_data['GPSAltitude'])) { $new_data['Altitude'] = sprintf('%1$s%2$01.4f', $refs, $meters = self::_rational_to_decimal($exif_data['GPSAltitude'])); $new_data['AltitudeFeet'] = sprintf('%1$s%2$01.2f', $refs, $meters * 3.280839895013); } if (isset($exif_data['GPSTimeStamp'])) { $rational = $exif_data['GPSTimeStamp']; $new_data['TimeStampH'] = sprintf('%1$02d', $hours = self::_rational_to_decimal($rational[0])); $new_data['TimeStampM'] = sprintf('%1$02d', $minutes = self::_rational_to_decimal($rational[1])); $new_data['TimeStampS'] = sprintf('%1$02d', $seconds = self::_rational_to_decimal($rational[2])); $new_data['TimeStamp'] = sprintf('%1$02d:%2$02d:%3$02d', $hours, $minutes, $seconds); } if (isset($exif_data['GPSDateStamp'])) { $parts = explode(':', $exif_data['GPSDateStamp']); $new_data['DateStampY'] = $parts[0]; $new_data['DateStampM'] = $parts[1]; $new_data['DateStampD'] = $parts[2]; $new_data['DateStamp'] = $exif_data['GPSDateStamp']; } if (isset($exif_data['GPSMapDatum'])) { $new_data['MapDatum'] = $exif_data['GPSMapDatum']; } if (!empty($new_data)) { $results['mla_exif_metadata']['GPS'] = $new_data; } //error_log( __LINE__ . " mla_fetch_attachment_image_metadata( {$post_id} ) results = " . var_export( $results, true ), 0 ); return $results; }