post_type = constant( 'Advanced_Ads::POST_TYPE_SLUG' ); add_filter( 'gettext', array( $this, 'replace_cheating_message' ), 20, 2 ); } /** * Return an instance of this class. * * @return object A single instance of this class. */ public static function get_instance() { // If the single instance hasn't been set, set it now. if ( null == self::$instance ) { self::$instance = new self; } return self::$instance; } /** * add heading for extra column of ads list * remove the date column * * @since 1.3.3 * @param arr $columns */ public function ad_list_columns_head( $columns ){ $new_columns = array(); if( is_array( $columns ) ){ foreach( $columns as $key => $value ) { $new_columns[ $key ] = $value; if ( $key == 'title' ){ $new_columns[ 'ad_details' ] = __( 'Ad Details', 'advanced-ads' ); $new_columns[ 'ad_timing' ] = __( 'Ad Planning', 'advanced-ads' ); $new_columns[ 'ad_shortcode' ] = __( 'Ad Shortcode', 'advanced-ads' ); } } } else { $new_columns[ 'ad_details' ] = __( 'Ad Details', 'advanced-ads' ); $new_columns[ 'ad_timing' ] = __( 'Ad Planning', 'advanced-ads' ); $new_columns[ 'ad_shortcode' ] = __( 'Ad Shortcode', 'advanced-ads' ); } // white-listed columns $whitelist = apply_filters( 'advanced-ads-ad-list-allowed-columns', array( 'cb', // checkbox 'title', 'ad_details', 'ad_timing', 'ad_shortcode', 'taxonomy-advanced_ads_groups', ) ); // remove non-white-listed columns foreach( $new_columns as $_key => $_value ){ if( ! in_array( $_key, $whitelist ) ){ unset( $new_columns[ $_key ] ); } } return $new_columns; } /** * display ad details in ads list * * @since 1.3.3 * @param string $column_name name of the column * @param int $ad_id id of the ad */ public function ad_list_columns_content($column_name, $ad_id) { if ( $column_name == 'ad_details' ) { $ad = new Advanced_Ads_Ad( $ad_id ); // load ad type title $types = Advanced_Ads::get_instance()->ad_types; $type = ( ! empty($types[$ad->type]->title)) ? $types[$ad->type]->title : 0; // load ad size $size = 0; if ( ! empty($ad->width) || ! empty($ad->height) ) { $size = sprintf( '%d x %d', $ad->width, $ad->height ); } $size = apply_filters( 'advanced-ads-list-ad-size', $size, $ad ); include ADVADS_BASE_PATH . 'admin/views/ad-list-details-column.php'; } } /** * display ad details in ads list * * @since 1.6.11 * @param string $column_name name of the column * @param int $ad_id id of the ad */ public function ad_list_columns_timing($column_name, $ad_id) { if ( $column_name == 'ad_timing' ) { $ad = new Advanced_Ads_Ad( $ad_id ); $expiry = false; $post_future = false; $post_start = get_post_time('U', true, $ad->id ); $html_classes = 'advads-filter-timing'; $expiry_date_format = get_option( 'date_format' ). ', ' . get_option( 'time_format' ); if( isset( $ad->expiry_date ) && $ad->expiry_date ){ $html_classes .= ' advads-filter-any-exp-date'; $expiry = $ad->expiry_date; if( $ad->expiry_date < time() ){ $html_classes .= ' advads-filter-expired'; } } if( $post_start > time() ){ $post_future = $post_start; $html_classes .= ' advads-filter-future'; } ob_start(); do_action_ref_array( 'advanced-ads-ad-list-timing-column-after', array( $ad, &$html_classes ) ); $content_after = ob_get_clean(); include ADVADS_BASE_PATH . 'admin/views/ad-list-timing-column.php'; } } /** * display ad shortcode in ads list * * @since 1.8.2 * @param string $column_name name of the column * @param int $ad_id id of the ad */ public function ad_list_columns_shortcode($column_name, $ad_id) { if ( $column_name == 'ad_shortcode' ) { $ad = new Advanced_Ads_Ad( $ad_id ); include ADVADS_BASE_PATH . 'admin/views/ad-list-shortcode-column.php'; } } /** * display ad shortcode in ads list * * @since 1.10.5 * @param array $hidden An array of columns hidden by default. * @param WP_Screen $screen WP_Screen object of the current screen. */ public function hide_ad_list_columns( $hidden, $screen ) { if( isset( $screen->id ) && 'edit-' . Advanced_Ads::POST_TYPE_SLUG === $screen->id ){ $hidden[] = 'ad_shortcode'; } return $hidden; } /** * adds filter dropdowns before the 'Filter' button on the ad list table */ public function ad_list_add_filters() { $screen = get_current_screen(); if ( ! isset( $screen->id ) || $screen->id !== 'edit-advanced_ads' ) { return; } include ADVADS_BASE_PATH . 'admin/views/ad-list-filters.php'; } /** * edit ad bulk update messages * * @since 1.4.7 * @param arr $messages existing bulk update messages * @param arr $counts numbers of updated ads * @return arr $messages * * @see wp-admin/edit.php */ public function ad_bulk_update_messages(array $messages, array $counts){ $post = get_post(); $messages[Advanced_Ads::POST_TYPE_SLUG] = array( 'updated' => _n( '%s ad updated.', '%s ads updated.', $counts['updated'], 'advanced-ads' ), 'locked' => _n( '%s ad not updated, somebody is editing it.', '%s ads not updated, somebody is editing them.', $counts['locked'], 'advanced-ads' ), 'deleted' => _n( '%s ad permanently deleted.', '%s ads permanently deleted.', $counts['deleted'], 'advanced-ads' ), 'trashed' => _n( '%s ad moved to the Trash.', '%s ads moved to the Trash.', $counts['trashed'], 'advanced-ads' ), 'untrashed' => _n( '%s ad restored from the Trash.', '%s ads restored from the Trash.', $counts['untrashed'], 'advanced-ads' ), ); return $messages; } /** * order ads by title on ads list * * @since 1.3.18 * @param arr $vars array with request vars */ public function ad_list_request($vars){ // order ads by title on ads list if ( is_admin() && empty( $vars['orderby'] ) && isset( $vars['post_type'] ) && $this->post_type == $vars['post_type'] ) { $vars = array_merge( $vars, array( 'orderby' => 'title', 'order' => 'ASC' ) ); } return $vars; } /** * show instructions to create first ad above the ad list * * @return type */ public function no_ads_yet_notice(){ $screen = get_current_screen(); if ( ! isset( $screen->id ) || $screen->id !== 'edit-advanced_ads' ) { return; } // get number of ads $existing_ads = Advanced_Ads::get_number_of_ads(); // only display if there are no more than 2 ads if( 3 > $existing_ads ){ echo '
'; include ADVADS_BASE_PATH . 'admin/views/ad-list-no-ads.php'; echo '
'; } } /** * prepare the ad post type to be saved * * @since 1.0.0 * @param int $post_id id of the post * @todo handling this more dynamic based on ad type */ public function save_ad($post_id) { if ( ! current_user_can( Advanced_Ads_Plugin::user_cap( 'advanced_ads_edit_ads') ) // only use for ads, no other post type || ! isset($_POST['post_type']) || $this->post_type != $_POST['post_type'] || ! isset($_POST['advanced_ad']['type']) || wp_is_post_revision( $post_id ) ) { return; } // get ad object $ad = new Advanced_Ads_Ad( $post_id ); if ( ! $ad instanceof Advanced_Ads_Ad ) { return; } // filter to allow change of submitted ad settings $_POST['advanced_ad'] = apply_filters( 'advanced-ads-ad-settings-pre-save', $_POST['advanced_ad'] ); $ad->type = $_POST['advanced_ad']['type']; /** * deprecated since introduction of "visitors" in 1.5.4 */ if ( isset($_POST['advanced_ad']['visitor']) ) { $ad->set_option( 'visitor', $_POST['advanced_ad']['visitor'] ); } else { $ad->set_option( 'visitor', array() ); } // visitor conditions if ( isset($_POST['advanced_ad']['visitors']) ) { $ad->set_option( 'visitors', $_POST['advanced_ad']['visitors'] ); } else { $ad->set_option( 'visitors', array() ); } $ad->url = 0; if ( isset($_POST['advanced_ad']['url']) ) { // May contain placeholders added by the tracking add-on. $ad->url = trim( $_POST['advanced_ad']['url'] ); } // save size $ad->width = 0; if ( isset($_POST['advanced_ad']['width']) ) { $ad->width = absint( $_POST['advanced_ad']['width'] ); } $ad->height = 0; if ( isset($_POST['advanced_ad']['height']) ) { $ad->height = absint( $_POST['advanced_ad']['height'] ); } if ( ! empty($_POST['advanced_ad']['description']) ) { $ad->description = esc_textarea( $_POST['advanced_ad']['description'] ); } else { $ad->description = ''; } if ( ! empty($_POST['advanced_ad']['content']) ) { $ad->content = $_POST['advanced_ad']['content']; } else { $ad->content = ''; } $output = isset( $_POST['advanced_ad']['output'] ) ? $_POST['advanced_ad']['output'] : array(); // Find Advanced Ads shortcodes. if ( ! empty( $output['allow_shortcodes'] ) ) { $shortcode_pattern = get_shortcode_regex( array( 'the_ad', 'the_ad_group', 'the_ad_placement' ) ); $output['has_shortcode'] = preg_match( '/' . $shortcode_pattern . '/s', $ad->content ); } // Set output. $ad->set_option( 'output', $output ); if ( ! empty($_POST['advanced_ad']['conditions']) ){ $ad->conditions = $_POST['advanced_ad']['conditions']; } else { $ad->conditions = array(); } // prepare expiry date if ( isset($_POST['advanced_ad']['expiry_date']['enabled']) ) { $year = absint( $_POST['advanced_ad']['expiry_date']['year'] ); $month = absint( $_POST['advanced_ad']['expiry_date']['month'] ); $day = absint( $_POST['advanced_ad']['expiry_date']['day'] ); $hour = absint( $_POST['advanced_ad']['expiry_date']['hour'] ); $minute = absint( $_POST['advanced_ad']['expiry_date']['minute'] ); $expiration_date = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $year, $month, $day, $hour, $minute, '00' ); $valid_date = wp_checkdate( $month, $day, $year, $expiration_date ); if ( !$valid_date ) { $ad->expiry_date = 0; } else { $_gmDate = date_create( $expiration_date, Advanced_Ads_Admin::get_wp_timezone() ); $_gmDate->setTimezone( new DateTimeZone( 'UTC' ) ); $gmDate = $_gmDate->format( 'Y-m-d-H-i' ); list( $year, $month, $day, $hour, $minute ) = explode( '-', $gmDate ); $ad->expiry_date = gmmktime($hour, $minute, 0, $month, $day, $year); } } else { $ad->expiry_date = 0; } $image_id = ( isset( $_POST['advanced_ad']['output']['image_id'] ) ) ? absint( $_POST['advanced_ad']['output']['image_id'] ) : 0; if ( $image_id ) { $attachment = get_post( $image_id ); if ( $attachment && 0 === $attachment->post_parent ) { wp_update_post( array( 'ID' => $image_id, 'post_parent' => $post_id ) ); } } $ad->save(); } /** * prepare the ad post type to be removed * * @param int $post_id id of the post */ public function delete_ad( $post_id ) { global $wpdb; if ( ! current_user_can( 'delete_posts' ) ) { return; } if ( $post_id > 0 ) { $post_type = get_post_type( $post_id ); if ( $post_type == $this->post_type ) { $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %d", '_advanced-ads_parent_id', $post_id ) ); } } } /** * add information above the ad title * * @since 1.5.6 * @param obj $post */ public function edit_form_above_title($post){ if ( ! isset($post->post_type) || $post->post_type != $this->post_type ) { return; } // highlight Dummy ad if this is the first ad if( ! Advanced_Ads::get_number_of_ads() ){ ?>ID ); $placement_types = Advanced_Ads_Placements::get_placement_types(); $placements = Advanced_Ads::get_ad_placements_array(); // -TODO use model // display general and wizard information include ADVADS_BASE_PATH . 'admin/views/ad-info-top.php'; // display ad injection information include ADVADS_BASE_PATH . 'admin/views/placement-injection-top.php'; } /** * add information about the ad below the ad title * * @since 1.1.0 * @param obj $post */ public function edit_form_below_title($post){ if ( ! isset($post->post_type) || $post->post_type != $this->post_type ) { return; } $ad = new Advanced_Ads_Ad( $post->ID ); include ADVADS_BASE_PATH . 'admin/views/ad-info.php'; } /** * add information below the ad edit form * * @since 1.7.3 * @param obj $post */ public function edit_form_end($post){ if ( ! isset($post->post_type) || $post->post_type != $this->post_type ) { return; } include ADVADS_BASE_PATH . 'admin/views/ad-info-bottom.php'; } /** * add meta values below submit box * * @since 1.3.15 */ public function add_submit_box_meta(){ global $post, $wp_locale; if ( $post->post_type !== Advanced_Ads::POST_TYPE_SLUG ) { return; } $ad = new Advanced_Ads_Ad( $post->ID ); // get time set for ad or current timestamp (both GMT) $utc_ts = $ad->expiry_date ? $ad->expiry_date : time(); $utc_time = date_create( '@' . $utc_ts ); $tz_option = get_option( 'timezone_string' ); $exp_time = clone $utc_time; if ( $tz_option ) { $exp_time->setTimezone( Advanced_Ads_Admin::get_wp_timezone() ); } else { $tz_name = Advanced_Ads_Admin::timezone_get_name( Advanced_Ads_Admin::get_wp_timezone() ); $tz_offset = substr( $tz_name, 3 ); $off_time = date_create( $utc_time->format( 'Y-m-d\TH:i:s' ) . $tz_offset ); $offset_in_sec = date_offset_get( $off_time ); $exp_time = date_create( '@' . ( $utc_ts + $offset_in_sec ) ); } list( $curr_year, $curr_month, $curr_day, $curr_hour, $curr_minute ) = explode( '-', $exp_time->format( 'Y-m-d-H-i' ) ); $enabled = 1 - empty($ad->expiry_date); include ADVADS_BASE_PATH . 'admin/views/ad-submitbox-meta.php'; } /** * use CodeMirror for plain text input field * * needs WordPress 4.9 and higher * * @since 1.8.15 */ public function use_code_editor(){ global $wp_version; if ( 'advanced_ads' !== get_current_screen()->id || defined( 'ADVANCED_ADS_DISABLE_CODE_HIGHLIGHTING' ) || -1 === version_compare( $wp_version, '4.9' ) ) { return; } // Enqueue code editor and settings for manipulating HTML. $settings = wp_enqueue_code_editor( array( 'type' => 'application/x-httpd-php' ) ); // Bail if user disabled CodeMirror. if ( false === $settings ) { return; } wp_add_inline_script( 'code-editor', sprintf( 'jQuery( function() { if( jQuery( "#advads-ad-content-plain" ).length && typeof Advanced_Ads_Admin !== "undefined" ){ Advanced_Ads_Admin.editor = wp.codeEditor.initialize( "advads-ad-content-plain", %s ); Advanced_Ads_Admin.editor.codemirror.on("keyup", Advanced_Ads_Admin.check_ad_source); jQuery( function() { Advanced_Ads_Admin.check_ad_source(); } ); } } );', wp_json_encode( $settings ) ) ); } /** * edit ad update messages * * @since 1.4.7 * @param arr $messages existing post update messages * @return arr $messages * * @see wp-admin/edit-form-advanced.php */ public function ad_update_messages($messages = array()){ $post = get_post(); // added to hide error message caused by third party code that uses post_updated_messages filter wrong if( ! is_array( $messages )){ return $messages; } $messages[Advanced_Ads::POST_TYPE_SLUG] = array( 0 => '', // Unused. Messages start at index 1. 1 => __( 'Ad updated.', 'advanced-ads' ), 4 => __( 'Ad updated.', 'advanced-ads' ), /* translators: %s: date and time of the revision */ 5 => isset( $_GET['revision'] ) ? sprintf( __( 'Ad restored to revision from %s', 'advanced-ads' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, 6 => __( 'Ad saved.', 'advanced-ads' ), // published 7 => __( 'Ad saved.', 'advanced-ads' ), // saved 8 => __( 'Ad submitted.', 'advanced-ads' ), 9 => sprintf( __( 'Ad scheduled for: %1$s.', 'advanced-ads' ), // translators: Publish box date format, see http://php.net/date date_i18n( __( 'M j, Y @ G:i', 'advanced-ads' ), strtotime( $post->post_date ) ) ), 10 => __( 'Ad draft updated.', 'advanced-ads' ) ); return $messages; } /** * whether to show the wizard welcome message or not * * @since 1.7.4 * @return bool true, if wizard welcome message should be displayed */ public function show_wizard_welcome(){ $user_id = get_current_user_id(); if( ! $user_id ) { return true; } $hide_wizard = get_user_meta( $user_id, 'advanced-ads-hide-wizard', true ); global $post; return ( ! $hide_wizard && 'edit' !== $post->filter ) ? true : false; } /** * whether to start the wizard by default or not * * @since 1.7.4 * return bool true, if wizard should start automatically */ public function start_wizard_automatically(){ $user_id = get_current_user_id(); if( ! $user_id ) { return true; } $hide_wizard = get_user_meta( $user_id, 'advanced-ads-hide-wizard', true ); global $post; // true if the wizard was never started or closed return ( ( ! $hide_wizard && 'edit' !== $post->filter ) || 'false'=== $hide_wizard ) ? true : false; } /** * Check if an ad is not valid for 'Post Content' placement * * @param obj $ad Advanced_Ads_Ad object * @return string with error if not valid, empty string if valid */ public static function check_ad_dom_is_not_valid( Advanced_Ads_Ad $ad ) { $adContent = ( isset( $ad->content ) ) ? $ad->content : ''; if ( ! extension_loaded( 'dom' ) || ! $adContent ) { return false; } $wpCharset = get_bloginfo('charset'); $adDom = new DOMDocument('1.0', $wpCharset); $libxml_previous_state = libxml_use_internal_errors( true ); // clear existing errors libxml_clear_errors(); // source for this regex: http://stackoverflow.com/questions/17852537/preg-replace-only-specific-part-of-string $adContent = preg_replace('#(document.write.+)loadHtml('' . $adContent); $errors = ''; foreach( libxml_get_errors() as $_error ) { // continue, if there is '&' symbol, but not HTML entity if ( false === stripos( $_error->message, 'htmlParseEntityRef:' ) ) { $errors .= print_r( $_error, true ); } } libxml_use_internal_errors( $libxml_previous_state ); return $errors; } /** * Replace 'You need a higher level of permission.' message if user role does not have required permissions. * * @param string $translation Translated text. * @param string $text Text to translate. * @return string $translation Translated text. */ public function replace_cheating_message( $translated_text, $untranslated_text ) { global $typenow; if ( isset( $typenow ) && $untranslated_text === 'You need a higher level of permission.' && $typenow === $this->post_type ) { $translated_text = __( 'You don’t have access to ads. Please deactivate and re-enable Advanced Ads again to fix this.', 'advanced-ads' ) . ' ' . __( 'Get help', 'advanced-ads' ) . ''; } return $translated_text; } }