array( 'single' => true, 'sanitize_callback' => __NAMESPACE__ . '\sanitize_description', 'show_in_rest' => true, 'context' => array( 'create', 'update' ), 'php_filter' => FILTER_UNSAFE_RAW, ), 'org-name' => array( 'single' => true, 'sanitize_callback' => 'sanitize_text_field', 'show_in_rest' => true, 'context' => array( 'create', 'update' ), 'php_filter' => FILTER_UNSAFE_RAW, ), 'org-url' => array( 'single' => true, 'sanitize_callback' => 'esc_url_raw', 'show_in_rest' => true, 'context' => array( 'create', 'update' ), 'php_filter' => FILTER_VALIDATE_URL, ), 'org-pledge-email' => array( 'single' => true, 'sanitize_callback' => 'sanitize_email', 'show_in_rest' => false, 'context' => array( 'create' ), 'php_filter' => FILTER_VALIDATE_EMAIL, ), ); $generated = array( 'org-domain' => array( 'single' => true, 'sanitize_callback' => 'sanitize_text_field', 'show_in_rest' => false, ), 'pledge-email-confirmed' => array( 'single' => true, 'sanitize_callback' => 'wp_validate_boolean', 'show_in_rest' => false, ), 'pledge-confirmed-contributors' => array( 'single' => true, 'sanitize_callback' => 'absint', 'show_in_rest' => false, ), 'pledge-total-hours' => array( 'single' => true, 'sanitize_callback' => 'absint', 'show_in_rest' => false, ), ); switch ( $subset ) { case 'user_input': $return = $user_input; break; case 'generated': $return = $generated; break; default: $return = array_merge( $user_input, $generated ); break; } return $return; } /** * Sanitize description fields. * * @param string $insecure * * @return string */ function sanitize_description( $insecure ) { $secure = wp_kses_data( $insecure ); $secure = wp_unslash( wp_rel_nofollow( $secure ) ); return $secure; } /** * Register post meta keys for the custom post type. * * @return void */ function register_pledge_meta() { $meta = get_pledge_meta_config(); foreach ( $meta as $key => $args ) { $meta_key = META_PREFIX . $key; register_post_meta( Pledge\CPT_ID, $meta_key, $args ); } } /** * Schedule cron jobs. * * This needs to run on the `init` action, because Cavalcade isn't fully loaded before that, and events * wouldn't be scheduled. * * @see https://dotorg.trac.wordpress.org/changeset/15351/ */ function schedule_cron_jobs() { if ( ! wp_next_scheduled( 'update_all_cached_pledge_data' ) ) { wp_schedule_event( time(), 'hourly', 'update_all_cached_pledge_data' ); } } /** * Regularly update the cached data for all pledges. * * Outside of this cron job, it's only updated when a contributor post changes status, but it's possible for * a contributor to edit their profile's # of hours at any time. If we didn't regularly check and update it, * then it could be permanently out of date. */ function update_all_cached_pledge_data() { $pledges = get_posts( array( 'post_type' => Pledge\CPT_ID, 'post_status' => 'publish', 'numberposts' => 1000, ) ); foreach ( $pledges as $pledge ) { update_single_cached_pledge_data( $pledge->ID ); } } /** * Adds meta boxes for the custom post type. * * @return void */ function add_meta_boxes() { add_meta_box( 'pledge-email', __( 'Pledge Email', 'wporg-5ftf' ), __NAMESPACE__ . '\render_meta_boxes', Pledge\CPT_ID, 'normal', 'high' ); add_meta_box( 'org-info', __( 'Organization Information', 'wporg-5ftf' ), __NAMESPACE__ . '\render_meta_boxes', Pledge\CPT_ID, 'normal', 'high' ); add_meta_box( 'pledge-contributors', __( 'Contributors', 'wporg-5ftf' ), __NAMESPACE__ . '\render_meta_boxes', Pledge\CPT_ID, 'normal', 'high' ); } /** * Builds the markup for all meta boxes * * @param WP_Post $pledge * @param array $box */ function render_meta_boxes( $pledge, $box ) { $readonly = ( ! current_user_can( 'edit_page', $pledge->ID ) || Pledge\DEACTIVE_STATUS === $pledge->post_status ); $is_manage = true; $pledge_id = $pledge->ID; $data = array(); foreach ( get_pledge_meta_config() as $key => $config ) { $data[ $key ] = get_post_meta( $pledge->ID, META_PREFIX . $key, $config['single'] ); } $contributors = Contributor\get_pledge_contributors_data( $pledge->ID ); echo '
%s
field does not have a value.', 'wporg-5ftf' ),
sanitize_key( $key )
)
);
} elseif ( false === $submission[ $key ] ) {
$error->add(
'required_field_invalid',
sprintf(
__( 'The %s
field has an invalid value.', 'wporg-5ftf' ),
sanitize_key( $key )
)
);
}
}
if ( ! empty( $error->get_error_messages() ) ) {
return $error;
}
return true;
}
/**
* Get the metadata for a given pledge, or a default set if no pledge is provided.
*
* @param int $pledge_id Pledge to fetch data from.
* @param string $subset Optional. The part of the config to return: 'user_input', 'generated', or 'all'.
*
* @return array Pledge data
*/
function get_pledge_meta( $pledge_id = 0, $subset = '' ) {
// Get existing pledge, if it exists.
$pledge = get_post( $pledge_id );
$keys = get_pledge_meta_config( $subset );
$meta = array();
// Get POST'd submission, if it exists.
$submission = PledgeForm\get_form_submission();
if ( isset( $submission['empty_post'] ) && $submission['empty_post'] ) {
$submission = array();
}
foreach ( $keys as $key => $config ) {
if ( isset( $submission[ $key ] ) ) {
$meta[ $key ] = $submission[ $key ];
} elseif ( $pledge instanceof WP_Post ) {
$meta_key = META_PREFIX . $key;
$meta[ $key ] = get_post_meta( $pledge->ID, $meta_key, true );
} else {
$meta[ $key ] = $config['default'] ?: '';
}
}
return $meta;
}
/**
* Isolate the domain from a given URL and remove the `www.` if necessary.
*
* @param string $url
*
* @return string
*/
function get_normalized_domain_from_url( $url ) {
$domain = wp_parse_url( $url, PHP_URL_HOST );
$domain = preg_replace( '#^www\.#', '', $domain );
return $domain;
}
/**
* Enqueue CSS file for admin page.
*
* @return void
*/
function enqueue_assets() {
wp_register_style(
'5ftf-admin',
plugins_url( 'assets/css/admin.css', __DIR__ ),
array(),
filemtime( FiveForTheFuture\PATH . '/assets/css/admin.css' )
);
wp_register_script(
'5ftf-admin',
plugins_url( 'assets/js/admin.js', __DIR__ ),
array( 'jquery', 'wp-util' ),
filemtime( FiveForTheFuture\PATH . '/assets/js/admin.js' ),
true
);
$pledge_id = is_admin() ? get_the_ID() : absint( $_REQUEST['pledge_id'] ?? 0 );
$auth_token = sanitize_text_field( $_REQUEST['auth_token'] ?? '' );
$script_data = array(
// The global ajaxurl is not set on the frontend.
'ajaxurl' => admin_url( 'admin-ajax.php', 'relative' ),
'pledgeId' => $pledge_id,
'manageNonce' => wp_create_nonce( 'manage-contributors' ),
'authToken' => $auth_token,
'removePrompt' => __( 'Are you sure you want to remove this pledge?', 'wporg-5ftf' ),
);
wp_add_inline_script(
'5ftf-admin',
sprintf(
'var FiveForTheFuture = JSON.parse( decodeURIComponent( \'%s\' ) );',
rawurlencode( wp_json_encode( $script_data ) )
),
'before'
);
if ( is_admin() ) {
$current_page = get_current_screen();
if ( Pledge\CPT_ID === $current_page->id ) {
wp_enqueue_style( '5ftf-admin' );
wp_enqueue_script( '5ftf-admin' );
}
} else {
global $post;
if ( is_a( $post, 'WP_Post' ) ) {
$pledge_id = absint( $_REQUEST['pledge_id'] ?? 0 );
$auth_token = sanitize_text_field( $_REQUEST['auth_token'] ?? '' );
$can_manage = Auth\can_manage_pledge( $pledge_id, $auth_token );
if ( ! is_wp_error( $can_manage ) && has_shortcode( $post->post_content, '5ftf_pledge_form_manage' ) ) {
wp_enqueue_script( '5ftf-admin' );
}
}
}
}