def sort_callback(self, a, b): ''' Callback to sort the list by specific fields. @access private @see WP_List_Util::sort() @param object|array a One object to compare. @param object|array b The other object to compare. @return int 0 if both objects equal. -1 if second object should come first, 1 otherwise. ''' if Php.empty(self, 'orderby'): return 0 a = Php.Array(a) b = Php.Array(b) for field, direction in self.orderby.items(): if not Php.isset(a, field) or not Php.isset(b, field): continue if a[field] == b[field]: continue #results = 'DESC' === direction ? array( 1, -1 ) : array( -1, 1 ) results = array(1, -1) if 'DESC' == direction else array(-1, 1) if Php.is_numeric(a[field]) and Php.is_numeric(b[field]): #return ( a[ field ] < b[ field ] ) ? results[0] : results[1] return results[0] if (a[field] < b[field]) else results[1] #return 0 > strcmp( a[ field ], b[ field ] ) ? results[0] : results[1] return results[0] if ( 0 > Php.strcmp(a[field], b[field])) else results[1] return 0
def is_first_order_clause(self, query): ''' Determine whether a query clause is first-order. A first-order meta query clause is one that has either a 'key' or a 'value' array key. @param array query Meta query arguments. @return bool Whether the query clause is a first-order clause. ''' return Php.isset(query, 'key') or Php.isset(query, 'value')
def apply_filters_ref_array(tag, args, *OtherArgs): #Orig: ( tag, args ): ''' Execute functions hooked on a specific filter hook, specifying arguments in an array. @see apply_filters() This function is identical, but the arguments passed to the functions hooked to `tag` are supplied using an array. @global array wp_filter Stores all of the filters @global array merged_filters Merges the filter hooks using this function. @global array wp_current_filter Stores the list of current filters with the current one last @param string tag The name of the filter hook. @param array args The arguments supplied to the functions hooked to tag. @return mixed The filtered value after all hooked functions are applied to it. ''' #global var==>WB.Wj.var, except: var=WB.Wj.var=same Obj,mutable array wp_filter = WpC.WB.Wj.wp_filter # global wp_filter merged_filters = WpC.WB.Wj.merged_filters # global merged_filters wp_current_filter = WpC.WB.Wj.wp_current_filter # global wp_current_filter AllArgs = tag, args, *OtherArgs # Do 'all' actions first if Php.isset(wp_filter, 'all'): wp_current_filter.append(tag) # php2python.com/wiki/function.func-get-args/ all_args = Php.func_get_args(AllArgs) _wp_call_all_hook(all_args) if not Php.isset(wp_filter, tag): if Php.isset(wp_filter, 'all'): wp_current_filter.popitem() return args[0] if not Php.isset(wp_filter, 'all'): wp_current_filter.append(tag) # Sort if not Php.isset(merged_filters, tag): wp_filter[tag] = Php.ksort(wp_filter[tag]) merged_filters[tag] = True # No need to reset in py since for loop alawys starts at elem#1 in list #reset( wp_filter[ tag ] ) #do { #Php: the first iteration of a do-while loop is guaranteed to run # (the truth expression is only checked at the end of the iteration) for Tag in [True, *wp_filter[tag]]: if Tag is False: break for the_ in Php.Array(Php.current(wp_filter[tag])): if not Php.is_null(the_['function']): args[0] = Php.call_user_func_array( the_['function'], Php.array_slice(args, 0, int(the_['accepted_args']))) #} while ( next(wp_filter[tag]) is not False ) wp_current_filter.popitem() return args[0]
def sanitize_query(self, queries): ''' Ensure the 'meta_query' argument passed to the class constructor is well-formed. Eliminates empty items and ensures that a 'relation' is set. @param array queries Array of query clauses. @return array Sanitized array of query clauses. ''' clean_queries = array() if not Php.is_array(queries): return clean_queries for key, query in queries.items(): if 'relation' == key: relation = query elif not Php.is_array(query): continue # First-order clause. elif self.is_first_order_clause(query): #if 'value' in query and array() == query['value']: if Php.isset(query, 'value') and array() == query['value']: unset(query['value']) clean_queries[key] = query # Otherwise, it's a nested query, so we recurse. else: cleaned_query = self.sanitize_query(query) if cleaned_query: # if not Php.empty(locals(), 'cleaned_query'): clean_queries[key] = cleaned_query if not clean_queries: # if Php.empty(locals(), 'clean_queries'): return clean_queries # Sanitize the 'relation' key provided in the query. if Php.isset(locals(), 'relation') and 'OR' == relation.upper(): clean_queries['relation'] = 'OR' self.has_or_relation = True # If there is only a single clause, call the relation 'OR'. # This value will not actually be used to join clauses, but it # simplifies the logic around combining key-only queries. elif 1 == len(clean_queries): clean_queries['relation'] = 'OR' # Default to AND. else: clean_queries['relation'] = 'AND' return clean_queries
def pluck(self, field, index_key=None): ''' Plucks a certain field out of each object in the list. This has the same functionality and prototype of array_column() (PHP 5.5) but also supports objects. @param int|str field Field from the object to place instead of the entire object @param int|str index_key Optional. Field from the object to use as keys for the new array. Default None. @return array Array of found values. If `index_key` is set, an array of found values with keys corresponding to `index_key`. If `index_key` is None, array keys from the original `list` will be preserved in the results. ''' if not index_key: # This is simple. Could at some point wrap array_column() # if we knew we had an array of arrays. for key, value in self.output.items(): print('pluck', field, key, value) if Php.is_object(value): #self.output[ $key ] = $value->$field #Php returns None if no attr found, rather than raise error self.output[key] = getattr(value, field, None) else: try: self.output[key] = value[field] except: self.output[key] = None # Php> false[1] #Out=> NULL return self.output # When index_key is not set for a particular item, push the value # to the end of the stack. This is how array_column() behaves. newlist = array() for value in self.output: if Php.is_object(value): #if isset( $value->$index_key ): if Php.isset(value, index_key): #$newlist[ $value->$index_key ] = $value->$field newlist[getattr(value, index_key)] = getattr(value, field) else: #$newlist[] = $value->$field newlist[None] = getattr(value, field) else: if Php.isset(value, index_key): newlist[value[index_key]] = value[field] else: newlist[None] = value[field] self.output = newlist return self.output
def remove_filter(tag, function_to_remove, priority=10): ''' Removes a function from a specified filter hook. This function removes a function attached to a specified filter hook. This method can be used to remove default functions attached to a specific filter hook and possibly replace them with a substitute. To remove a hook, the function_to_remove and priority arguments must match when the hook was added. This goes for both filters and actions. No warning will be given on removal failure. @global array wp_filter Stores all of the filters @global array merged_filters Merges the filter hooks using this function. @param string tag The filter hook to which the function to be removed is hooked. @param callable function_to_remove The name of the function which should be removed. @param int priority Optional. The priority of the function. Default 10. @return bool Whether the function existed before it was removed. ''' function_to_remove = _wp_filter_build_unique_id(tag, function_to_remove, priority) #r= Php.isset( GLOBALS['wp_filter'][ tag ][ priority ], function_to_remove ) r = Php.isset(WpC.WB.Wj.wp_filter[tag][priority], function_to_remove) if r is True: del WpC.WB.Wj.wp_filter[tag][priority][function_to_remove] if Php.empty(WpC.WB.Wj.wp_filter[tag], 'priority'): del WpC.WB.Wj.wp_filter[tag][priority] if Php.empty(WpC.WB.Wj.wp_filter, 'tag'): WpC.WB.Wj.wp_filter[tag] = array() del WpC.WB.Wj.merged_filters[tag] return r
def metadata_exists(meta_type, object_id, meta_key): ''' Determine if a meta key is set for a given object @param string meta_type Type of object metadata is for (e.g., comment, post, or user) @param int object_id ID of the object metadata is for @param string meta_key Metadata key. @return bool True of the key is set, False if not. ''' if not meta_type or not Php.is_numeric(object_id): return False object_id = xFn.AbsInt(object_id) if not object_id: return False # This filter is documented in wp-includes/meta.php */ check = WiPg.apply_filters("get_{}_metadata".format(meta_type), None, object_id, meta_key, True) if None is not check: return bool(check) meta_cache = WiCa.wp_cache_get(object_id, meta_type + '_meta') if not meta_cache: meta_cache = update_meta_cache(meta_type, array(object_id)) meta_cache = meta_cache[object_id] if Php.isset(meta_cache, meta_key): return True return False
def register_globals(self): ''' Set up the WordPress Globals. The query_vars property will be extracted to the GLOBALS. So care should be taken when naming global variables that might interfere with the WordPress environment. @access public @global WP_Query wp_query @global string query_string Query string for the loop. @global array posts The found posts. @global WP_Post|None post The current post, if available. @global string request The SQL statement for the request. @global int more Only set, if single page or post. @global int single If single page or post. Only set, if single page or post. @global WP_User authordata Only set, if author archive. ''' wp_query = WpC.WB.Wj.wp_query # global wp_query GLOBALS = WpC.WB.Wj.__dict__ # global GLOBALS # Extract updated query vars back into global namespace. for key, value in Php.Array(wp_query.query_vars).items(): GLOBALS[key] = value GLOBALS['query_string'] = self.query_string #GLOBALS['posts'] = & wp_query.posts GLOBALS['posts'] = wp_query.posts # array is mutable so won't need & #GLOBALS['post'] = wp_query.post if Php.isset(wp_query,'post') else None GLOBALS['post'] = getattr(wp_query, 'post', None) GLOBALS['request'] = wp_query.request if wp_query.is_single() or wp_query.is_page(): GLOBALS['more'] = 1 GLOBALS['single'] = 1 if wp_query.is_author() and Php.isset(wp_query, 'post'): GLOBALS['authordata'] = get_userdata(wp_query.post.post_author)
def wp_register_plugin_realpath(File): ''' Register a plugin's real path. This is used in plugin_basename() to resolve symlinked paths. @see WiFc.wp_normalize_path() @global array wp_plugin_paths @staticvar string wp_plugin_path @staticvar string wpmu_plugin_path @param string File Known path to the file. @return bool Whether the path was able to be registered. ''' #global var==>WpC.WB.Wj.var, except: var=WpC.WB.Wj.var=same Obj,mutable array #global wp_plugin_paths #ini in wp.settings to array() wp_plugin_paths = WpC.WB.Wj.wp_plugin_paths # Normalize, but store as static to avoid recalculation of a constant value #static wp_plugin_path = None, wpmu_plugin_path = None if not Php.isset(wp_register_plugin_realpath, 'wp_plugin_path'): wp_register_plugin_realpath.wp_plugin_path = WiFc.wp_normalize_path( WpC.WB.Wj.WP_PLUGIN_DIR) wp_register_plugin_realpath.wpmu_plugin_path = WiFc.wp_normalize_path( WpC.WB.Wj.WPMU_PLUGIN_DIR) plugin_path = WiFc.wp_normalize_path(dirname(File)) plugin_realpath = WiFc.wp_normalize_path(dirname(realpath(File))) #if plugin_path === wp_plugin_path or plugin_path === wpmu_plugin_path: if (plugin_path == wp_register_plugin_realpath.wp_plugin_path or plugin_path == wp_register_plugin_realpath.wpmu_plugin_path): return False #if plugin_path !== plugin_realpath: if plugin_path != plugin_realpath: wp_plugin_paths[plugin_path] = plugin_realpath return True
def get_error_data(self, code=''): '''Retrieve error data for error code. @param string|int code Optional. Error code. @return mixed Error data, if it exists. ''' if not code: # if empty code = self.get_error_code() if Php.isset(self.error_data, code): return self.error_data[code]
def callback(self, matches): ''' preg_replace_callback hook @access public @param array matches preg_replace regexp matches @return string ''' index = intval(substr(matches[0], 9, -1)) return urlencode(self._matches[index]) if Php.isset( self._matches, index) else ''
def remove_all_filters(tag, priority=False): ''' Remove all of the hooks from a filter. @global array wp_filter Stores all of the filters @global array merged_filters Merges the filter hooks using this function. @param string tag The filter to remove hooks from. @param int|bool priority Optional. The priority number to remove. Default False. @return True True when finished. ''' #global var==>WpC.WB.Wj.var, except: var=WpC.WB.Wj.var=same Obj,mutable array wp_filter = WpC.WB.Wj.wp_filter # global wp_filter merged_filters = WpC.WB.Wj.merged_filters # global merged_filters if Php.isset(wp_filter, tag): if priority is False: wp_filter[tag] = array() elif Php.isset(wp_filter[tag], priority): wp_filter[tag][priority] = array() del merged_filters[tag] return True
def find_compatible_table_alias(self, clause, parent_query): alias = False for sibling in parent_query: # If the sibling has no alias yet, there's nothing to check. if Php.empty(sibling, 'alias'): continue # We're only interested in siblings that are first-order clauses. if not Php.is_array(sibling) or not self.is_first_order_clause( sibling): continue compatible_compares = array() # Clauses connected by OR can share joins as long as they have "positive" operators. if 'OR' == parent_query['relation']: compatible_compares = array('=', 'IN', 'BETWEEN', 'LIKE', 'REGEXP', 'RLIKE', '>', '>=', '<', '<=') # Clauses joined by AND with "negative" operators share a join only if they also share a key. elif (Php.isset(sibling, 'key') and Php.isset(clause, 'key') and sibling['key'] == clause['key']): compatible_compares = array('!=', 'NOT IN', 'NOT LIKE') clause_compare = clause['compare'].upper() sibling_compare = sibling['compare'].upper() if (Php.in_array(clause_compare, compatible_compares) and Php.in_array(sibling_compare, compatible_compares)): alias = sibling['alias'] break # Filters the table alias identified as compatible with the current clause. # @param string|bool alias Table alias, or False if none was found. # @param array clause First-order query clause. # @param array parent_query Parent of clause. # @param object self WP_Meta_Query object. return WiPg.apply_filters('meta_query_find_compatible_table_alias', alias, clause, parent_query, self)
def parse_query_vars(self, qv): ''' Constructs a meta query based on 'meta_*' query vars @param array qv The query variables ''' meta_query = array() # ODict() # array() # For orderby=meta_value to work correctly, simple query needs to be # first (so that its table join is against an unaliased meta table) and # needs to be its own clause (so it doesn't interfere with the logic of # the rest of the meta_query). primary_meta_query = array() # ODict() # array() for key in ('key', 'compare', 'type'): if not Php.empty(qv, "meta_" + key): primary_meta_query[key] = qv["meta_" + key] # WP_Query sets 'meta_value' = '' by default. if Php.isset(qv, 'meta_value') and '' != qv['meta_value'] and ( not Php.is_array(qv['meta_value']) or qv['meta_value']): primary_meta_query['value'] = qv['meta_value'] existing_meta_query = qv['meta_query'] if ( Php.isset(qv, 'meta_query') and Php.is_array( qv['meta_query'])) else array() # ODict() # array() #if not Php.empty(locals(), 'primary_meta_query') and existing_meta_query: if primary_meta_query and existing_meta_query: meta_query = array( # Supports array( ('a',11), 22, 33, (2,22) ) ('relation', 'AND'), primary_meta_query, existing_meta_query, ) elif primary_meta_query: #not Php.empty(locals(),'primary_meta_query'): meta_query = array( # Supports array( ('a',11), 22, 33, (2,22) ) primary_meta_query) elif existing_meta_query: #not Php.empty(locals(),'existing_meta_query'): meta_query = existing_meta_query self.__init__(meta_query)
def get_current_network_id(self): ''' Retrieves the current network ID. @return int The ID of the current network. ''' return self.Bj.SId if not self.is_multisite(): return 1 current_network = get_network(self) if not Php.isset(current_network, 'id'): return get_main_network_id(self) return Php.absint(current_network.id)
def did_action(tag, Wj=None): ''' Retrieve the number of times an action is fired. @global array wp_actions Increments the amount of times action was triggered. @param string tag The name of the action hook. @return int The number of times action hook tag is fired. ''' #global var==>WpC.WB.Wj.var, except: var=WpC.WB.Wj.var=same Obj,mutable array if Wj is None: Wj = WpC.WB.Wj wp_actions = Wj.wp_actions # global wp_actions if not Php.isset(wp_actions, tag): return 0 return wp_actions[tag]
def delete_option(option): ''' Removes option by name. Prevents removal of protected WordPress options. @global wpdb wpdb WordPress database abstraction object. @param string option Name of option to remove. Expected to not be SQL-escaped @return bool True, if option is successfully deleted. False on failure. ''' wpdb = WpC.WB.Wj.wpdb # global wpdb option = Php.trim(option) if Php.empty(locals(), 'option'): return False wp_protect_special_option(option) # Get the ID, if no ID then return row = wpdb.get_row( wpdb.prepare( "SELECT autoload FROM {} WHERE option_name" " = %s".format(wpdb.options), option)) if Php.is_null(row): return False # Fires immediately before an option is deleted. # @param string option Name of the option to delete. WiPg.do_action('delete_option', option) result = wpdb.delete(wpdb.options, array(('option_name', option))) if not wp_installing(): if 'yes' == row.autoload: alloptions = wp_load_alloptions() if Php.is_array(alloptions) and Php.isset(alloptions, option): del (alloptions[option]) WiCa.wp_cache_set('alloptions', alloptions, 'options') else: WiCa.wp_cache_delete(option, 'options') if result: # Fires after a specific option has been deleted. # The dynamic portion of the hook name, `option`, refers to the option name # @param string option Name of the deleted option. WiPg.do_action("delete_option_" + option, option) # Fires after an option has been deleted. # @param string option Name of the deleted option. WiPg.do_action('deleted_option', option) return True return False
def get_error_messages(self, code=''): ''' Retrieve all error messages or error messages matching code. @param string|int code Optional. Retrieve messages matching code, if exists. @return array Error strings on success, or empty array on failure (if using code parameter). Return all messages if no code specified. ''' if not code: # if empty all_messages = array() # [] for code, messages in Php.Array(self.errors.items()): all_messages = Php.array_merge(all_messages, messages) return all_messages if Php.isset(self.errors, code): return self.errors[code] else: return array()
def parse_query(self, query=''): ''' Parse arguments passed to the term query with default query parameters @param string|array query WP_Term_Query arguments. See WP_Term_Query::__construct() ''' if not query: # if Php.empty(locals(), 'query'): query = self.query_vars print("WcTQ.parse_query: query=", query) taxonomies = Php.Array(query['taxonomy']) if Php.isset( query, 'taxonomy') else None print("WcTQ.parse_query: taxonomies=", taxonomies) # Filters the terms query default arguments. # Use {@see 'get_terms_args'} to filter the passed arguments. # @param array defaults An array of default get_terms() arguments. # @param array taxonomies An array of taxonomies. self.query_var_defaults = WiPg.apply_filters('get_terms_defaults', self.query_var_defaults, taxonomies) query = WiFc.wp_parse_args(query, self.query_var_defaults) print("WcTQ.parse_query: query=", query) query['number'] = Php.absint(query['number']) query['offset'] = Php.absint(query['offset']) # 'parent' overrides 'child_of'. #must use Php.intval or int(''): invalid literal for int() with base 10: '' if 0 < Php.intval(query['parent']): query['child_of'] = False if 'all' == query['get']: query['childless'] = False query['child_of'] = 0 query['hide_empty'] = 0 query['hierarchical'] = False query['pad_counts'] = False query['taxonomy'] = taxonomies print("WcTQ.parse_query: taxonomies=", taxonomies) self.query_vars = query # Fires after term query vars have been parsed. # @param WP_Term_Query self Current instance of WP_Term_Query. WiPg.do_action('parse_term_query', self)
def has_filter(tag, function_to_check=False): ''' Check if any filter has been registered for a hook. @global array wp_filter Stores all of the filters. @param string tag The name of the filter hook. @param callable|bool function_to_check Optional. The callback to check for. Default False. @return False|int If function_to_check is omitted, returns boolean for whether the hook has anything registered. When checking a specific function, the priority of that hook is returned, or False if the function is not attached. When using the function_to_check argument, this function may return a non-boolean value that evaluates to False (e.g.) 0, so use the === operator for testing the return value. ''' # Don't reset the internal array pointer #VT Need to implement pointer!!! wp_filter = WpC.WB.Wj.wp_filter # = GLOBALS['wp_filter'] = globals()['wp_filter'] #VT# Since wp_filter shares the same mutable array, need to shallow copy it #VT# But there is no array pointer in py, and wp_filter is not modifed below #VT# So comment out: import copy #shallow copy only if array can be changed #VT# wp_filter = copy.copy(wp_filter) has = not Php.empty(wp_filter, tag) # Make sure at least one priority has a filter callback if has: exists = False for callbacks in wp_filter[tag]: if callbacks: # not Php.empty(locals(), 'callbacks'): exists = True break if not exists: has = False if function_to_check is False or has is False: return has idx = _wp_filter_build_unique_id(tag, function_to_check, False) if not idx: return False for priority in Php.Array(array_keys(wp_filter[tag])): if Php.isset(wp_filter[tag][priority], idx): return priority return False
def get_terms(self): ''' Get terms, based on query_vars. @global wpdb wpdb WordPress database abstraction object. @return array ''' import wp.i.taxonomy as WiTx wpdb = WpC.WB.Wj.wpdb # global wpdb self.parse_query(self.query_vars) args = self.query_vars #pprint(self.query_vars) # TypeError: unhashable type: 'instancemethod' # userdata is array, inspect.ismethod(A.__repr__) is True print('WP_Term_Query.get_terms: self.query_vars=', self.query_vars) # Set up meta_query so it's available to 'pre_get_terms'. self.meta_query = WcMQ.WP_Meta_Query() self.meta_query.parse_query_vars(args) # Fires before terms are retrieved. # @param WP_Term_Query self Current instance of WP_Term_Query. WiPg.do_action('pre_get_terms', self) taxonomies = args['taxonomy'] print("WcTQ.get_terms: taxonomies=", taxonomies) # Save queries by not crawling the tree in the case of multiple taxes or a flat tax. has_hierarchical_tax = False if taxonomies: for _tax in taxonomies: if WiTx.is_taxonomy_hierarchical(_tax): has_hierarchical_tax = True if not has_hierarchical_tax: args['hierarchical'] = False args['pad_counts'] = False # 'parent' overrides 'child_of'. if 0 < Php.intval(args['parent']): args['child_of'] = False if 'all' == args['get']: args['childless'] = False args['child_of'] = 0 args['hide_empty'] = 0 args['hierarchical'] = False args['pad_counts'] = False # Filters the terms query arguments. # @param array args An array of get_terms() arguments. # @param array taxonomies An array of taxonomies. args = WiPg.apply_filters('get_terms_args', args, taxonomies) #pprint(args) # TypeError: unhashable type: 'instancemethod' # userdata is array, inspect.ismethod(A.__repr__) is True print('WP_Term_Query.get_terms: args=', args) # Avoid the query if the queried parent/child_of term has no descendants. child_of = args['child_of'] parent = args['parent'] if child_of: _parent = child_of elif parent: _parent = parent else: _parent = False if _parent: in_hierarchy = False for _tax in taxonomies: hierarchy = WiTx._get_term_hierarchy(_tax) if Php.isset(hierarchy, _parent): in_hierarchy = True if not in_hierarchy: return array() # 'term_order' is a legal sort order only when joining the relationship # table. _orderby = self.query_vars['orderby'] if 'term_order' == _orderby and Php.empty(self.query_vars, 'object_ids'): _orderby = 'term_id' orderby = self.parse_orderby(_orderby) if orderby: orderby = "ORDER BY " + orderby order = self.parse_order(self.query_vars['order']) if taxonomies: self.sql_clauses['where']['taxonomy'] = ( "tt.taxonomy IN ('" + Php.implode("', '", Php.array_map(WiF.esc_sql, taxonomies)) + "')") exclude = args['exclude'] exclude_tree = args['exclude_tree'] include = args['include'] inclusions = '' if include: # if not Php.empty(locals(), 'include'): exclude = '' exclude_tree = '' inclusions = Php.implode(',', WiFc.wp_parse_id_list(include)) if inclusions: # if not Php.empty(locals(), 'inclusions'): self.sql_clauses['where']['inclusions'] = ('t.term_id IN ( ' + inclusions + ' )') exclusions = array() # Php.array_map( int, exclusions=List) if exclude_tree: # if not Php.empty(locals(), 'exclude_tree'): exclude_tree = WiFc.wp_parse_id_list(exclude_tree) excluded_children = exclude_tree for extrunk in exclude_tree: excluded_children = Php.array_merge( excluded_children, Php.Array( get_terms( taxonomies[0], array( ('child_of', Php.intval(extrunk)), ('fields', 'ids'), ('hide_empty', 0), )))) exclusions = Php.array_merge(excluded_children, exclusions) if exclude: # if not Php.empty(locals(), 'exclude'): exclusions = Php.array_merge(WiFc.wp_parse_id_list(exclude), exclusions) # 'childless' terms are those without an entry in the flattened term hierarchy. childless = bool(args['childless']) if childless: for _tax in taxonomies: term_hierarchy = WiTx._get_term_hierarchy(_tax) exclusions = Php.array_merge(Php.array_keys(term_hierarchy), exclusions) if exclusions: # if not Php.empty(locals(), 'exclusions'): exclusions = 't.term_id NOT IN (' + Php.implode( ',', Php.array_map(Php.intval, exclusions)) + ')' else: exclusions = '' # Filters the terms to exclude from the terms query. # @param string exclusions `NOT IN` clause of the terms query. # @param array args An array of terms query arguments. # @param array taxonomies An array of taxonomies. exclusions = WiPg.apply_filters('list_terms_exclusions', exclusions, args, taxonomies) if exclusions: # if not Php.empty(locals(), 'exclusions'): # Must do string manipulation here for backward compatibility with filter. self.sql_clauses['where']['exclusions'] = preg_replace( '/^\s*AND\s*/', '', exclusions) print("\n WcTQ.get_terms: args['name'] =", args['name']) print("WcTQ.get_terms: taxonomies=", taxonomies) if not Php.empty(args, 'name'): names = Php.Array(args['name']) print("WcTQ.get_terms: names=", names, taxonomies) #foreach ( names as &_name ) { #modify list entries during for loop stackoverflow.com/questions/4081217 for k, _name in names.items( ): #use enumerate(names) if type(names)=list # `sanitize_term_field()` returns slashed data. #_name = Php.stripslashes( WiTx.sanitize_term_field( # 'name', _name, 0, Php.reset(taxonomies), 'db')) names[k] = Php.stripslashes( WiTx.sanitize_term_field('name', _name, 0, Php.reset(taxonomies), 'db')) print("WcTQ.get_terms: names=", names, taxonomies) self.sql_clauses['where']['name'] = "t.name IN ('" + Php.implode( "', '", Php.array_map(WiF.esc_sql, names)) + "')" if not Php.empty(args, 'slug'): if Php.is_array(args['slug']): slug = Php.array_map(WiF.sanitize_title, args['slug']) self.sql_clauses['where'][ 'slug'] = "t.slug IN ('" + Php.implode("', '", slug) + "')" else: slug = WiF.sanitize_title(args['slug']) self.sql_clauses['where']['slug'] = "t.slug = 'slug'" if not Php.empty(args, 'term_taxonomy_id'): if Php.is_array(args['term_taxonomy_id']): tt_ids = Php.implode( ',', Php.array_map(Php.intval, args['term_taxonomy_id'])) self.sql_clauses['where']['term_taxonomy_id'] = \ "tt.term_taxonomy_id IN ({})".format(tt_ids) else: self.sql_clauses['where']['term_taxonomy_id'] = wpdb.prepare( "tt.term_taxonomy_id = %s", args['term_taxonomy_id']) # PyMySQL %d->%s if not Php.empty(args, 'name__like'): self.sql_clauses['where']['name__like'] = wpdb.prepare( "t.name LIKE %s", '%' + wpdb.esc_like(args['name__like']) + '%') if not Php.empty(args, 'description__like'): self.sql_clauses['where']['description__like'] = wpdb.prepare( "tt.description LIKE %s", '%' + wpdb.esc_like(args['description__like']) + '%') if not Php.empty(args, 'object_ids'): object_ids = args['object_ids'] if not Php.is_array(object_ids): object_ids = array(object_ids) object_ids = Php.implode(', ', Php.array_map(Php.intval, object_ids)) self.sql_clauses['where'][ 'object_ids'] = "tr.object_id IN ({})".format(object_ids) # When querying for object relationships, the 'count > 0' check # added by 'hide_empty' is superfluous. if not Php.empty(args['object_ids']): args['hide_empty'] = False if '' != parent: parent = Php.intval(parent) self.sql_clauses['where']['parent'] = "tt.parent = 'parent'" hierarchical = args['hierarchical'] if 'count' == args['fields']: hierarchical = False if args['hide_empty'] and not hierarchical: self.sql_clauses['where']['count'] = 'tt.count > 0' number = args['number'] offset = args['offset'] # Don't limit the query results when we have to descend the family tree. if number and not hierarchical and not child_of and '' == parent: if offset: limits = 'LIMIT ' + offset + ',' + number else: limits = 'LIMIT ' + number else: limits = '' if not Php.empty(args, 'search'): self.sql_clauses['where']['search'] = self.get_search_sql( args['search']) # Meta query support. join = '' distinct = '' # Reparse meta_query query_vars, in case they were modified in a 'pre_get_terms' callback. self.meta_query.parse_query_vars(self.query_vars) mq_sql = self.meta_query.get_sql('term', 't', 'term_id') meta_clauses = self.meta_query.get_clauses() if not Php.empty(args, 'meta_clauses'): join += mq_sql['join'] self.sql_clauses['where']['meta_query'] = preg_replace( '/^\s*AND\s*/', '', mq_sql['where']) distinct += "DISTINCT" selects = array() #switch ( args['fields'] ) { # case 'all': AF = args['fields'] if AF in ('all', 'all_with_object_id', 'tt_ids', 'slugs'): selects = array('t.*', 'tt.*') if ('all_with_object_id' == args['fields'] and not Php.empty(args, 'object_ids')): selects[None] = 'tr.object_id' #elif AF in ('ids', 'id=>parent'): elif AF in ('ids', 'id=>parent', 'id.parent'): selects = array('t.term_id', 'tt.parent', 'tt.count', 'tt.taxonomy') elif AF == 'names': selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name', 'tt.taxonomy') elif AF == 'count': orderby = '' order = '' selects = array('COUNT(*)', ) #elif AF == 'id=>name': elif AF in ('id=>name', 'id.name'): selects = array('t.term_id', 't.name', 'tt.count', 'tt.taxonomy') #elif AF == 'id=>slug': elif AF in ('id=>slug', 'id.slug'): selects = array('t.term_id', 't.slug', 'tt.count', 'tt.taxonomy') _fields = args['fields'] # Filters the fields to select in the terms query. # Field lists modified using this filter will only modify the term fields returned # by the function when the `fields` parameter set to 'count' or 'all'. In all other # cases, the term fields in the results array will be determined by the `fields` # parameter alone. # Use of this filter can result in unpredictable behavior, and is not recommended. # @param array selects An array of fields to select for the terms query. # @param array args An array of term query arguments. # @param array taxonomies An array of taxonomies. fields = Php.implode( ', ', WiPg.apply_filters('get_terms_fields', selects, args, taxonomies)) join += (" INNER JOIN " + wpdb.term_taxonomy + " AS tt ON t.term_id = tt.term_id") if not Php.empty(self.query_vars, 'object_ids'): join += (" INNER JOIN {} AS tr ON tr.term_taxonomy_id = " "tt.term_taxonomy_id".format(wpdb.term_relationships)) where = Php.implode(' AND ', self.sql_clauses['where']) # Filters the terms query SQL clauses. # @param array pieces Terms query SQL clauses. # @param array taxonomies An array of taxonomies. # @param array args An array of terms query arguments. pieces = ('fields', 'join', 'where', 'distinct', 'orderby', 'order', 'limits') clauses = WiPg.apply_filters('terms_clauses', Php.compact(locals(), pieces), taxonomies, args) #fields = isset( clauses[ 'fields' ] ) ? clauses[ 'fields' ] : '' fields = clauses.get('fields', '') join = clauses.get('join', '') where = clauses.get('where', '') distinct = clauses.get('distinct', '') orderby = clauses.get('orderby', '') order = clauses.get('order', '') limits = clauses.get('limits', '') if where: where = "WHERE " + where self.sql_clauses['select'] = "SELECT {} {}".format(distinct, fields) self.sql_clauses['from'] = "FROM {} AS t {}".format(wpdb.terms, join) self.sql_clauses['orderby'] = orderby + " " + order if orderby else '' self.sql_clauses['limits'] = limits #self.request = "{self.sql_clauses['select']} {self.sql_clauses['from']} {where} {self.sql_clauses['orderby']} {self.sql_clauses['limits']}" self.request = "{} {} {} {} {}".format(self.sql_clauses['select'], self.sql_clauses['from'], where, self.sql_clauses['orderby'], self.sql_clauses['limits']) # args can be anything. Only use the args defined in defaults to compute the key. key = Php.md5( Php.serialize( WiFc.wp_array_slice_assoc( args, Php.array_keys(self.query_var_defaults))) + Php.serialize(taxonomies) + self.request) last_changed = WiFc.wp_cache_get_last_changed('terms') cache_key = "get_terms:{}:{}".format(key, last_changed) cache = WiCa.wp_cache_get(cache_key, 'terms') if False != cache: if 'all' == _fields: cache = Php.array_map(WiTx.get_term, cache) self.terms = cache print("WcTQ get_terms 1 self.terms=", self.terms) return self.terms if 'count' == _fields: count = wpdb.get_var(self.request) WiCa.wp_cache_set(cache_key, count, 'terms') return count terms = wpdb.get_results(self.request) print("WcTQ get_terms 2 terms=", terms) if 'all' == _fields or 'all_with_object_id' == _fields: WiTx.update_term_cache(terms) print("WcTQ get_terms 3 terms=", terms) # Prime termmeta cache. if args['update_term_meta_cache']: term_ids = WiFc.wp_list_pluck(terms, 'term_id') WiTx.update_termmeta_cache(term_ids) print("WcTQ get_terms 4 terms=", terms) if not terms: # if Php.empty(locals(), 'terms'): WiCa.wp_cache_add(cache_key, array(), 'terms', WpC.WB.Wj.DAY_IN_SECONDS) return array() print("WcTQ get_terms 5 terms=", terms) if child_of: for _tax in taxonomies: children = WiTx._get_term_hierarchy(_tax) if children: # if not Php.empty(locals(), 'children'): terms = _get_term_children(child_of, terms, _tax) print("WcTQ get_terms 6 terms=", terms) # Update term counts to include children. if args['pad_counts'] and 'all' == _fields: for _tax in taxonomies: _pad_term_counts(terms, _tax) # Make sure we show empty categories that have children. if hierarchical and args['hide_empty'] and Php.is_array(terms): for k, term in terms.items(): Continue2 = False #VT added to translate php: continue 2 if not term.count: children = get_term_children(term.term_id, term.taxonomy) if Php.is_array(children): for child_id in children: child = WiTx.get_term(child_id, term.taxonomy) if child.count: #continue 2 Continue2 = True #VT added to translate php: continue 2 continue #VT added to translate php: continue 2 # It really is empty. del terms[k] if Continue2: #VT added to translate php: continue 2 continue #VT added to translate php: continue 2 print("WcTQ get_terms 7 terms=", terms) # When querying for terms connected to objects, we may get # duplicate results. The duplicates should be preserved if # `fields` is 'all_with_object_id', but should otherwise be # removed. if not Php.empty(args, 'object_ids') and 'all_with_object_id' != _fields: _tt_ids = array() # need to be sperate mutable obj _terms = array() # need to be sperate mutable obj for term in terms: if Php.isset(_tt_ids, getattr(term, 'term_id', None)): continue _tt_ids[term.term_id] = 1 _terms[None] = term terms = _terms _terms = array() # array() #if 'id=>parent' == _fields: if _fields in ('id=>parent', 'id.parent'): for term in terms: _terms[term.term_id] = term.parent elif 'ids' == _fields: #for i,term in enumerate(terms): # _terms[i] = int(term.term_id) for term in terms: _terms[None] = int(term.term_id) elif 'tt_ids' == _fields: for term in terms: _terms[None] = int(term.term_taxonomy_id) elif 'names' == _fields: #for i,term in enumerate(terms): # _terms[i] = term.name for term in terms: _terms[None] = term.name elif 'slug' == _fields: for term in terms: _terms[None] = term.slug #elif 'id=>name' == _fields: elif _fields in ('id=>name', 'id.name'): for term in terms: _terms[term.term_id] = term.name #elif 'id=>slug' == _fields: elif _fields in ('id=>slug', 'id.slug'): for term in terms: _terms[term.term_id] = term.slug if _terms: # if not Php.empty(locals(), '_terms'): terms = _terms # Hierarchical queries are not limited, so 'offset' and 'number' must be handled now. if hierarchical and number and Php.is_array(terms): if offset >= len(terms): terms = array() # array() else: terms = Php.array_slice(terms, offset, number, True) WiCa.wp_cache_add(cache_key, terms, 'terms', WpC.WB.Wj.DAY_IN_SECONDS) if 'all' == _fields or 'all_with_object_id' == _fields: terms = Php.array_map(WiTx.get_term, terms) self.terms = terms return self.terms
def get_metadata(meta_type, object_id, meta_key='', single=False): ''' Retrieve metadata for the specified object. @param string meta_type Type of object metadata is for (e.g., comment, post, or user) @param int object_id ID of the object metadata is for @param string meta_key Optional. Metadata key. If not specified, retrieve all metadata for the specified object. @param bool single Optional, default is False. If True, return only the first value of the specified meta_key. This parameter has no effect if meta_key is not specified. @return mixed Single metadata value, or array of values = list = [] !!! ''' if not meta_type or not isinstance(object_id, int): return False object_id = abs(object_id) if not object_id: return False print('get_metadata meta_type={}, object_id ={}, meta_key={}'.format( meta_type, object_id, meta_key)) # Filter whether to retrieve metadata of a specific type. # The dynamic portion of the hook, `meta_type`, refers to the meta # object type (comment, post, or user). Returning a non-None value # will effectively short-circuit the function. # @param None|array|string value The value get_metadata() should return - # a single metadata value, or an array of values. # @param int object_id Object ID. # @param string meta_key Meta key. # @param bool single Whether to return only the first value of the # specified meta_key. check = WiPg.apply_filters("get_{}_metadata".format(meta_type), None, object_id, meta_key, single) if check is not None: if single and Php.is_array(check): return check[0] else: return check meta_cache = WiCa.wp_cache_get(object_id, meta_type + '_meta') if not meta_cache: meta_cache = update_meta_cache(meta_type, array(object_id)) # wp> $m = false; wp> $m[1] => NULL meta_cache = meta_cache[object_id] # The folllowing is BAD! since meta_cache = array( (object_id, array)) # so object_id in meta_cache is always False! #meta_cache = meta_cache[object_id] if object_id in meta_cache else None # Can use array_key_exists or object_id in meta_cache.keys() if not meta_key: print('\n get_metadata not meta_key, return meta_cache =', meta_cache) return meta_cache #if meta_cache.get(meta_key, None) is not None: if Php.isset(meta_cache, meta_key): mkey = meta_cache[meta_key] print('get_metadata:', meta_type, object_id, meta_key, single, mkey) if single: return WiFc.maybe_unserialize(mkey[0]) else: #print('get_metadata return:', Php.array_map(WiFc.maybe_unserialize, mkey)) #return [ WiFc.maybe_unserialize(v) for v in mkey ] return Php.array_map(WiFc.maybe_unserialize, mkey) #same as: #print('\n get_metadata not isset(meta_cache, meta_key)', meta_cache, meta_key) if single: return '' else: return array()
def wp_generate_tag_cloud( tags, args = '' ): ''' Generates a tag cloud (heatmap) from provided data. @todo Complete functionality. @param array tags List of tags. @param string|array args { Optional. Array of string of arguments for generating a tag cloud. @type int smallest Smallest font size used to display tags. Paired with the value of `unit`, to determine CSS text size unit. Default 8 (pt). @type int largest Largest font size used to display tags. Paired with the value of `unit`, to determine CSS text size unit. Default 22 (pt). @type string unit CSS text size unit to use with the `smallest` and `largest` values. Accepts any valid CSS text size unit. Default 'pt'. @type int number The number of tags to return. Accepts any positive integer or zero to return all. Default 0. @type string format Format to display the tag cloud in. Accepts 'flat' (tags separated with spaces), 'list' (tags displayed in an unordered list), or 'array' (returns an array). Default 'flat'. @type string separator HTML or text to separate the tags. Default "\n" (newline). @type string orderby Value to order tags by. Accepts 'name' or 'count'. Default 'name'. The {@see 'tag_cloud_sort'} filter can also affect how tags are sorted. @type string order How to order the tags. Accepts 'ASC' (ascending), 'DESC' (descending), or 'RAND' (random). Default 'ASC'. @type int|bool filter Whether to enable filtering of the final output via {@see 'wp_generate_tag_cloud'}. Default 1|True. @type string topic_count_text Nooped plural text from _n_noop() to supply to tag tooltips. Default None. @type callable topic_count_text_callback Callback used to generate nooped plural text for tag tooltips based on the count. Default None. @type callable topic_count_scale_callback Callback used to determine the tag count scaling value. Default default_topic_count_scale(). } @return string|array Tag cloud as a string or an array, depending on 'format' argument. ''' defaults = array( ('smallest', 8), ('largest', 22), ('unit', 'pt'), ('number', 0), ('format','flat'), ('separator',"\n"), ('orderby','name'),('order','ASC'), ('topic_count_text', None), ('topic_count_text_callback', None), ('topic_count_scale_callback', 'default_topic_count_scale'), ('filter',1), ) args = wp_parse_args( args, defaults ) Return = array() if ( 'array' == args['format'] ) else '' if Php.empty( tags ): return Return # Juggle topic count tooltips: if Php.isset( args, 'topic_count_text' ): # First look for nooped plural support via topic_count_text. translate_nooped_plural = args['topic_count_text'] elif not Php.empty( args['topic_count_text_callback'] ): # Look for the alternative callback style. Ignore the previous default. if args['topic_count_text_callback'] == 'default_topic_count_text': translate_nooped_plural = _n_noop( '%s topic', '%s topics' ) else: translate_nooped_plural = False elif Php.isset( args, 'single_text' ) and Php.isset( args, 'multiple_text' ): # If no callback exists, look for the old-style single_text and multiple_text arguments. translate_nooped_plural = _n_noop( args['single_text'], args['multiple_text'] ) else: # This is the default for when no callback, plural, or argument is passed in. translate_nooped_plural = _n_noop( '%s topic', '%s topics' ) # Filters how the items in a tag cloud are sorted. # @param array tags Ordered array of terms. # @param array args An array of tag cloud arguments. tags_sorted = WiPg.apply_filters( 'tag_cloud_sort', tags, args ) if Php.empty( tags_sorted ): return Return if tags_sorted != tags: tags = tags_sorted unset( tags_sorted ) else: if 'RAND' == args['order']: shuffle( tags ) else: # SQL cannot save you; this is a second (potentially different) sort on a subset of data. if 'name' == args['orderby']: uasort( tags, '_wp_object_name_sort_cb' ) else: uasort( tags, '_wp_object_count_sort_cb' ) if 'DESC' == args['order']: tags = array_reverse( tags, True ) if args['number'] > 0: tags = array_slice( tags, 0, args['number'] ) counts = array() real_counts = array(); # For the alt tag for key, tag in Php.Array(tags).items(): real_counts[ key ] = tag.count counts[ key ] = Php.call_user_func( args['topic_count_scale_callback'], tag.count ) # Php min() = Php.Min() here is is different from the py builtin min() !! min_count = Php.Min( counts ) # Php max() = Php.Max() here is is different from the py builtin max() !! spread = Php.Max( counts ) - min_count if spread <= 0: spread = 1 font_spread = args['largest'] - args['smallest'] if font_spread < 0: font_spread = 1 font_step = font_spread / spread # Assemble the data that will be used to generate the tag cloud markup. tags_data = array() for key, tag in tags.items(): tag_id = tag.id if Php.isset( tag, id ) else key count = counts[ key ] real_count = real_counts[ key ] if translate_nooped_plural: title = Php.sprintf( translate_nooped_plural( translate_nooped_plural, real_count ), number_format_i18n( real_count ) ) else: title = Php.call_user_func( args['topic_count_text_callback'], real_count, tag, args ) Php.ArrayAppend( tags_data, array( ('id' , tag_id), ('url' , tag.link if '#' != tag.link else '#'), ('name' , tag.name), ('title' , title), ('slug' , tag.slug), ('real_count', real_count), ('class' , 'tag-link-' + tag_id), ('font_size' , args['smallest'] + ( count - min_count ) * font_step), ) ) # Filters the data used to generate the tag cloud. # @param array tags_data An array of term data for term used to generate the tag cloud. tags_data = WiPg.apply_filters( 'wp_generate_tag_cloud_data', tags_data ) a = array() # generate the output links array for key, tag_data in tags_data.items(): Class = tag_data['class'] + ' tag-link-position-' + ( key + 1 ) Php.ArrayAppend(a, "<a href='" + esc_url( tag_data['url'] ) + "' class='" + esc_attr( Class ) + "' title='" + esc_attr( tag_data['title'] ) + "' style='font-size: " + esc_attr( str_replace( ',', '.', tag_data['font_size'] ) + args['unit'] ) + ";'>" + esc_html( tag_data['name'] ) + "</a>") #switch ( args['format'] ) { if args['format'] == 'array' : Return = a # no need for php: & a, since a is a mutable array elif args['format'] == 'list' : Return = "<ul class='wp-tag-cloud'>\n\t<li>" Return += join( "</li>\n\t<li>", a ) Return += "</li>\n</ul>\n" else: Return = join( args['separator'], a ) if args['filter']: # Filters the generated output of a tag cloud. # The filter is only evaluated if a True value is passed # to the filter argument in wp_generate_tag_cloud(). # @see wp_generate_tag_cloud() # @param array|string Return String containing the generated HTML tag cloud output # or an array of tag links if the 'format' argument # equals 'array'. # @param array tags An array of terms used in the tag cloud. # @param array args An array of wp_generate_tag_cloud() arguments. return WiPg.apply_filters( 'wp_generate_tag_cloud', Return, tags, args ) else: return Return
def parse_request(self, extra_query_vars=''): ''' Parse request to find correct WordPress query. Sets up the query variables based on the request. There are also many filters and actions that can be used to further manipulate the result. @access public @global WP_Rewrite wp_rewrite @param array|string extra_query_vars Set the extra query variables. ''' import wp.i.taxonomy as WiTx wp_rewrite = WpC.WB.Wj.wp_rewrite # global wp_rewrite # Filters whether to parse the request. # @param bool bool Whether or not to parse the request. Default True. # @param WP self Current WordPress environment instance. # @param array|string extra_query_vars Extra passed query variables. if not apply_filters('do_parse_request', True, self, extra_query_vars): return self.query_vars = array() post_type_query_vars = array() if Php.is_array(extra_query_vars): #self.extra_query_vars = & extra_query_vars self.extra_query_vars = extra_query_vars # mutable array don't need & elif extra_query_vars: # elif not Php.empty(locals(),'extra_query_vars'): parse_str(extra_query_vars, self.extra_query_vars) # Process PATH_INFO, REQUEST_URI, and 404 for permalinks. # Fetch the rewrite rules. rewrite = wp_rewrite.wp_rewrite_rules() if rewrite: # if not Php.empty(locals(), 'rewrite'): # If we match a rewrite rule, this will be cleared. error = '404' self.did_permalink = True #pathinfo=_SERVER['PATH_INFO'] if Php.isset(_SERVER,'PATH_INFO') else '' pathinfo = getattr(_SERVER, 'PATH_INFO', '') #list( pathinfo ) = explode( '?', pathinfo ) pathinfo = Php.explode('?', pathinfo)[0] pathinfo = Php.str_replace("%", "%25", pathinfo) #list( req_uri ) = explode( '?', _SERVER['REQUEST_URI'] ) req_uri = Php.explode('?', _SERVER['REQUEST_URI'])[0] self = _SERVER['PHP_SELF'] home_path = trim(parse_url(home_url(), PHP_URL_PATH), '/') home_path_regex = sprintf('|^%s|i', preg_quote(home_path, '|')) # Trim path info from the end and the leading home path from the # front. For path info requests, this leaves us with the requesting # filename, if any. For 404 requests, this leaves us with the # requested permalink. req_uri = Php.str_replace(pathinfo, '', req_uri) req_uri = trim(req_uri, '/') req_uri = preg_replace(home_path_regex, '', req_uri) req_uri = trim(req_uri, '/') pathinfo = trim(pathinfo, '/') pathinfo = preg_replace(home_path_regex, '', pathinfo) pathinfo = trim(pathinfo, '/') self = trim(self, '/') self = preg_replace(home_path_regex, '', self) self = trim(self, '/') # The requested permalink is in pathinfo for path info requests and # req_uri for other requests. #if not Php.empty(locals(), 'pathinfo') and ...: if pathinfo and not Php.preg_match( '|^.*' + wp_rewrite.index + '$|', pathinfo): requested_path = pathinfo else: # If the request uri is the index, blank it out so that we don't try to match it against a rule. if req_uri == wp_rewrite.index: req_uri = '' requested_path = req_uri requested_file = req_uri self.request = requested_path # Look for matches. request_match = requested_path if not request_match: #if Php.empty(locals(), 'request_match'): # An empty request could only match against ^$ regex if Php.isset(rewrite, '$'): self.matched_rule = '$' query = rewrite['$'] matches = array('') else: for match, query in Php.Array(rewrite).items(): # If the requested file is the anchor of the match, prepend it to the path info. #if not Php.empty(locals(), 'requested_file') and ...: if requested_file and Php.strpos( match, requested_file ) is 0 and requested_file != requested_path: request_match = requested_file + '/' + requested_path if (Php.preg_match("#^{}#".format(match), request_match, matches) or Php.preg_match( "#^{}#".format(match), urldecode(request_match), matches)): if wp_rewrite.use_verbose_page_rules and Php.preg_match( '/pagename=\$matches\[([0-9]+)\]/', query, varmatch): # This is a verbose page match, let's check to be sure about it. page = get_page_by_path(matches[varmatch[1]]) if not page: continue post_status_obj = get_post_status_object( page.post_status) if (not post_status_obj.public and not post_status_obj.protected and not post_status_obj.private and post_status_obj.exclude_from_search): continue # Got a match. self.matched_rule = match break if Php.isset(self, 'matched_rule'): # Trim the query of everything up to the '?'. query = preg_replace("!^.+\?!", '', query) # Substitute the substring matches into the query. query = Php.addslashes(WP_MatchesMapRegex.Apply( query, matches)) self.matched_query = query # Parse the query. parse_str(query, perma_query_vars) # If we're processing a 404 request, clear the error var since we found something. if '404' == error: unset(error, _GET['error']) # If req_uri is empty or if it is a request for ourself, unset error. #if Php.empty(locals(), 'requested_path') and ...: if not requested_path or requested_file == self or Php.strpos( _SERVER['PHP_SELF'], 'wp-admin/') is not False: unset(error, _GET['error']) if (Php.isset(locals(), 'perma_query_vars') and #Php.strpos(_SERVER['PHP_SELF'], 'wp-admin/') is not False ): 'wp-admin/' not in _SERVER['PHP_SELF']): del perma_query_vars # unset( perma_query_vars ) self.did_permalink = False # Filters the query variables whitelist before processing. # Allows (publicly allowed) query vars to be added, removed, or changed prior # to executing the query. Needed to allow custom rewrite rules using your own arguments # to work, or any other custom query variables you want to be publicly available. # @param array public_query_vars The array of whitelisted query variables. self.public_query_vars = apply_filters('query_vars', self.public_query_vars) for post_type, t in get_post_types(array(), 'objects').items(): if is_post_type_viewable(t) and t.query_var: post_type_query_vars[t.query_var] = post_type for wpvar in self.public_query_vars: if Php.isset(self.extra_query_vars, wpvar): self.query_vars[wpvar] = self.extra_query_vars[wpvar] elif Php.isset(_POST, wpvar): self.query_vars[wpvar] = _POST[wpvar] elif Php.isset(_GET, wpvar): self.query_vars[wpvar] = _GET[wpvar] elif Php.isset(perma_query_vars, wpvar): self.query_vars[wpvar] = perma_query_vars[wpvar] if not Php.empty(self.query_vars, wpvar): if not Php.is_array(self.query_vars[wpvar]): self.query_vars[wpvar] = str(self.query_vars[wpvar]) else: for vkey, v in self.query_vars[wpvar].items(): if not is_object(v): self.query_vars[wpvar][vkey] = str(v) if Php.isset(post_type_query_vars, wpvar): self.query_vars['post_type'] = post_type_query_vars[wpvar] self.query_vars['name'] = self.query_vars[wpvar] # Convert urldecoded spaces back into + for taxonomy, t in WiTx.get_taxonomies(array(), 'objects').items(): if t.query_var and Php.isset(self.query_vars, t.query_var): self.query_vars[t.query_var] = Php.str_replace( ' ', '+', self.query_vars[t.query_var]) # Don't allow non-publicly queryable taxonomies to be queried from the # front end. if not is_admin(): for taxonomy, t in WiTx.get_taxonomies( array(('publicly_queryable', False)), 'objects').items(): # Disallow when set to the 'taxonomy' query var. # Non-publicly queryable taxonomies cannot register custom query # vars. See register_taxonomy(). if (Php.isset(self.query_vars, 'taxonomy') and taxonomy == self.query_vars['taxonomy']): unset(self.query_vars['taxonomy'], self.query_vars['term']) # Limit publicly queried post_types to those that are publicly_queryable if Php.isset(self.query_vars, 'post_type'): queryable_post_types = get_post_types( array(('publicly_queryable', True))) if not Php.is_array(self.query_vars['post_type']): if not Php.in_array(self.query_vars['post_type'], queryable_post_types): unset(self.query_vars['post_type']) else: self.query_vars['post_type'] = array_intersect( self.query_vars['post_type'], queryable_post_types) # Resolve conflicts between posts with numeric slugs and date archive queries. self.query_vars = wp_resolve_numeric_slug_conflicts(self.query_vars) for var in Php.Array(self.private_query_vars): if Php.isset(self.extra_query_vars, var): self.query_vars[var] = self.extra_query_vars[var] if Php.isset(locals(), 'error'): self.query_vars['error'] = error # Filters the array of parsed query variables. # @param array query_vars The array of requested query variables. self.query_vars = apply_filters('request', self.query_vars) # Fires once all query variables for the current request have been parsed. # @param WP &self Current WordPress environment instance (passed by reference). WiPg.do_action_ref_array('parse_request', array(self)) # &self ) )
def update_meta_cache(meta_type, object_ids): '''Update the metadata cache for the specified objects. @param string meta_type Type of object metadata is for (e.g., comment, post, or user) @param int|array object_ids Array or comma delimited list of object IDs to update cache for @return array|False Metadata cache for the specified objects, or False on failure. ''' #global var==>WpC.WB.Wj.var, except: var=WpC.WB.Wj.var=same Obj,mutable array wpdb = WpC.WB.Wj.wpdb # global wpdb print('update_meta_cache meta_type={}, object_ids={}'.format( meta_type, object_ids)) if not meta_type or not object_ids: print('update_meta_cache not meta_type or not object_ids:') return False table = _get_meta_table(meta_type) if not table: print('update_meta_cache not table:') return False column = WiF.sanitize_key(meta_type + '_id') #if not isinstance(object_ids, (list,tuple,)): if not Php.is_array(object_ids): #import re #Re = re.compile('[^0-9,]') #object_ids = Re.sub('', object_ids) object_ids = Php.preg_replace('|[^0-9,]|', '', object_ids) #object_ids= object_ids.split(',') object_ids = Php.explode(',', object_ids) # object_ids = [ val for val in object_ids.values() ] #object_ids = [int(val) for val in object_ids] #same as: object_ids = Php.array_map(Php.intval, object_ids) print('update_meta_cache object_ids=', object_ids) cache_key = meta_type + '_meta' ids = array() cache = array() for Id in object_ids: cached_object = WiCa.wp_cache_get(Id, cache_key) if False is cached_object: ids[None] = Id else: cache[Id] = cached_object if not ids: # if Php.empty(locals(), 'ids'): return cache # Get meta info #id_list = ','.join(str(ids)) #BAD!!#= [,2,6,8,3,4,] id_list = ','.join([str(Id) for Id in ids]) id_column = 'umeta_id' if 'user' == meta_type else 'meta_id' #meta_list = wpdb->get_results( "SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC", ARRAY_A ) # in wp-db.php get_results( , ARRAY_A) = column name-keyed row arrays Sql = ("SELECT {}, meta_key, meta_value FROM {} WHERE {} IN ({}) ORDER BY " "{} ASC".format(column, table, column, id_list, id_column)) #meta_list = wDB.GetDB(MetaC, table).Exec(Sql) meta_list = wpdb.get_results(Sql, 'ARRAY_A') # in wp-db.php get_results( , ARRAY_A) = column name-keyed row arrays print('\n update_meta_cache meta_list =', meta_list) if meta_list: # if not Php.empty(locals(), 'meta_list'): for metarow in meta_list: mpid = int(metarow[column]) mkey = metarow['meta_key'] mval = metarow['meta_value'] # Force subkeys to be arry type: if not Php.isset(cache, mpid) or not Php.is_array(cache[mpid]): cache[mpid] = array() if (not Php.isset(cache[mpid], mkey) or not Php.is_array(cache[mpid][mkey])): cache[mpid][mkey] = array() # Add a value to the current pid/key: cache[mpid][mkey][None] = mval for Id in ids: if not Php.isset(cache, Id): cache[Id] = array() WiCa.wp_cache_add(Id, cache[Id], cache_key) print('\n update_meta_cache return cache =', cache) return cache
def send_headers(self): ''' Sends additional HTTP headers for caching, content type, etc. Sets the Content-Type header. Sets the 'error' status (if passed) and optionally exits. If showing a feed, it will also send Last-Modified, ETag, and 304 status if needed. @since 4.4.0 `X-Pingback` header is added conditionally after posts have been queried in handle_404(). @access public ''' headers = array() # array() status = None exit_required = False if is_user_logged_in(): headers = array_merge(headers, wp_get_nocache_headers()) if Php.empty(self.query_vars, 'error'): status = int(self.query_vars['error']) if 404 == status: if not is_user_logged_in(): headers = array_merge(headers, wp_get_nocache_headers()) headers['Content-Type'] = get_option( 'html_type') + '; charset=' + get_option('blog_charset') elif Php.in_array(status, array(403, 500, 502, 503)): exit_required = True elif Php.empty(self.query_vars, 'feed'): headers['Content-Type'] = get_option( 'html_type') + '; charset=' + get_option('blog_charset') else: # Set the correct content type for feeds Type = self.query_vars['feed'] if 'feed' == self.query_vars['feed']: Type = get_default_feed() headers['Content-Type'] = feed_content_type( Type) + '; charset=' + get_option('blog_charset') # We're showing a feed, so WP is indeed the only thing that last changed if (not Php.empty(self.query_vars, 'withcomments') #or False !== strpos( self.query_vars['feed'], 'comments-' ) or 'comments-' in self.query_vars['feed'] or (Php.empty(self.query_vars, 'withoutcomments') and (not Php.empty(self.query_vars, 'p') or not Php.empty(self.query_vars, 'name') or not Php.empty(self.query_vars, 'page_id') or not Php.empty(self.query_vars, 'pagename') or not Php.empty(self.query_vars, 'attachment') or not Php.empty(self.query_vars, 'attachment_id')))): wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), False) else: wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), False) if not wp_last_modified: wp_last_modified = date('D, d M Y H:i:s') wp_last_modified += ' GMT' wp_etag = '"' + md5(wp_last_modified) + '"' headers['Last-Modified'] = wp_last_modified headers['ETag'] = wp_etag # Support for Conditional GET if Php.isset(_SERVER, 'HTTP_IF_NONE_MATCH'): client_etag = WiF.wp_unslash(_SERVER['HTTP_IF_NONE_MATCH']) else: client_etag = False client_last_modified = '' if Php.empty( _SERVER, 'HTTP_IF_MODIFIED_SINCE') else trim( _SERVER['HTTP_IF_MODIFIED_SINCE']) # If string is empty, return 0. If not, attempt to parse into a timestamp client_modified_timestamp = strtotime( client_last_modified) if client_last_modified else 0 # Make a timestamp for our most recent modification... wp_modified_timestamp = strtotime(wp_last_modified) if (((client_modified_timestamp >= wp_modified_timestamp) and (client_etag == wp_etag)) if (client_last_modified and client_etag) else ((client_modified_timestamp >= wp_modified_timestamp) or (client_etag == wp_etag))): status = 304 exit_required = True # Filters the HTTP headers before they're sent to the browser. # @param array headers The list of headers to be sent. # @param WP self Current WordPress environment instance. headers = apply_filters('wp_headers', headers, self) if status: # if not Php.empty(locals(), 'status'): status_header(status) # If Last-Modified is set to False, it should not be sent (no-cache situation). if (Php.isset(headers, 'Last-Modified') and False is headers['Last-Modified']): Php.unset(headers, 'Last-Modified') # In PHP 5.3+, make sure we are not sending a Last-Modified header. if function_exists('header_remove'): #@header_remove( 'Last-Modified' ) header_remove('Last-Modified') else: # In PHP 5.2, send an empty Last-Modified header, but only as a # last resort to override a header already sent. #WP23021 for header in headers_list(): if 0 is stripos(header, 'Last-Modified'): headers['Last-Modified'] = '' break for name, field_value in Php.Array(headers).items(): #@header(name +": "+ field_value) header(name + ": " + field_value) if exit_required: import sys sys.exit() # Fires once the requested HTTP headers for caching, content type, etc. have been sent. # @param WP &self Current WordPress environment instance (passed by reference). # remove & from &self since self won't get changed during func call WiPG.do_action_ref_array('send_headers', array(self)) # ( &self )
def wp_initial_constants(self): #global blog_id # VT change to self.blog_id # Constants for expressing human-readable data sizes in their respective number of bytes. self.define('KB_IN_BYTES', 1024) self.define('MB_IN_BYTES', 1024 * self.KB_IN_BYTES) self.define('GB_IN_BYTES', 1024 * self.MB_IN_BYTES) self.define('TB_IN_BYTES', 1024 * self.GB_IN_BYTES) #current_limit = @ini_get( 'memory_limit' ) #current_limit_int = wp_convert_hr_to_bytes( current_limit ) ## Define memory limits. #if not self.defined( 'WP_MEMORY_LIMIT' ): # if False is wp_is_ini_value_changeable( 'memory_limit' ): # self.define( 'WP_MEMORY_LIMIT', current_limit ) # elif WB.Wj.is_multisite(): # self.define( 'WP_MEMORY_LIMIT', '64M' ) # else: # self.define( 'WP_MEMORY_LIMIT', '40M' ) #if not self.defined( 'WP_MAX_MEMORY_LIMIT' ): # if False is wp_is_ini_value_changeable( 'memory_limit' ): # self.define( 'WP_MAX_MEMORY_LIMIT', current_limit ) # elif -1 == current_limit_int or current_limit_int > 268435456: # self.define( 'WP_MAX_MEMORY_LIMIT', current_limit ) #268435456 = 256M # else: # self.define( 'WP_MAX_MEMORY_LIMIT', '256M' ) ## Set memory limits. #wp_limit_int = wp_convert_hr_to_bytes( self.WP_MEMORY_LIMIT ) #if -1 != current_limit_int and ( -1 == wp_limit_int or wp_limit_int > current_limit_int ): # @ini_set( 'memory_limit', self.WP_MEMORY_LIMIT ) #if not isset(blog_id): if not Php.isset(self, 'blog_id'): self.blog_id = 1 if not self.defined('WP_CONTENT_DIR'): self.define('WP_CONTENT_DIR', self.ABSPATH + 'wp-content') # no trailing slash, full paths only - WP_CONTENT_URL is self.defined further down # Add self.define('WP_DEBUG', True); to wp-config.php to enable display of notices during development. if not self.defined('WP_DEBUG'): self.define('WP_DEBUG', False) # Add self.define('WP_DEBUG_DISPLAY', null); to wp-config.php use the globally configured setting for # display_errors and not force errors to be displayed. Use False to force display_errors off. if not self.defined('WP_DEBUG_DISPLAY'): self.define('WP_DEBUG_DISPLAY', True) # Add self.define('WP_DEBUG_LOG', True); to enable error logging to wp-content/debug.log. if not self.defined('WP_DEBUG_LOG'): self.define('WP_DEBUG_LOG', False) if not self.defined('WP_CACHE'): self.define('WP_CACHE', False) # Add self.define('SCRIPT_DEBUG', True); to wp-config.php to enable loading of non-minified, # non-concatenated scripts and stylesheets. if not self.defined('SCRIPT_DEBUG'): #if not empty( GLOBALS['wp_version'] ): if not Php.empty(self, 'wp_version'): #develop_src = False !== strpos( GLOBALS['wp_version'], '-src' ) develop_src = '-src' in self.wp_version else: develop_src = False self.define('SCRIPT_DEBUG', develop_src) # Private if not self.defined('MEDIA_TRASH'): self.define('MEDIA_TRASH', False) if not self.defined('SHORTINIT'): self.define('SHORTINIT', False) # Constants for features added to WP that should short-circuit their plugin implementations self.define('WP_FEATURE_BETTER_PASSWORDS', True) # Constants for expressing human-readable intervals # in their respective number of seconds. # Please note that these values are approximate and are provided for convenience. # For example, MONTH_IN_SECONDS wrongly assumes every month has 30 days and # YEAR_IN_SECONDS does not take leap years into account. # If you need more accuracy please consider using the DateTime class (https://secure.php.net/manual/en/class.datetime.php). self.define('MINUTE_IN_SECONDS', 60) self.define('HOUR_IN_SECONDS', 60 * self.MINUTE_IN_SECONDS) self.define('DAY_IN_SECONDS', 24 * self.HOUR_IN_SECONDS) self.define('WEEK_IN_SECONDS', 7 * self.DAY_IN_SECONDS) self.define('MONTH_IN_SECONDS', 30 * self.DAY_IN_SECONDS) self.define('YEAR_IN_SECONDS', 365 * self.DAY_IN_SECONDS)
def __init__(self, meta_query=False): ''' Constructor. @param array meta_query { Array of meta query clauses. When first-order clauses or sub-clauses use strings as their array keys, they may be referenced in the 'orderby' parameter of the parent query. @type str relation Optional. The MySQL keyword used to join the clauses of the query. Accepts 'AND', or 'OR'. Default 'AND'. @type array { Optional. An array of first-order clause parameters, or another fully-formed meta query. @type str key Meta key to filter by. @type str value Meta value to filter by. @type str compare MySQL operator used for comparing the value. Accepts '=', '!=', '>', '>=', '<', '<=', 'LIKE','NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'REGEXP', 'NOT REGEXP', 'RLIKE', 'EXISTS' or 'NOT EXISTS'. Default is 'IN' when `value`=array, '=' otherwise. @type str type MySQL data type that the meta_value column will be CAST to for comparisons. Accepts 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', or 'UNSIGNED'. Default is 'CHAR'. } } Inherited classes no long need to define 'self._obj=array()' in __init__() ''' # Array of metadata queries. # See WP_Meta_Query::__init__() for information on meta query arguments. # @access public @var array self.queries = array() # The relation between the queries. Can be one of 'AND' or 'OR'. # @access public @var string "self.relation" # Database table to query for the metadata. # @access public @var string "self.meta_table" # Column in meta_table that represents the ID of the object the metadata belongs to. # @access public @var string "self.meta_id_column" # Database table that where the metadata's objects are stored (eg self.wpdb.users). # @access public @var string "self.primary_table" # Column in primary_table that represents the ID of the object. # @access public @var string "self.primary_id_column" # A flat list of table aliases used in JOIN clauses. # @access protected @var array self.table_aliases = array() # A flat list of clauses, keyed by clause 'name'. # @access protected @var array self.clauses = array() # Whether the query contains any OR relations. # @access protected @var bool "self.has_or_relation = False" if not meta_query: return #if 'relation' in meta_query and strtoupper( meta_query['relation'] ) == 'OR': if (Php.isset(meta_query, 'relation') and Php.strtoupper(meta_query['relation']) == 'OR'): self.relation = 'OR' else: self.relation = 'AND' self.queries = self.sanitize_query(meta_query)
def set_props(self, args): ''' Sets post type properties. @param array|str args arguments for registering a post type. ''' import wp.i.post as WpP args = WiFc.wp_parse_args(args) # Filters the arguments for registering a post type. # @param array args Array of arguments for registering a post type. # @param string post_type Post type key. #args = apply_filters( 'register_post_type_args', args, self.name ) #has_edit_link = bool( args['_edit_link']) #err: '_edit_link' not in args! #has_edit_link = bool( args.get('_edit_link', None) ) has_edit_link = not Php.empty(args, '_edit_link') # Args prefixed with an underscore are reserved for internal use. defaults = array( ('labels', array()), ('description', ''), ('public', False), ('hierarchical', False), ('exclude_from_search', None), ('publicly_queryable', None), ('show_ui', None), ('show_in_menu', None), ('show_in_nav_menus', None), ('show_in_admin_bar', None), ('menu_position', None), ('menu_icon', None), ('capability_type', 'post'), ('capabilities', array()), ('map_meta_cap', None), ('supports', array()), ('register_meta_box_cb', None), ('taxonomies', array()), ('has_archive', False), ('rewrite', True), ('query_var', True), ('can_export', True), ('delete_with_user', None), ('_builtin', False), ('_edit_link', 'post.php?post=%d'), ) args = Php.array_merge(defaults, args) args['name'] = self.name # If not set, default to the setting for public. if None == args['publicly_queryable']: args['publicly_queryable'] = args['public'] # If not set, default to the setting for public. if None == args['show_ui']: args['show_ui'] = args['public'] # If not set, default to the setting for show_ui. if None == args['show_in_menu'] or not args['show_ui']: args['show_in_menu'] = args['show_ui'] # If not set, default to the whether the full UI is shown. if None == args['show_in_admin_bar']: args['show_in_admin_bar'] = bool(args['show_in_menu']) # If not set, default to the setting for public. if None == args['show_in_nav_menus']: args['show_in_nav_menus'] = args['public'] # If not set, default to True if public, False if publi: if None == args['exclude_from_search']: args['exclude_from_search'] = not args['public'] # Back compat with quirky handling in version 3.0. #14122. if (Php.empty(args, 'capabilities') and None is args['map_meta_cap'] and Php.in_array(args['capability_type'], array( 'post', 'page'))): args['map_meta_cap'] = True # If not set, default to False. if None == args['map_meta_cap']: args['map_meta_cap'] = False # If there's no specified edit link and no UI, remove the edit link. if not args['show_ui'] and not has_edit_link: args['_edit_link'] = '' #args['cap']=WpP.get_post_type_capabilities(Php.Object(args)) args['cap'] = WpP.get_post_type_capabilities(Php.Object(args), Wj=self.Wj) del args['capabilities'] if Php.is_array(args['capability_type']): args['capability_type'] = args['capability_type'][0] if False != args['query_var']: if True == args['query_var']: args['query_var'] = self.name else: args['query_var'] = WiF.sanitize_title_with_dashes( args['query_var']) if False != args['rewrite'] and ( self.Wj.is_admin() or '' != WiO.get_option('permalink_structure')): if not Php.is_array(args['rewrite']): args['rewrite'] = array() if Php.empty(args['rewrite'], 'slug'): args['rewrite']['slug'] = self.name if not Php.isset(args['rewrite'], 'with_front'): args['rewrite']['with_front'] = True if not Php.isset(args['rewrite'], 'pages'): args['rewrite']['pages'] = True if not Php.isset(args['rewrite'], 'feeds') or not args['has_archive']: args['rewrite']['feeds'] = bool(args['has_archive']) if not Php.isset(args['rewrite'], 'ep_mask'): if Php.isset(args, 'permalink_epmask'): args['rewrite']['ep_mask'] = args['permalink_epmask'] else: args['rewrite']['ep_mask'] = EP_PERMALINK for property_name, property_value in args.items(): setattr(self, property_name, property_value) self.labels = WpP.get_post_type_labels(self) #print('\n VT self.lables =', self.labels, type(self.labels)) self.label = self.labels.name
def get_sql_for_clause(self, clause, parent_query, clause_key=''): ''' Generate SQL JOIN and WHERE clauses for a first-order query clause. "First-order" means that it's an array with a 'key' or 'value'. @global wpdb wpdb WordPress database abstraction object. @param array clause Query clause, passed by reference. @param array parent_query Parent query array. @param string clause_key Optional. The array key used to name the clause in the original `meta_query` parameters. If not provided, a key will be generated automatically @return array { Array containing JOIN & WHERE SQL clauses to append to a 1st-order query @type string join SQL fragment to append to the main JOIN clause. @type string where SQL fragment to append to the main WHERE clause. } @return array clause since clause passed by ref, need to return clause ''' wpdb = WpC.WB.Wj.wpdb # global wpdb sql_chunks = array( ('where', array()), ('join', array()), ) if Php.isset(clause, 'compare'): clause['compare'] = clause['compare'].upper() else: clause['compare'] = 'IN' if (Php.isset( clause, 'value') and Php.is_array(clause['value'])) else '=' if (not Php.in_array( clause['compare'], array('=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS', 'NOT EXISTS', 'REGEXP', 'NOT REGEXP', 'RLIKE'))): clause['compare'] = '=' meta_compare = clause['compare'] # First build the JOIN clause, if one is required. join = '' # We prefer to avoid joins if possible. Look for an existing join compatible with this clause. alias = self.find_compatible_table_alias(clause, parent_query) if False is alias: i = len(self.table_aliases) alias = 'mt' + i if i else self.meta_table # JOIN clauses for NOT EXISTS have their own syntax. if 'NOT EXISTS' == meta_compare: join += " LEFT JOIN self.meta_table" join += " AS " + alias if i else '' join += wpdb.prepare( " ON (self.primary_table.self.primary_id_column = {} AND {} = %s )" .format(alias.self.meta_id_column, alias.meta_key), clause['key']) # All other JOIN clauses. else: join += " INNER JOIN self.meta_table" join += " AS alias" if i else '' join += " ON ( self.primary_table.self.primary_id_column = {} )".format( alias.self.meta_id_column) self.table_aliases[None] = alias sql_chunks['join'][None] = join # Save the alias to this clause, for future siblings to find. clause['alias'] = alias # Determine the data type. _meta_type = clause['type'] if Php.isset(clause, 'type') else '' meta_type = self.get_cast_for_type(_meta_type) clause['cast'] = meta_type # Fallback for clause keys is the table alias. Key must be a string. if is_int(clause_key) or not clause_key: clause_key = clause['alias'] # Ensure unique clause keys, so none are overwritten. iterator = 1 clause_key_base = clause_key while Php.isset(self.clauses, clause_key): clause_key = clause_key_base + '-' + iterator iterator += 1 # Store the clause in our flat array. #self.clauses[ clause_key ] =& clause # =& is assignment by reference, "means that both vars pointing at the # same data, and nothing is copied anywhere" self.clauses[ clause_key] = clause # py array or {} are mutable same obj # Next, build the WHERE clause. # meta_key. if 'key' in clause: if 'NOT EXISTS' == meta_compare: sql_chunks['where'][ None] = alias + '.' + self.meta_id_column + ' IS NULL' else: sql_chunks['where'][None] = wpdb.prepare( "alias.meta_key = %s", trim(clause['key'])) # meta_value. if 'value' in clause: meta_value = clause['value'] if meta_compare in ('IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'): if not Php.is_array(meta_value): meta_value = preg_split('/[,\s]+/', meta_value) else: meta_value = trim(meta_value) #switch ( meta_compare ) { if meta_compare in ('IN', 'NOT IN'): meta_compare_string = '(' + substr( str_repeat(',%s', len(meta_value)), 1) + ')' where = wpdb.prepare(meta_compare_string, meta_value) elif meta_compare in ('BETWEEN', 'NOT BETWEEN'): meta_value = Php.array_slice(meta_value, 0, 2) where = wpdb.prepare('%s AND %s', meta_value) elif meta_compare in ('LIKE', 'NOT LIKE'): meta_value = '%' + wpdb.esc_like(meta_value) + '%' where = wpdb.prepare('%s', meta_value) # EXISTS with a value is interpreted as '='. elif meta_compare == 'EXISTS': meta_compare = '=' where = wpdb.prepare('%s', meta_value) # 'value' is ignored for NOT EXISTS. elif meta_compare == 'NOT EXISTS': where = '' else: where = wpdb.prepare('%s', meta_value) if where: if 'CHAR' == meta_type: sql_chunks['where'][None] = "{} {} {}".format( alias.meta_value, meta_compare, where) else: sql_chunks['where'][None] = "CAST({} AS {}) {} {}".format( alias.meta_value, meta_type, meta_compare, where) # Multiple WHERE clauses (for meta_key and meta_value) should # be joined in parentheses. if 1 < len(sql_chunks['where']): sql_chunks['where'] = array( '( ' + Php.implode(' AND ', sql_chunks['where']) + ' )') #return sql_chunks return sql_chunks, clause #since clause passed by ref, need to return