'invoice', PostTypes::EASY_INVOICE_QUOTE_POST_TYPE => 'quote' ]; if ( ! isset( $types[ $post->post_type ] ) ) { return; } if ( self::isStaff() ) { return; } /** * Filter whether this request counts as the client viewing the document. * * @param bool $record Default true. * @param \WP_Post $post The document. */ if ( ! apply_filters( 'easy_invoice_record_document_view', true, $post ) ) { return; } self::record( (int) $post->ID, $types[ $post->post_type ] ); } /** * Write the view. * * @param int $document_id Post id. * @param string $type 'invoice' or 'quote'. * @return void */ public static function record( int $document_id, string $type ): void { $now = current_time( 'mysql' ); $first = (string) get_post_meta( $document_id, self::META_FIRST, true ); $count = (int) get_post_meta( $document_id, self::META_COUNT, true ); if ( '' === $first ) { update_post_meta( $document_id, self::META_FIRST, $now ); } update_post_meta( $document_id, self::META_LAST, $now ); update_post_meta( $document_id, self::META_COUNT, $count + 1 ); update_post_meta( $document_id, self::META_IP, self::anonymisedIp() ); /** * Fires when a client views an invoice or quote. * * @param int $document_id Post id. * @param string $type 'invoice' or 'quote'. * @param bool $first_view True the first time. */ do_action( 'easy_invoice_document_viewed', $document_id, $type, '' === $first ); } /** * View summary for display. * * @param int $document_id Post id. * @return array{first:string,last:string,count:int,from:string} */ public static function summary( int $document_id ): array { return [ 'first' => (string) get_post_meta( $document_id, self::META_FIRST, true ), 'last' => (string) get_post_meta( $document_id, self::META_LAST, true ), 'count' => (int) get_post_meta( $document_id, self::META_COUNT, true ), 'from' => (string) get_post_meta( $document_id, self::META_IP, true ), ]; } /** * Short human label: "Viewed 3× · 2 hours ago" or "Not viewed yet". * * @param int $document_id Post id. * @return string */ public static function label( int $document_id ): string { $s = self::summary( $document_id ); if ( 0 === $s['count'] || '' === $s['last'] ) { return __( 'Not viewed yet', 'easy-invoice' ); } $ago = human_time_diff( strtotime( $s['last'] ), current_time( 'timestamp' ) ); return 1 === $s['count'] /* translators: %s: how long ago. */ ? sprintf( __( 'Viewed %s ago', 'easy-invoice' ), $ago ) /* translators: %1$d: number of views; %2$s: how long ago. */ : sprintf( __( 'Viewed %1$d× · last %2$s ago', 'easy-invoice' ), $s['count'], $ago ); } /** * Is the current user someone who works on invoices rather than pays them? * * @return bool */ private static function isStaff(): bool { if ( ! is_user_logged_in() ) { return false; } if ( current_user_can( 'manage_options' ) ) { return true; } return function_exists( 'easy_invoice_user_can' ) && easy_invoice_user_can( 'ei_view_invoices' ); } /** * The viewer's IP with the host part removed. * * @return string */ private static function anonymisedIp(): string { $ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : ''; if ( '' === $ip ) { return ''; } if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) { $parts = explode( '.', $ip ); $parts[3] = '0'; return implode( '.', $parts ); } if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) { $packed = inet_pton( $ip ); if ( false !== $packed ) { return (string) inet_ntop( substr( $packed, 0, 8 ) . str_repeat( "\0", 8 ) ); } } return ''; } }