Ejemplo n.º 1
0
 /**
  * Runs activation function and sets up default WP options for new blog,
  * a.k.a. when a registered user creates a new blog
  *
  * @param int $blog_id
  * @param int $user_id
  *
  * @see add_action( 'wpmu_new_blog', ... )
  */
 function wpmuNewBlog($blog_id, $user_id)
 {
     $this->blog_id = (int) $blog_id;
     $this->user_id = (int) $user_id;
     switch_to_blog($this->blog_id);
     if (!$this->isBookSetup()) {
         $this->wpmuActivate();
         array_walk($this->opts, function ($v, $k) {
             if (empty($v)) {
                 delete_option($k);
             } else {
                 update_option($k, $v);
             }
         });
     }
     // Set current metadata version to skip redundant upgrade routines
     update_option('pressbooks_metadata_version', \PressBooks\Metadata::$currentVersion);
     flush_rewrite_rules(false);
     do_action('pressbooks_new_blog');
     restore_current_blog();
     if (is_user_logged_in()) {
         (new \PressBooks\Catalog())->deleteCache();
         \PressBooks\Redirect\location(get_admin_url($this->blog_id));
     }
 }
Ejemplo n.º 2
0
/**
 * Force the user to edit custom-css posts in our custom editor.
 */
function redirect_css_editor()
{
    $post_id = absint(@$_REQUEST['post']);
    if (!$post_id) {
        return;
    }
    // Do nothing
    $post = get_post($post_id);
    if (!$post) {
        return;
    }
    // Do nothing
    if ('custom-css' != $post->post_type) {
        return;
    }
    // Do nothing
    $redirect_url = get_bloginfo('url') . '/wp-admin/themes.php?page=pb_custom_css&slug=' . $post->post_name;
    \PressBooks\Redirect\location($redirect_url);
}
Ejemplo n.º 3
0
 /**
  * Add Book by URL
  */
 static function formAddByUrl()
 {
     check_admin_referer('bulk-books');
     // Nonce auto-generated by WP_List_Table
     $catalog = new static();
     $user_id = $catalog->getUserId();
     // Set Redirect URL
     if (get_current_user_id() != $user_id) {
         $redirect_url = get_bloginfo('url') . '/wp-admin/index.php?page=pb_catalog&user_id=' . $user_id;
     } else {
         $redirect_url = get_bloginfo('url') . '/wp-admin/index.php?page=pb_catalog';
     }
     $url = parse_url(\PressBooks\Sanitize\canonicalize_url($_REQUEST['add_book_by_url']));
     $main = parse_url(network_site_url());
     if (strpos($url['host'], $main['host']) === false) {
         $_SESSION['pb_errors'][] = __('Invalid URL.', 'pressbooks');
         \PressBooks\Redirect\location($redirect_url);
     }
     if ($url['host'] == $main['host']) {
         // Get slug using the path
         $slug = str_replace($main['path'], '', $url['path']);
         $slug = trim($slug, '/');
         $slug = explode('/', $slug);
         $slug = $slug[0];
     } else {
         // Get slug using host
         $slug = str_replace($main['host'], '', $url['host']);
         $slug = trim($slug, '.');
         $slug = explode('.', $slug);
         $slug = $slug[0];
     }
     $book_id = get_id_from_blogname($slug);
     if (!$book_id) {
         $_SESSION['pb_errors'][] = __('No book found.', 'pressbooks');
         \PressBooks\Redirect\location($redirect_url);
     }
     //		if ( ! get_blog_option( $book_id, 'blog_public' ) ) {
     //			$_SESSION['pb_errors'][] = __( 'Book is not public', 'pressbooks' );
     //			\PressBooks\Redirect\location( $redirect_url );
     //		}
     $catalog->saveBook($book_id, array());
     $catalog->deleteCache();
     // Ok!
     $_SESSION['pb_notices'][] = __('Settings saved.');
     // Redirect back to form
     \PressBooks\Redirect\location($redirect_url);
 }
