Internalize get_theme_mod CSS Into Stylesheet?

This code adds custom CSS selections from the theme customizer. What I hate about this code is that it outputs the style tags directly into the site’s html, rather than tacking the selections onto my stylesheet or placing them in a separate stylesheet – which makes for bad coding.

Is there a way to tack this CSS onto the end of the theme’s internal style.css or generate a new stylesheet to place it in? (Or maybe this is a bad idea?)

function mytheme_customize_css()
{
    ?>
         <style type="text/css">
             html, body, .container { background:<?php echo get_theme_mod('primary_color', '#000000'); ?>; }
         </style>
    <?php
}
add_action( 'wp_head', 'mytheme_customize_css');

Solutions Collecting From Web of "Internalize get_theme_mod CSS Into Stylesheet?"

I think is possible following this workflow:

  1. add an action to 'updated_option' hook to see when the theme mods are updated, and when it happen run a function that

    1. get the content of style.css as a string using file_get_contents
    2. get your customization and append them to the style.css string
    3. write a the new string in a new css file, saving it in an accessible folder, maybe in a subdir of uploas folder (that should be writable by WordPress) using file_put_contents
    4. if something goes wrong on file operations (it can always happen) use code in OP as fallback
  2. filter 'stylesheet_uri' hook to return the url of customized file if it exists

  3. In your theme be sure that the stylesheet is included using get_stylesheet_uri()

So point #1 code:

add_action( 'updated_option', function( $option ) {
  $theme = get_option( 'stylesheet' );
  if ( $option === "theme_mods_{$theme}" ) {
    my_update_stylesheet();
  }
});

function my_update_stylesheet() {
  $css = @file_get_contents( get_template_directory() . '/style.css' );
  if ( ! $css ) { // if we can't read file use your function in OP as fallback
    add_action( 'wp_head', 'mytheme_customize_css');
  }
  $color = get_theme_mod('primary_color', '#000000');
  $css .= PHP_EOL . sprintf( 'html, body, .container { background:%s; }', $color );
  $upload = wp_upload_dir(); 
  $path = $upload['basedir'] . '/thememod';
  if ( ! is_dir( $path ) ) {
     wp_mkdir_p( $path );
  }
  $newfile = @file_put_contents( $path . '/style.css', $css );
  if ( ! $newfile ) { // if we can't write file use your function in OP as fallback
    add_action( 'wp_head', 'mytheme_customize_css');
  }
}

And point #2

add_filter( 'stylesheet_uri', function( $uri ) {
  $upload = wp_upload_dir(); 
  if ( file_exists( $upload['basedir'] . '/thememod/style.css' ) ) {
    $uri = $upload['baseurl'] . '/thememod/style.css';
  }
  return $uri;
});