* @license GPL-3.0+
* @link https://anspress.io
* @copyright 2014 Rahul Aryan
*/
/**
* Get slug of base page.
*
* @return string
* @since 2.0.0
* @since 3.0.0 Return `questions` if base page is not selected.
*/
function ap_base_page_slug() {
$base_page = get_post( ap_opt( 'base_page' ) );
if ( ! $base_page ) {
return 'questions';
}
$slug = $base_page->post_name;
if ( $base_page->post_parent > 0 ) {
$parent_page = get_post( $base_page->post_parent );
$slug = $parent_page->post_name . '/' . $slug;
}
return apply_filters( 'ap_base_page_slug', $slug );
}
/**
* Retrive permalink to base page.
*
* @return string URL to AnsPress base page
* @since 2.0.0
* @since 3.0.0 Return link to questions page if base page not selected.
*/
function ap_base_page_link() {
if ( empty( ap_opt( 'base_page' ) ) ) {
return home_url( '/questions/' );
}
return get_permalink( ap_opt( 'base_page' ) );
}
/**
* Get all theme names from AnsPress themes directory.
*
* @return array
*/
function ap_theme_list() {
$themes = array();
$dirs = array_filter( glob( ANSPRESS_THEME_DIR . '/*' ), 'is_dir' );
foreach ( $dirs as $dir ) {
$themes[ basename( $dir ) ] = basename( $dir );
}
return $themes;
}
/**
* Get location to a file. First file is being searched in child theme and then active theme
* and last fall back to AnsPress theme directory.
*
* @param string $file file name.
* @param mixed $plugin Plugin path. File is search inside AnsPress extension.
* @return string
* @since 0.1
* @since 2.4.7 Added filter `ap_get_theme_location`
*/
function ap_get_theme_location( $file, $plugin = false ) {
$child_path = get_stylesheet_directory() . '/anspress/' . $file;
$parent_path = get_template_directory() . '/anspress/' . $file;
// Checks if the file exists in the theme first,
// Otherwise serve the file from the plugin.
if ( file_exists( $child_path ) ) {
$template_path = $child_path;
} elseif ( file_exists( $parent_path ) ) {
$template_path = $parent_path;
} elseif ( false !== $plugin ) {
$template_path = $plugin . '/templates/' . $file;
} else {
$template_path = ANSPRESS_THEME_DIR . '/' . $file;
}
/**
* Filter AnsPress template file.
*
* @param string $template_path Path to template file.
* @since 2.4.7
*/
return apply_filters( 'ap_get_theme_location', $template_path );
}
/**
* Get url to a file
* Used for enqueue CSS or JS.
*
* @param string $file File name.
* @param mixed $plugin Plugin path, if calling from AnsPress extension.
* @return string
* @since 2.0
*/
function ap_get_theme_url( $file, $plugin = false, $ver = true ) {
$child_path = get_stylesheet_directory() . '/anspress/' . $file;
$parent_path = get_template_directory() . '/anspress/' . $file;
// Checks if the file exists in the theme first.
// Otherwise serve the file from the plugin.
if ( file_exists( $child_path ) ) {
$template_url = get_stylesheet_directory_uri() . '/anspress/' . $file;
} elseif ( file_exists( $parent_path ) ) {
$template_url = get_template_directory_uri() . '/anspress/' . $file;
} elseif ( false !== $plugin ) {
$template_url = $plugin . 'templates/' . $file;
} else {
$template_url = ANSPRESS_THEME_URL . '/' . $file;
}
return apply_filters( 'ap_theme_url', $template_url . ( true === $ver ? '?v=' . AP_VERSION : '' ) );
}
/**
* Check if current page is AnsPress. Also check if showing question or
* answer page in buddypress.
*
* @return boolean
*/
function is_anspress() {
// If buddypress installed.
if ( function_exists( 'bp_current_component' ) ) {
$bp_com = bp_current_component();
if ( 'questions' === $bp_com || 'answers' === $bp_com ) {
return true;
}
}
$queried_object = get_queried_object();
if ( empty( $queried_object ) || ! is_object( $queried_object ) ) {
return false;
}
if ( ! isset( $queried_object->ID ) ) {
return false;
}
if ( (int) ap_opt( 'base_page' ) === $queried_object->ID ) {
return true;
}
return false;
}
/**
* Check if current page is question page.
*
* @return boolean
*/
function is_question() {
if ( is_anspress() && 'question' === ap_current_page() ) {
return true;
}
return false;
}
/**
* Is if current AnsPress page is ask page.
*
* @return boolean
*/
function is_ask() {
if ( is_anspress() && ap_current_page() === 'ask' ) {
return true;
}
return false;
}
/**
* Get current question ID in single question page.
*
* @return integer|false
*/
function get_question_id() {
if ( is_question() && get_query_var( 'question_id' ) ) {
return (int) get_query_var( 'question_id' );
}
if ( is_question() && get_query_var( 'question' ) ) {
return get_query_var( 'question' );
}
if ( is_question() && get_query_var( 'question_name' ) ) {
$_post = get_page_by_path( get_query_var( 'question_name' ), OBJECT, 'question' ); // @codingStandardsIgnoreLine
return $_post->ID;
}
if ( get_query_var( 'edit_q' ) ) {
return get_query_var( 'edit_q' );
}
if ( ap_answer_the_object() ) {
return ap_get_post_field( 'post_parent' );
}
return false;
}
/**
* Return human readable time format.
*
* @param string $time Time.
* @param boolean $unix Is $time is unix.
* @param integer $show_full_date Show full date after some period. Default is 7 days in epoch.
* @param boolean|string $format Date format.
* @return string|null
* @since 2.4.7 Checks if showing default date format is enabled.
*/
function ap_human_time( $time, $unix = true, $show_full_date = 604800, $format = false ) {
if ( false === $format ) {
$format = get_option( 'date_format' );
}
if ( ! is_numeric( $time ) && ! $unix ) {
$time = strtotime( $time );
}
// If default date format is enabled then just return date.
if ( ap_opt( 'default_date_format' ) ) {
return date_i18n( $format, $time );
}
if ( $time ) {
if ( $show_full_date + $time > current_time( 'timestamp', true ) ) {
return sprintf(
/* translators: %s: human-readable time difference */
__( '%s ago', 'anspress-question-answer' ),
human_time_diff( $time, current_time( 'timestamp', true ) )
);
}
return date_i18n( $format, $time );
}
}
/**
* Check if user answered on a question.
*
* @param integer $question_id Question ID.
* @param integer $user_id User ID.
* @return boolean
*/
function ap_is_user_answered( $question_id, $user_id ) {
global $wpdb;
$cache = wp_cache_get( $user_id, 'ap_is_user_answered' );
if ( false !== $cache ) {
return $cache > 0 ? true : false;
}
$count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts where post_parent = %d AND ( post_author = %d AND post_type = 'answer')", $question_id, $user_id ) ); // db call ok.
wp_cache_set( $user_id, $count, 'ap_is_user_answered' );
return $count > 0 ? true : false;
}
/**
* Return link to asnwers.
*
* @param boolean|integer $question_id Question ID.
* @return string
*/
function ap_answers_link( $question_id = false ) {
if ( ! $question_id ) {
return get_permalink() . '#answers';
}
return get_permalink( $question_id ) . '#answers';
}
/**
* Return edit link for question and answer.
*
* @param mixed $_post Post.
* @return string
* @since 2.0.1
*/
function ap_post_edit_link( $_post ) {
$_post = ap_get_post( $_post );
$nonce = wp_create_nonce( 'edit-post-' . $_post->ID );
$base_page = 'question' === $_post->post_type ? ap_get_link_to( 'ask' ) : ap_get_link_to( 'edit' );
$edit_link = add_query_arg( array( 'id' => $_post->ID, '__nonce' => $nonce ), $base_page );
return apply_filters( 'ap_post_edit_link', $edit_link );
}
/**
* Trim strings.
*
* @param string $text String.
* @param int $limit Limit string to.
* @param string $ellipsis Ellipsis.
* @return string
*/
function ap_truncate_chars( $text, $limit = 40, $ellipsis = '...' ) {
$text = str_replace( array( "\r\n", "\r", "\n", "\t" ), ' ', $text );
if ( strlen( $text ) > $limit ) {
$endpos = strpos( $text, ' ', (string) $limit );
if ( false !== $endpos ) {
$text = trim( substr( $text, 0, $endpos ) ) . $ellipsis;
}
}
return $text;
}
/**
* Convert number to 1K, 1M etc.
*
* @param integer $num Number to convert.
* @param integer $precision Precision.
* @return string
*/
function ap_short_num( $num, $precision = 2 ) {
if ( $num >= 1000 && $num < 1000000 ) {
$n_format = number_format( $num / 1000, $precision ) . 'K';
} elseif ( $num >= 1000000 && $num < 1000000000 ) {
$n_format = number_format( $num / 1000000, $precision ) . 'M';
} elseif ( $num >= 1000000000 ) {
$n_format = number_format( $num / 1000000000, $precision ) . 'B';
} else {
$n_format = $num;
}
return $n_format;
}
/**
* Sanitize comma delimited strings.
*
* @param string|array $str Comma delimited string.
* @param string $pieces_type Type of piece, string or number.
* @return string
*/
function sanitize_comma_delimited( $str, $pieces_type = 'int' ) {
$str = ! is_array( $str ) ? explode( ',', $str ) : $str;
if ( ! empty( $str ) ) {
$str = wp_unslash( $str );
$glue = 'int' !== $pieces_type ? '","' : ',';
$sanitized = [];
foreach ( $str as $s ) {
if ( '0' == $s || ! empty ( $s ) ) {
$sanitized[] = 'int' === $pieces_type ? intval( $s ) : sanitize_text_field( $s );
}
}
$new_str = implode( $glue, esc_sql( $sanitized ) );
if ( 'int' !== $pieces_type ) {
return '"' . $new_str . '"';
}
return $new_str;
}
}
/**
* Check if doing ajax request.
*
* @return boolean
* @since 2.0.1
* @since 3.0.0 Check if `ap_ajax_action` is set.
*/
function ap_is_ajax() {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $_REQUEST['ap_ajax_action'] ) ) { // input var ok.
return true;
}
return false;
}
/**
* Allow HTML tags.
*
* @return array
* @since 0.9
*/
function ap_form_allowed_tags() {
global $ap_kses_check;
$ap_kses_check = true;
$allowed_style = array(
'align' => true,
);
$allowed_tags = array(
'p' => array(
'style' => $allowed_style,
'title' => true,
),
'span' => array(
'style' => $allowed_style,
),
'a' => array(
'href' => true,
'title' => true,
),
'br' => array(),
'em' => array(),
'strong' => array(
'style' => $allowed_style,
),
'pre' => array(),
'code' => array(),
'blockquote' => array(),
'img' => array(
'src' => true,
'style' => $allowed_style,
),
'ul' => array(),
'ol' => array(),
'li' => array(),
'del' => array(),
'br' => array(),
);
/*
* FILTER: ap_allowed_tags
* Before passing allowed tags
*/
return apply_filters( 'ap_allowed_tags', $allowed_tags );
}
/**
* Send a array as a JSON.
*
* @param array $result Results.
*/
function ap_send_json( $result = array() ) {
header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
$result['is_ap_ajax'] = true;
$json = '
' . wp_json_encode( $result, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP ) . '
';
wp_die( $json ); // xss ok.
}
/**
* Highlight matching words.
*
* @param string $text String.
* @param string $words Words need to higlight.
* @return string
* @since 2.0
*/
function ap_highlight_words( $text, $words ) {
$words = explode( ' ', $words );
foreach ( $words as $word ) {
// Quote the text for regex.
$word = preg_quote( $word );
// Highlight the words.
$text = preg_replace( "/\b($word)\b/i", '\1', $text );
}
return $text;
}
/**
* Return response with type and message.
*
* @param string $id messge id.
* @param bool $only_message return message string instead of array.
* @return string
* @since 2.0.0
*/
function ap_responce_message( $id, $only_message = false ) {
$msg = array(
'success' => array( 'type' => 'success', 'message' => __( 'Success', 'anspress-question-answer' ) ),
'something_wrong' => array( 'type' => 'error', 'message' => __( 'Something went wrong, last action failed.', 'anspress-question-answer' ) ),
'comment_edit_success' => array( 'type' => 'success', 'message' => __( 'Comment updated successfully.', 'anspress-question-answer' ) ),
'cannot_vote_own_post' => array( 'type' => 'warning', 'message' => __( 'You cannot vote on your own question or answer.', 'anspress-question-answer' ) ),
'no_permission_to_view_private' => array( 'type' => 'warning', 'message' => __( 'You do not have permission to view private posts.', 'anspress-question-answer' ) ),
'captcha_error' => array( 'type' => 'error', 'message' => __( 'Please check captcha field and resubmit it again.', 'anspress-question-answer' ) ),
'post_image_uploaded' => array( 'type' => 'success', 'message' => __( 'Image uploaded successfully', 'anspress-question-answer' ) ),
'answer_deleted_permanently' => array( 'type' => 'success', 'message' => __( 'Answer has been deleted permanently', 'anspress-question-answer' ) ),
'upload_limit_crossed' => array( 'type' => 'warning', 'message' => __( 'You have already attached maximum numbers of allowed uploads.', 'anspress-question-answer' ) ),
'profile_updated_successfully' => array( 'type' => 'success', 'message' => __( 'Your profile has been updated successfully.', 'anspress-question-answer' ) ),
'voting_down_disabled' => array( 'type' => 'warning', 'message' => __( 'Voting down is disabled.', 'anspress-question-answer' ) ),
'you_cannot_vote_on_restricted' => array( 'type' => 'warning', 'message' => __( 'You cannot vote on restricted posts', 'anspress-question-answer' ) ),
);
/*
* FILTER: ap_responce_message
* Can be used to alter response messages
* @var array
* @since 2.0.1
*/
$msg = apply_filters( 'ap_responce_message', $msg );
if ( isset( $msg[ $id ] ) && $only_message ) {
return $msg[ $id ]['message'];
}
if ( isset( $msg[ $id ] ) ) {
return $msg[ $id ];
}
return false;
}
/**
* Format an array as valid AnsPress ajax response.
*
* @param array|string $results Response to send.
* @return array
*/
function ap_ajax_responce( $results ) {
if ( ! is_array( $results ) ) {
$message_id = $results;
$results = array();
$results['message'] = $message_id;
}
$results['ap_responce'] = true;
if ( isset( $results['message'] ) ) {
$error_message = ap_responce_message( $results['message'] );
if ( false !== $error_message ) {
$results['message'] = $error_message['message'];
$results['message_type'] = $error_message['type'];
}
}
// Send requested template.
if ( isset( $results['template'] ) ) {
$template_file = ap_get_theme_url( 'js-template/' . $results['template'] . '.html' );
if ( ap_env_dev() ) {
$template_file = $template_file . '&time=' . time();
}
$results['apTemplate'] = array(
'name' => $results['template'],
'template' => $template_file,
);
}
/*
* FILTER: ap_ajax_responce
* Can be used to alter ap_ajax_responce
* @var array
* @since 2.0.1
*/
$results = apply_filters( 'ap_ajax_responce', $results );
return $results;
}
/**
* Array map callback.
*
* @param array $a Array.
* @return mixed
*/
function ap_meta_array_map( $a ) {
return $a[0];
}
/**
* Return the current page url.
*
* @param array $args Arguments.
* @return string
* @since 2.0.0
*/
function ap_current_page_url( $args ) {
$base = rtrim( get_permalink(), '/' );
if ( get_option( 'permalink_structure' ) !== '' ) {
$link = $base . '/';
if ( ! empty( $args ) ) {
foreach ( $args as $k => $s ) {
$link .= $k . '/' . $s . '/';
}
}
} else {
$link = add_query_arg( $args, $base );
}
return $link;
}
/**
* Sort array by order value. Group array which have same order number and then sort them.
*
* @param array $array Array to order.
* @return array
* @since 2.0.0
*/
function ap_sort_array_by_order( $array ) {
$new_array = array();
if ( ! empty( $array ) && is_array( $array ) ) {
$group = array();
foreach ( (array) $array as $k => $a ) {
if ( ! is_array( $a ) ) {
return;
}
$order = $a['order'];
$group[ $order ][] = $a;
$group[ $order ]['order'] = $order;
}
usort( $group, 'ap_sort_order_callback' );
foreach ( (array) $group as $a ) {
foreach ( (array) $a as $k => $newa ) {
if ( 'order' !== $k ) {
$new_array[] = $newa;
}
}
}
return $new_array;
}
}
/**
* Callback for @uses ap_sort_array_by_order.
*
* @param array $a Array.
* @param array $b Array.
* @return integer
*/
function ap_sort_order_callback( $a, $b ) {
return $a['order'] - $b['order'];
}
/**
* Echo anspress links.
*
* @param string|array $sub Sub page.
* @since 2.1
*/
function ap_link_to( $sub ) {
echo ap_get_link_to( $sub ); // xss ok.
}
/**
* Return link to AnsPress pages.
*
* @param string|array $sub Sub pages/s.
* @return string
*/
function ap_get_link_to( $sub ) {
/**
* Define default AnsPress page slugs.
*
* @var array
*/
$default_pages = array(
'question' => ap_opt( 'question_page_slug' ),
'ask' => ap_opt( 'ask_page_slug' ),
'users' => ap_opt( 'users_page_slug' ),
'user' => ap_opt( 'user_page_slug' ),
);
$default_pages = apply_filters( 'ap_default_page_slugs', $default_pages );
if ( is_array( $sub ) && isset( $sub['ap_page'] ) && isset( $default_pages[ $sub['ap_page'] ] ) ) {
$sub['ap_page'] = $default_pages[ $sub['ap_page'] ];
} elseif ( ! is_array( $sub ) && ! empty( $sub ) && isset( $default_pages[ $sub ] ) ) {
$sub = $default_pages[ $sub ];
}
$base = rtrim( ap_base_page_link(), '/' );
$args = '';
if ( get_option( 'permalink_structure' ) !== '' ) {
if ( ! is_array( $sub ) && 'base' !== $sub ) {
$args = $sub ? '/' . $sub : '';
} elseif ( is_array( $sub ) ) {
$args = '/';
if ( ! empty( $sub ) ) {
foreach ( (array) $sub as $s ) {
$args .= $s . '/';
}
}
}
$args = rtrim( $args, '/' ) . '/';
} else {
if ( ! is_array( $sub ) ) {
$args = $sub ? '&ap_page=' . $sub : '';
} elseif ( is_array( $sub ) ) {
$args = '';
if ( ! empty( $sub ) ) {
foreach ( $sub as $k => $s ) {
$args .= '&' . $k . '=' . $s;
}
}
}
}
return esc_url( apply_filters( 'ap_link_to', $base . $args, $sub ) );
}
/**
* Return the total numbers of post.
*
* @param string $post_type Post type.
* @param boolean|string $ap_type ap_meta type.
* @return array
* @since 2.0.0
* @TODO use new qameta table.
*/
function ap_total_posts_count( $post_type = 'question', $ap_type = false, $user_id = false ) {
global $wpdb;
if ( 'question' === $post_type ) {
$type = "p.post_type = 'question'";
} elseif ( 'answer' === $post_type ) {
$type = "p.post_type = 'answer'";
} else {
$type = "(p.post_type = 'question' OR p.post_type = 'answer')";
}
$meta = '';
$join = '';
if ( 'flag' === $ap_type ) {
$meta = 'AND qameta.flags > 0';
$join = "INNER JOIN {$wpdb->ap_qameta} qameta ON p.ID = qameta.post_id";
} elseif ( 'unanswered' === $ap_type ) {
$meta = 'AND qameta.answers = 0';
$join = "INNER JOIN {$wpdb->ap_qameta} qameta ON p.ID = qameta.post_id";
} elseif ( 'best_answer' === $ap_type ) {
$meta = 'AND qameta.selected > 0';
$join = "INNER JOIN {$wpdb->ap_qameta} qameta ON p.ID = qameta.post_id";
}
$where = "WHERE p.post_status NOT IN ('trash', 'draft') AND $type $meta";
if ( false !== $user_id && (int) $user_id > 0 ) {
$where .= ' AND p.post_author = ' . (int) $user_id;
}
$where = apply_filters( 'ap_total_posts_count', $where );
$query = "SELECT count(*) as count, p.post_status FROM $wpdb->posts p $join $where GROUP BY p.post_status";
$cache_key = md5( $query );
$count = wp_cache_get( $cache_key, 'counts' );
if ( false !== $count ) {
return $count;
}
$count = $wpdb->get_results( $query, ARRAY_A ); // @codingStandardsIgnoreLine
$counts = array();
foreach ( (array) get_post_stati() as $state ) {
$counts[ $state ] = 0;
}
$counts['total'] = 0;
foreach ( (array) $count as $row ) {
$counts[ $row['post_status'] ] = $row['count'];
$counts['total'] += $row['count'];
}
wp_cache_set( $cache_key, (object) $counts, 'counts' );
return (object) $counts;
}
/**
* Return total numbers of published questions.
*
* @return integer
*/
function ap_total_published_questions() {
$posts = ap_total_posts_count();
return $posts->publish;
}
/**
* Get total numbers of solved question.
*
* @param string $type Valid values are int or object.
* @return int|object
*/
function ap_total_solved_questions( $type = 'int' ) {
global $wpdb;
$query = "SELECT count(*) as count, p.post_status FROM $wpdb->posts p INNER JOIN $wpdb->ap_qameta qameta ON p.ID = qameta.post_id WHERE p.post_type = 'question' AND qameta.selected_id IS NOT NULL AND qameta.selected_id > 0 GROUP BY p.post_status";
$cache_key = md5( $query );
$count = wp_cache_get( $cache_key, 'counts' );
if ( false !== $count ) {
return $count;
}
$count = $wpdb->get_results( $query, ARRAY_A ); // unprepared SQL ok, db call ok.
$counts = array( 'total' => 0 );
foreach ( get_post_stati() as $state ) {
$counts[ $state ] = 0;
}
foreach ( (array) $count as $row ) {
$counts[ $row['post_status'] ] = (int) $row['count'];
$counts['total'] += (int) $row['count'];
}
wp_cache_set( $cache_key, (object) $counts, 'counts' );
$counts = (object) $counts;
if ( 'int' === $type ) {
return $counts->publish + $counts->private_post;
}
return $counts;
}
/**
* Get current sorting type.
*
* @return string
* @since 2.1
*/
function ap_get_sort() {
return ap_sanitize_unslash( 'ap_sort', 'p', null );
}
/**
* Register AnsPress menu.
*
* @param string $slug Menu slug.
* @param string $title Menu title.
* @param string $link Menu link.
*/
function ap_register_menu( $slug, $title, $link ) {
anspress()->menu[ $slug ] = array( 'title' => $title, 'link' => $link );
}
/**
* Remove white space from string.
*
* @param string $contents String.
* @return string
*/
function ap_trim_traling_space( $contents ) {
return preg_replace( '#(^( |\s)+|( |\s)+$)#', '', $contents );
}
/**
* Replace square brackets in a string.
*
* @param string $contents String.
*/
function ap_replace_square_bracket( $contents ) {
$contents = str_replace( '[', '[', $contents );
$contents = str_replace( ']', ']', $contents );
return $contents;
}
/**
* Create base page for AnsPress.
*
* This function is called in plugin activation. This function checks if base page already exists,
* if not then it create a new one and update the option.
*
* @see anspress_activate
* @since 2.3
*/
function ap_create_base_page() {
// Check if page already exists.
$page_id = ap_opt( 'base_page' );
$_post = ap_get_post( $page_id );
if ( ! $_post ) {
$args = array();
$args['post_type'] = 'page';
$args['post_content'] = '[anspress]';
$args['post_status'] = 'publish';
$args['post_title'] = __( 'Questions', 'anspress-question-answer' );
$args['post_name'] = 'questions';
$args['comment_status'] = 'closed';
// Now create post.
$new_page_id = wp_insert_post( $args );
if ( $new_page_id ) {
$page = ap_get_post( $new_page_id );
ap_opt( 'base_page', $page->ID );
ap_opt( 'base_page_id', $page->post_name );
}
}
}
/**
* Return question id with solved prefix if answer is accepted.
*
* @param boolean|integer $question_id Question ID.
* @return string
*
* @since 2.3 [@see ap_page_title]
*/
function ap_question_title_with_solved_prefix( $question_id = false ) {
if ( false === $question_id ) {
$question_id = get_question_id();
}
$solved = ap_have_answer_selected( $question_id );
if ( ap_opt( 'show_solved_prefix' ) ) {
return get_the_title( $question_id ) . ' ' . ($solved ? __( '[Solved] ', 'anspress-question-answer' ) : '');
}
return get_the_title( $question_id );
}
/**
* Verify the __nonce field.
*
* @param string $action Action.
* @return bool
* @since 2.4
*/
function ap_verify_nonce( $action ) {
return wp_verify_nonce( ap_sanitize_unslash( '__nonce', 'p' ), $action );
}
/**
* Verify default ajax nonce field.
*
* @return boolean
*/
function ap_verify_default_nonce() {
$nonce_name = isset( $_REQUEST['ap_ajax_nonce'] ) ? 'ap_ajax_nonce' : '__nonce'; // input var okay.
if ( ! isset( $_REQUEST[ $nonce_name ] ) ) { // input var okay.
return false;
}
return wp_verify_nonce( ap_sanitize_unslash( $nonce_name, 'p' ), 'ap_ajax_nonce' );
}
/**
* Parse search string to array.
*
* @param string $str search string.
* @return array
*/
function ap_parse_search_string( $str ) {
$output = array();
// Split by space.
$bits = explode( ' ', $str );
// Process pairs.
foreach ( $bits as $id => $pair ) {
// Split the pair.
$pair_bits = explode( ':', $pair );
// This was actually a pair.
if ( count( $pair_bits ) === 2 ) {
$values = explode( ',', $pair_bits[1] );
$sanitized = array();
if ( is_array( $values ) && ! empty( $values ) ) {
foreach ( $values as $value ) {
if ( ! empty( $value ) ) {
$sanitized[] = sanitize_text_field( $value );
}
}
}
if ( count( $sanitized ) > 0 ) {
// Use left part of pair as index and push right part to array.
if ( ! empty( $pair_bits[0] ) ) {
$output[ sanitize_text_field( $pair_bits[0] ) ] = $sanitized;
}
}
// Remove this pair from $bits.
unset( $bits[ $id ] );
} // Not a pair, presumably reached the query.
else {
// Exit the loop.
break;
}
}
// Rebuild query with remains of $bits.
$output['q'] = sanitize_text_field( implode( ' ', $bits ) );
return $output;
}
/**
* Send properly formatted AnsPress json string.
*
* @param array|string $response Response array or string.
*/
function ap_ajax_json( $response ) {
ap_send_json( ap_ajax_responce( $response ) );
}
/**
* Check if object is profile menu item.
*
* @param object $menu Menu Object.
* @return boolean
*/
function ap_is_profile_menu( $menu ) {
return in_array( 'anspress-page-profile', $menu->classes, true );
}
/**
* Get the IDs of answer by question ID.
*
* @param integer $question_id Question post ID.
* @return object
* @since 2.4
*/
function ap_questions_answer_ids( $question_id ) {
global $wpdb;
$cache = wp_cache_get( $question_id, 'ap_questions_answer_ids' );
if ( false !== $cache ) {
return $cache;
}
$ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'answer' AND post_parent=%d", $question_id ) ); // db call ok.
wp_cache_set( $question_id, $ids, 'ap_questions_answer_ids' );
return $ids;
}
/**
* Whitelist array items.
*
* @param array $master_keys Master keys.
* @param array $array Array to filter.
* @return array
*/
function ap_whitelist_array( $master_keys, $array ) {
return array_intersect_key( $array, array_flip( $master_keys ) );
}
/**
* Read env file of AnsPress.
*
* @return string
*/
function ap_read_env() {
$file = ANSPRESS_DIR . '/env';
$cache = wp_cache_get( 'ap_env', 'ap' );
if ( false !== $cache ) {
return $cache;
}
if ( file_exists( $file ) ) {
// Get the contents of env file.
$content = file_get_contents( $file ); // @codingStandardsIgnoreLine.
wp_cache_set( 'ap_env', $content, 'ap' );
return $content;
}
}
/**
* Check if anspress environment is development.
*
* @return boolean
*/
function ap_env_dev() {
if ( 'development' === ap_read_env() ) {
return true;
}
return false;
}
/**
* Append table name in $wpdb.
*/
function ap_append_table_names() {
global $wpdb;
$wpdb->ap_qameta = $wpdb->prefix . 'ap_qameta';
$wpdb->ap_votes = $wpdb->prefix . 'ap_votes';
$wpdb->ap_views = $wpdb->prefix . 'ap_views';
$wpdb->ap_reputations = $wpdb->prefix . 'ap_reputations';
$wpdb->ap_subscribers = $wpdb->prefix . 'ap_subscribers';
$wpdb->ap_email_queues = $wpdb->prefix . 'ap_email_queues';
$wpdb->ap_email_content = $wpdb->prefix . 'ap_email_content';
}
ap_append_table_names();
/**
* Check if $_REQUEST var exists and get value. If not return default.
*
* @param string $var Variable name.
* @param mixed $default Default value.
* @return mixed
* @since 3.0.0
*/
function ap_isset_post_value( $var, $default = '' ) {
if ( isset( $_REQUEST[ $var ] ) ) { // input var okay.
return wp_unslash( $_REQUEST[ $var ] ); // input var okay, xss ok, sanitization ok.
}
return $default;
}
/**
* Get active list filter by filter key.
*
* @param string|null $filter Filter key.
* @return false|string|array
* @since 4.0.0
*/
function ap_get_current_list_filters( $filter = null ) {
$default = [ 'order_by' => ap_opt( 'question_order_by' ) ];
$filters = wp_unslash( ap_isset_post_value( 'filters' ) );
if ( empty( $filters ) || ! is_array( $filters ) ) {
$filters = [];
}
$filters = $filters + $default;
$filters = array_unique( array_filter( $filters ), SORT_REGULAR );
foreach ( (array) $filters as $k => $f ) {
if ( is_array( $f ) ) {
$filters[ $k ] = array_unique( array_filter( $f ), SORT_REGULAR );
}
}
if ( null === $filter ) {
return $filters;
}
if ( ! empty( $filters[ $filter ] ) ) {
return $filters[ $filter ];
}
return [];
}
/**
* Sanitize and unslash string or array or post/get value at the same time.
*
* @param string|array $str String or array to sanitize. Or post/get key name.
* @param boolean|string $from Get value from `$_REQUEST` or `query_var`. Valid values: request, query_var.
* @param mixed $default Default value if variable not found.
* @return array|string
* @since 3.0.0
*/
function ap_sanitize_unslash( $str, $from = false, $default = '' ) {
// If not false then get from $_REQUEST or query_var.
if ( false !== $from ) {
if ( in_array( strtolower( $from ), [ 'request', 'post', 'get', 'p', 'g', 'r' ], true ) ) {
$str = ap_isset_post_value( $str, $default );
} elseif ( 'query_var' === $from ) {
$str = get_query_var( $str );
}
}
if ( '' === $str ) {
return $default;
}
if ( is_array( $str ) ) {
$str = wp_unslash( $str );
return array_map( 'sanitize_text_field', $str );
}
return sanitize_text_field( wp_unslash( $str ) );
}
/**
* Return post status based on AnsPress options.
*
* @param boolean|integer $user_id ID of user creating question.
* @param string $post_type Post type, question or answer.
* @param boolean $edit Is editing post.
* @return string
* @since 3.0.0
*/
function ap_new_edit_post_status( $user_id = false, $post_type = 'question', $edit = false ) {
if ( false === $user_id ) {
$user_id = get_current_user_id();
}
$new_edit = $edit ? 'edit' : 'new';
$option_key = $new_edit . '_' . $post_type . '_status';
$status = 'publish';
// If super admin or user have no_moderation cap.
if ( is_super_admin( $user_id ) || user_can( $user_id, 'ap_no_moderation' ) ) {
return $status;
}
if ( ap_opt( $option_key ) === 'moderate' && ! ( user_can( $user_id, 'ap_moderator' ) || is_super_admin( $user_id ) ) ) {
$status = 'moderate';
}
// If anonymous post status is set to moderate.
if ( empty( $user_id ) && ap_opt( 'anonymous_post_status' ) === 'moderate' ) {
$status = 'moderate';
}
return $status;
}
/**
* Find duplicate post by content.
*
* @param string $content Post content.
* @param string $post_type Post type.
* @param integer|false $question_id Question ID.
* @return boolean|false
* @since 3.0.0
*/
function ap_find_duplicate_post( $content, $post_type = 'question', $question_id = false ) {
if ( ! ap_opt( 'duplicate_check' ) ) {
return false;
}
global $wpdb;
$content = ap_sanitize_description_field( $content );
// Return if content is empty. But blank content will be checked.
if ( empty( $content ) ) {
return false;
}
$question_q = false !== $question_id ? $wpdb->prepare( ' AND post_parent= %d', $question_id ) : '';
$var = (int) $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_content = %s AND post_type = %s {$question_q} LIMIT 1", $content, $post_type ) ); // @codingStandardsIgnoreLine
if ( $var > 0 ) {
return $var;
}
return false;
}
/**
* Check if question suggestion is disabled.
*
* @return boolean
* @since 3.0.0
*/
function ap_disable_question_suggestion() {
/**
* Modify ap_disable_question_suggestion.
*
* @param boolean $enable Default is false.
* @since 3.0.0
*/
return (bool) apply_filters( 'ap_disable_question_suggestion', false );
}
/**
* Pre fetch users and update cache.
*
* @param array $ids User ids.
* @since 4.0.0
*/
function ap_post_author_pre_fetch( $ids ) {
$users = get_users( [ 'include' => $ids, 'fields' => array( 'ID', 'user_login', 'user_nicename', 'user_email', 'display_name' ) ] );
foreach ( (array) $users as $user ) {
update_user_caches( $user );
}
update_meta_cache( 'user', $ids );
}
/**
* Activity type to human readable title.
*
* @param string $type Activity type.
* @return string
*/
function ap_activity_short_title( $type ) {
$title = array(
'new_question' => __( 'asked', 'anspress-question-answer' ),
'approved_question' => __( 'approved', 'anspress-question-answer' ),
'approved_answer' => __( 'approved', 'anspress-question-answer' ),
'new_answer' => __( 'answered', 'anspress-question-answer' ),
'delete_answer' => __( 'deleted answer', 'anspress-question-answer' ),
'restore_answer' => __( 'restored answer', 'anspress-question-answer' ),
'new_comment' => __( 'commented', 'anspress-question-answer' ),
'delete_comment' => __( 'deleted comment', 'anspress-question-answer' ),
'new_comment_answer' => __( 'commented on answer', 'anspress-question-answer' ),
'edit_question' => __( 'edited question', 'anspress-question-answer' ),
'edit_answer' => __( 'edited answer', 'anspress-question-answer' ),
'edit_comment' => __( 'edited comment', 'anspress-question-answer' ),
'edit_comment_answer' => __( 'edited comment on answer', 'anspress-question-answer' ),
'answer_selected' => __( 'selected answer', 'anspress-question-answer' ),
'answer_unselected' => __( 'unselected answer', 'anspress-question-answer' ),
'status_updated' => __( 'updated status', 'anspress-question-answer' ),
'best_answer' => __( 'selected as best answer', 'anspress-question-answer' ),
'unselected_best_answer' => __( 'unselected as best answer', 'anspress-question-answer' ),
'changed_status' => __( 'changed status', 'anspress-question-answer' ),
);
$title = apply_filters( 'ap_activity_short_title', $title );
if ( isset( $title[ $type ] ) ) {
return $title[ $type ];
}
return $type;
}
/**
* Return canonical URL of current page.
*
* @return string
* @since 3.0.0
*/
function ap_canonical_url() {
$canonical_url = ap_get_link_to( get_query_var( 'ap_page' ) );
if ( is_question() ) {
$canonical_url = get_permalink( get_question_id() );
}
/**
* Filter AnsPress canonical URL.
*
* @param string $canonical_url Current URL.
* @return string
* @since 3.0.0
*/
$canonical_url = apply_filters( 'ap_canonical_url', $canonical_url );
return esc_url( $canonical_url );
}
/**
* For user display name
* It can be filtered for adding cutom HTML.
*
* @param mixed $args Arguments.
* @return string
* @since 0.1
*/
function ap_user_display_name( $args = array() ) {
global $post;
$defaults = array(
'user_id' => get_the_author_meta( 'ID' ),
'html' => false,
'echo' => false,
'anonymous_label' => __( 'Anonymous', 'anspress-question-answer' ),
);
if ( ! is_array( $args ) ) {
$defaults['user_id'] = $args;
$args = $defaults;
} else {
$args = wp_parse_args( $args, $defaults );
}
extract( $args ); // @codingStandardsIgnoreLine
$user = get_userdata( $user_id );
if ( $user ) {
$return = ! $html ? $user->display_name : '' . $user->display_name . '';
} elseif ( $post && in_array( $post->post_type, [ 'question', 'answer' ], true ) ) {
$post_fields = ap_get_post_field( 'fields' );
if ( ! $html ) {
if ( is_array( $post_fields ) && ! empty( $post_fields['anonymous_name'] ) ) {
$return = $post_fields['anonymous_name'];
} else {
$return = $anonymous_label;
}
} else {
if ( is_array( $post_fields ) && ! empty( $post_fields['anonymous_name'] ) ) {
$return = $post_fields['anonymous_name'] . __( ' (anonymous)', 'anspress-question-answer' );
} else {
$return = $anonymous_label;
}
}
} else {
if ( ! $html ) {
$return = $anonymous_label;
} else {
$return = $anonymous_label;
}
}
/**
* FILTER: ap_user_display_name
* Filter can be used to alter display name
*
* @var string
* @since 2.0.1
*/
$return = apply_filters( 'ap_user_display_name', $return, $args );
if ( ! $echo ) {
return $return;
}
echo $return; // xss okay.
}
/**
* Return Link to user pages.
*
* @param boolean|integer $user_id user id.
* @param string $sub page slug.
* @return string
* @since unknown
*/
function ap_user_link( $user_id = false, $sub = false ) {
$link = '';
if ( false === $user_id ) {
$user_id = get_the_author_meta( 'ID' );
}
if ( $user_id < 1 ) {
$link = '#anonymousUser';
} else {
if ( function_exists( 'bp_core_get_userlink' ) ) {
return bp_core_get_userlink( $user_id, false, true );
} elseif ( function_exists( 'userpro' ) ) {
global $userpro;
return $userpro->permalink( $user_id );
}
if ( empty( $user_id ) ) {
return false;
}
$link = get_author_posts_url( $user_id );
}
return apply_filters( 'ap_user_link', $link, $user_id, $sub );
}
/**
* Return current page in user profile.
*
* @since 2.0.1
* @return string
* @since 2.4.7 Added new filter `ap_active_user_page`.
*/
function ap_active_user_page() {
$user_page = sanitize_text_field( get_query_var( 'user_page' ) );
if ( ! empty( $user_page ) ) {
return $user_page;
}
$page = 'about';
return apply_filters( 'ap_active_user_page', $page );
}
/**
* Return or echo hovercard data attribute.
*
* @param integer $user_id User id.
* @param boolean $echo Echo or return? default is true.
* @return string
*/
function ap_hover_card_attributes( $user_id, $echo = true ) {
if ( $user_id > 0 ) {
$attr = ' data-userid="' . $user_id . '"';
if ( true !== $echo ) {
return $attr;
}
echo $attr; // xss okay.
}
}
/**
* User name and link with anchor tag.
*
* @param string $user_id User ID.
* @param boolean $echo Echo or return.
*/
function ap_user_link_anchor( $user_id, $echo = true ) {
$name = ap_user_display_name( $user_id );
if ( $user_id < 1 ) {
if ( $echo ) {
echo $name; // xss okay.
} else {
return $name;
}
}
$html = '';
$html .= $name;
$html .= '';
if ( $echo ) {
echo $html; // xss okay.
}
return $html;
}
/**
* Remove stop words from a string.
*
* @param string $str String from need to be filtered.
* @return string
*/
function ap_remove_stop_words( $str ) {
// EEEEEEK Stop words.
$common_words = array( 'a','able','about','above','abroad','according','accordingly','across','actually','adj','after','afterwards','again','against','ago','ahead','ain\'t','all','allow','allows','almost','alone','along','alongside','already','also','although','always','am','amid','amidst','among','amongst','an','and','another','any','anybody','anyhow','anyone','anything','anyway','anyways','anywhere','apart','appear','appreciate','appropriate','are','aren\'t','around','as','a\'s','aside','ask','asking','associated','at','available','away','awfully','b','back','backward','backwards','be','became','because','become','becomes','becoming','been','before','beforehand','begin','behind','being','believe','below','beside','besides','best','better','between','beyond','both','brief','but','by','c','came','can','cannot','cant','can\'t','caption','cause','causes','certain','certainly','changes','clearly','c\'mon','co','co.','com','come','comes','concerning','consequently','consider','considering','contain','containing','contains','corresponding','could','couldn\'t','course','c\'s','currently','d','dare','daren\'t','definitely','described','despite','did','didn\'t','different','directly','do','does','doesn\'t','doing','done','don\'t','down','downwards','during','e','each','edu','eg','eight','eighty','either','else','elsewhere','end','ending','enough','entirely','especially','et','etc','even','ever','evermore','every','everybody','everyone','everything','everywhere','ex','exactly','example','except','f','fairly','far','farther','few','fewer','fifth','first','five','followed','following','follows','for','forever','former','formerly','forth','forward','found','four','from','further','furthermore','g','get','gets','getting','given','gives','go','goes','going','gone','got','gotten','greetings','h','had','hadn\'t','half','happens','hardly','has','hasn\'t','have','haven\'t','having','he','he\'d','he\'ll','hello','help','hence','her','here','hereafter','hereby','herein','here\'s','hereupon','hers','herself','he\'s','hi','him','himself','his','hither','hopefully','how','howbeit','however','hundred','i','i\'d','ie','if','ignored','i\'ll','i\'m','immediate','in','inasmuch','inc','inc.','indeed','indicate','indicated','indicates','inner','inside','insofar','instead','into','inward','is','isn\'t','it','it\'d','it\'ll','its','it\'s','itself','i\'ve','j','just','k','keep','keeps','kept','know','known','knows','l','last','lately','later','latter','latterly','least','less','lest','let','let\'s','like','liked','likely','likewise','little','look','looking','looks','low','lower','ltd','m','made','mainly','make','makes','many','may','maybe','mayn\'t','me','mean','meantime','meanwhile','merely','might','mightn\'t','mine','minus','miss','more','moreover','most','mostly','mr','mrs','much','must','mustn\'t','my','myself','n','name','namely','nd','near','nearly','necessary','need','needn\'t','needs','neither','never','neverf','neverless','nevertheless','new','next','nine','ninety','no','nobody','non','none','nonetheless','noone','no-one','nor','normally','not','nothing','notwithstanding','novel','now','nowhere','o','obviously','of','off','often','oh','ok','okay','old','on','once','one','ones','one\'s','only','onto','opposite','or','other','others','otherwise','ought','oughtn\'t','our','ours','ourselves','out','outside','over','overall','own','p','particular','particularly','past','per','perhaps','placed','please','plus','possible','presumably','probably','provided','provides','q','que','quite','qv','r','rather','rd','re','really','reasonably','recent','recently','regarding','regardless','regards','relatively','respectively','right','round','s','said','same','saw','say','saying','says','second','secondly','see','seeing','seem','seemed','seeming','seems','seen','self','selves','sensible','sent','serious','seriously','seven','several','shall','shan\'t','she','she\'d','she\'ll','she\'s','should','shouldn\'t','since','six','so','some','somebody','someday','somehow','someone','something','sometime','sometimes','somewhat','somewhere','soon','sorry','specified','specify','specifying','still','sub','such','sup','sure','t','take','taken','taking','tell','tends','th','than','thank','thanks','thanx','that','that\'ll','thats','that\'s','that\'ve','the','their','theirs','them','themselves','then','thence','there','thereafter','thereby','there\'d','therefore','therein','there\'ll','there\'re','theres','there\'s','thereupon','there\'ve','these','they','they\'d','they\'ll','they\'re','they\'ve','thing','things','think','third','thirty','this','thorough','thoroughly','those','though','three','through','throughout','thru','thus','till','to','together','too','took','toward','towards','tried','tries','truly','try','trying','t\'s','twice','two','u','un','under','underneath','undoing','unfortunately','unless','unlike','unlikely','until','unto','up','upon','upwards','us','use','used','useful','uses','using','usually','v','value','various','versus','very','via','viz','vs','w','want','wants','was','wasn\'t','way','we','we\'d','welcome','well','we\'ll','went','were','we\'re','weren\'t','we\'ve','what','whatever','what\'ll','what\'s','what\'ve','when','whence','whenever','where','whereafter','whereas','whereby','wherein','where\'s','whereupon','wherever','whether','which','whichever','while','whilst','whither','who','who\'d','whoever','whole','who\'ll','whom','whomever','who\'s','whose','why','will','willing','wish','with','within','without','wonder','won\'t','would','wouldn\'t','x','y','yes','yet','you','you\'d','you\'ll','your','you\'re','yours','yourself','yourselves','you\'ve','z','zero' );
return preg_replace( '/\b(' . implode( '|', $common_words ) . ')\b/', '', $str );
}
/**
* Search array by key and value.
*
* @param array $array Array to search.
* @param string $key Array key to search.
* @param mixed $value Value of key supplied.
* @return array
* @since 4.0.0
*/
function ap_search_array( $array, $key, $value ) {
$results = array();
if ( is_array( $array ) ) {
if ( isset( $array[ $key ] ) && $array[ $key ] == $value ) {
$results[] = $array;
}
foreach ( $array as $subarray ) {
$results = array_merge( $results, ap_search_array( $subarray, $key, $value ) );
}
}
return $results;
}
/**
* Get all AnsPress add-ons data.
*
* @since 4.0.0
* @return array
*/
function ap_get_addons() {
$cache = wp_cache_get( 'addons', 'anspress' );
$option = get_option( 'anspress_addons', [] );
if ( false !== $cache ) {
return $cache;
}
$all_files = [];
foreach ( [ 'pro', 'free' ] as $folder ) {
$path = ANSPRESS_ADDONS_DIR . DS . $folder;
if ( file_exists( $path ) ) {
$files = scandir( $path );
foreach ( $files as $file ) {
$ext = pathinfo( $file, PATHINFO_EXTENSION );
if ( 'php' === $ext ) {
$all_files[] = $folder . DS . $file;
}
}
}
}
$all_files = apply_filters( 'ap_addon_files', $all_files );
$addons = [];
foreach ( (array) $all_files as $file ) {
if ( is_array( $file ) ) {
$id = $file['name'];
$path = $file['path'];
} else {
$id = wp_normalize_path( $file );
$path = ANSPRESS_ADDONS_DIR . DS . $file;
}
$data = get_file_data( $path, array(
'name' => 'Addon Name',
'addonuri' => 'Addon URI',
'description' => 'Description',
'author' => 'Author',
'authoruri' => 'Author URI',
'pro' => 'Pro',
) );
$data['pro'] = 'yes' === strtolower( $data['pro'] ) ? true : false;
$data['path'] = wp_normalize_path( $path );
$data['active'] = isset( $option[ $id ] ) ? true : false;
$data['id'] = $id;
if ( ! empty( $data['name'] ) ) {
$addons[ $id ] = $data;
}
}
wp_cache_set( 'addons', $addons, 'anspress' );
return $addons;
}
/**
* Return all active addons.
*
* @return array
* @since 4.0.0
*/
function ap_get_active_addons() {
$active_addons = [];
foreach ( ap_get_addons() as $addon ) {
if ( $addon['active'] ) {
$active_addons[ $addon['id'] ] = $addon;
}
}
return $active_addons;
}
/**
* Activate an addon and trigger addon activation hook.
*
* @param string $addon_name Addon file name.
* @return boolean
*/
function ap_activate_addon( $addon_name ) {
if ( ap_is_addon_active( $addon_name ) ) {
return false;
}
global $ap_addons_activation;
$opt = get_option( 'anspress_addons', [] );
$all_addons = ap_get_addons();
$addon_name = wp_normalize_path( $addon_name );
if ( isset( $all_addons[ $addon_name ] ) ) {
$opt[ $addon_name ] = true;
update_option( 'anspress_addons', $opt );
require_once $all_addons[ $addon_name ]['path'];
if ( isset( $ap_addons_activation[ $addon_name ] ) ) {
call_user_func( $ap_addons_activation[ $addon_name ] );
}
do_action( 'ap_addon_activated', $addon_name );
return true;
}
return false;
}
/**
* Deactivate addons.
*
* @param string $addon_name Addons file name.
* @return boolean
*/
function ap_deactivate_addon( $addon_name ) {
if ( ! ap_is_addon_active( $addon_name ) ) {
return false;
}
$opt = get_option( 'anspress_addons', [] );
$all_addons = ap_get_addons();
$addon_name = wp_normalize_path( $addon_name );
if ( isset( $all_addons[ $addon_name ] ) ) {
unset( $opt[ $addon_name ] );
update_option( 'anspress_addons', $opt );
do_action( 'ap_addon_deactivated', $addon_name );
return true;
}
return false;
}
/**
* Check if addon is active.
*
* @param string $addon Addon file name without path.
* @return boolean
* @since 4.0.0
*/
function ap_is_addon_active( $addon ) {
$addons = ap_get_active_addons();
if ( isset( $addons[ $addon ] ) ) {
return true;
}
return false;
}
/**
* Trigger question and answer update hooks.
*
* @param object $_post Post object.
* @param string $event Event name.
* @since 4.0.0
*/
function ap_trigger_qa_update_hook( $_post, $event ) {
$_post = ap_get_post( $_post );
// Check if post type is question or answer.
if ( ! in_array( $_post->post_type, [ 'question', 'answer' ], true ) ) {
return;
}
/**
* Triggered right after updating question/answer.
*
* @param object $_post Inserted post object.
* @since 0.9
*/
do_action( 'ap_after_update_' . $_post->post_type, $_post, $event );
}
/**
* Find item in in child array.
*
* @param mixed $needle Needle to find.
* @param mixed $haystack Haystack.
* @param boolean $strict Strict match.
* @return boolean
*/
function ap_in_array_r( $needle, $haystack, $strict = false ) {
foreach ( $haystack as $item ) {
if ( ( $strict ? $item === $needle : $item == $needle ) || (is_array( $item ) && in_array_r( $needle, $item, $strict )) ) {
return true;
}
}
return false;
}
/**
* Return short link to a item.
*/
function ap_get_short_link( $args ) {
$base = ap_get_link_to( 'shortlink' );
return add_query_arg( $args, $base );
}
/**
* Register a callback function which triggred
* after activating an addon.
*
* @param string $addon Name of addon.
* @param string|array $cb Callback function name.
* @since 4.0.0
*/
function ap_addon_activation_hook( $addon, $cb ) {
global $ap_addons_activation;
$addon = wp_normalize_path( $addon );
$ap_addons_activation[ $addon ] = $cb;
}
/**
* Insert a value or key/value pair after a specific key in an array. If key doesn't exist, value is appended
* to the end of the array.
*
* @param array $array
* @param string $key
* @param array $new
*
* @return array
*/
function ap_array_insert_after( $array = [], $key, $new ) {
$keys = array_keys( $array );
$index = array_search( $key, $keys );
$pos = false === $index ? count( $array ) : $index + 1;
return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) );
}