Ejemplo n.º 4
0
 /**
  * Catch form submissions
  *
  * @see pressbooks/admin/templates/import.php
  */
 public static function formSubmit()
 {
     // --------------------------------------------------------------------------------------------------------
     // Sanity check
     if (false == static::isFormSubmission() || false == current_user_can('edit_posts')) {
         // Don't do anything in this function, bail.
         return;
     }
     // --------------------------------------------------------------------------------------------------------
     // Determine at what stage of the import we are and do something about it
     $redirect_url = get_bloginfo('url') . '/wp-admin/tools.php?page=pb_import';
     $current_import = get_option('pressbooks_current_import');
     // Revoke
     if (@$_GET['revoke'] && check_admin_referer('pb-revoke-import')) {
         self::revokeCurrentImport();
         \PressBooks\Redirect\location($redirect_url);
     }
     if (@$_GET['import'] && is_array(@$_POST['chapters']) && is_array($current_import) && isset($current_import['file']) && check_admin_referer('pb-import')) {
         // --------------------------------------------------------------------------------------------------------
         // Do Import
         @set_time_limit(300);
         $ok = false;
         switch ($current_import['type_of']) {
             case 'epub':
                 $importer = new Epub\Epub201();
                 $ok = $importer->import($current_import);
                 break;
             case 'wxr':
                 $importer = new Wordpress\Wxr();
                 $ok = $importer->import($current_import);
                 break;
             case 'odt':
                 $importer = new Odf\Odt();
                 $ok = $importer->import($current_import);
                 break;
             case 'docx':
                 $importer = new Ooxml\Docx();
                 $ok = $importer->import($current_import);
                 break;
             case 'html':
                 $importer = new Html\Xhtml();
                 $ok = $importer->import($current_import);
         }
         $msg = "Tried to import a file of type {$current_import['type_of']} and ";
         $msg .= $ok ? 'succeeded :)' : 'failed :(';
         self::log($msg, $current_import);
         if ($ok) {
             // Success! Redirect to organize page
             $success_url = get_bloginfo('url') . '/wp-admin/admin.php?page=pressbooks';
             \PressBooks\Redirect\location($success_url);
         }
     } elseif (@$_GET['import'] && !@empty($_FILES['import_file']['name']) && @$_POST['type_of'] && check_admin_referer('pb-import')) {
         // --------------------------------------------------------------------------------------------------------
         // Set the 'pressbooks_current_import' option
         $allowed_file_types = array('epub' => 'application/epub+zip', 'xml' => 'application/xml', 'odt' => 'application/vnd.oasis.opendocument.text', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
         $overrides = array('test_form' => false, 'mimes' => $allowed_file_types);
         if (!function_exists('wp_handle_upload')) {
             require_once ABSPATH . 'wp-admin/includes/file.php';
         }
         $upload = wp_handle_upload($_FILES['import_file'], $overrides);
         if (!empty($upload['error'])) {
             // Error, redirect back to form
             $_SESSION['pb_notices'][] = $upload['error'];
             \PressBooks\Redirect\location($redirect_url);
         }
         $ok = false;
         switch ($_POST['type_of']) {
             case 'wxr':
                 $importer = new Wordpress\Wxr();
                 $ok = $importer->setCurrentImportOption($upload);
                 break;
             case 'epub':
                 $importer = new Epub\Epub201();
                 $ok = $importer->setCurrentImportOption($upload);
                 break;
             case 'odt':
                 $importer = new Odf\Odt();
                 $ok = $importer->setCurrentImportOption($upload);
                 break;
             case 'docx':
                 $importer = new Ooxml\Docx();
                 $ok = $importer->setCurrentImportOption($upload);
                 break;
         }
         $msg = "Tried to upload a file of type {$_POST['type_of']} and ";
         $msg .= $ok ? 'succeeded :)' : 'failed :(';
         self::log($msg, $upload);
         if (!$ok) {
             // Not ok?
             $_SESSION['pb_errors'][] = sprintf(__('Your file does not appear to be a valid %s.', 'pressbooks'), strtoupper($_POST['type_of']));
             unlink($upload['file']);
         }
     } elseif (@$_GET['import'] && @$_POST['type_of'] === 'html' && check_admin_referer('pb-import')) {
         // check if it's a valid url
         if (false == filter_var($_POST['import_html'], FILTER_VALIDATE_URL)) {
             $_SESSION['pb_errors'][] = __('Your URL does not appear to be valid', 'pressbooks');
             \PressBooks\Redirect\location($redirect_url);
         }
         // HEAD request, check for a valid response from server
         $remote_head = wp_remote_head($_POST['import_html']);
         // Something failed
         if (is_wp_error($remote_head)) {
             error_log('\\PressBooks\\Import::formSubmit html import error, wp_remote_head()' . $remote_head->get_error_message());
             $_SESSION['pb_errors'][] = $remote_head->get_error_message();
             \PressBooks\Redirect\location($redirect_url);
         }
         // weebly.com (and likely some others) prevent HEAD requests, but allow GET requests
         if (200 !== $remote_head['response']['code'] && 405 !== $remote_head['response']['code']) {
             $_SESSION['pb_errors'][] = __('The website you are attempting to reach is not returning a successful response header on a HEAD request: ' . $remote_head['response']['code'], 'pressbooks');
             \PressBooks\Redirect\location($redirect_url);
         }
         // ensure the media type is HTML (not JSON, or something we can't deal with)
         if (false === strpos($remote_head['headers']['content-type'], 'text/html') && false === strpos($remote_head['headers']['content-type'], 'application/xhtml+xml')) {
             $_SESSION['pb_errors'][] = __('The website you are attempting to reach is not returning HTML content', 'pressbooks');
             \PressBooks\Redirect\location($redirect_url);
         }
         // GET http request
         $body = wp_remote_get($_POST['import_html']);
         // check for wp error
         if (is_wp_error($body)) {
             $error_message = $body->get_error_message();
             error_log('\\PressBooks\\Import::formSubmit error, import_html' . $error_message);
             $_SESSION['pb_errors'][] = $error_message;
             \PressBooks\Redirect\location($redirect_url);
         }
         // check for a successful response code on GET request
         if (200 !== $body['response']['code']) {
             $_SESSION['pb_errors'][] = __('The website you are attempting to reach is not returning a successful response on a GET request: ' . $body['response']['code'], 'pressbooks');
             \PressBooks\Redirect\location($redirect_url);
         }
         // add our url
         $body['url'] = $_POST['import_html'];
         $importer = new Html\Xhtml();
         $ok = $importer->setCurrentImportOption($body);
         $msg = "Tried to upload a file of type {$_POST['type_of']} and ";
         $msg .= $ok ? 'succeeded :)' : 'failed :(';
         self::log($msg, $body['headers']);
         if (!$ok) {
             // Not ok?
             $_SESSION['pb_errors'][] = sprintf(__('Your file does not appear to be a valid %s.', 'pressbooks'), strtoupper($_POST['type_of']));
         }
     }
     // Default, back to form
     \PressBooks\Redirect\location($redirect_url);
 }
Ejemplo n.º 5
0
function restrict_access()
{
    global $wpdb;
    $user = wp_get_current_user();
    $restricted = $wpdb->get_results('SELECT * FROM wp_sitemeta WHERE meta_key = "pressbooks_network_managers"');
    if ($restricted) {
        $restricted = maybe_unserialize($restricted[0]->meta_value);
    } else {
        $restricted = array();
    }
    $check_against_url = parse_url((is_ssl() ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], PHP_URL_PATH);
    $redirect_url = get_site_url() . '/wp-admin/network/';
    // ---------------------------------------------------------------------------------------------------------------
    // Don't let user go to any of these pages, under any circumstances
    $restricted_urls = array('themes', 'theme-(install|editor)', 'plugins', 'plugin-(install|editor)', 'settings', 'update-core');
    $expr = '~/wp-admin/network/(' . implode('|', $restricted_urls) . ')\\.php$~';
    if (in_array($user->ID, $restricted) && preg_match($expr, $check_against_url)) {
        \PressBooks\Redirect\location($redirect_url);
    }
}
	/**
	 * Uses v1/api to get an array of public books from a PB instance
	 * 
	 * @param string $endpoint API url
	 * @return array of books
	 * [2] => Array(
	 * 	[title] => Brad can has book
	 * 	[author] => Brad Payne
	 * 	[license] => cc-by-sa
	 *  )
	 *  [5] => Array(
	 * 	[title] => Help, I'm a Book!
	 * 	[author] => Frank Zappa
	 * 	[license] => cc-by-nc-sa
	 *  )
	 */
	static function getPublicBooks( $endpoint, $search = '' ) {
		$books = array();
		$current_book = get_current_blog_id();
		$domain = parse_url( $endpoint, PHP_URL_HOST );
		$titles = ( ! empty( $search ) ) ? '?titles=' . $search : '';

		// build the url, get list of public books
		$public_books = wp_remote_get( $endpoint . 'books' . '/' . $titles );

		if ( is_wp_error( $public_books ) ) {
			error_log( '\PBT\Search\getPublicBooks error: ' . $public_books->get_error_message() );
			\PressBooks\Redirect\location( get_bloginfo( 'url' ) . '/wp-admin/admin.php?page=api_search_import' );
		}

		$public_books_array = json_decode( $public_books['body'], true );

		// something goes wrong at the API level/response
		if ( 0 == $public_books_array['success'] ) {
			return;
		}

		// a valid response
		if ( false !== ( $public_books_array ) ) {
			foreach ( $public_books_array['data'] as $id => $val ) {
				$books[$id] = array(
				    'title' => $public_books_array['data'][$id]['book_meta']['pb_title'],
				    'author' => $public_books_array['data'][$id]['book_meta']['pb_author'],
				    'license' => $public_books_array['data'][$id]['book_meta']['pb_book_license'],
				    'domain' => $domain,
				);
			}
		}

		// don't return results from the book where the search is happening, only if searching this instance of PB
		if ( isset( $books[$current_book] ) && $endpoint == network_home_url() ) {
			unset( $books[$current_book] );
		}

		// cache public books for 12 hours
		set_transient( 'pbt-public-books-' . $domain, $books, 43200 );

		return $books;
	}
Ejemplo n.º 7
0
 /**
  * Catch form submissions
  *
  * @see pressbooks/admin/templates/export.php
  */
 static function formSubmit()
 {
     if (false == static::isFormSubmission() || false == current_user_can('edit_posts')) {
         // Don't do anything in this function, bail.
         return;
     }
     // Set locale to UTF8 so escapeshellcmd() doesn't strip valid characters.
     setlocale(LC_CTYPE, 'UTF8', 'en_US.UTF-8');
     putenv('LC_CTYPE=en_US.UTF-8');
     // Download
     if (!empty($_GET['download_export_file'])) {
         $filename = sanitize_file_name($_GET['download_export_file']);
         static::downloadExportFile($filename);
     }
     // Delete
     if (isset($_POST['delete_export_file']) && isset($_POST['filename']) && check_admin_referer('pb-delete-export')) {
         $filename = sanitize_file_name($_POST['filename']);
         $path = static::getExportFolder();
         unlink($path . $filename);
         delete_transient('dirsize_cache');
         /** @see get_dirsize() */
         \PressBooks\Redirect\location(get_bloginfo('url') . '/wp-admin/admin.php?page=pb_export');
     }
     // Export
     if ('yes' == @$_GET['export'] && is_array(@$_POST['export_formats']) && check_admin_referer('pb-export')) {
         // --------------------------------------------------------------------------------------------------------
         // Define modules
         $x = $_POST['export_formats'];
         $modules = array();
         if (isset($x['pdf'])) {
             $modules[] = '\\PressBooks\\Export\\Prince\\Pdf';
         }
         if (isset($x['mpdf'])) {
             $modules[] = '\\PressBooks\\Export\\Mpdf\\Pdf';
         }
         if (isset($x['epub'])) {
             $modules[] = '\\PressBooks\\Export\\Epub\\Epub201';
             // Must be set before MOBI
         }
         if (isset($x['epub3'])) {
             $modules[] = '\\PressBooks\\Export\\Epub3\\Epub3';
             // Must be set before MOBI
         }
         if (isset($x['mobi'])) {
             if (!isset($x['epub'])) {
                 // Make sure Epub source file is generated
                 $modules[] = '\\PressBooks\\Export\\Epub\\Epub201';
                 // Must be set before MOBI
             }
             $modules[] = '\\PressBooks\\Export\\Mobi\\Kindlegen';
             // Must be set after EPUB
         }
         if (isset($x['icml'])) {
             $modules[] = '\\PressBooks\\Export\\InDesign\\Icml';
         }
         if (isset($x['xhtml'])) {
             $modules[] = '\\PressBooks\\Export\\Xhtml\\Xhtml11';
         }
         if (isset($x['wxr'])) {
             $modules[] = '\\PressBooks\\Export\\WordPress\\Wxr';
         }
         if (isset($x['vanillawxr'])) {
             $modules[] = '\\PressBooks\\Export\\WordPress\\VanillaWxr';
         }
         if (isset($x['odt'])) {
             $modules[] = '\\PressBooks\\Export\\Odt\\Odt';
         }
         // --------------------------------------------------------------------------------------------------------
         // Clear cache? Range is 1 hour.
         $last_export = get_option('pressbooks_last_export');
         $within_range = time() - $last_export;
         if ($within_range > 60 * 60) {
             \PressBooks\Book::deleteBookObjectCache();
             update_option('pressbooks_last_export', time());
         }
         // --------------------------------------------------------------------------------------------------------
         // Do Export
         @set_time_limit(300);
         $redirect_url = get_bloginfo('url') . '/wp-admin/admin.php?page=pb_export';
         $conversion_error = array();
         $validation_warning = array();
         $outputs = array();
         foreach ($modules as $module) {
             /** @var \PressBooks\Export\Export $exporter */
             $exporter = new $module(array());
             if (!$exporter->convert()) {
                 $conversion_error[$module] = $exporter->getOutputPath();
             } else {
                 if (!$exporter->validate()) {
                     $validation_warning[$module] = $exporter->getOutputPath();
                 }
             }
             // Add to outputs array
             $outputs[$module] = $exporter->getOutputPath();
             // Stats hook
             do_action('pressbooks_track_export', substr(strrchr($module, '\\'), 1));
         }
         delete_transient('dirsize_cache');
         /** @see get_dirsize() */
         // --------------------------------------------------------------------------------------------------------
         // MOBI cleanup
         if (isset($x['mobi']) && !isset($x['epub'])) {
             unlink($outputs['\\PressBooks\\Export\\Epub\\Epub201']);
         }
         // --------------------------------------------------------------------------------------------------------
         // No errors?
         if (empty($conversion_error) && empty($validation_warning)) {
             // Ok!
             \PressBooks\Redirect\location($redirect_url);
         }
         // --------------------------------------------------------------------------------------------------------
         // Error exceptions
         if (isset($validation_warning['\\PressBooks\\Export\\Prince\\Pdf'])) {
             // The PDF is garbage and we don't want the user to have it.
             // Delete file. Report error instead of warning.
             unlink($validation_warning['\\PressBooks\\Export\\Prince\\Pdf']);
             $conversion_error['\\PressBooks\\Export\\Prince\\Pdf'] = $validation_warning['\\PressBooks\\Export\\Prince\\Pdf'];
             unset($validation_warning['\\PressBooks\\Export\\Prince\\Pdf']);
         }
         // --------------------------------------------------------------------------------------------------------
         // Errors :(
         if (count($conversion_error)) {
             // Conversion error
             \PressBooks\Redirect\location($redirect_url . '&export_error=true');
         }
         if (count($validation_warning)) {
             // Validation warning
             \PressBooks\Redirect\location($redirect_url . '&export_warning=true');
         }
     }
 }
	/**
	 *  Imports user selected chapters from an instance of PB 
	 * 
	 * @param array $chapters
	 * Array(
	  [5] => Array(
	    [222] => chapter
	    )
	  [14] => Array(
	    [164] => front-matter
	    )
	  )
	 * @return type
	 */
	function import( array $chapters ) {

		$this->chapters = $chapters;

		$chapters_to_import = $this->getChapters();

		libxml_use_internal_errors( true );

		foreach ( $chapters_to_import as $new_post ) {

			// Load HTMl snippet into DOMDocument using UTF-8 hack
			$utf8_hack = '<?xml version="1.0" encoding="UTF-8"?>';
			$doc = new \DOMDocument();
			$doc->loadHTML( $utf8_hack . $new_post['post_content'] );

			// Download images, change image paths
			$doc = $this->scrapeAndKneadImages( $doc );

			$html = $doc->saveXML( $doc->documentElement );

			// Remove auto-created <html> <body> and <!DOCTYPE> tags.
			$html = preg_replace( '/^<!DOCTYPE.+?>/', '', str_replace( array( '<html>', '</html>', '<body>', '</body>' ), array( '', '', '', '' ), $html ) );

			$import_post = array(
			    'post_title' => $new_post['post_title'],
			    'post_content' => $html,
			    'post_type' => $new_post['post_type'],
			    'post_status' => $new_post['post_status'],
			);

			// set post parent	
			if ( 'chapter' == $new_post['post_type'] ) {
				$post_parent = $this->getChapterParent();
				$import_post['post_parent'] = $post_parent;
			}

			// woot, woot!
			$pid = wp_insert_post( $import_post );

			// check for errors, redirect and record 
			if ( is_wp_error( $pid ) ) {
				error_log( '\PBT\Import\PBImport()->import error at `wp_insert_post()`: ' . $pid->get_error_message() );
				\PBT\Search\ApiSearch::revokeCurrentImport();
				\PressBooks\Redirect\location( get_bloginfo( 'url' ) . '/wp-admin/admin.php?page=api_search_import' );
			}

			// set post metadata
			$this->setPostMeta( $pid, $new_post );

			\PressBooks\Book::consolidatePost( $pid, get_post( $pid ) );
		}

		return \PBT\Search\ApiSearch::revokeCurrentImport();
	}
Ejemplo n.º 9
0
/**
 * Redirect away from (what we consider) bad WordPress admin pages
 */
function redirect_away_from_bad_urls()
{
    if (is_super_admin()) {
        return;
    }
    // Do nothing
    $check_against_url = parse_url((is_ssl() ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], PHP_URL_PATH);
    $redirect_url = get_site_url(get_current_blog_id(), '/wp-admin/');
    // ---------------------------------------------------------------------------------------------------------------
    // If user is on post-new.php, check for valid post_type
    if (preg_match('~/wp-admin/post-new\\.php$~', $check_against_url)) {
        if (!in_array(@$_REQUEST['post_type'], \PressBooks\PostType\list_post_types())) {
            $_SESSION['pb_notices'][] = __('Unsupported post type.', 'pressbooks');
            \PressBooks\Redirect\location($redirect_url);
        }
    }
    // ---------------------------------------------------------------------------------------------------------------
    // Don't let user go to any of these pages, under any circumstance
    $restricted = array('edit-tags', 'export', 'import', 'link-(manager|add)', 'nav-menus', 'options-(discussion|media|permalink|reading|writing)', 'plugin-(install|editor)', 'plugins', 'theme-editor', 'update-core', 'widgets');
    // Todo: Fine grained control over: options-general.php
    $expr = '~/wp-admin/(' . implode('|', $restricted) . ')\\.php$~';
    if (preg_match($expr, $check_against_url)) {
        $_SESSION['pb_notices'][] = __('You do not have sufficient permissions to access that URL.', 'pressbooks');
        \PressBooks\Redirect\location($redirect_url);
    }
}
Ejemplo n.º 10
0
 /**
  * Save custom CSS to database (and filesystem)
  *
  * @see pressbooks/templates/admin/custom-css.php
  */
 static function formSubmit()
 {
     if (false == static::isFormSubmission() || false == current_user_can('edit_theme_options')) {
         // Don't do anything in this function, bail.
         return;
     }
     // Process form
     if ('yes' == @$_GET['customcss'] && isset($_POST['my_custom_css']) && check_admin_referer('pb-custom-css')) {
         $slug = isset($_POST['slug']) ? $_POST['slug'] : 'web';
         $redirect_url = get_bloginfo('url') . '/wp-admin/themes.php?page=pb_custom_css&slug=' . $slug;
         if (@$_POST['post_id_integrity'] != md5(NONCE_KEY . @$_POST['post_id'])) {
             // A hacker trying to overwrite posts?.
             error_log('\\PressBooks\\CustomCss::formSubmit error: unexpected value for post_id_integrity');
             \PressBooks\Redirect\location($redirect_url . '&customcss_error=true');
         }
         // Write to database
         $my_post = array('ID' => absint($_POST['post_id']), 'post_content' => static::cleanupCss($_POST['my_custom_css']));
         $response = wp_update_post($my_post, true);
         if (is_wp_error($response)) {
             // Something went wrong?
             error_log('\\PressBooks\\CustomCss::formSubmit error, wp_update_post(): ' . $response->get_error_message());
             \PressBooks\Redirect\location($redirect_url . '&customcss_error=true');
         }
         // Write to file
         $my_post['post_content'] = stripslashes($my_post['post_content']);
         // We purposely send \\A0 to WordPress, but we want to send \A0 to the file system
         $filename = static::getCustomCssFolder() . sanitize_file_name($slug . '.css');
         file_put_contents($filename, $my_post['post_content']);
         // Update "version"
         update_option('pressbooks_last_custom_css', time());
         // Ok!
         \PressBooks\Redirect\location($redirect_url);
     }
 }